The header file just like below
#define CoverWinAPI extern "C" __declspec(dllexport)
CoverWinAPI BOOL RunDll();
CoverWinAPI void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnCurrent,PROC pfnNew,HMODULE hmodCaller);
#pragma comment(linker,"/export:MyCreateWindowExW=_MyCreateWindowExW@48")
CoverWinAPI HWND WINAPI MyCreateWindowExW(
_In_opt_ DWORD dwExStyle,
_In_opt_ LPCWSTR lpClassName,
_In_opt_ LPCWSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int X,
_In_ int Y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam);
when I don't use #pragma comment ,the export funtion name is _MyCreateWindowExW@48.
But when I use #pragma comment(linker,"/export:MyCreateWindowExW=_MyCreateWindowExW@48")
, MSVC compile fail and show that unresolved external symbol _MyCreateWindowExW@48
. What cause this error?
CodePudding user response:
The problem you encountered is due to the way function names are decorated by the compiler.
_MyCreateWindowExW@48
is a x86-style decorated name, valid for x86 build only, its x64 counterpart is simply MyCreateWindowExW
(x64 has only one calling convention which resembles __cdecl
in that the caller is the one responsible for managing the stack allocation).
Contrary to the official documentation, neither export #pragma
nor /EXPORT
linker option work with undecorated names, they both expect the name to be fully decorated. This is mentioned here.
Small note
There are several ways to export from Dll, such as:
__declspec(dllexport)
#pragma comment(linker,"/export:...")
ORlink.exe /EXPORT
- DEF file
Using only one of them is usually enough, so in your example __declspec(dllexport)
is superfluous, even more so considering that it exports a decorated name, which is not what you wanted.
Solution #1 (IMO cumbersome)
Use #ifdef
to provide appropriate decorated name for each platform:
#define CoverWinAPI extern "C"
CoverWinAPI BOOL RunDll();
CoverWinAPI void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller);
#ifndef _WIN64
#pragma comment(linker,"/export:MyCreateWindowExW=_MyCreateWindowExW@48")
#else
#pragma comment(linker,"/export:MyCreateWindowExW")
#endif
CoverWinAPI HWND WINAPI MyCreateWindowExW(...);
Solution #2 (suggested)
Add a DEF file to your project:
LIBRARY CoverWinAPI
EXPORTS
MyCreateWindowExW
RunDll
ReplaceIATEntryInOneMod
Then your declarations could be rewritten like so:
#define CoverWinAPI WINAPI
BOOL CoverWinAPI RunDll();
void CoverWinAPI ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller);
HWND CoverWinAPI MyCreateWindowExW(...);
This works because apparently linker does try to match DEF file entries vs. both decorated and undecorated names.