2

我有一个我已经编写和测试过的未管理的 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 函数 'Database Creator!Database_Creator.Form1::parse_raw_gsod_file_nocb' 使堆栈失衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

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

有人有想法么?谢谢

4

1 回答 1

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
);
于 2013-02-24T04:18:46.087 回答