0

I'm trying to use the code snippet shown at the end of this page to read multi-language version resource for executable files.

But, for example, when I run the code below for this file:

enter image description here

I get my nCnt as 1 for only one resource, i.e. English.

What am I doing wrong?

LPCTSTR buff = L"path-to\\file.exe";

struct LANGANDCODEPAGE {
  WORD wLanguage;
  WORD wCodePage;
} *lpTranslate;

DWORD dwDummy;
DWORD dwSz = GetFileVersionInfoSize(buff, &dwDummy);
if(dwSz > 0)
{
    BYTE* pData = new (std::nothrow)BYTE[dwSz];
    if(pData)
    {
        if(GetFileVersionInfo(buff, NULL, dwSz, pData))
        {
            //Get language info
            UINT ncbSz;
            LANGANDCODEPAGE* pLcp;
            if(VerQueryValue(pData, L"\\VarFileInfo\\Translation", (VOID**)&pLcp, &ncbSz))
            {
                UINT nCnt = ncbSz / sizeof(struct LANGANDCODEPAGE);

                CString strQuery;
                UINT nczBufLn;
                LPCTSTR pDescBuf;

                for(UINT i = 0; i < nCnt; i++)
                {
                    strQuery.Format(L"\\StringFileInfo\\%04x%04x\\FileDescription", 
                        pLcp[i].wLanguage, pLcp[i].wCodePage);
                    if(VerQueryValue(pData, (LPTSTR)strQuery.GetString(), (VOID**)&pDescBuf, &nczBufLn))
                    {
                        wprintf(L"Description%d: %s\n", i, pDescBuf);
                    }
                }
            }
        }

        delete[] pData;
    }
}
Machavity
  • 30,841
  • 27
  • 92
  • 100
c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • 1
    [The `Translation` table is not always reliable](https://stackoverflow.com/questions/37953472/) – Remy Lebeau Nov 22 '17 at 18:06
  • @RemyLebeau: Well, that is not exactly the same thing. I don't even get to calling `VerQueryValue` on `L"\\StringFileInfo\\%04x%04x\\FileDescription"`, the call with `L"\\VarFileInfo\\Translation"` returns size for 1 language when I am expecting 3. That is my issue. – c00000fd Nov 22 '17 at 19:23
  • I understand the issue. My point is, the translation table is susceptible to human error, and it is a common mistake to code the table incorrectly. You may have 3 languages available but the table only has 1 entry. Use a resource editor to verify. Some resource compilers don't report mismatches like this. – Remy Lebeau Nov 22 '17 at 19:36

1 Answers1

1

There are two ways to store multi-language version resources.

The best way is of course to have one resource entry with multiple translation blocks. These will be accessible with VerQueryValue.

The other way is to store multiple resource entries, one for each language. This is the way you store other types of localized resources (bitmaps, strings etc.). EnumResourceLanguages should be able to enumerate them but GetFileVersionInfo will probably just pick the language that matches your thread or UI language.

Anders
  • 97,548
  • 12
  • 110
  • 164
  • I see. So what you're saying is that one of my options is to parse PE header manually. (I don't have an `HMODULE` handle for `EnumResourceLanguages`.) – c00000fd Nov 22 '17 at 19:43
  • If this is some sort of PE version viewer/utility and you want to support all version types then yes, you must do some manual parsing. You might be able to trick `VerQueryValueW` on non-Win9x systems into reading raw resource data but it is a bit risky because it might do some extra work in `GetFileVersionInfo` to massage the data. – Anders Nov 22 '17 at 20:02
  • No I need it to be compatible with Windows 95. – c00000fd Nov 22 '17 at 20:46
  • Then you must parse yourself, the 32-bit version resource is stored in Unicode and the API on Win9x uses extra data to store translated strings. – Anders Nov 22 '17 at 20:58
  • Yeah, dude, I'm kidding about Win95. But yes, otherwise it looks like I need to be parsing it manually. (I just stepped into `GetFileVersionInfo*` and `VerQueryValue` APIs and besides raising & muting all kinds of exceptions internally, they are very inefficient. Each API basically calls `LoadLibraryEx` to map the file into memory and then releases it. Even if all you need is the size of the resource.) – c00000fd Nov 22 '17 at 21:47
  • `GetFileVersionInfoSize` does not return just the size of the resource, it might lie and return a larger size if the other functions might require space to do Unicode conversion. Not sure if NT systems support 16-bit ANSI resources, if not then it will not lie in the W version of the functions. – Anders Nov 23 '17 at 13:28