问题
MSDN's remarks section, described here, specifically mentions there is a difference between the loading types of the following function.
Since my module is portable and loads models dynamically, I'm not allowed / able to use any pre-processors commands:
#if (PSAPI_VERSION == 2)
(GetProcAddress("kernel32.dll", OBFUSCATE(L"K32GetMappedFileNameW")));
#elif (PSAPI_VERSION == 1)
(GetProcAddress("psapi.dll", OBFUSCATE(L"GetMappedFileNameW")));
#endif
In addition -
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
Doesn't make it much clearer of how windows version is exactly coordinated with the PSAPI version.
回答1:
The GetMappedFileName() documentation specifically says:
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.
If static linking is not an option for you, and you need to dynamically load the function at runtime without using #ifdef
statements, then simply check both DLLs unconditionally, eg:
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);
Or, just do what the documentation says - simply ignore kernel32 altogether and just use psapi.dll by itself on all Windows versions. On Windows 7 and later, psapi.GetMappedFileNameW()
is a wrapper for 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);
来源:https://stackoverflow.com/questions/29369597/how-to-load-getmappedfilename-correctly-based-on-windows-version