从c++ Console App Works调用c++ DLL,从c# Console App调用有堆栈溢出
本文关键字:App 调用 Console c++ 栈溢出 堆栈 Works DLL | 更新日期: 2023-09-27 17:50:31
我收到一些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函数添加了一些调试语句,它似乎在函数返回之前击中了每个语句。但它似乎抛出错误从函数返回。欢迎大家提出真知灼见。
谢谢。
CallingConvention属性在[DllImport]声明中缺失。没有迹象表明您在C声明中使用了__stdcall。Cdecl可能是必需的。这确实会导致SO,堆栈没有被清理。
调试+ Windows +寄存器并观察调用前后ESP寄存器的值,它应该是相同的。如果您禁用了pinvokestack失衡管理调试器警告,那么请确保将其重新打开。忽略这个警告可不是一个好主意。
并调试本机代码,验证传递的参数值。有如此多的参数,其中一个错误的声明就足以导致失败。ref双数组似乎有问题,添加[MarshalAs]并传递IntPtr,而不是双精度数组。
.net数组不像c++中那样是指针。
标记c#方法为private,使用使用Marshal的公共方法进行包装。复制返回的指针到。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全局方法)
在c++分配中,调用c++方法来释放。
假设粘合代码是正确的,可能只是DLL函数占用了大量堆栈。我自己也遇到过类似的情况,结果是在c++堆栈上分配了一些非常大的对象。当从本机代码调用时,在调用之前只使用了一小块堆栈,因此堆栈上有足够的剩余空间。当从托管代码调用时,已经消耗了大量堆栈,因此没有足够的空间剩余。如果您查看导致溢出的c++函数,您可能会看到它试图将一个大对象放在堆栈上。