对 PInvoke 函数“[...]”的调用堆栈不平衡

发布于 2024-09-03 05:32:17 字数 644 浏览 8 评论 0原文

我在使用了很长一段时间的一些东西上遇到了这个奇怪的错误。这可能是 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中用过这个,没有问题。

I'm getting this weird error on some stuff I've been using for quite a while. It may be a new thing in Visual Studio 2010 but I'm not sure.
I'm trying to call a unamanged function written in C++ from C#.
From what I've read on the internet and the error message itself it's got something to do with the fact that the signature in my C# file is not the same as the one from C++ but I really can't see it.
First of all this is my unamanged function below:

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

And here is my function in C#:

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

When I debug into C++ I see all arguments just fine so thus I can only think it's got something to do with transforming from TEngine (which is a pointer to a class named CEngine) to IntPtr. I've used this before in VS2008 with no problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

遗弃M 2024-09-10 05:32:17

我有一个 _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 的默认调用约定?

I had a _cdecl c++ dll that I called without any trouble from Visual Studio 2008, and then the identical code in Visual Studio 2010 would not work. I got the same PInvoke ... has unbalanced the stack error as well.

The solution for me was to specify the calling convention in the DllImport(...) attribute:
From:

[DllImport(CudaLibDir)] 

To:

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

I guess they changed the default calling convention for DLLImport between .NET 3.5 and .NET 4.0?

忆依然 2024-09-10 05:32:17

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

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

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

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

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

It could also be that in the .NET Framework version 3.5, the pInvokeStackImbalance MDA is disabled by default. Under 4.0 (or maybe VS2010) it is enabled by default.

Yes. Technically, the code was always wrong, and previous versions of
the framework silently corrected it.

To quote the .NET Framework 4 Migration Issues document: "To improve
performance in interoperability with unmanaged code, incorrect calling
conventions in a platform invoke now cause the application to fail. In
previous versions, the marshaling layer resolved these errors up the
stack... If you have binaries that cannot be updated, you can include
the <NetFx40_PInvokeStackResilience> element in your application's configuration file to enable calling
errors to be resolved up the stack as in earlier versions. However,
this may affect the performance of your application."

An easy way to fix this is to specify the calling convention and make sure it is the same as in the DLL. A __declspec(dllexport) should yield a cdecl format.

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl)]
浪漫人生路 2024-09-10 05:32:17

也许问题出在调用约定上。您确定非托管函数被编译为 stdcall 而不是其他东西(我猜是 fastcall )?

Maybe the problem lies in the calling convention. Are you sure the unmanaged function was compiled as stdcall and not something else ( i would guess fastcall ) ?

如果您的 DLL 名称为 MyDLL.dll,并且您想在

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

对我有用的 Dll 中使用函数 MyFunction,请使用以下代码。

Use the following code, if say your DLL has the name MyDLL.dll and you want to use the function MyFunction within the Dll

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

this worked for me.

心凉 2024-09-10 05:32:17

就我而言(VB 2010 和使用 Intel Fortran 2011 XE 编译的 DLL),当我的应用程序面向 .NET Framework 4 时,就会出现问题。如果我将目标框架更改为版本 3.5,那么一切都会按预期正常工作。
所以,我猜测原因是 .Net Framework 4 中引入的某些内容,但我目前不知道是哪一个

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

In my case (VB 2010 and DLL compiled with Intel Fortran 2011 XE) the problem exists when my application targets .NET Framework 4. If I change targeted framework to version 3.5, then everything works fine as expected.
So, I would guess the reason is something introduced in .Net Framework 4 but I have no idea at the moment which one

Update: The problem was solved by recompiling Fortran DLL and explicitly specifying STDCALL as calling convention for export names in the DLL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文