How do I call a function in C ++ Dll from C # that has a void * callback and an object parameter

I am trying to create a wrapper for a C dll, and I am trying to call a function that accepts a callback function, gets the object as a pointer passed back.

.H file

extern int SetErrorHandler(void (*handler) (int, const char*, void*), void *data_ptr); 

A handler is a callback function that is called when an error occurs, and data_ptr is any object (state) that is passed to you, in the case of my application, which will be just that (the current object).

I can call functions in a dll that uses marshalled constant types like strings of simple types, ints, etc. But I canโ€™t understand how easy it is to march a pointer to a C # object, which is a state.

To pass an object reference to a C function from what I found by doing a search here, otherwise it seems that I need a structure type to be able to sort the function, so I created a structure to store my object:

 [StructLayout(LayoutKind.Sequential)] struct MyObjectState { public object state; } 

EDIT: I tried to put the [MarshalAs(UnmanagedType.Struct, SizeConst = 4)] attribute in the public object state property, but this causes the same error, so I deleted it, it looks like it won't work.

The structure contains one property of the object to store any object for the callback function.

I declared a delegate in C # as follows:

 delegate void ErrorHandler(int errorCode, IntPtr name, IntPtr data); 

Then I declared the import function in C # as follows:

 [DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)] static extern int SetErrorHandler handler, IntPtr data); 

Then I created a callback function in my C # code:

 void MyErrorHandler(int errorCode, IntPtr name, IntPtr data) { var strName = Marshal.PtrToStringAnsi(name); var state = new MyObjectState(); Marshal.PtrToStructure(data, state); Console.WriteLine(strName); } 

I can call the library function as follows:

 var state = new MyObjectState() { state = this }; IntPtr pStruct = Marshal.AllocHGlobal(Marshal.SizeOf(state)); Marshal.StructureToPtr(state, pStruct, true); int ret = SetErrorHandler(MyErrorHandler, pStruct); 

The call is called and the callback function is called, but I cannot access the data in the callback function, and when I try Marshal.PtrToStructure , I get the error message:

A structure should not be a class of values.

I searched a lot here and found various things in Marshall and void *, but nothing helped me get this to work

Thanks.

+6
source share
2 answers

You make it more complicated than necessary. Your C # client should not use the data_ptr parameter, because the C # delegate already has a built-in mechanism to maintain the this pointer.

So you can just pass IntPtr.Zero delegate. Inside the delegate of the error handler, you simply ignore the value of data_ptr , since this will be available.

If you do not follow this description, here is a short program illustrating what I mean. Note that MyErrorHandler is an instance method that acts as an error handler and can modify instance data.

 class Wrapper { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate void ErrorHandler(int errorCode, string name, IntPtr data); [DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)] static extern int SetErrorHandler(ErrorHandler handler, IntPtr data); void MyErrorHandler(int errorCode, string name, IntPtr data) { lastError = errorCode; lastErrorName = name; } public Wrapper() { SetErrorHandler(MyErrorHandler, IntPtr.Zero); } public int lastError { get; set; } public string lastErrorName { get; set; } } class Program { static void Main(string[] args) { Wrapper wrapper = new Wrapper(); } } 
+3
source

There may be a very good way to do this, but I gave up a long time. The solution I came up with is a bit hacky, but it is very efficient and works with everything that I threw at it:

C # โ†’ Managed C ++ โ†’ Native Calls

By doing this this way, you end up writing a little wrapper in managed C ++, which is a little painful, but I found it more capable and less painful than all this marshaling code.

Honestly, although I am in the hope that someone will give a non-evasive answer, I struggled with this for a long time.

+2
source

Source: https://habr.com/ru/post/913002/


All Articles