11

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?

3

2 Answers 2

19

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);
Sign up to request clarification or add additional context in comments.

Comments

3

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.