Pasar una función de callback C # a través de Interop / pinvoke

Estoy escribiendo una aplicación C # que usa servicios de Interop para acceder a funciones en una DLL C ++ nativa. Ya estoy usando alrededor de 10 funciones diferentes que están funcionando.

Ahora no estoy seguro de cómo pasar una callback como un parámetro para que la DLL pueda llamar a mi código.

Aquí está el prototipo de función de la DLL:

typedef void (WINAPI * lpfnFunc)(const char *arg1, const char *arg2) 

Y la función que me permite pasar el tipo anterior:

 int WINAPI SetFunc(lpfnFunc f) 

Aquí está mi código C # para las definiciones de delegado y función:

 public delegate void Func(string arg1, string arg2); public static void MyFunc(string arg1, string arg2) 

Aquí está mi código C # para la función de interoperabilidad SetFunc:

 [DllImport("lib.dll", CharSet = CharSet.Ansi)] public static extern int SetFunc(Func lpfn); 

Y finalmente aquí está el código donde llamo a la función SetFunc y le paso mi callback:

 SetFunc(new Func(MyFunc)); 

Lamentablemente, mi función no se llama cuando debería ser. El valor de retorno de la función SetFunc devuelve el código de error para un Éxito, por lo que no llama a mi función o no funciona porque mi código es incorrecto.

Esto funciona para mí:

Calc.h (Calc.dll, C ++):

 extern "C" __declspec(dllexport) double Calc(double x, double y, double __stdcall p(double, double)); 

Calc.cpp (Calc.dll, C ++):

 #include "calc.h" __declspec(dllimport) double Calc(double x, double y, double __stdcall p(double, double)) { double s = p(x*x, y*y); return x * y + s; } 

Program.cs (Sample.exe, C #):

 class Program { delegate double MyCallback(double x, double y); [DllImport("Calc.dll", CallingConvention = CallingConvention.Cdecl)] static extern double Calc(double x, double y, [MarshalAs(UnmanagedType.FunctionPtr)]MyCallback func); static void Main(string[] args) { double z = Calc(1, 2, (x, y) => 45); } } 

¿Puedes intentar cambiar el delegado de Func a

  public delegate void Func([In, MarshalAs(UnmanagedType.LPStr)] string arg1, [In, MarshalAs(UnmanagedType.LPStr)] string arg2); 

Y el método SetFunc para

 [DllImport("lib", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)] public static extern int SetFunc(Func lpfn);