C++从 C++ 调用的 DLL控制台应用程序工作,从 C# 控制台应用程序调用有堆栈溢出

发布于 2024-11-02 09:01:08 字数 1358 浏览 3 评论 0原文

我收到了一些用于另一个项目的 C/C++ 代码。我将其放入 DLL 中,然后从 C++ 测试工具中调用该 DLL。它工作得很好,并且与代码只是函数调用时的结果相匹配。

不过,我随后尝试让 DLL 在 C# 应用程序中运行。我转换了测试工具,并进行了 DLL 调用,但收到了堆栈溢出异常。

在 C++ 中,我添加:

 #include "proxy_rec_02.h"  
 #pragma comment(lib,"proxy_rec_02.lib")  

并像这样调用函数:

 proxy_rec_main(simtime,mx$gl,mz$gl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,outputs);

其中标头包含:

void DLL_EXPORT proxy_rec_main(double simtime, double mx$gl, double mz$gl, double ry, int start_dig,  
                               int blytarg_on, double blytarg, int spread_on, int last_call, double *outputs);

在 C# 中,我使用:

using System.Runtime.InteropServices;

[DllImport("proxy_rec_02.dll")]
unsafe static extern void proxy_rec_main(double simtime, double mxSgl, double mzSgl, double ry, int start_dig,        
                                  int blytarg_on, double blytarg, int spread_on, int last_call, ref double[] outputs);

使用这样的函数调用:

proxy_rec_main(simtime,mxSgl,mzSgl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,ref outputs);

DLL 函数在 for 循环中被多次调用。 C++ 代码运行得很好。 C# 代码引发堆栈溢出错误。我向 proxy_rec_main 函数添加了一些调试状态维护,它似乎在函数返回之前命中了每个语句。但它似乎在函数返回时抛出错误。任何见解都将受到欢迎。

谢谢。

I recieved some C/C++ code for use in another project. I put it into a DLL and then called the DLL from a C++ test harness. It worked fine and matched the results from when the code was just a function call.

However, I then tried to get the DLL to work from a C# application. I converted the test harness, and made the DLL call but I am recieving a stack overflow exception.

In C++ I added:

 #include "proxy_rec_02.h"  
 #pragma comment(lib,"proxy_rec_02.lib")  

And called the function like this:

 proxy_rec_main(simtime,mx$gl,mz$gl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,outputs);

Where the header contains:

void DLL_EXPORT proxy_rec_main(double simtime, double mx$gl, double mz$gl, double ry, int start_dig,  
                               int blytarg_on, double blytarg, int spread_on, int last_call, double *outputs);

In C# I'm using:

using System.Runtime.InteropServices;

and

[DllImport("proxy_rec_02.dll")]
unsafe static extern void proxy_rec_main(double simtime, double mxSgl, double mzSgl, double ry, int start_dig,        
                                  int blytarg_on, double blytarg, int spread_on, int last_call, ref double[] outputs);

With a function call like this:

proxy_rec_main(simtime,mxSgl,mzSgl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,ref outputs);

The DLL function is called many times in a for loop. The C++ code runs just fine. The C# code throws a stack overflow error. I added some debug statemaints to the proxy_rec_main function and it seems to hit each statement before the function returns. But it seems to throw the error on return from the function. Any insights would be welcome.

Thanks.

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

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

发布评论

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

评论(3

别念他 2024-11-09 09:01:08

[DllImport] 声明中缺少 CallingConvention 属性。没有迹象表明您在 C 声明中使用 __stdcall,因此可能需要 CallingConvention.Cdecl。这确实会导致 SO,堆栈没有被清理。

Debug + Windows + Registers,观察调用前后ESP寄存器的值,应该是相同的。如果您禁用了 PInvokeStackImbalance 托管调试器警告,请务必将其重新打开。忽略这个警告并不是一个好主意。

并调试本机代码,验证传递的参数值。有如此多的争论,其中一个的一个糟糕的声明就足以让他们搬起石头砸自己的脚。

The CallingConvention property is missing from the [DllImport] declaration. There's no sign of you using __stdcall in the C declaration so CallingConvention.Cdecl is likely to be required. This can indeed cause an SO, the stack doesn't get cleaned-up.

Debug + Windows + Registers and observe the value of the ESP register before and after the call, it should be same. If you disabled the PInvokeStackImbalance managed debugger warning then be sure to turn it back on. Ignoring this warning is not a good idea.

And debug the native code, verify the passed argument values. There are so many arguments that a single bad declaration for one of them is enough to shoot the foot.

梦在深巷 2024-11-09 09:01:08

ref 双数组似乎有问题,
将 [MarshalAs] 添加到其中并传递 IntPtr,而不是双精度数组。

.net 数组不是指针,不像 C++ 中的指针。

将该 C# 方法标记为私有,
使用 Marshal.Copy 将返回的指针传输到 .net 数组的公共方法进行包装。

在 .net 中分配时传输数组的示例:

[DllImport(EntryPoint="ExternalMethod"]
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), In] IntPtr);

public void ManagedWrapper(ref double[] array)
{
    IntPtr unmanagedMem = Marshal.AllocHGlobal(1000);
    Marshal.Copy(array, unmanagedMem, 0, 1000);
    ExternalMethodInvoke(unmanagedMem); // use try finally for freeing
    Marshal.Copy(unmanagedMem, array, 1, 1000);
    Marshal.FreeHGlobal(unmanagedMem);
}

在本机中分配时传输数组的示例:

[DllImport(EntryPoint="ExternalMethod"]
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr);

[DllImport(EntryPoint="ExternalDeleteArray"]
private static void ExternalDeleteArrayInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr);

public void ManagedWrapper(ref double[] array)
{
    IntPtr unmanagedMem;
    ExternalMethodInvoke(out unmanagedMem); // use try finally for freeing
    Marshal.Copy(unmanagedMem, array, 1, 1000);
    ExternalDeleteArrayInvoke(unmanagedMem);
}

如果 c# 端分配数组,请不要忘记在 c# 中分配和取消分配。
(使用 marshal 的 (de)allocate h 全局方法。)

在 C++ 分配中,调用 C++ 方法来取消分配。

The ref double array seems problematic,
Add [MarshalAs] to it and pass IntPtr, not a double array.

.net arrays are not pointers, as they are in C++.

Mark that c# method as private,
wrap with public method that uses Marshal.Copy to transfer returned pointer to .net array.

Example for transferring array when allocated in .net:

[DllImport(EntryPoint="ExternalMethod"]
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), In] IntPtr);

public void ManagedWrapper(ref double[] array)
{
    IntPtr unmanagedMem = Marshal.AllocHGlobal(1000);
    Marshal.Copy(array, unmanagedMem, 0, 1000);
    ExternalMethodInvoke(unmanagedMem); // use try finally for freeing
    Marshal.Copy(unmanagedMem, array, 1, 1000);
    Marshal.FreeHGlobal(unmanagedMem);
}

Example for transferring array when allocated in native:

[DllImport(EntryPoint="ExternalMethod"]
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr);

[DllImport(EntryPoint="ExternalDeleteArray"]
private static void ExternalDeleteArrayInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr);

public void ManagedWrapper(ref double[] array)
{
    IntPtr unmanagedMem;
    ExternalMethodInvoke(out unmanagedMem); // use try finally for freeing
    Marshal.Copy(unmanagedMem, array, 1, 1000);
    ExternalDeleteArrayInvoke(unmanagedMem);
}

If c# side allocates array, do not forget to allocate and deallocate in c#.
(using marshal's (de)allocate h global methods.)

In C++ allocates, call C++ method to deallocate.

不必了 2024-11-09 09:01:08

假设胶水代码是正确的,可能只是 DLL 函数占用了大量堆栈。我自己也遇到过类似的情况,结果发现C++堆栈上分配了一些非常大的对象。当从本机代码调用时,在调用之前仅使用了一点堆栈,因此堆栈上有足够的剩余空间。当从托管代码调用时,大量堆栈已被消耗,因此没有足够的空间。如果您查看导致溢出的 C++ 函数,您可能会发现它正在尝试将一个大对象放入堆栈中。

Assuming the glue code is correct, it might just be that the DLL function takes up a lot of stack. I ran into a similar situation myself, and it turned out that there was some very large object allocated on the C++ stack. When called from native code, there was only a little bit stack used before the call so there was enough remaining space on the stack. When called from managed code, a lot of the stack was already consumed so that there wasn't enough space left. If you look at the C++ function that is causing the overflow, you may see that it is trying to put a large object on the stack.

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