1

以下の 2 つの空の関数を含む DLL ファイルを作成しました。

extern "C" __declspec(dllexport) void __stdcall myFunc1() {
    // just empty function
}

extern "C" __declspec(dllexport) void __cdecl myFunc2() {
    // just empty function
}

C# では、DLLImport以下のように属性を使用して関数を呼び出すことができました。

[DllImport("myDLL", CallingConvention=CallingConvention.StdCall)]
private extern static void myFunc1();

[DllImport("myDLL", CallingConvention=CallingConvention.Cdecl)]
private extern static void myFunc2();

そのため、属性LoadLibrary()の代わりにkernel32.dllを直接使用して再試行しました。DllImport

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void MyFunc1();

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void MyFunc2();

ただし、 MyFunc2()が機能する場所で MyFunc1( ) を呼び出すと、ランタイム エラーが発生します。

そこで、C++ で置き換え__stdcall__cdeclDLL を再コンパイルしてから、C# で MyFunc1() を再度呼び出しました。

そして..うまくいきました。

いったいなぜ __stdcall 呼び出し規約が C# の pinvoke で機能しないのですか?

4

1 に答える 1

7

ここで何が起こっているかというと、C++ コードで から__cdeclに切り替える__stdcallと、コンパイラは関数がエクスポートされる名前を修飾します。代わりに、またはおそらくmyFunc1としてエクスポートされます。それでも、名前が飾られています。または依存関係ビューアーでそうなっていることを確認できます。myFunc1@0_myFunc1@0dumpbin

を呼び出すとGetProcAddress、という名前の関数が見つからないため、myFunc1が返されますNULL。戻り値をチェックしないので、関係なく続行します。関数を呼び出そうとすると、実行時エラーがスローされます。

完全なコードを示していないため、これのほとんどを推測する必要がありました。もう 1 つの重要な教訓は、Win32 関数を呼び出すときにエラーをチェックすることです。

于 2015-09-06T21:12:34.947 に答える