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関数'DatabaseCreator!Database_Creator.Form1 :: parse_raw_gsod_file_nocb'の呼び出しにより、スタックのバランスが崩れました。これは、マネージドPInvokeシグニチャがアンマネージドターゲットシグニチャと一致しないことが原因である可能性があります。PInvokeシグニチャの呼び出し規約とパラメータがターゲットのアンマネージドシグニチャと一致することを確認してください。

私はここで同様の質問を見ましたが、受け入れられた答えを完全には理解していません。

誰かアイデアはありますか?ありがとう

4

1 に答える 1

5

したがって、私の問題は呼び出し規約の不一致が原因であることがわかりました。このドキュメントによると、C /C++プログラムのWindowsでのデフォルトの呼び出し規約は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 に答える