对PInvoke函数'[...]'的调用使堆栈失衡

时间:2010-05-31 07:19:12

标签: c# c++ pinvoke unmanaged managed

我在一段时间内一直在使用的东西上遇到了这个奇怪的错误。它可能是Visual Studio 2010中的新功能,但我不确定 我试图用C#调用用C ++编写的无人函数。
从我在互联网上阅读的内容和错误信息本身来看,这与我的C#文件中的签名与C ++中的签名不同,但我真的看不到它。
首先,这是我在下面的无人函数:

TEngine GCreateEngine(int width,int height,int depth,int deviceType);

这是我在C#中的功能:

[DllImport("Engine.dll", EntryPoint = "GCreateEngine", CallingConvention = CallingConvention.StdCall)]  
        public static extern IntPtr CreateEngine(int width,int height,int depth,int device);

当我调试到C ++时,我看到所有参数都很好,因此我只能认为它与从TEngine(一个名为CEngine的类的指针)转换为IntPtr有关。我之前在VS2008中使用过这个问题没有问题。

5 个答案:

答案 0 :(得分:85)

我有一个_cdecl c ++ dll,我在Visual Studio 2008中没有遇到任何麻烦,然后Visual Studio 2010中的相同代码无效。我得到了相同的PInvoke ...也没有平衡堆栈错误。

我的解决方案是在DllImport(...)属性中指定调用约定: 从:

[DllImport(CudaLibDir)] 

要:

[DllImport(CudaLibDir, CallingConvention = CallingConvention.Cdecl)]

我猜他们在.NET 3.5和.NET 4.0之间更改了DLLImport的默认调用约定?

答案 1 :(得分:48)

也可能是在.NET Framework 3.5版中,默认情况下禁用pInvokeStackImbalance MDA。在4.0(或者VS2010)下,它是enabled by default

  

是。从技术上讲,代码总是错误的,以前的版本   框架默默地纠正了它。

     

引用.NET Framework 4 Migration Issues document:"改进   与非托管代码的互操作性能,不正确的调用   平台调用中的约定现在导致应用程序失败。在   以前的版本,编组层解决了这些错误   堆栈...如果您有无法更新的二进制文件,则可以包括   < NetFx40_PInvokeStackResilience>应用程序的配置文件中的元素以启用调用   像早期版本一样,要在堆栈中解决错误。然而,   这可能会影响您的应用程序的性能。"

解决此问题的一种简单方法是指定调用约定并确保它与DLL中的相同。 __declspec(dllexport)应该产生 cdecl 格式。

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl)]

答案 2 :(得分:21)

问题可能在于调用约定。你确定非托管函数被编译为stdcall而不是其他东西(我猜想快速调用)?

答案 3 :(得分:5)

使用以下代码,如果您的DLL名称为 MyDLL.dll ,并且您想在Dll中使用 MyFunction 功能

[DllImport("MyDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunction();

这对我有用。

答案 4 :(得分:2)

在我的情况下(VB 2010和使用英特尔Fortran 2011 XE编译的DLL),当我的应用程序面向.NET Framework 4时,问题就出现了。如果我将目标框架更改为版本3.5,那么一切都正常工作。 所以,我猜这个原因是.Net Framework 4中引入的内容,但我现在还不知道哪一个

更新:通过重新编译Fortran DLL并显式指定STDCALL作为DLL中导出名称的调用约定来解决问题。