Reputation: 65
The exception:
Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'D:\UI_still_in_progress\user_interface\bin\Debug\WindowsFormsApplication1.vshost.exe'.
Basically my application has a background real time process in c++ which communicates with a micro-processor. Ive set up a c++ dll file which allows me to pass data from the c++ application and c# UI in real time.
My problem is that I have to create a finite state machine to make sure the physical device and c++ app are all doing what they should be based on whats going on in the UI. so my goal is to pass simple integers representing the states from c# to c++.
The real time data is passing from c++ to c# with no issues using the following implementation:
c++ .h file snippet:
extern "C" __declspec (dllexport) int grabx();
extern "C" __declspec (dllexport) void setFSMstate(int s);
C++ .cpp file snippet:
int grabx()
{
return x0;
}
void setFSMstate(int s)
{
state = s;
}
c# class
public class MyDllMethods {
[DllImport("dllTESTER.dll")]
public static extern int grabx();
[DllImport("dllTESTER.dll")]
public static extern void setFSMstate(int s);
}
c# method calls
xx = MyDllMethods.grabx();
MyDllMethods.setFSMstate(2);
The grabx()
function works fine and i can read the x value from the device in real time. When my UI moves to a new screen i attempt to change the state in every application by passing a 2
into setFSMstate()
. When this method is called the exception is thrown.
I am quite new to P/Invoke so if there is anything I missed please help out. I may have marshaled it wrong but im confident that type int
is the same in c# and c++?
Upvotes: 2
Views: 606
Reputation: 26853
The problem you're running into is a calling convention mismatch. Calling conventions specify how parameters are passed to functions, and how their return values are passed back to the caller. Your C++ functions are being declared with an implicit calling convention of __cdecl
, but P/Invoke's default calling convention is __stdcall
.
To fix this, you just have to change your P/Invoke configuration:
[DllImport("dllTESTER.dll", CallingConvention = CallingConvention.Cdecl)]
(The reason you didn't have any problems with your first method is that it doesn't have any parameters—__cdecl
and __stdcall
pass parameters differently, but they both specify that integer return values are stored in the EAX register.)
Upvotes: 3