Holy cow, I wrote a book!
The documentation for the
VerQueryValue function states that the first parameter
"pointer to the buffer containing the version-information resource
returned by the GetFileVersionInfo function."
Some people, however, decide to bypass this step and
pass a pointer to data that was obtained some other way,
and then wonder why
VerQueryValue doesn't work.
The documentation says that the first parameter to
VerQueryValue must be a buffer returned by
the GetFileVersionInfo function for a reason.
The buffer returned by
GetFileVersionInfo is an opaque data block
specifically formatted so that VerQueryValue
You're not supposed to look inside that buffer, and you certainly
can't try to "obtain the data some other way".
Because if you do,
VerQueryValue will look for something in a buffer
that is not formatted in the manner the function expects.
(And it can't even detect that the buffer is improperly formatted
because there is no cbSize parameter to the
VerQueryValue function that tells it how big the
Without that information, VerQueryValue can't check
that, say, all the internal values are in range, since it
doesn't know what "out-of-range" is!
Is a value of 4000 out of range?
It would be if the buffer were only 3000 bytes long.
But it would be okay if the buffer were 5000 bytes long.
Since there is no size parameter, the
the VerQueryValue function is forced to assume that
everything is okay.)
If it wasn't obvious enough from the documentation that you
can't just pass a pointer to a version resource
obtained "some other way",
it's even more obvious once you see
the format of 32-bit version resources.
Notice that all strings are stored in Unicode.
But if you call the ANSI version
VerQueryValueA to request a string,
the function has to give you a pointer to an ANSI string.
There is no ANSI version of the string in the raw version
resource, so what can it possibly return?
You can't return a pointer to something that doesn't exist.
VerQueryValueA needs to produce an ANSI string,
and it does so from memory that GetFileVersionInfo
prepared when the resources were extracted.
That there is no cbSize parameter to VerQueryValue
was a failure of the original design of the function,
but a slightly more understandable one when you look at the original
design of 16-bit version resources:
Since 16-bit Windows didn't have Unicode support,
there was only one version of VerQueryValue,
and it operated on ANSI strings.
The 16-bit version resource format used ANSI strings,
so VerQueryValue could just return a pointer
into the raw version resource.
No character set conversion was necessary, and therefore no
need to reserve additional space as a string conversion
no need for GetFileVersionInfo to "prepare"
a buffer so that VerQueryValue could convert
from one character set to another.