对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中导出名称的调用约定解决了此问题。