When good functions [seem to] go bad

by Michael S. Kaplan, published on 2011/02/11 07:01 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2011/02/11/10128045.aspx


In many cases it isn't the question that is complicated; it is the impact of surrounding features that make the answers so complicated!

A while back, the question that was asked was:

Hello,

I’m trying to get the file version for mshtml.dll at runtime, when I call GetFileVersionInfo (from shell\osshell\version\filever.cpp) with either the full path (C:\windows\system32\mshtml.dll) or just the binary name, it always gives me: 8.00.7600.16385 (win7_rtm.090713-1255) – the IE8 RTM version, regardless of which TP (test pass, think of it as a service pack for IE) is on the machine.

According to the filever tool, the version I actually have on my machine is:

>filever /v C:\Windows\System32\mshtml.dll
<snip>
        FileVersion             8.00.7600.16625 (win7_gdr.100629-1617)

How can I get GetFileVersionInfo give me this version?

Thanks!

Okay, the way the question was asked was complicated the time, too. :-)

But at its simplest level the question was just "how do I get the version number?" since the wrong answer was (apparently) being returned.

Anyone want to take a guess as to what might be going on, what might cause a[n apparent] lie to be told here?

Hint: Ask yourself why I might care about the answer here as a way to figure out what the answer might be....


Milan on 11 Feb 2011 7:15 AM:

With hint it's trivial, there's .mui file involved.

Michael S. Kaplan on 11 Feb 2011 7:25 AM:

Go on...

Milan on 11 Feb 2011 7:50 AM:

Acording to documentation (msdn.microsoft.com/.../ms647003(v=vs.85).aspx):

"

File version info has fixed and non-fixed part. The fixed part contains information like version number. The non-fixed part contains things like strings. In the past GetFileVersionInfo was taking

version information from the binary (exe/dll). Currently, it is querying fixed version from language neutral file (exe/dll) and the non-fixed part from mui file, merges them and returns to the user. If the given binary does not have a mui file then behavior is as in previous version.

"

My .mui contains "File Version: 8.00.6001.18702 (longhorn_ie8_rtm(wmbla).090308-0339)" in it's dynamic part so GetFileVersionInfo returns it.

I guess filever is not using GetFileVersionInfo but parses resource directly.

Ivan Rouzanov on 11 Feb 2011 9:53 AM:

"In the past GetFileVersionInfo was taking version information from the binary (exe/dll). Currently, it is querying fixed version from language neutral file (exe/dll) and the non-fixed part from mui file, merges them and returns to the user. If the given binary does not have a mui file then behavior is as in previous version."

msdn.microsoft.com/.../ms647003(VS.85).aspx

Jeremy Drake on 11 Feb 2011 10:48 AM:

It's always good when you can tell the user to RTFM:

msdn.microsoft.com/.../ms647003(v=VS.85).aspx

"""

Remarks

File version info has fixed and non-fixed part. The fixed part contains information like version number. The non-fixed part contains things like strings. In the past GetFileVersionInfo was taking version information from the binary (exe/dll). Currently, it is querying fixed version from language neutral file (exe/dll) and the non-fixed part from mui file, merges them and returns to the user.

"""

I suppose you could format the version number yourself from the fixed part (the binary version number).  That's what I tend to do (though I don't put anything other than the raw dot-delimited four-part version number in the string version field).  Or you could try to convince GetFileVersionInfoEx to give you the lauguage-neutral non-fixed data (though the FM on that function doesn't tell you what flag to pass for that, I assume it's 0, none of the above), if you can even use that function since it is only available on Vista+, and most people still have to support at least XP.  Or you could use the resource functions directly to look up the RT_VERSION data (FindResourceEx says passing MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) gives you the resources for the current thread's current language, so how would you specify you want the neutral version of the resources?).  Or if all that fails, you could always go traipsing around in the PE file format and that way be sure nobody's pulling any slight-of-hand with which file's data you get back.  In case you can't tell, I tend to really hate it when the system thinks it's smarter than me and tells me "You asked for info from *this* file?  I'm sure what you really wanted is info from this *OTHER* file, so I'll just return that instead."  That's right up there with "You want to know what version of Windows you're running on?  Good luck with that.  Here, let me *lie to you* about that so you can try to load the wrong driver and with any luck, that will bluescreen the system and really annoy the user."

But let's go back to the original question for a second.  Trying to query the version of a DLL at runtime generally tends to be used for figuring out if it supports a given feature.  Better to test for that feature directly, and only if that's not possible, fall back to comparing the binary version from the "fixed data" that's not returned from the MUI anyway.

Little Commenter on 11 Feb 2011 12:51 PM:

GetFileVersionInfo is getting info from MUI files (when available) and merges this info with fixed info from language neutral file.

My proposed answer: Use GetFileVersionInfoEx and pass as first parameter FILE_VER_GET_NEUTRAL. This way you will obtain the resource from the language neutral file, not from the MUI file.

Jeremy Drake on 11 Feb 2011 3:11 PM:

@Little Commenter: the docs for GetFileVersionInfoEx say of FILE_VER_GET_NEUTRAL: "This flag must be combined with FILE_VER_GET_LOCALISED."  The description of what happens in this case seems to match the behavior of GetFileVersionInfo, which is what the original poster had problems with.


go to newer or older post, or back to index or month or day