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

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

问题描述:

我有一个未编译的C ++ DLL,我已经编写和测试。在未经管理的控制台应用程序中构建和运行时,未经授权的代码会很好。函数声明如下所示。

I have an unmanged C++ dll that I have written and tested. The unmanged code woks fine when built and run in an unmanged console app. The function declaration is shown below.

#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#文件中声明函数像这样:

I am trying to call this from a managed application. I declare the function in my C# file like this:

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

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

These functions are then being executed on a couple parallel tasks like shown below:

// 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);

它看起来运行正常,但然后(我相信函数已完成执行)以下错误。

It appears to run fine at first but then (I believe when the function has finished executing) I get the following error.


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

A call to PInvoke function 'Database Creator!Database_Creator.Form1::parse_raw_gsod_file_nocb' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

类似问题这里,但我不太明白接受的答案。

I saw a similar question here but I don't quite understand the accepted answer.

任何人都有什么想法?
感谢

Anyone have any ideas? Thanks

原因是我的问题是由于调用约定不匹配。根据此文档,默认呼叫在Windows的C / C ++程序的约定是Cdecl。此外,根据此文档 PInvoke的默认调用约定是StdCall。我原来没有指定任何调用约定,所以它是默认的StdCall。因为这些约定指定了在函数调用之后如何清除堆栈,所以在函数执行结束时抛出错误是很有意义的。

So it turns out my problem was due to calling convention mismatch. According to this document the default calling convention in windows for C/C++ programs is Cdecl. Also, according to this document the default calling convention for PInvoke is StdCall. I originally did not specify any calling convention so it was defaulting to StdCall. Since these conventions specify how the stack is cleaned up after the function call, it makes sense that the error was being thrown at the end of the function's execution.

更改我的PInvoke声明到此固定我的问题:

Changing my PInvoke declaration to this fixed my problem:

[DllImport("GSODDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int parse_raw_gsod_file_nocb(
  [MarshalAs(UnmanagedType.LPStr)] string path,
  int temp_threshold
);