Making C++ DLL for C#

2019-02-24 22:22发布

问题:

I have made a very simple Dll like this:

extern "C"
{
  __declspec(dllexport) int Try(int v)
  {
    return 10 + v;
  }
}

Then I want to use it in my C# app:

class Program
{
    [DllImport("TestLib.dll")]
    public static extern int Try(int v);

    static void Main(string[] args)
    {
        Console.WriteLine("Wynik: " + Try(20));
        Console.ReadLine();
    }
}

It was working until I have tried to pas parameter. Now I have following error at runtime:

A call to PInvoke function 'ConsoleApplication2!ConsoleApplication1.Program::Try' 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.

I have no idea where is the problem.

回答1:

The error message you've got contains a good advice indeed:

Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

You should have the same calling convention specified on both sides (C++ dll and C# assembly). In C++ you can specify it by prepending function declaration with one of __cdecl, __stdcall, etc.


extern "C"
{
  __declspec(dllexport) int __stdcall Try(int v)
  {
    return 10 + v;
  }
}

On the C# side you specify it with DllImport attribute, the default one is CallingConvention.StdCall which corresponds to __stdcall in C++, so, it looks like you have a __cdecl on the C++ side. To fix the issue either use __stdcall in your DLL as shown above, or use CDecl in C# like this:


class Program
{
    [DllImport("TestLib.dll", CallingConvention=CallingConvention.Cdecl)]
    public static extern int Try(int v);

    static void Main(string[] args)
    {
        Console.WriteLine("Wynik: " + Try(20));
        Console.ReadLine();
    }
}



回答2:

The default calling convention in C and C++ is __cdecl; the default calling convention used by .NET P/Invoke is __stdcall -- you need to reconcile these two.

  • Either make your native function __stdcall, as Hans suggested:

    __declspec(dllexport) int __stdcall Try(int v)
    
  • Or make your managed P/Invoke signature use __cdecl:

    [DllImport("TestLib.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int Try(int v);
    


标签: c# c++ dll