The function defined in C++ dll is:
static double (*Func1)(double);
EXTERN_C __declspec(dllexport) __stdcall double TestDelegate(double (*fun)(double))
{
Func1 = fun;
return Func1(25.0);
}
void My_Real_purpose()
{
SomeClass a;
a.SetFunction(Func1);//Define behaviour of a by C# in runtime
a.DoSomething();//Even I want it runs in another thread!
}
And I tried to call it in C# like this:
class A
{
[DllImport("DllName.dll")]
public extern static double TestDelegate(IntPtr f);
public delegate double MyFuncDelegate(double x);
public static double MyFunc(double x)
{
return Math.Sqrt(x);
}
static MyFuncDelegate ff;
static GCHandle gch;
public static double Invoke()
{
ff = new MyFuncDelegate(MyFunc);
gch = GCHandle.Alloc(ff);
double c = TestDelegate(Marshal.GetFunctionPointerForDelegate(ff));//Error occurs this line
gch.Free();
return c;
}
}
It is compiled without error.But when it runs,VS2012 display an error of "Access Violation Exception".
I have searched and tried a lot of ways,such as passing a delegate rather than a IntPtr,but all of them turned out to be failed.
So,what is the correct way to use an API function in a dll which contains function pointer?Or how to realize "My_Real_purpose" function?
Pass-by-pointer means to pass a pointer argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the variable to which the pointer argument points. When you use pass-by-pointer, a copy of the pointer is passed to the function.
C programming allows passing a pointer to a function. To do so, simply declare the function parameter as a pointer type.
A pointer is a variable whose value is the address of another variable or memory block, i.e., direct address of the memory location. Like any variable or constant, you must declare a pointer before using it to store any variable or block address.
Which of the following is a correct syntax to pass a Function Pointer as an argument? Explanation: None.
Your delegate uses the cdecl
calling convention. In C# you would therefore declare the delegate like this:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double CallbackDelegate(double x);
As an alternative, you could decide to declare the function pointer in C++ as __stdcall
, in which case you would remove the UnmanagedFunctionPointer
attribute and rely on the default calling convention being CallingConvention.StdCall
.
Implement it like this:
public static double MyFunc(double x)
{
return Math.Sqrt(x);
}
In order to keep the unmanaged function pointer alive (guarding against GC), you need to hold an instance of the delegate in a variable.
private static CallbackDelegate delegateInstance;
....
delegateInstance = MyFunc;
In the simple example that you have here, the C++ code does not use the unmanaged function pointer outside of TestDelegate
, but in a more complex example you may do so, in which case you must keep the unmanaged function pointer alive.
The function that you import is declared like this:
[DllImport("DllName.dll")]
public extern static double TestDelegate(CallbackDelegate f);
You can then call it like this:
double retval = TestDelegate(delegateInstance);
On the C++ side, I'd explicitly specify the calling convention for the callback, e.g. __stdcall
(you haven't done that in your code, and I think the default is __cdecl
):
// Include the calling convention (__stdcall) for the Callback
typedef double (__stdcall * Callback)(double);
// Just use "Callback" here, instead of repeating
// the above function prototype
extern "C" __declspec(dllexport) __stdcall double TestDelegate(Callback func)
{
return func(25.0);
}
// BTW: Can export also using .DEF file to avoid __stdcall name mangling
On the C# side, you can try something like this:
public delegate double CallbackDelegate(double x);
// PInvoke declaration for the native DLL exported function
[DllImport("YourDLL.dll", CallingConvention = CallingConvention.StdCall)]
public static extern double TestDelegate(CallbackDelegate func);
private double MyFunctionCallback(double x)
{
// ... Implement your C# callback code ...
}
CallbackDelegate managedDelegate = new CallbackDelegate(MyFunctionCallback);
// Call into the native DLL, passing the managed callback
TestDelegate(managedDelegate);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With