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

时间:2013-02-24 04:18:46

标签: 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
  );
}
}

我试图从托管应用程序调用它。我在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,但我不太明白接受的答案。

有人有什么想法吗? 感谢

1 个答案:

答案 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
);