A customer was writing a test to verify that their patching system was working properly, but they found that even after the patch was installed, a call to VerQueryValue reported that the file was still the original version. Why was the VerQueryValue function reporting the wrong version?

Recall that the version resource is, well, a resource. And one of the things that happens with resources is that they can get redirected based on the language the user is running. When you ask for the resources of a language-neutral DLL, the loader redirects your request to the appropriate language-specific DLL. That way, if you're running on an English system, the resources come from the DLL with English resources, whereas if you're running on a German system, the resources come from the DLL with German resources.

The customer's patch updated only the language-neutral DLL (since it was a code fix that involved no resource changes). When the GetFileVersionInfo function loaded the DLL and asked for its resources, the loader redirected the request to the English satellite DLL.

To disable this redirection, you can use the GetFileVersionInfo function and don't pass the FILE_VER_GET_LOCALIZED flag or the FILE_VER_GET_NEUTRAL flag. Michael Kaplan covered this a few years ago. If you use the plain GetFileVersionInfo function, the version information that comes back is a blend of the language-neutral and the localized information: The binary version information comes from the language-neutral DLL, whereas the string version information comes from the localized DLL. The strings come from the localized DLL because you want the information like FileDescription to be something meaningful to the user.

It does mean, though, that if you are extracting version information for testing and verification purposes, you need to be mindful of where you are getting them from so that you get the values you expect.