I've spent a day of my life solving this problem and I don't want anyone el开发者_StackOverflow社区se to have to do the same. So here is both the problem and solution:
Problem: You're getting a PInvokeStackImbalance exception when trying to use methods in a C++ dll in your C# code. Here's the typical declaration you see given in the examples...
Example that doesn't work
(C++ .h file)
extern "C" {
__declspec(dllexport) int Addints(int a, int b);
}
(C++ .cpp file)
extern int Addints(int a, int b) {
return a+b;
}
(C# .cs file)
[DllImport("testdll.dll")]
static extern int Addints(int a, int b);
static void Main(string[] args)
{
Console.WriteLine("Hello world lets add some stuff");
Int32 a = 3;
Int32 b = 5;
Console.WriteLine(Addints(a,b));
}
When you run this it complains that you've unbalanced the stack (on noes!) and that you really shouldn't continue. It also says that you should check the signature of your method to make sure they match.
Lies all lies.
Fix: What you need to do is add one ~tiny thing to your DLLImport statement like this:
This is the fix
[DllImport("testdll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int Addints(int a, int b);
Yes, that CallingConvention thing? Reeeeeeeeeeealy important.
A few other tips:
- Make sure you build both your dll and C# exe for the same target. Win32 and x86 (for example) respectively - Make sure your dll is built with the /clr option (Project properties - Config properties - General) - Keep in mind that your C++ int, float, string may not be the same size on the other side of the boundary (check here to see how the types match up) - And for a really good step by step example check programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-csshedemon
I hate to do this but your answer is not the entire answer. By default C/C++ uses a Cdecl calling convention so the reason you have to decalare it is obvious.
The real solution would just declare the calling convention within the C++ code.
http://msdn.microsoft.com/en-us/library/zxk0tw93(v=VS.100).aspx
There are other calling conventions also http://msdn.microsoft.com/en-us/library/984x0h58.aspx so your answer really depends on the calling convention of the C/C++ unmanaged code.
I suspect the reason VS2008 has more to do with the .NET Framework 3.5 then anything.
Just change your function to this:
__declspec(dllexport) int __stdcall Addints(int a, int b);
Short Version:
Make sure your DllImport statement in C# includes the CallingConvention parameter set to CallingConvention.Cdecl
See above for more details
Yes that's lovely. It also works, however - reading what I wrote just a tad more closely I said that this was a fix to the "typical declaration you see given in the examples". What examples you might ask? Well here's a few:
dotnetperls.com/dllimport
programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs/
blogs.msdn.com/b/jonathanswift/archive/2006/10/02/780637.aspx
msdn.microsoft.com/en-us/library/aa984739(VS.71).aspx
msdn.microsoft.com/en-us/library/26thfadc.aspx
www.codeguru.com/columns/kate/article.php/c3947
www.apachetechnology.net/KC/NativeDLL2Net.aspx
As of yet I hadn't seen that variant. Nevertheless, if they both work then where's the rub? If you need kudos then here you go: bravo! kudos! Now people have two options to choose from. Oh and btw your "answer is not the entire answer":
(C++ .h) extern "C" {
__declspec(dllexport) int __stdcall Addints(int a, int b); }
(C++ .cpp) int __stdcall Addints(int a, int b) {
return a+b; }
You also need to change the cpp file as well.
Once again - I'm on VS2010 with .Net 4 (not sure what you were referring to there with the comment about VS2008.)
Sorry for the broken link earlier Platform Invoke Data Types can be found here:
http://msdn.microsoft.com/en-us/library/ac7ay120.aspx
精彩评论