August 27th, 2009

Windows SDK V7.0/V7.0A Incompatibility Workaround

Hi,

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.dllwhile 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   &n bsp;       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

#endif

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?

#if (PSAPI_VERSION > 1)

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).

Workaround

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.

For example:

cl /MD /EHsc  /D _WIN32_WINNT=0x501 mytest.cpp /link Psapi.lib

Or

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

Or

cl /MD /EHsc  /D PSAPI_VERSION=2 mytest.cpp /link Psapi.lib

 

Hope this is helpful J

Nada  AboElseoud

 

Category
C++
Topics
WinSDK

0 comments

Discussion are closed.