PInvoke-Reverse PInvoke and __stdcall – __cdecl


I came across this issue yesterday and thought that I will blog about the same. The example below demonstrates a simple PInvoke and Reverse PInvoke through delegates. The initial call was defined to use the __cdecl convention. As you can notice when executing the code the stack gets corrupted and the for loop ends prematurely.


 


Copy code to: nat.cpp


Compile: cl /LD nat.cpp


 


#include <stdio.h>


#include <string.h>


typedef void ( *callback)(wchar_t * str);


extern “C” __declspec(dllexport) void caller(wchar_t * input, int count, callback call)


{


      for(int i = 0; i < count; i++)


      {


            call(input);


      }


}


 


Copy code to: man.cs


Compile: csc man.cs


 


using System.Runtime.InteropServices;


public class foo


{


    public delegate void callback(string str);


    public static void callee(string str)


    {


        System.Console.WriteLine(“Managed: “ +str);


    }


    public static int Main()


    {


        caller(“Hello World!”, 10, new callback(foo.callee));


        return 0;


    }


    [DllImport(“nat.dll”,CallingConvention=CallingConvention.StdCall)]


    public static extern void caller(string str, int count, callback call);


}


 


The above code prints the “Managed: Hello World!” twice and exits. To fix this let us change the calling convention to __stdcall.


 


Copy code to: nat.cpp


Compile: cl /LD nat.cpp


 


#include <stdio.h>


#include <string.h>


typedef void (__stdcall *callback)(wchar_t * str);


extern “C” __declspec(dllexport) void __stdcall caller(wchar_t * input, int count, callback call)


{


      for(int i = 0; i < count; i++)


      {


            call(input);


      }


}


 


Now if you run the code it will print the message “Managed: Hello World!” 10 times. Marshalling and getting the signatures can be extremely subtle.


Comments (4)

  1. Is there an MDA that allows you to detect this calling convention mismatch?

    Also you might want to read this – http://blogs.msdn.com/mithuns/archive/2006/12/11/pay-attention-to-the-calling-convention.aspx

  2. Rodney says:

    Sir, thank you ever so much for posting this!  You dug me out of a very big hole!

  3. Chris says:

    6 years later, this still works. 🙂 Thanks.

  4. vishal says:

    here you start the program execution from C# project. as it has delegate for callee, it can call back function in C# from C++. but what if my start up project is C++? it does not have fun ptr or delegate for callee. then how to go for it?