My name is Nada AboElseoud and I am a QA in VC++ Libraries team. I joined MS in February 2009. I would like to talk here about an incompatibility issue with WinSDK v7.0*.
If you are a developer who has recently migrated to WinSDK v7.0 (standalone SDK) or v7.0A (inbox with VS 2010), you may encounter these kinds of errors “The procedure entry point K32*** could not be located in the dynamic link library KERNEL32.dll” while running your application. This implies that you are running your application on an OS other than Windows7 or Windows Server 2008 R2. This blog will explain this blocking issue and provide the workaround.
Let me explain first why this issue happens. For performance reasons, some APIs have been moved from Psapi.dll to Kernel32.dll in Windows7 and Windows Server 2008 R2. WinSDK v7.0* is reflecting these modifications to be compatible with the new system dlls. This is by design, but wait! If you are trying to link your application to Psapi.lib and then targeting any pre Windows7 or pre Windows Server 2008 R2, you will get this runtime error. Breaking this down, all APIs from Psapi.dll are copied to Kernel32.dll in Windows7 and Windows Server 2008 R2 (Psapi.dll remain unchanged though). Linking to Psapi.lib marks these APIs as Kernel32 APIs to load them from Kernel32.dll instead. Following is the list of these APIs.
//Snapshot from Psapi.lib – WinSDK V7.0*
#if (PSAPI_VERSION > 1)
#define EnumProcesses K32EnumProcesses
#define EnumProcessModules K32EnumProcessModules
#define EnumProcessModulesEx K32EnumProcessModulesEx
#define GetModuleBaseNameA K32GetModuleBaseNameA
#define GetModuleBaseNameW K32GetModuleBaseNameW
#define GetModuleFileNameExA K32GetModuleFileNameExA
#define GetModuleFileNameExW K32GetModuleFileNameExW
#define GetModuleInformation K32GetModuleInformation
#define EmptyWorkingSet K32EmptyWorkingSet
#define QueryWorkingSet K32QueryWorkingSet
#define QueryWorkingSetEx K32QueryWorkingSetEx
#define InitializeProcessForWsWatch K32InitializeProcessForWsWatch
#define GetWsChanges K32GetWsChanges
#define GetWsChangesEx K32GetWsChangesEx
#define GetMappedFileNameW K32GetMappedFileNameW
#define GetMappedFileNameA K32GetMappedFileNameA
#define EnumDeviceDrivers K32EnumDeviceDrivers
#define GetDeviceDriverBaseNameA K32GetDeviceDriverBaseNameA
#define GetDeviceDriverBaseNameW K32GetDeviceDriverBaseNameW
#define GetDeviceDriverFileNameA K32GetDeviceDriverFileNameA
#define GetDeviceDriverFileNameW K32GetDeviceDriverFileNameW
#define GetProcessMemoryInfo K32GetProcessMemoryInfo
#define GetPerformanceInfo K32GetPerformanceInfo
#define EnumPageFilesW K32EnumPageFilesW
#define EnumPageFilesA K32EnumPageFilesA
#define GetProcessImageFileNameA K32GetProcessImageFileNameA
#define GetProcessImageFileNameW K32GetProcessImageFileNameW
Now, it should be obvious why by calling some API (say EnumProcessModules) you get this runtime error “The procedure entry point K32EnumProcessModules could not be located in the dynamic link library KERNEL32.dll” pointing to a different API name.
However, did you notice the IF condition involved?
This means that these APIs are defined/tagged only if the PSAPI_VERSION > 1. By default this value is set to 2 and _WIN32_WINNT is set to _WIN32_WINNT_MAXVER (which is 0x601 for Win7).
After reading about this issue, you may be able now to figure out the solution. Simply,
if you target any OS prior to Windows7 and Windows 2008 R2, what you need to do is to define _WIN32_WINNT to a previous version (before 0x601) or to define Psapi_version to 1.
cl /MD /EHsc /D _WIN32_WINNT=0x501 mytest.cpp /link Psapi.lib
cl /MD /EHsc /D PSAPI_VERSION=1 mytest.cpp /link Psapi.lib
Does this mean that this generated exe will work fine on Windows7 and Windows Server 2008 R2 as well? Definitely. As stated above, Psapi.dll is not modified and the workaround is just loading the APIs from Psapi.dll.
Otherwise, if you are just targeting Windows7 (or Windows 2008 R2), to take advantage of this performance boost, you can simply use the default predefined macros or explicitly define them as below.
cl /MD /EHsc /D _WIN32_WINNT=0x601 mytest.cpp /link Psapi.lib
cl /MD /EHsc /D PSAPI_VERSION=2 mytest.cpp /link Psapi.lib
Hope this is helpful J
Wow! Really? I've found that more than a month ago for our application cross-compiled for IA64, and fixed by the definition. The solution I've found by using Goodle. So, for me, you're somewhat late.
if you *really* care about perf, you can dynamically determine if you're running on Win7 and use GetProcAddress to get all these DLL entry points, instead of building 2 separate apps.
good post! thanks for the info