PInvokeStackImbalance异常的解决方案(从C#调用非托管C++ dll)-VS2010
我花了一天的时间来解决这个问题,我不希望其他人也这样做。因此,问题和解决方案如下:
问题:尝试在 C# 代码中使用 C++ dll 中的方法时,出现 PInvokeStackImbalance 异常。这是您在示例中看到的典型声明...
不起作用的示例
(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));
}
当您运行此命令时,它会抱怨您已经使堆栈不平衡(不!)并且您确实不应该'继续。它还说您应该检查方法的签名以确保它们匹配。
谎言全是谎言。
修复:您需要做的就是在 DLLImport 语句中添加一个小东西,如下所示:
这就是修复
[DllImport("testdll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int Addints(int a, int b);
是的,那个 CallingConvention 的东西吗?非常重要。
其他一些提示:
- 确保为同一目标构建 dll 和 C# exe。分别为 Win32 和 x86
- 确保您的 dll 是使用 /clr 选项构建的(项目属性 - 配置属性 - 常规)
- 请记住,您的 C++ int、float、string 在边界的另一侧可能大小不同(请检查 此处< /a> 查看类型如何匹配)
- 对于一个非常好的逐步示例,请检查programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs
I've spent a day of my life solving this problem and I don't want anyone else 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-cs
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
shedemon
我讨厌这样做,但你的答案并不是完整的答案。默认情况下,C/C++ 使用 Cdecl 调用约定,因此您必须声明它的原因是显而易见的。
真正的解决方案只是在 C++ 代码中声明调用约定。
http://msdn.microsoft.com/en- us/library/zxk0tw93(v=VS.100).aspx
还有其他调用约定 http://msdn.microsoft.com/en-us/library/984x0h58.aspx 所以你的答案实际上取决于 C/C++ 非托管代码的调用约定。
我怀疑 VS2008 与 .NET Framework 3.5 的关系更大。
只需将您的功能更改为:
shedemon
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:
简短版本:
确保 C# 中的 DllImport 语句包含设置为 CallingConvention.Cdecl 的 CallingConvention 参数,
请参阅上文了解更多详细信息
Short Version:
Make sure your DllImport statement in C# includes the CallingConvention parameter set to CallingConvention.Cdecl
See above for more details
是的,那很可爱。然而,它也有效 - 仔细阅读我写的内容,我说这是对“您在示例中看到的典型声明”的修复。您可能会问什么例子?这里有一些:
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
到目前为止我还没有看到该变体。然而,如果它们都有效,那么问题在哪里呢?如果您需要荣誉,那么就在这里:太棒了!荣誉!现在人们有两种选择。哦,顺便说一句,你的“答案不是完整的答案”:
你还需要更改 cpp 文件。
再一次 - 我在使用 .Net 4 的 VS2010(不知道你在关于 VS2008 的评论中指的是什么。)
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":
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.)
抱歉,之前的平台调用数据类型链接已损坏,可以在这里找到:
http:// msdn.microsoft.com/en-us/library/ac7ay120.aspx
Sorry for the broken link earlier Platform Invoke Data Types can be found here:
http://msdn.microsoft.com/en-us/library/ac7ay120.aspx