3

I have some reasonably tried and tested code which uses the Windows API calls to read FileVersionInfo strings, like "FileVersion" and "CompanyName".

I found it failed with one particular 3rd party DLL. The problem seems to be this:

Reading the \VarFileInfo\Translation value, I get 040904B0 (US English, Unicode). But when I then attempt to call VerQueryValue on \StringFileInfo\040904B0\CompanyName, it returns false.

But tweaking the code to use the Windows Latin-1 ANSI codepage works: \StringFileInfo\040904E4\CompanyName.

So, the code page in the string table doesn't match the \VarFileInfo\Translation value.

According to the example resource at the bottom of MSDN's VERSIONINFO resource documentation, this is an appropriate thing to do!

Given this, can I use the published VersionInfo APIs to correctly read the strings for this file, without "guessing" the codepage?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Roddy
  • 66,617
  • 42
  • 165
  • 277
  • 2
    In our experience we've found that the `VarFileInfo\\Translation` value is often wrong (e.g. it will indicate German but the `StringFileInfo` table is only in English). In our code we try first of all for the user's default language (`GetUserDefaultLangID()`) followed by the `Translation` value, and failing both of those we loop through several variants of US-English (1200, 1252, 437) as a fallback. – Jonathan Potter Jun 21 '16 at 20:19
  • @JonathanPotter Thanks. That's the kind of heuristic I was hoping to avoid, but I suspect it's the only way :) – Roddy Jun 21 '16 at 20:27
  • @JonathanPotter: why not use the `\Translation` value first, in case it actually exists, and then fall back to `GetUserDefaultLangID()`? Why use the user language first and then fall back to the `\Translation` value? `FormatMessage()` has some additional fallbacks: "*FormatMessage looks for a message for LANGIDs in the following order: 1.Language neutral 2.Thread LANGID, based on the thread's locale value 3.User default LANGID, based on the user's default locale value 4.System default LANGID, based on the system default locale value 5.US English*" – Remy Lebeau Jun 21 '16 at 20:47
  • @RemyLebeau If the version info block is available in the user's choice of language it seems sensible to try to show it to them in that language. It's been a long time now but I seem to remember we developed this based on observations of how Explorer (e.g. the Properties dialog) behaves. – Jonathan Potter Jun 21 '16 at 20:48
  • @Roddy: Can you show the actual `VERSIONINFO` resource from the DLL? In your case, both the `\Translation` value and the actual resource are in US-English, it is only the codepage that is mismatched. So you could loop through the available resources until you find one with a matching language. – Remy Lebeau Jun 21 '16 at 20:48
  • @JonathanPotter: right, which usually means checking the `\Translation` table first to locate a resource in a matching language, and then perform fallbacks as needed only if it is not found. – Remy Lebeau Jun 21 '16 at 20:49
  • @RemyLebeau Unfortunately the `Translation` table can not, in our experience, be relied upon. – Jonathan Potter Jun 21 '16 at 20:50
  • @RemyLebeau - XN Resource Editor just shows the strings as English (United States). The "\Translation" isn't shown. How would I get a 'decompiled' VERSIONINFO? DLL is actually VLCPlayer libvlc.dll if that helps – Roddy Jun 21 '16 at 21:11
  • 1
    @Roddy: XN has an "Export resource" feature. But no matter. I have `libvlc.dll` and do see the codepage mismatch in it, as well as in `axvlc.dll` and `libvlccore.dll`. I have [reported the bug](https://trac.videolan.org/vlc/ticket/17090) to VideoLAN. – Remy Lebeau Jun 21 '16 at 22:33
  • 1
    I submitted a [patch](https://mailman.videolan.org/pipermail/vlc-devel/2016-June/108289.html) to fix the two broken resource files. – theB Jun 22 '16 at 01:46
  • @RemyLebeau, theB : Thanks. I was unsure (based on that MS example) if this was a vlc bug or 'as designed'. – Roddy Jun 22 '16 at 08:08

1 Answers1

3

Unfortunately the VERSIONINFO structure, when compiled from a resource file, allows you to define languages that don't exist in the string block, and string blocks that have no entry in the language table. In other words, the structure isn't sanity checked. As Jonathan Potter mentions in comments, your best bet when working with an arbitrary library is to use a heuristic search for the string block that best fits your application.

In your case, however, you're using the VLC libraries which currently define their version information as follows: (trimmed so it doesn't take half a page)

BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904E4"
    BEGIN
      (...)
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x409, 1200
  END
END

As you can see the language in the translation block is en-us CP1200 (UTF-16LE), but the string block is tagged en-us CP1252 (ANSI Latin 1). Oddly enough the information for the main executable is correct, and the information is nearly identical.

Remy Lebeau submitted a bug report for the issue, and I've submitted a patch.

As of 24-Jun-2016 the patch has been accepted and backported to the 2.2 maintenance branch.

Community
  • 1
  • 1
theB
  • 6,450
  • 1
  • 28
  • 38