by Michael S. Kaplan, published on 2005/05/01 12:43 -07:00, original URI: http://blogs.msdn.com/michkap/archive/2005/05/01/413835.aspx
I wanted to clarify the way that unicows.lib works.
This .LIB file is not the usual sort. It has in it a bunch of symbols, for each API that unicows.dll supports. Lets look at what a bit of that looks like -- say running the following on unicows.lb and kernedl32.lib looking at a particular API (I'll try using my favorite API -- CompareString):
link -dump -all unicows.lib >link_unicows.txt
link -dump -all kernel32.lib >link_kernel32.txt
The output is huge (over 11mb) for unicows.lib, and most of them are obviously for other functions anyway, which is why I dumped them both to a file. Here is what kernel32.lib has to say about CompareStringW:
19400 _CompareStringW@24
19400 __imp__CompareStringW@24
2D _CompareStringW@24
2D __imp__CompareStringW@24
Version : 0
Machine : 14C (x86)
TimeDateStamp: 41C232BB Thu Dec 16 17:13:31 2004
SizeOfData : 00000020
DLL name : KERNEL32.dll
Symbol name : _CompareStringW@24
Type : code
Name type : undecorate
Hint : 59
Name : CompareStringW
Archive member name at 19470: KERNEL32.dll/
41C232BB time/date Thu Dec 16 17:13:31 2004
uid
gid
0 mode
35 size
correct header end
_CompareStringW@24
Now looking at the bigger unicows.lib file and its references to CompareString. Those who are curious can run the above command line -- it is a huge file.
The biggest part of all this is the names that are the same between them. By putting unicows.lib before kernel32.lib, any time anyone tries to reference CompareStringW in any of its forms, it will find MSLU's rather than the operating system's. Simple misdirection, really. Now the rules of the linker in looking for symbols are simple: look in all of the .OBJ files, then look in all of the .LIB files, in order from left to right as they are explicitly listed.
So the trick is just to put unicows.lib first -- it will win!
The rest is a little bit trickier -- there is a pointer called _kernel32_CompareStringW_Thunk which will sit in the user's image, and it points to a function also inside of the user's image called ResolveThunk(). This ResolveThunk() function is the one that does the work to figure out what platform you are running on and then call either the function in unicows.dll or the one in the operating system (calling something like the same GetProcAddress that you would call if you wanted a function pointer). It then fixes up that pointer in _kernel32_CompareStringW_Thunk to call the function it selected, so that ResolveThunk() never needs to be called again for the function that was just resolved.
Think of it as a static version of the information that is dynamically generated when you use DelayLoad.
Now I do not want to take credit for this work, the real genius here comes from two people: Bryan Tuttle (most likely person to fix and least likely person to break the Windows build on any given day of the week, and the person who originally pointed out to me the real problems in Godot using DelayLoad itself and blocking others from using it) and the recently retired Dan Spalding (also known to many as the father of the linker or the linker god at Microsoft and the original author of the Delayload technology on which much of this approach is based).
And of course I am oversimplifying here, as there are many interesting gotchas that unicows.lib hits (from failure cases to functions that are not there to functions that are hard to call to avoiding assembly language and more), which I'll talk about another day....
This post brought to you by "U" (U+0055, a.k.a. LATIN CAPITAL LETTER U)
(Because "U" is for Unicows, Unicode, and UBetcha!)
# James Todd on Monday, May 02, 2005 10:44 AM:
# Michael S. Kaplan on Monday, May 02, 2005 11:01 AM:
# James Todd on Monday, May 02, 2005 12:20 PM:
referenced by