对PInvoke函数“”的调用使堆栈不平衡

我在一段时间以来一直在使用这个奇怪的错误。 这可能是Visual Studio 2010中的新事物,但我不确定。
我试图调用从C#编写的C ++的unamanged函数。
从我在互联网上读到的错误信息本身来看,我的C#文件中的签名与C ++中的签名是不一样的,但实际上我看不到它。
首先这是我下面的无法理解的function:

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); 

当我debugging到C ++,我看到所有的参数就好了,所以我只能认为它是从TEngine(这是一个名为CEngine类的指针)转换为IntPtr。 我以前在VS2008中使用过,没有任何问题。

也许问题在于调用约定。 你确定非托pipe函数编译为stdcall而不是别的(我猜快速调用)?

我有一个_cdecl c ++ dll,我没有任何麻烦从Visual Studio 2008中调用,然后在Visual Studio 2010中相同的代码将无法正常工作。 我得到了相同的PInvoke …也有不平衡的堆栈错误。

我的解决scheme是在DllImport(…)属性中指定调用约定:From:

 [DllImport(CudaLibDir)] 

至:

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

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

也可能是在.NET Framework 3.5版本中,pInvokeStackImbalance MDA默认是禁用的。 在4.0以下(或者VS2010)它默认启用 。

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

引用“ .NET Framework 4迁移问题”文档 :“为了提高与非托pipe代码的互操作性,现在在平台上调用不正确的调用约定现在会导致应用程序失败,在之前的版本中,编组层将这些错误解决了。 。如果您的二进制文件无法更新,您可以在应用程序的configuration文件中包含< NetFx40_PInvokeStackResilience >元素,以便像早期版本一样在堆栈中parsing调用错误,但这可能会影响应用程序的性能。

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

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

使用下面的代码,如果说您的DLL的名称为MyDLL.dll,并且您希望在Dll中使用MyFunction函数

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

这对我工作。

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

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