Kevin Kevin - 1 month ago 19
C# Question

A call to PInvoke function [function name] has unbalanced the stack

I'm attempting to use PInvoke to call an unmanaged C++ DLL and I'm getting errors (see below). Using

depends.exe
I can see the mangled name in the exported function list, hence the weird
EntryPoint
name. Although this exception appears, if I continue to
Step Over
while debugging, the function returns and
ptr
equals 1 and "Success" is printed.

I've tried some of the suggestions found in other posts, but nothing worked. I figured
uint32_t
is pretty self explanatory. I've tried changing the C# PInvoke signature to use
long
and
ulong
however the exception is still thrown and the value of
ptr
is a very large number. I've also tried setting
CharSet
and
ExactSpelling
properties for the
DllImport
attribute but that didn't seem to work either.

My question is, what am I doing that's causing an exception, and if I can't/shouldn't ignore the exception-how can that be done?

Unmanaged C++



MyClass.h

class __declspec(dllexport) MyClass
{
public:
uint32_t runCommand(uint32_t start);
};


MyClass.cpp

uint32_t MyClass::runCommand(uint32_t start);
{
uint32_t status = 1;
return status;
}


Managed C#



P/Invoke Signature

[DllImport("myClass.dll",
EntryPoint = "?runCommand@MyClass@myClass@@QAEII@Z",
CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 runCommand(UInt32 baseAddress);


Usage

public static void Do()
{
UInt32 a = 0xA000;
UInt32 ptr = runCommand(a);
Console.Write("Success!");
}


Error:


Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\Users...\TestApp.vshost.exe'.

Additional information: A call to PInvoke function 'TestApp!TestApp.CSMyClass::runCommand' 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.


Using Visual Studio 2015, and C# application is .NET Framework 4.6.

Answer

There is a mismatch in calling conventions, which causes the stack unbalance.

Since runCommand is a member function of MyClass, the calling convention used for it is not __cdecl, but __thiscall (note that there is an implicit "this" pointer passed as argument with non-static member functions of C++ classes).

You may want to either export a pure C interface function (not a C++ class member function) from your DLL for P/Invoke'ing, or you can use C++/CLI to build a tiny bridging layer between native and managed code, wrapping your C++ native class in a .NET managed class written in C++/CLI, and use that managed class wrapper from C#.