stdcall 调用约定和在 C# 中使用 pinvoke

stdcall calling convention and using pinvoke in C#

我创建了一个 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();

所以我直接用 kernel32.dll 的 LoadLibrary() 代替 DllImport 属性再次尝试。

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

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

但是当我调用 MyFunc1() 时发生运行时错误 MyFunc2() 工作的地方

所以我在 C++ 中用 __cdecl 替换了 __stdcall,重新编译了 DLL,然后在 C# 中再次调用了 MyFunc1()。

而且..它起作用了。

为什么 __stdcall 调用约定不能在 C# 中使用 pinvoke?

这里发生的事情是,当您在 C++ 代码中从 __cdecl 切换到 __stdcall 时,编译器会修饰导出函数的名称。它不是 myFunc1,而是导出为 myFunc1@0_myFunc1@0。都一样,名字是装饰的。您可以使用 dumpbin 或 Dependency Viewer 检查是否如此。

当您调用 GetProcAddress 时,它找不到名为 myFunc1 的函数,因此 returns NULL。您不检查 return 值,因此无论如何都要继续。当您尝试调用该函数时,会引发 运行 时间错误。

我不得不猜测其中的大部分内容,因为您没有显示完整的代码。另一个重要的教训是在调用 Win32 函数时检查错误。