简体   繁体   English

PInvokeStackImbalance异常的解决方案(从C#调用非托管C ++ dll)-VS2010

[英]Solution to PInvokeStackImbalance exception (Calling unmanaged C++ dll from C#) - VS2010

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. 问题 :尝试在C#代码中的C ++ dll中使用方法时,会收到PInvokeStackImbalance异常。 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: 修复 :您需要做的是在您的DLLImport语句中添加一个小东西,如下所示:

This is the fix 这是修复

[DllImport("testdll.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern int Addints(int a, int b);

Yes, that CallingConvention thing? 是的,那CallingConvention的东西? Reeeeeeeeeeealy important. Reeeeeeeeeealy很重要。

A few other tips: 其他一些技巧:
- Make sure you build both your dll and C# exe for the same target. -确保为同一目标同时构建dll和C#exe。 Win32 and x86 (for example) respectively 分别是Win32和x86
- Make sure your dll is built with the /clr option (Project properties - Config properties - General) -确保您的dll是使用/ clr选项构建的(项目属性-配置属性-常规)
- 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) -请注意,边界另一侧的C ++ int,float,string大小可能不相同(请在此处查看类型如何匹配)
- And for a really good step by step example check programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs -要获得一个非常好的分步示例,请查看程序员notebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs

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. 默认情况下,C / C ++使用Cdecl调用约定,因此显而易见,必须进行贴花的原因很明显。

The real solution would just declare the calling convention within the C++ code. 真正的解决方案只是在C ++代码中声明调用约定。

http://msdn.microsoft.com/en-us/library/zxk0tw93(v=VS.100).aspx http://msdn.microsoft.com/zh-CN/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. 还有其他调用约定http://msdn.microsoft.com/zh-cn/library/984x0h58.aspx,因此您的答案实际上取决于C / C ++非托管代码的调用约定。

I suspect the reason VS2008 has more to do with the .NET Framework 3.5 then anything. 我怀疑VS2008与.NET Framework 3.5有更多关系的原因。

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 确保C#中的DllImport语句包含设置为CallingConvention.Cdecl的CallingConvention参数

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 dotnetperls.com/dllimport
programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs/ 程序员notebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs/
blogs.msdn.com/b/jonathanswift/archive/2006/10/02/780637.aspx blogs.msdn.com/b/jonathanswift/archive/2006/10/02/780637.aspx
msdn.microsoft.com/en-us/library/aa984739(VS.71).aspx msdn.microsoft.com/zh-CN/library/aa984739(VS.71).aspx
msdn.microsoft.com/en-us/library/26thfadc.aspx msdn.microsoft.com/zh-CN/library/26thfadc.aspx
www.codeguru.com/columns/kate/article.php/c3947 www.codeguru.com/columns/kate/article.php/c3947
www.apachetechnology.net/KC/NativeDLL2Net.aspx 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. 您还需要更改cpp文件。

Once again - I'm on VS2010 with .Net 4 (not sure what you were referring to there with the comment about VS2008.) 再次-我使用的是.Net 4的VS2010(不知道您所说的是关于VS2008的评论)。

Sorry for the broken link earlier Platform Invoke Data Types can be found here: 抱歉,较早的链接断开可以在这里找到平台调用数据类型:

http://msdn.microsoft.com/en-us/library/ac7ay120.aspx http://msdn.microsoft.com/en-us/library/ac7ay120.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM