The GetFileVersionInfoSize
function returns two pieces of information. The return value is the amount of memory needed to record the version information of a file, and the DWORD
pointed to by the lpdwHandle
parameter is set to zero. What's the deal with this strange lpdwHandle
parameter?
That parameter used to do something.
The documentation for GetFileVersionInfo
used to read
dwHandle: The value returned by a preceding call to GetFileVersionInfoSize
in the lpdwHandle
parameter.
The purpose of that parameter is to allow GetFileVersionInfoSize
to pass information to GetFileVersionInfo
about what it found.
In 16-bit Windows and Windows 95, 98, and Me, the GetFileVersionInfoSize
function opened the target file and went searching for the version information. Once it was located, the size of the version was the return value and the file offset of the version information was stored in lpdwHandle
. The GetFileVersionInfo
function was very simple: It merely read dwLen
bytes from the file starting at file offset dwHandle
.
In the Windows NT series, this mechanism was abandoned. The handle is not used any more. Why not? I don't know, but I have some guesses.
First, Windows NT supports files larger than 2GB, so a 32-bit value isn't big enough to hold a file offset value.
Second, multitasking introduces a race condition in the GetFileVersionInfoSize
/GetFileVersionInfo
pattern. Whereas in 16-bit Windows, nobody could modify the file between the two calls due to co-operative multi-tasking, in 32-bit Windows, it's possible that somebody could sneak in and modify the file between the two calls, resulting in the call to GetFileVersionInfo
returning garbage. (Yes, Windows 95 has this race condition.)
Third, the amount of memory required to load the version resource is not the same as the actual size of the version resource. It's not enough just to seek to the specified location and read dwLen
bytes from it. For example, a program might load the version resources from a 32-bit module, and we've seen earlier that 32-bit version resources are Unicode. But that program might then call VerQueryValueA
to retrieve the version string in the ANSI code page. The GetFileVersionInfo
function needs to return a buffer that can hold not only the actual version resource but also enough memory to hold copies of all the strings in the version resource converted to the ANSI character set so that the VerQueryValueA
function could return them.
Whatever the reason, the Windows NT series of operating systems don't use the handle value. When you call GetFileVersionInfoSize
, the function looks for the version resource and returns the size of the memory block needed to record it. (Which, as we saw above, includes translation space for the ANSI strings.) When you call GetFileVersionInfo
, the function starts over from scratch and looks for the version resource and copies it into the buffer.
The dwHandle
parameter is now just a vestigial organ.
Prediction
People will take this as the opportunity to complain about the GetFileVersionInfo
family of functions. (Because all I have to do is mention a function name, and that makes it open season on all problems related to that function, as if every function I mention is one that I have total responsibility and authority over.)
There is still a race, is there not? If the size of the version info increases between the calls (and assuming your ealier admonition about the size parameter being the buffer size is heeded) the second call will fail to retrieve a complete representation of the version info.
So, to be correct, any program calling this function must do so in a loop, detecting this situation and retrying, right?
just tell us what you do have total responsibility and authority over, and then use that to filter out what people whinge about.
I propose we go one further. Raymond, please post all source code you are or have worked on and we will pick on it like unknowing amateur idiots. And don’t give me corporate reasons why you can’t do that.
I think you’ve reached the position where anything you post will get criticized straight away. You should try and post one of the book examples as your code and let people pick on it ;)
BTW, I’m a PLD Linux developer and actually don’t use Windows myself but I read your blog as I find it both amusing (great sense of humour) and very informative. Just ignore the whiners.
We hold Microsoft and its code to such a high standard; that’s why we complain when parts of it are hard to understand or hard to use…. or lack high-level overviews!
But your blog has gone a long way in demystifying many of its parts, and helping us understand why all of MS’s code can’t be the way we (each) want it to be.
But aren’t PE files limited to 4GB, even on 64 bit?
@GvG: even so, there are still two other reasons.
Weren’t there sufficient API differences (e.g. WM_CTLCOLOR) between Win16 and Win32 to justify changing the definitions to eliminate the superfluous handle?
Putting in predictions like that creates a nice little paradox – since people probably won’t complain about it once you predict that they will.
Or maybe you have less faith in the intelligence of people commenting on your blog than I do ;-)
Hey Raymond! I don’t like the way you removed the undocumented TRUENAME command from MS-DOS 7! How dare you? Put it back immediately!
(There… random enough for ya? I got a million of ’em!)
Raymondophile’s Corner:
We loves ya, Raymondo, really we do!
Even if I don’t like many “whining” comments that these posts get, I think that most of the time, they don’t hold *you* responsible… it’s just like you said, they take the post “as an opportunity” because it makes them remember a hard time.
That said, keep up the good work Raymond, I always like these “trivia” posts!
> Or maybe you have less faith in the intelligence of people commenting
> on your blog than I do ;-)
I think that’s *why* he put the prediction in: so people realize the futility and don’t do it. Still, I’m sure there’ll be some people who won’t get the hint, though…
Neil: I don’t see how the WM_CTLCOLOR change is anywhere near the same league as changing a function defition in terms of what would break. Besides, as Raymond said, the lpdwHandle parameter was still used in Windows 95.
[I have total responsibility and authority over nothing. -Raymond]
Ah, well in that case I have this major issue with nothing in which….
Just joking Raymond. Some of us really do appreciate the time and effort that goes into your blog. I know I for one have a much, much greater understanding of both Windows and the thought process that goes into such large scale development as a direct result. Don’t let the whining minority get you down.
The best part of Raymond’s prediction is we will now all talk about the prediction instead of the actual function in question, making this comment section utterly pointless.
I admit it was hard to resist!
In many cases, it might just be people with the same experience, because shared misery is half the misery. (And my eyes almost did fall out when I saw what I needed to doto get a DLL’s version. Not that I’d be complaning…)
Why is it called nothing anyway? Why not just leave it at null?
“[But why complain to me? If your complaint isn’t directed to me, then don’t post it on my blog. Go start your own blog. -Raymond]”
But, of course, the MS people who *are* responsible, or who would benefit from knowing how much pain some misfeature or other has caused users and programmers, are FAR more likely to read your blog, Raymond, than lots of other blogs scattered hither and yon.
Your blog is so good, and has so much great information, that it has become a valuable resource. Please don’t get upset because people want to comment about on-topic things that you mention which have caused them pain, and are the fault of other Microsoft programmers.