P/Invoke external method from C# to C++ - c#

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

Related

Swig : How to get string in a callback

I achieved interoperability between C# & C++ using SWIG.
However, the C ++ to C # callback does not work properly.
If you pass "std::wstring" to the callback on the C++ side, it will be treated as a "string" on the C# side, but only the first character of the string passed on the C++ side will be stored.
My goal is using "std::string" in argument of callback.
Creating a base class with virtual function in C++ and derive a class in C# which implement the virtual method.
I referred to this link.
Callback from C++ to C# using SWIG
My code what callback from C++ to C# using SWIG is following.
C++ : Header.h
#include <string>
#include <vector>
class CallbackBase
{
public:
virtual void Callback(const std::wstring& str) = 0;
};
class CppClass
{
public:
void SetString(const std::wstring &str);
std::wstring GetString();
void SetCallback(CallbackBase& callbackObject);
void ExeCallback();
private:
std::wstring string;
CallbackBase* pCallbackObj = NULL;
void InvokeCallback();
};
typedef CppClass* (*GetInstanceFuncPointer)(void);
extern "C" __declspec(dllexport) CppClass * CreateInstance(void);
C++ : Impl.cpp
#include <thread>
#include "Header.h"
void CppClass::SetString(const std::wstring& str)
{
string = str;
}
std::wstring CppClass::GetString()
{
return string;
}
void CppClass::SetCallback(CallbackBase &callbackObj)
{
pCallbackObj = &callbackObj;
}
void CppClass::ExeCallback()
{
std::thread *th = new std::thread(&CppClass::InvokeCallback, this);
th->join();
}
void CppClass::InvokeCallback()
{
if (pCallbackObj != NULL)
{
pCallbackObj->Callback(string);
}
}
__declspec(dllexport) CppClass* CreateInstance(void)
{
return new CppClass;
}
Swig : Interface file
%include <windows.i>
%include <wchar.i>
%include <std_wstring.i>
%module (directors="1") MyDLL
%{
#include "Header.h"
%}
%feature("director") CallbackBase;
%include "Header.h"
C# : main.cs
using System.Diagnostics;
namespace CsharpApp
{
public class MyCallback : CallbackBase
{
public override void Callback(string str)
{
Debug.WriteLine($"str = {str}"); // --> str = H
}
}
class Program
{
static void Main(string[] args)
{
MyCallback myCallbackObj = new MyCallback();
CppClass instance = MyDLL.CreateInstance();
string str = "Hello World!";
instance.SetString(str);
Debug.WriteLine($"str = {instance.GetString()}"); // --> str = Hello World!
instance.SetCallback(myCallbackObj);
instance.ExeCallback();
}
}
}
I'm getting the string twice on the C# side.
The first is "GetString()" in the main function.
In this case, "Hello World!" Is stored.
The second time I get it as an argument of the callback function.
In this case, only "H" is stored.
How can I correctly store the string in the callback function argument?

VC++ DLL throws error when call it from C#[EntryPointNotFound]

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.

Hooking to a C++ DLL event form C#

I want to hook a C# method to a C++ event written in the C++ DLL
C++ side
#include
extern "C"
{
typedef void (__stdcall *PFN_MYCALLBACK)();
int __stdcall MyUnmanagedApi(PFN_MYCALLBACK callback);
}
C# side
public delegate void MyCallback();
[DllImport("data_acquisition_sys.dll")]
public static extern void MyUnmanagedApi(MyCallback callback);
static void Main(string[] args) {
MyUnmanagedApi(
delegate()
{
Console.WriteLine("Called back by unmanaged side");
}
);
}
}
I followed the http://blogs.msdn.com/b/davidnotario/archive/2006/01/13/512436.aspx
Error
Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'MyUnmanagedApi' in DLL 'data_acquisition_sys.dll'. at affect_detection_sys.Program.MyUnmanagedApi(MyCallback callback) at affect_detection_sys.Program.Main(String[] args) in C:\Users\Public\Docume
For all interested parties, here is a working solution to the problem.
C++ side
extern "C"
{
typedef void (*callback_function)();
callback_function gCBF;
__declspec(dllexport) void StartAcquisition(callback_function callback) {
gCBF = callback;
cout << "Acquisition started" << endl;
}
void DoWork() {
gCBF()
}
}
C# side
[DllImport("data_acquisition_sys.dll", EntryPoint = "StartAcquisition")]
public static extern void StartAcquisition(MyCallback callback);
StartAcquisition(delegate()
{
Console.WriteLine("Called back by unmanaged side ");
}
);
Note that the callback_function is an empty method (), since returning and accepting back ANY data results in a runtime crash. This has been reported in other threads, but the answer hasn't been given.
MyUnmanagedApi returns int and you have declared void. Try this:
public delegate void MyCallback();
[DllImport("data_acquisition_sys.dll")]
public static extern int MyUnmanagedApi(MyCallback callback);
static void Main(string[] args) {
MyUnmanagedApi(
delegate()
{
Console.WriteLine("Called back by unmanaged side");
}
);
}
}

Callbacks from C++ back to C#

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.

NullReferenceException during C++ callback to C# function

developers!
I have very strange problem. My project has DLL writen in C++ and a GUI writen in C#. And I have implemented callback for some interoperability. I planed that C++ dll will call C# code in some circumstances. It works... but not long and I cant understand why. The problem marked in comment in C# part
Here the complete code of simplified sample:
C++ DLL:
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.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;
}
extern "C"
{
typedef void (*WriteSymbolCallback) (char Symbol);
WriteSymbolCallback Test;
_declspec(dllexport) void InitializeLib()
{
Test = NULL;
}
_declspec(dllexport) void SetDelegate(WriteSymbolCallback Callback)
{
Test = Callback;
}
_declspec(dllexport) void TestCall(const char* Text,int Length)
{
if(Test != NULL)
{
for(int i=0;i<Length;i++)
{
Test(Text[i]);
}
}
}
};
C# part:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CallBackClient
{
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void WriteToConsoleCallback(char Symbol);
[DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
private static extern void InitializeLib();
[DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
private static extern void SetDelegate(WriteToConsoleCallback Callback);
[DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
private static extern void TestCall(string Text,int Length);
private static void PrintSymbol(char Symbol)
{
Console.Write(Symbol.ToString());
}
static void Main(string[] args)
{
InitializeLib();
SetDelegate(new WriteToConsoleCallback(PrintSymbol));
string test = "Hello world!";
for (int i = 0; i < 15000; i++)
{
TestCall(test, test.Length);// It crashes when i == 6860!!!! Debugger told me about System.NullReferenceException
}
}
}
}
The problem is that it crashes in 6860th iteration! I believe that the problem is lack of my knowlege in the subject. Could sombody help me?
SetDelegate(new WriteToConsoleCallback(PrintSymbol));
Yes, this cannot work properly. The native code is storing a function pointer for the delegate object but the garbage collector cannot see this reference. As far as it is concerned, there are no references to the object. And the next collection destroys it. Kaboom.
You have to store a reference to the object yourself. Add a field in the class to store it:
private static WriteToConsoleCallback callback;
static void Main(string[] args)
{
InitializeLib();
callback = new WriteToConsoleCallback(PrintSymbol);
SetDelegate(callback);
// etc...
}
The rule is that the class that stores the object must have a lifetime at least as long as native code's opportunity to make the callback. It must be static in this particular case, that's solid.

Categories

Resources