如何根据windows版本正确加载GetMappedFileName

How to load GetMappedFileName correctly based on windows version

MSDN的备注部分,描述here,特别提到以下函数的加载类型有区别

由于我的模块是可移植的并且动态加载模型,我不允许/不能使用任何预处理器命令:

#if (PSAPI_VERSION == 2)
            (GetProcAddress("kernel32.dll", OBFUSCATE(L"K32GetMappedFileNameW")));
#elif (PSAPI_VERSION == 1)
            (GetProcAddress("psapi.dll", OBFUSCATE(L"GetMappedFileNameW")));
#endif

另外 -

Kernel32.dll on Windows 7 and Windows Server 2008 R2; Psapi.dll (if PSAPI_VERSION=1) on Windows 7 and Windows Server 2008 R2; Psapi.dll on Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP

并没有更清楚地说明 windows 版本与 PSAPI 版本的精确协调。

GetMappedFileName() documentation具体说:

Starting with Windows 7 and Windows Server 2008 R2, Psapi.h establishes version numbers for the PSAPI functions. The PSAPI version number affects the name used to call the function and the library that a program must load.

If PSAPI_VERSION is 2 or greater, this function is defined as K32GetMappedFileName in Psapi.h and exported in Kernel32.lib and Kernel32.dll. If PSAPI_VERSION is 1, this function is defined as GetMappedFileName in Psapi.h and exported in Psapi.lib and Psapi.dll as a wrapper that calls K32GetMappedFileName.

Programs that must run on earlier versions of Windows as well as Windows 7 and later versions should always call this function as GetMappedFileName. To ensure correct resolution of symbols, add Psapi.lib to the TARGETLIBS macro and compile the program with -DPSAPI_VERSION=1. To use run-time dynamic linking, load Psapi.dll.

如果静态链接不适合您,并且您需要在运行时动态加载函数而不使用 #ifdef 语句,那么只需无条件地检查两个 DLL,例如:

typedef DWORD WINAPI (*LPFN_GetMappedFileNameW)(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, DWORD nSize);

HINSTANCE hPsapi = NULL;
LPFN_GetMappedFileNameW lpGetMappedFileNameW = NULL; 

...

lpGetMappedFileNameW = (LPFN_GetMappedFileNameW) GetProcAddress(GetModuleHandle("kernel32.dll"), L"K32GetMappedFileNameW"));
if (lpGetMappedFileNameW == NULL)
{
    hPsapi = LoadLibraryW(L"psapi.dll");
    lpGetMappedFileNameW = (LPFN_GetMappedFileNameW) GetProcAddress(hPsapi, L"GetMappedFileNameW");
}

// use lpGetMappedFileNameW() as needed ...

if (hPsapi)
    FreeLibrary(hPsapi);

或者,按照文档中的说明操作 - 完全忽略 kernel32 并在所有 Windows 版本上单独使用 psapi.dll。在 Windows 7 及更高版本中,psapi.GetMappedFileNameW()kernel32.K32GetMappedFileNameW().

的包装器
typedef DWORD WINAPI (*LPFN_GetMappedFileNameW)(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, DWORD nSize);

HINSTANCE hPsapi = NULL;
LPFN_GetMappedFileNameW lpGetMappedFileNameW = NULL;

...

hPsapi = LoadLibraryW(L"psapi.dll");
lpGetMappedFileNameW = (LPFN_GetMappedFileNameW) GetProcAddress(hPsapi, L"GetMappedFileNameW");

// use lpGetMappedFileNameW() as needed ...

FreeLibrary(hPsapi);