Wednesday, November 5, 2008

A Sparsely Documented Aspect of GetProceAddress

A couple of weeks ago, in the course of developing a new version of my MD5 digest library, I moved the Unicode versions of the functions into a separate library, which the main library would manage, and load only if the Windows platform on which it is running fully supports Unicode. Among other things, this meant that I needed to use the GetProcAddress Windows API function to call the functions in the Unicode satellite library. According to the documentation, on the platforms that support it, Windows exposes both ANSI and Unicode versions of this function.

Accordingly, I took the documented type of LPCSTR for the lpProcName argument to mean that the Unicode veersion of the function took a Unicode string. Silly me!

After hours of trial and failure, I repeated my Google search, and examined some of the other articles, starting with HowTo: LoadLibrary and GetProcAddress?, which gives hints of a few key elements not given sufficient emphasis in the formal documentation. The discussion on the Experts Exchange board indicated that I needed to create a typedef to match the function prototype. Less obvious is that the lpProcName argument to GetProcAddress should probably be documented as something more like char *. For this, I am indebted to the following text, taken from RE: GetProcAddress Usage.


... you will see that the lpProcName parameter is *only* configured
for const char*; there is no TCHAR derived type for the string used
here. So regarless of whether you are running with UNICODE turned
on or not, the name of a function passed to GetProcAddress is
never UNICODE formatted.


In the course of writing this article, with the knowledge learned from these and other articles, and the working code, which is part of the published source code of MD5Digest: Dynamic Link Library for Computing MD5 Digest Strings, I made a closer inspection of the included code sample.


// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.

pGNSI = (PGNSI) GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")),
"GetNativeSystemInfo");
if(NULL != pGNSI)
pGNSI(&si);
else GetSystemInfo(&si);


Although the library name in the GetModuleHandle call is wrapped in a TEXT macro, the function name string in the GetProcAddress call is not. Pretty subtle, eh?