I have c++ and c# codes.
When I run my code, I want c++ codes calculate a value and my c# take the value and use it.
The value will change in c++, while running. And c# will take it.
c++ codes (simple):
int main()
{
int x;
void (int a); //calculate x and return x
}
how can I do this?
I tried with dll or I tried within adding reference. didn't work.
what should write in c# for getting x value?
edit: I'm trying to do like this:
NativeLib.h:
#ifndef _NATIVELIB_H_
#define _NATIVELIB_H_
#ifndef MYAPI
#define MYAPI
#endif
#ifdef __cplusplus
extern "C" {
#endif
//MYAPI void print_line(const char* str);
MYAPI void print_line(const int a);
#ifdef __cplusplus
}
#endif
#endif // _NATIVELIB_H_
NativeLib.cpp:
#include "NativeLib.h"
#include <stdio.h>
int x = 10;
MYAPI void print_line(const int a) {
int a = x;
}
c# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace PInvokeTest {
class Program {
static void Main(string[] args) {
print_line(a);
}
[DllImport("NativeLib.dll")]
private static extern void print_line(int a);
}
}
why do I get error?
Related
I'm trying to set up a test project to figure out how to correctly wrap a native C++ lib in a managed C++ DLL, to then be called by a C# application.
For my test case I have 3 application:
CPP lib
I compile a library with a class containing four functions.
1) return a double value
2) return a string
3) take a double by reference, modify it.
4) take a string by reference, modify it.
cpp_lib.h
namespace cpp_lib
{
class CPPLibFunctions{
public:
CPPLibFunctions();
public:
static double getValue();
static void incrementValue(double& val);
static std::string getText();
static void changeText(std::string& txt);
};
}
cpp_lib.cpp
#include "cpp_lib.h"
#include <stdexcept>
namespace cpp_lib{
CPPLibFunctions::CPPLibFunctions(){};
double CPPLibFunctions::getValue(){
return 5.5;
}
void CPPLibFunctions::incrementValue(double& val){
val += 1.0;
}
std::string CPPLibFunctions::getText(){
return "success";
}
void CPPLibFunctions::changeText(std::string& txt){
txt += "_123";
}
}
Managed CPP lib
This is a managed C++ project compiled to a DLL, which wraps the functions from cpp_lib.
managed_cpp_lib.h
#include "cpp_lib.h"
#pragma once
#include <msclr\marshal_cppstd.h>
using namespace System;
namespace managed_cpp_lib {
System::String^ stdToSysString(std::string str){
return gcnew System::String(str.c_str());
}
public ref class ManagedCppFunctions
{
private:
cpp_lib::CPPLibFunctions * cppLibFunctions;
public:
ManagedCppFunctions(){
cppLibFunctions = new cpp_lib::CPPLibFunctions();
}
double getValue(){
return cppLibFunctions->getValue();
}
void incrementValue(double& val){
cppLibFunctions->incrementValue(val);
}
System::String^ getText(){
return stdToSysString(cppLibFunctions->getText());
}
void changeText(System::String^ txt){
//this does not work:
std::string txtstd = msclr::interop::marshal_as<std::string>(txt);
cppLibFunctions->changeText(txtstd);
txt = stdToSysString(txtstd);
}
};
}
csharp_app
Lastly, cssharp_app is a C# console application, which references managed_cpp_lib, and calls the functions.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using managed_cpp_lib;
namespace csharp_app
{
class Program
{
static void Main(string[] args)
{
managed_cpp_lib.ManagedCppFunctions managedCppFunctions = new managed_cpp_lib.ManagedCppFunctions();
//works:
double val = managedCppFunctions.getValue();
Console.WriteLine("\managedCppFunctions.getValue() = {0}", val);
//works:
string txt = managedCppFunctions.getText();
Console.WriteLine("\managedCppFunctions.getText() = {0}", txt);
//does not work:
/*managedCppFunctions.incrementValue(val);
Console.WriteLine("\managedCppFunctions.incrementValue(val) = {0}", val);*/
//the string is not modified:
managedCppFunctions.changeText(txt);
Console.WriteLine("\managedCppFunctions.changeText(txt) = {0}", txt);
Console.WriteLine("...");
}
}
}
The output of csharp_app is:
managedCppFunctions.getValue() = 5.5
managedCppFunctions.getText() = success
managedCppFunctions.changeText(txt) = success
So managedCppFunctions.getValue() and managedCppFunctions.getText() works.
managedCppFunctions.changeText(txt) does not modify the content of the string.
I'm not sure how to implement managedCppFunctions.incrementValue(val).
What is the correct way to pass a double and a string by reference, to then change their values using managed C++ and C#?
I'm making messaging system with C library.
To send messages from C library (DLL), I made this DLL file and tried to callback from C to C#
here is C DLL Code
logging.h
#pragma once
#include <stdio.h>
struct loggingMessage {
void (*fp)(char *, int, int);
};
struct loggingMessage messageConfig;
__declspec(dllexport) void loggingInitialize();
__declspec(dllexport) void print();
__declspec(dllexport) void setEventCallBack(void(*fp)(char *, int, int));
logging.c
void loggingInitialize()
{
messageConfig.fp = NULL;
}
void print(char *str, int length)
{
char buf[1024];
memset(buf, 0, sizeof(char) * 1024);
sprintf(buf, "%s", str);
if (messageConfig.fp != NULL)
{
messageConfig.fp(buf, length, 0);
}
}
void setEventCallBack(void (*fp)(char *buf, int length, int debugLevel))
{
messageConfig.fp = fp;
char str[512] = "stringTmp";
fp(str, 1, 0);
fp(str, 1, 1);
fp(str, 1, 2);
fp(str, 1, 3);
}
Program.cs in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
delegate void EventCallback(string _input, int length, int level);
namespace console
{
class Program
{
[DllImport("logging.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void print();
[DllImport("logging.dll")]
public static extern void setEventCallBack(EventCallback fp);
[DllImport("logging.dll")]
public static extern void loggingInitialize();
public static void update(string _input, int length, int level)
{
Console.WriteLine("Message : {0} Length {1} Level {2}", _input, length , level);
}
static void Main(string[] args)
{
loggingInitialize();
setEventCallBack(update);
}
}
}
And in console I could see the message, but there was a error about function pointer.
I didn't understand what error was and I wonder how to debug and how to set parameters, pointers between C# and C.
You have declared your DllImport statements as CallingConvention = CallingConvention.StdCall however in your C code you declared them as __declspec, you need to use CallingConvention = CallingConvention.Cdecl instead on all of the imports (the default if you don't specify is CallingConvention.Winapi which maps to StdCall on most platforms).
I have written the following C++ shared library:
#include "iostream"
#if defined(_WIN32) || defined(_WIN64)
#define Q_DECL_EXPORT __declspec(dllexport)
#define Q_DECL_IMPORT __declspec(dllimport)
#else
#define Q_DECL_EXPORT
#define Q_DECL_IMPORT
#endif
#ifdef MATINCHESS_LIBRARY
# define MATINCHESS_API Q_DECL_EXPORT
#else
# define MATINCHESS_API Q_DECL_IMPORT
#endif
using namespace std;
string* memory;
extern "C"
{
MATINCHESS_API void Initialize();
MATINCHESS_API void Uninitialize();
MATINCHESS_API void Put(string text);
MATINCHESS_API string Get();
void Initialize()
{
memory = new string;
}
void Uninitialize()
{
delete memory;
}
void Put(string text)
{
memory->assign(text);
}
string Get()
{
return *memory;
}
}
And here is my C# console application:
using System;
using System.Runtime.InteropServices;
namespace MatinChess
{
class MainClass
{
const string MatinChessDLL = "libMatinChessDLL.so";
[DllImport(MatinChessDLL)]
public static extern void Initialize();
[DllImport(MatinChessDLL)]
public static extern void Uninitialize();
[DllImport(MatinChessDLL)]
public static extern void Put(string text);
[DllImport(MatinChessDLL)]
public static extern string Get();
public static void Main (string[] args)
{
Console.WriteLine ("Initializing...");
Initialize ();
Console.WriteLine ("Initialized");
Console.WriteLine ("Write: ");
Put (Console.ReadLine ());
Console.WriteLine ("Value is put.");
Console.WriteLine ("You wrote \"" + Get () + "\"");
Console.ReadKey ();
Console.WriteLine ("Uninitializing...");
Uninitialize ();
Console.WriteLine ("Uninitialized");
}
}
}
It safely initializes and puts the string from ReadLine, but when it wants to invoke Get method, it crashes with a long stack trace.
Please help me to find the issue.
You cannot marshal std::string from C++ to C#. You have to use a character buffer. See this question: Passing strings from C# to C++ dll and back -- minimal example
Here i created in DLL project in vc++ 2008. Following are two code files lib.h and lib.cpp.
lib.h
#include "stdafx.h";
class __declspec(dllexport) test
{
public:
test();
static void hello();
static void hello1();
};
class __declspec(dllexport) test1
{
public:
test1();
void hello_test1();
void hello1_test1();
};
lib.cpp
#include "stdafx.h"
#include "lib.h"
#include <stdio.h>
void test::hello()
{
printf("Hello");
}
void test::hello1()
{
printf("Hello1");
}
void test1::hello_test1()
{
printf("Hello_test1");
}
void test1::hello1_test1()
{
printf("Hello1_test1");
}
stdafx.h
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN
// Windows Header Files:
#include <windows.h>
dllMain.cpp
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I have written C# code to call the method of test and test1 classes:
ConsoleApp
[DllImport("lib.dll" )]
public static extern void hello();
[DllImport("lib.dll")]
public static extern void hello1();
[DllImport("lib.dll")]
public static extern void hello_test1();
[DllImport("lib.dll")]
public static extern void hello1_test1();
static void Main()
{
hello();
hello1();
hello_test1();
hello1_test1();
Console.ReadKey();
}
when i run above code i have got following error:
EntryPointNotFoundException: Unable to find an entry point named 'hello' in DLL 'lib.dll'
I know about how to call function only(without using Class) of vc++ DLL from C# but i don't know how to call method of any class and how to code that in proper way in vc++.
I know somewhere is mistake in my above code, please experts guide me about my mistake because i tried all from my side.
If anyone has full example like above then suggest me.
Thanks in advance..
As far as I'm aware there is no way to directly call a native class method from c#. The typical way to get around this is to make non-member functions that call the class methods and interact with those. Please refer to the following link for more specifics. It includes a direct example of what you are trying to do.
using a class defined in a c++ dll in c# code
After reading more of the answers it might be possible but it appears that the link shows the examples you are looking for.
#Jarrett Thanks for moving me towards to Marshal concept.
I added testClass.h and testClass.cpp in this project to marshal C++ classes
testClass.h
#ifndef __testClass_h__
#define __testClass_h__
#include "lib.h"
#ifdef __cplusplus
extern "C" {
#endif
extern LIBDLL_API test* createTestClass();
extern LIBDLL_API void disposeTestClass(test* pObject);
extern LIBDLL_API void callHello(test* pObject);
extern LIBDLL_API void callHelloTest1Class(test1* pObject);
#ifdef _cplusplus
#endif
}
#endif
testClass.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "stdafx.h"
#include "testClass.h"
extern "C" LIBDLL_API test* createTestClass()
{
return new test();
}
extern "C" LIBDLL_API void disposeTestClass(test* pObject)
{
if(pObject!=NULL)
{
delete pObject;
pObject=NULL;
}
}
extern "C" LIBDLL_API void callHello(test* pObject)
{
if(pObject!=NULL)
{
pObject->hello();
}
}
extern "C" LIBDLL_API void callHelloTest1Class(test1* pObject)
{
if(pObject!=NULL)
{
pObject->hello_test1();
}
}
lib.h
#include "stdafx.h";
#ifdef LIB_EXPORTS
#define LIBDLL_API __declspec(dllexport)
#else
#define LIBDLL_API __declspec(dllimport)
#endif
class LIBDLL_API test
{
public:
test();
virtual ~test();
static void hello();
static void hello1();
};
class LIBDLL_API test1
{
public:
test1();
void hello_test1();
void hello1_test1();
};
lib.cpp
#pragma once
#include "stdafx.h"
#include "lib.h"
#include <stdio.h>
#include <iostream>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
test::test()
{}
test::~test()
{}
void test::hello()
{
printf("\nHello");
}
void test::hello1()
{
printf("Hello1");
}
void test1::hello_test1()
{
printf("\nHello_test1");
}
void test1::hello1_test1()
{
printf("Hello1_test1");
}
And now create a console application and add some code in program.cs file
Program.cs
namespace ConsoleApplication1
{
class ConsoleApplication1
{
static void Main()
{
CS_Test_Class testClass = new CS_Test_Class();
testClass.hello();
testClass.hello_test1();
Console.ReadKey();
testClass.Dispose();
}
}
}
program.cs call the method of CS_Test_Class.cs So....
CS_Test_Class.cs
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
public class CS_Test_Class:IDisposable
{
[DllImport("lib.dll")]
public static extern IntPtr createTestClass();
[DllImport("lib.dll")]
static private extern void disposeTestClass(IntPtr pTestClassObject);
[DllImport("lib.dll")]
static private extern void callHello(IntPtr pTestClassObject);
[DllImport("lib.dll")]
static private extern void callHelloTest1Class(IntPtr pTestClassObject);
private IntPtr nativeObject;
public CS_Test_Class()
{
this.nativeObject = createTestClass();
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool bDisposing)
{
disposeTestClass(this.nativeObject);
this.nativeObject = IntPtr.Zero;
if (bDisposing)
GC.SuppressFinalize(this);
}
~CS_Test_Class()
{
Dispose(false);
}
public void hello()
{
callHello(this.nativeObject);
}
public void hello_test1()
{
callHelloTest1Class(this.nativeObject);
}
}
}
Marshling allows you to acces the class and method of c++ Dll. Microsoft provides facility to Marshal C-functions and also provides the mechanism to Marshal c++ clases.
Enjoy Marshling...
Thank you.
say I have a C++ library function for computing PI:
// pi.h:
#ifdef BUILDING_DLL
#define DLL_MACRO __declspec(dllexport)
#else
#define DLL_MACRO __declspec(dllimport)
#endif
namespace Cpp {
class PI {
public:
static double DLL_MACRO compute();
};
};
// pi.cpp:
#include "pi.h"
#include <cmath>
double
Cpp::PI::compute() {
// Leibnitz summation formulae:
double sum = 0.0;
for(long n = 0; n < 100*1000*1000; n++)
sum += 4.0*pow(-1.0, n)/(2*n + 1.0);
return sum;
}
I need to call this function from C#, and I want to use C++/CLI as a "bridge". However this C++ function is somewhat slow. Therefore the C# code calling this function need to get callbacks telling it how far the function has come in %.
The C# code might need some state, e.g. a progress bar, to deal with this info.
So the callbacks from C++ must enter into a member function on the C# side.
So I introduce:
// piCLI.h: The C++/CLI "bridge" between C# and C++
#include "pi.h"
#pragma once
namespace CLI {
public ref class PI abstract {
public:
double compute() {
return Cpp::PI::compute();
}
virtual void progress(int percentCompleted) = 0;
};
};
and
namespace CSharp
{
public class PI : CLI.PI
{
public override void progress(int percentCompleted)
{
System.Console.WriteLine(percentCompleted + "% completed.");
}
}
}
Now invoking CSharp.PI.compute() works fine :-). It forwards the call to Cpp::PI::compute() as intended.
But how do I get the C++ library to forward progress updates to CSharp.PI.progress() whilst Cpp::PI::compute() is running?
Thanks in advance for any answers!
I would take a function pointer/delegate approach as well:
// pi.h:
#pragma once
#ifndef DLL_MACRO
#ifdef BUILDING_DLL
#define DLL_MACRO __declspec(dllexport)
#else
#define DLL_MACRO __declspec(dllimport)
#endif
#endif
namespace Cpp {
typedef void (__stdcall *ComputeProgressCallback)(int);
class PI {
public:
static double DLL_MACRO compute(ComputeProgressCallback callback);
};
}
// pi.cpp:
#include "pi.h"
#include <cmath>
double Cpp::PI::compute(Cpp::ComputeProgressCallback callback) {
double sum = 0.;
for (long n = 0L; n != 100000000L; ++n) {
sum += 4. * std::pow(-1., n) / (2L * n + 1.);
callback(/*impl*/);
}
return sum;
}
// piCLI.h: The C++/CLI "bridge" between C# and C++
#pragma once
#include "pi.h"
namespace CLI {
public delegate void ComputeProgressDelegate(int percentCompleted);
public ref class PI abstract sealed {
public:
static double compute(ComputeProgressDelegate^ callback) {
using System::IntPtr;
using System::Runtime::InteropServices::Marshal;
IntPtr cbPtr = Marshal::GetFunctionPointerForDelegate(callback);
return Cpp::PI::compute(
static_cast<Cpp::ComputeProgressCallback>(cbPtr.ToPointer())
);
}
};
}
namespace CSharp {
public static class PI {
public static double compute() {
CLI.PI.compute(
percentCompleted => System.Console.WriteLine(
percentCompleted.ToString() + "% completed."
)
);
}
}
}
Or, to override an abstract progress method rather than creating a delegate on the C# side:
// piCLI.h: The C++/CLI "bridge" between C# and C++
#pragma once
#include "pi.h"
namespace CLI {
public ref class PI abstract {
delegate void ComputeProgressDelegate(int percentCompleted);
public:
double compute() {
using System::IntPtr;
using System::Runtime::InteropServices::Marshal;
ComputeProgressDelegate^ callback = gcnew ComputeProgressDelegate(
this,
&PI::progress
);
IntPtr cbPtr = Marshal::GetFunctionPointerForDelegate(callback);
return Cpp::PI::compute(
static_cast<Cpp::ComputeProgressCallback>(cbPtr.ToPointer())
);
}
protected:
virtual void progress(int percentCompleted) abstract;
};
}
namespace CSharp {
public sealed class PI : CLI.PI {
protected override void progress(int percentCompleted) {
System.Console.WriteLine(
percentCompleted.ToString() + "% completed."
);
}
}
}
Pass a C++/cli defined Native function to your native C++ as a callback and upon callback use a gcroot to call your managed C# function.