stdcall calling convention and using pinvoke in C#

2019-08-07 14:08发布

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条回答
霸刀☆藐视天下
2楼-- · 2019-08-07 14:17

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.

查看更多
登录 后发表回答