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 函数时检查错误。
我创建了一个 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 函数时检查错误。