A call to PInvoke function [function name] has unbalanced the stack
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#.
Why do I get PInvokeStackImbalance was detected for this simple example?
You need to instead use either
[DllImport("CommonNativeLib.dll", CallingConvention = CallingConvention.Cdecl)]
or
extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) ...
because regular C functions work differently than the Windows API functions; their "calling conventions" are different, meaning how they pass around parameters is different. (This was hinted at in the error.)
pinvokestackimbalance -- how can I fix this or turn it off?
First, understand that the code is wrong (and always has been). The "pInvokeStackImbalance" is not an exception per se, but a managed debugging assistant. It was off by default in VS2008, but a lot of people did not turn it on, so it's on by default in VS2010. The MDA does not run in Release mode, so it won't trigger if you build for release.
In your case, the calling convention is incorrect. DllImport
defaults to CallingConvention.WinApi
, which is identical to CallingConvention.StdCall
for x86 desktop code. It should be CallingConvention.Cdecl
.
This can be done by editing the line [DllImport("ImageOperations.dll")]
to be:
[DllImport("ImageOperations.dll", CallingConvention = CallingConvention.Cdecl)]
For more information, see this MSDN reference
PinvokeStackImbalance error (C#)
public int SendMail(..., long smtpPortNo);
It is excessively unlikely that the last argument is correct. Makes no sense at all to store a value that must be less than 65536 in a 64-bit long argument. It surely should be int instead. A classic Visual Basic accident, versions before VB.NET used Long
to declare a 32-bit integer.
Why this didn't generate the diagnostic in 3.5 is hard to guess, it certainly should. Maybe you just never ran it with a debugger attached with the MDA enabled. Stack corruption caused by getting the declaration wrong has a habit of healing itself so it doesn't necessarily have to bomb at runtime. Still, a very, very unhealthy problem that can cause pretty random code execution.
Three basic things you can do about it. On top of the list with bells on is to use a telephone, you want the author of this library to fix his bug. Next is to try to flip the ignore bit and turn the MDA off: Debug > Exceptions > Managed Debugging Assistants, untick "PInvokeStackImbalance". And I probably ought to mention the new 4.0 config file option, <NetFx40_PInvokeStackResilience>
, hesitantly.
But, really, that telephone must be your real fix.
Calling a C++ function from C# - unbalanced stack
IIRC, you need to decorate the delegate signature with a calling convention. Unfortunately, this can only be done via IL or generating the stub with Reflection.Emit.
You can try this:
protected static Type MakeDelegateType(Type returntype, List<Type> paramtypes)
{
ModuleBuilder dynamicMod = ... ; // supply this
TypeBuilder tb = dynamicMod.DefineType("delegate-maker" + Guid.NewGuid(),
TypeAttributes.Public | TypeAttributes.Sealed, typeof(MulticastDelegate));
tb.DefineConstructor(MethodAttributes.RTSpecialName |
MethodAttributes.SpecialName | MethodAttributes.Public |
MethodAttributes.HideBySig, CallingConventions.Standard,
new Type[] { typeof(object), typeof(IntPtr) }).
SetImplementationFlags(MethodImplAttributes.Runtime);
var inv = tb.DefineMethod("Invoke", MethodAttributes.Public |
MethodAttributes.Virtual | MethodAttributes.NewSlot |
MethodAttributes.HideBySig,
CallingConventions.Standard ,returntype,null,
new Type[]
{
// this is the important bit
typeof(System.Runtime.CompilerServices.CallConvCdecl)
},
paramtypes.ToArray(), null, null);
inv.SetImplementationFlags(MethodImplAttributes.Runtime);
var t = tb.CreateType();
return t;
}
Related Topics
Using Regex to Get Text Between Multiple HTML Tags
Getting Selected Value of a Combobox
How to Access Resourcedictionary in Wpf from C# Code
More Elegant Exception Handling Than Multiple Catch Blocks
Update Float Array from C++ Native Plugin
How to Render Encoded Tags as Proper HTML, Rather Than Text
Change Forecolor Af a Special Word in Gridview Cell
C#/.Net Analysis Tool to Find Race Conditions/Deadlocks
C# Serialized JSON Date to Ruby
Add the Where Clause Dynamically in Entity Framework
Convert from Word Document to HTML
C# Generics Compared to C++ Templates
Dependency Injection with a Static Logger, Static Helper Class
Configure Multiple Database Entity Framework 6
Linux, Mono, Shared Libs and Unresolved Symbols
How to Add a Local Script File to The HTML of a Webbrowser Control