PInvoke error when calling unmanaged (C++) functio

2020-04-17 04:56发布

问题:

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

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.

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

回答1:

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.

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