问题
I created a DLL file which includes two empty functions below.
extern "C" __declspec(dllexport) void __stdcall myFunc1() {
// just empty function
}
extern "C" __declspec(dllexport) void __cdecl myFunc2() {
// just empty function
}
In C#, I could call the functions using DLLImport
attribute like below.
[DllImport("myDLL", CallingConvention=CallingConvention.StdCall)]
private extern static void myFunc1();
[DllImport("myDLL", CallingConvention=CallingConvention.Cdecl)]
private extern static void myFunc2();
So I tried again directly with LoadLibrary()
of kernel32.dll instead of DllImport
attribute.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void MyFunc1();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void MyFunc2();
However a runtime error occurs when I call MyFunc1() where MyFunc2() works.
So I replaced __stdcall
with __cdecl
in C++, recompiled the DLL and then called MyFunc1() again in C#.
And.. It worked.
Why on earth doesn't __stdcall calling convention work with pinvoke in C#?
回答1:
What's happening here is that when you switch from __cdecl
to __stdcall
in the C++ code, the compiler decorates the name by which the function is exported. Instead of myFunc1
it is exported as myFunc1@0
or perhaps _myFunc1@0
. All the same, the name is decorated. You can check that this is so with dumpbin
or Dependency Viewer.
When you call GetProcAddress
, it cannot find a function named myFunc1
and so returns NULL
. You don't check for return values, and so carry on regardless. When you try to call the function, a run time error is thrown.
I've had to guess most of this because you did not show complete code. The other big lesson is to check for errors when calling Win32 functions.
来源:https://stackoverflow.com/questions/32427445/stdcall-calling-convention-and-using-pinvoke-in-c-sharp