从C#调用非托管(C++)函数时出现PInvoke错误

nal*_*d88 2 c# c++ dll pinvoke marshalling

我有一个我编写和测试的无人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
  );
}
}
Run Code Online (Sandbox Code Playgroud)

我试图从托管应用程序调用它.我在我的C#文件中声明了这个函数,如下所示:

 [DllImport("GSODDLL.dll")]
 public static extern int parse_raw_gsod_file_nocb(
   [MarshalAs(UnmanagedType.LPStr)] string path,
   int temp_threshold
 );
Run Code Online (Sandbox Code Playgroud)

然后,这些函数将在几个并行任务上执行,如下所示:

// 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);
Run Code Online (Sandbox Code Playgroud)

它似乎一开始运行正常但后来(我相信函数执行完毕后)我得到以下错误.

调用PInvoke函数'Database Creator!Database_Creator.Form1 :: parse_raw_gsod_file_nocb'使堆栈失去平衡.这很可能是因为托管PInvoke签名与非托管目标签名不匹配.检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配.

我在这里看到了类似的问题,但我不太明白接受的答案.

有人有主意吗?谢谢

nal*_*d88 5

所以事实证明我的问题是由于调用约定不匹配.根据这个文档,Windows中C/C++程序的默认调用约定是Cdecl.此外,根据该文档,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
);
Run Code Online (Sandbox Code Playgroud)