Search code examples
c#pinvokemarshalling

Getting IntPtr of a delegate and invoking


To simulate a call from c++, I'm trying the following code

    private delegate void CppFuncDelegate(string message);

    private static void Main(string[] args)
    {
        Console.WriteLine("+++ BEGIN TEST +++");

        Action<string> action = str => Console.WriteLine("Received:" + str);
        IntPtr delegatePtr = action.Method.MethodHandle.GetFunctionPointer();

        CppFuncDelegate cppFuncDelegate = (CppFuncDelegate)
           Marshal.GetDelegateForFunctionPointer(delegatePtr, 
                                                        typeof(CppFuncDelegate));
        cppFuncDelegate.Invoke("Hello");
    }

but I get

PInvokeStackImbalance was detected. A call to PInvoke function 'Test!Test.Program+CppFuncDelegate::Invoke' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

Can anyone tell me what I'm doing wrong?

NOTE: Please don't tell me to do action.Invoke(); that's not what this exercise is about. I want to get IntPtr handle to the delegate and use GetDelegateForFunctionPointer() and then invoke the returned delegate.

Thanks.


Solution

  • You cannot use GetDelegateForFunctionPointer() to get delegate of managed function. This is from MSDN:

    You cannot pass an invalid function pointer to GetDelegateForFunctionPointer. In addition, you can only use this method for pure unmanaged function pointers. You cannot use this method with function pointers obtained through C++ or from GetFunctionPointer. You cannot use this method to create a delegate from a function pointer to another managed delegate.

    I'm not sure why you can't do this, but I guess it's because Microsoft's Common Language Runtime uses FastCall calling convention, but FastCall is not supported for PInvoke.