How to pass function pointer from C# to a C++ Dll?

a 夏天 提交于 2021-01-21 07:58:25

问题


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?


回答1:


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);



回答2:


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);


来源:https://stackoverflow.com/questions/43226928/how-to-pass-function-pointer-from-c-sharp-to-a-c-dll

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!