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

时间:2011-01-14 16:29:12

标签: c# windows dll pinvoke dllimport

我花了一整天的时间来解决这个问题,我不希望任何其他人也必须这样做。所以这是问题和解决方案:

问题:当您尝试在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));
        }

当你运行它时,它抱怨你已经使堆栈失去平衡(在noes!)并且你真的不应该继续。它还说你应该检查方法的签名,以确保它们匹配。

谎言所有的谎言。

修复:您需要做的是在DLLImport语句中添加一个小小的东西:

这是修复

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

是的,那CallingConvention的事情? Reeeeeeeeeeealy很重要。

其他一些提示:
- 确保为同一目标构建dll和C#exe。分别为Win32和x86(例如) - 确保您的dll是使用/ clr选项构建的(项目属性 - 配置属性 - 常规)
- 请记住,您的C ++ int,float,string可能与边界另一侧的大小不同(选中here以查看类型如何匹配)
- 并为一个非常好的一步一步的例子检查programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs

4 个答案:

答案 0 :(得分:1)

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有什么关系呢。

只需将您的功能更改为:

__declspec(dllexport) int __stdcall Addints(int a, int b); 

答案 1 :(得分:0)

简短版本:

确保C#中的DllImport语句包含CallingConvention参数设置为CallingConvention.Cdecl

见上文了解更多详情

答案 2 :(得分:0)

是的,这很可爱。然而它也有效 - 阅读我写得更紧密的内容我说这是对“你在例子中给出的典型声明”的修正。您可能会问什么样的例子?那么这里有几个:

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

到目前为止,我还没有看到那种变体。然而,如果他们两个工作,那么摩擦是什么?如果你需要荣誉,那么你去吧:勇敢!荣誉!现在人们有两种选择可供选择。哦,顺便说一下你的“答案不是完整答案”:

 (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; }

您还需要更改cpp文件。

再次 - 我在VS2010上使用.Net 4(不确定你在那里引用了关于VS2008的评论。)

答案 3 :(得分:0)

很抱歉,之前发生的断开链接可以在此处找到平台调用数据类型:

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