我有一个我编写并测试过的无法管理的C ++ DLL。在无人控制台应用程序中构建和运行时,无人管理的代码很好用。函数声明如下所示。
#ifndef IMPORT_MYLIB
# define MYLIB_API __declspec(dllexport)
#else
# define MYLIB_API __declspec(dllimport)
#endif
namespace gsod_data_parsing {
extern "C"
{
MYLIB_API int parse_raw_gsod_file_nocb(
const char *path,
int temp_threshold
);
}
}
我试图从托管应用程序调用它。我在C#文件中声明了这个函数:
[DllImport("GSODDLL.dll")]
public static extern int parse_raw_gsod_file_nocb(
[MarshalAs(UnmanagedType.LPStr)] string path,
int temp_threshold
);
然后,这些函数将在几个并行任务上执行,如下所示:
// Start a task - this runs on the background thread...
task1 = Task.Factory.StartNew(() =>
{
int t1 = parse_raw_gsod_file_nocb(filePaths[i], this._frostTemp);
return (t1 == 0);
}, this._tokenSource.Token);
它似乎先运行正常然后(我相信函数执行完毕后)我得到以下错误。
调用PInvoke函数'数据库 Creator!Database_Creator.Form1 :: parse_raw_gsod_file_nocb'有 堆栈不平衡。这可能是因为托管PInvoke 签名与非托管目标签名不匹配。检查一下 调用约定和PInvoke签名匹配的参数 目标非托管签名。
我看到了一个类似的问题here,但我不太明白接受的答案。
有人有什么想法吗? 感谢
答案 0 :(得分:5)
事实证明我的问题是由于调用约定不匹配。根据这个document,C / C ++程序的Windows中的默认调用约定是Cdecl。此外,根据此document,PInvoke的默认调用约定是StdCall。我最初没有指定任何调用约定,因此它默认为StdCall。由于这些约定规定了在函数调用之后如何清理堆栈,因此在函数执行结束时抛出错误是有道理的。
将我的PInvoke声明更改为此问题:
[DllImport("GSODDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int parse_raw_gsod_file_nocb(
[MarshalAs(UnmanagedType.LPStr)] string path,
int temp_threshold
);