【问题标题】:Solution to PInvokeStackImbalance exception (Calling unmanaged C++ dll from C#) - VS2010PInvokeStackImbalance异常的解决方案(从C#调用非托管C++ dll) - VS2010
【发布时间】:2011-01-14 16:29:12
【问题描述】:

我已经用了一天的时间来解决这个问题,我不希望其他人也这样做。所以这是问题和解决方案:

问题:在 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 语句中添加一个 ~tiny 的东西,如下所示:

这是解决办法

[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 在边界另一侧的大小可能不同(检查 here 以查看类型如何匹配)
- 对于一个非常好的逐步示例,请查看programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs

【问题讨论】:

  • 您应该能够在 Windows 上使用默认调用约定,如果您不能,那么您可能会遇到其他问题。我当然可以在不声明调用约定的情况下导入非托管库。
  • 您应该做的是提出这个问题,然后在下面提供您的“修复”部分作为答案。这是一个问答网站,不是论坛。见stackoverflow.com/about
  • 我应该添加我使用的库,必须准确定义 8、16、32 和 64 位有符号和无符号数字。 .NET 恰好定义了相同的类型。
  • Hello First-Post trolls... Ramhound,我的配置是 VS2010,XP 上的 .NET4。我的设置没有问题。 SwDevMan81,哎呀,如果你等一下而不是跳到我身上,你会看到我那样做的:P 和拉米?是的,我尝试了所有这些,但你仍然没有得到我帖子的要点。只是想帮助人们,如果您不欣赏,请见谅。
  • 我有完全相同的设置,我的非托管库可以通过声明调用约定来导入,你的解决方案不是完整的答案。

标签: c# windows dll pinvoke dllimport


【解决方案1】:

谢蒙

我讨厌这样做,但您的答案不是完整的答案。默认情况下,C/C++ 使用 Cdecl 调用约定,因此必须对其进行 decalare 的原因是显而易见的。

真正的解决方案只是在 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); 

【讨论】:

    【解决方案2】:

    短版:

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

    详情见上文

    【讨论】:

      【解决方案3】:

      是的,这很可爱。但是,它也可以工作 - 仔细阅读我写的内容,我说这是对“您在示例中看到的典型声明”的修复。你可能会问什么例子?好吧,这里有一些:

      dotnetperls.com/dllimport
      程序员notebook.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 文件。

      再一次 - 我在 .Net 4 上使用 VS2010(不确定您在评论中提到的关于 VS2008 的内容。)

      【讨论】:

      • 继续给人们“提示”,但忽略应该简单地匹配 C/C++ 非托管代码的调用约定的部分。我很清楚您使用的是 Visual 2010,我也在使用它,与您列出的完全相同的设置。我关于 Visual Studio 2008 ( .NET Framework 3.5 ) 的声明与您的代码过去工作的原因有关。
      【解决方案4】:

      抱歉,之前的 Platform Invoke Data Types 链接断开:

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

      【讨论】:

        猜你喜欢
        • 2011-01-24
        • 1970-01-01
        • 2021-03-28
        • 1970-01-01
        • 1970-01-01
        • 2013-01-07
        • 1970-01-01
        • 1970-01-01
        • 2011-03-04
        相关资源
        最近更新 更多