C # C ++ Interop callback

I recently worked on the interaction of C # with C ++, in particular, setting up a callback function that is called from the C ++ DLL.

namespace TomCSharpDLLImport { class Program { public delegate void TomDelegate(int a, int b); [DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void GetData(); [DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void SetCallback(TomDelegate aCallback); static void Main(string[] args) { TomDelegate lTD = new TomDelegate(Program.TomCallback); SetCallback(lTD); //Sets up the callback int thread = Thread.CurrentThread.ManagedThreadId; GetData(); //This calls the callback in unmanaged code while (true) ; } //Callback function which is called from the unmanaged code public static void TomCallback(int a, int b) { Console.WriteLine("A: {0} B: {1}", a, b); int thread = Thread.CurrentThread.ManagedThreadId; } } } 

The question is, when a program control enters the TomCallback function, I expected it to hit the while (true) loop in Main. However, instead, the program simply exits. I can’t help but discern my behavior, part of me imagines that this is as expected, but part of me expected that this will continue mainly.

What did I expect ...

  • The GetData () function is called
  • GetData function calls a callback
  • The callback function returns to GetData li>
  • GetData returns to main ()

However, this is not entirely correct.

Someone will be kind enough to explain what is happening.

To save space, I did not send unmanaged code, however, if necessary, I am happy to publish

Edit: I turned on unmanaged debugging (completely forgot to do this), and now I see a crash.

Runtime Check Error # 0 - ESP value was not properly stored during function call. This is usually the result of calling a function declared with one call, with a function pointer declared with another calling convention.

Source code since this is a crash

 #include "stdafx.h" typedef void (*callback_function)(int, int); extern "C" __declspec(dllexport) void SetCallback(callback_function aCallback); extern "C" __declspec(dllexport) void GetData(); callback_function gCBF; __declspec(dllexport) void SetCallback(callback_function aCallback) { gCBF = aCallback; } __declspec(dllexport) void GetData() { gCBF(1, 2); } 
+7
source share
2 answers

You must convert the managed callback to a Native Function Pointer (IntPtr in C #) using

 IntPtr Marshal.GetFunctionPointerForDelegate(Delegate d) 

method.

Your use of SetCallback () with System.Delegate as an argument is incorrect.

Do it

 SetCallback(Marshal.GetFunctionPointerForDelegate(lTD)); 

and redeclare SetCallback as

 /// StdCall is crucial here [DllImport("TomDllNative.dll", CallingConvention = CallingConvention.StdCall)] public static extern void SetCallback(IntPtr aCallback); 
+11
source

I had the same problem as the OP (same error message). The accepted answer did not help at all, which even @ TomP89 allows in the comments.

This is not surprising because the error message indicates that the convention of calling the callback function is incorrect, while the proposed solution changes the convention of calling the function that passes the callback , which leads to an imbalance in the stack if the library export is cdecl functions (as is the case by default for all functions outside the Win32 API).

It turns out that .Net accepts the default stdcall calling convention for any delegate. Typically, unmanaged code will accept the same calling convention as its exported functions (in this case mine: "cdecl").

So, the true solution (which finally worked for me) changes the callback convention to "cdecl". This question shows how this is done, in short:

  [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void TomDelegate(int a, int b); 
+4
source

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


All Articles