Home > Enterprise >  Why pragma comment(linker,"/export ...") unresolved external symbol
Why pragma comment(linker,"/export ...") unresolved external symbol

Time:06-12

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.
the output of dumpbin.exe 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:...") OR link.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.

  • Related