2

I am really confused with this function. Currently I am successful in retrieving the FileVersion and ProductVersion. Now I want to retrieve more information within the application, like FileDescription and CompanyName.

DWORD dwLen;
VS_FIXEDFILEINFO    *pFileInfo;
UINT                pLenFileInfo;

dwLen = GetFileVersionInfoSize("D:/firefox.exe", NULL);

BYTE *sKey = new BYTE[dwLen];

GetFileVersionInfo("D:/firefox.exe", NULL, dwLen, sKey);

VerQueryValue(sKey, "\\", (LPVOID*)&pFileInfo, &pLenFileInfo);

// at now i can retrieve file Version with structure VS_FIXEDFILEINFO

VerQueryValue(sKey, "\\StringFileInfo\\%04x%09x\\FileDescription", (LPVOID*) &pFileInfo, &pLenFileInfo);

delete[] sKey;

cout << pFileInfo;

// it return address buffer `00230428`;

How exactly can I return the FileDescription, like Firefox? What structure is used to retrieve the FileDescription in the 3rd LPVOID parameter? In my code, I pass pFileInfo twice into VerQueryValue().

EDIT:

DWORD dwLen;
    
struct LANGANDCODEPAGE {
        WORD wLanguage;
        WORD wCodePage;
    } *lpTranslate;
    
dwLen = GetFileVersionInfoSize("D:/firefox.exe", NULL);
        
BYTE *sKey = new BYTE[dwLen];
TCHAR *sCompanyName = new char[1024];
        
GetFileVersionInfo("D:/firefox.exe", NULL, dwLen, sKey);
    
VerQueryValue(sKey, "\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &pLenFileInfo);

VerQueryValue(test, "\\StringFileInfo\\%04x%09x\\FileDescription", (LPVOID*)&sCompanyName, &pLenFileInfo);

delete[] sKey;

cout << lpTranslate -> wLanguage;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • There is a code example in the [VerQueryValue documentation](https://learn.microsoft.com/en-us/windows/desktop/api/winver/nf-winver-verqueryvaluew). You DO NOT use a `VS_FIXEDFILEINFO*` to receive the `FileDescription` (or any other localized field), you need a `TCHAR*` instead. – Remy Lebeau Nov 02 '18 at 19:07
  • All fields under "StringFileInfo" key are strings. You must pass a pointer to a character array as 3rd argument to the function. – zett42 Nov 02 '18 at 19:08
  • @zett42 i try to create new LPVOID sFileDescription. and pass to argument 3 and cout << sFileDescription. it return address 00000000. – Daivd Larch Nov 02 '18 at 19:12
  • @RemyLebeau I create TCHAR* sFileDescription and pass to paremeter 3 (LPVOID*)&sFileDescription. and try to cout sFileDescription. application stopped. – Daivd Larch Nov 02 '18 at 19:14
  • 1
    @DaivdLarch you have to check the return value of `VerQueryValue()` to make sure `sFileDescription` is pointing at valid memory before you can use it: "*If the specified version-information structure exists, and version information is available, the return value is nonzero. If the address of the length buffer is zero, no value is available for the specified version-information name. If the specified name does not exist or the specified resource is not valid, the return value is zero.*" – Remy Lebeau Nov 02 '18 at 19:15
  • Another error: You have "%04x%09x" in the key string. Replace this with literal language and codepage. – zett42 Nov 02 '18 at 19:17
  • @RemyLebeau It return 0, it means failure – Daivd Larch Nov 02 '18 at 19:18
  • @zett42 i add my new edit question. but its weird i try to cout wLanguage. it return 0. and wCodepage it return 1200 = Unicode. – Daivd Larch Nov 02 '18 at 19:26
  • @RemyLebeau i know the return value. but what the structure to point? i try to create with TCHAR and allocate 1024 byte. and solved the stopped working when run but it return `-` – Daivd Larch Nov 02 '18 at 19:28
  • You clearly did not read the documentation. Go read it. – Remy Lebeau Nov 02 '18 at 22:46

1 Answers1

4
VerQueryValue(test, "\\StringFileInfo\\%04x%09x\\FileDescription",
   (LPVOID*)&sCompanyName, &pLenFileInfo);

The second parameter should be of this format "\\StringFileInfo\\NxM\\FileDescription" where N and M are wLanguage and wCodePage. Following the example in comment section, you can use "%04x%04x" as print format specifier to create a string. Example:

BOOL foo()
{
    const char* filename = "c:\\windows\\hh.exe";
    int dwLen = GetFileVersionInfoSize(filename, NULL);
    if(!dwLen)
        return 0;

    auto *sKey = new BYTE[dwLen];
    std::unique_ptr<BYTE[]> skey_automatic_cleanup(sKey);
    if(!GetFileVersionInfo(filename, NULL, dwLen, sKey))
        return 0;

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

    UINT cbTranslate = 0;
    if(!VerQueryValue(sKey, "\\VarFileInfo\\Translation",
        (LPVOID*)&lpTranslate, &cbTranslate))
        return 0;

    for(unsigned int i = 0; i < (cbTranslate / sizeof(LANGANDCODEPAGE)); i++)
    {
        char subblock[256];
        //use sprintf if sprintf_s is not available
        sprintf_s(subblock, "\\StringFileInfo\\%04x%04x\\FileDescription",
            lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
        char *description = NULL;
        UINT dwBytes;
        if(VerQueryValue(sKey, subblock, (LPVOID*)&description, &dwBytes))
            MessageBox(0, description, 0, 0);
    }
    return TRUE;
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • I just try to compile and see its work or not. but it not popup messagebox. just compile success without error. – Daivd Larch Nov 02 '18 at 19:55
  • 1
    You are leaking `sKey` and `description`. You need to `delete[]` them when you are done using it. In fact, you should not even be allocating any memory for `description` at all, since `VerQueryValue()` returns a pointer to data that is stored within `sKey`, so `sKey` is the only memory that needs to be allocated – Remy Lebeau Nov 02 '18 at 22:47
  • Thanks @RemyLebeau Specially the second allocation was a major leak. Fixed it. – Barmak Shemirani Nov 02 '18 at 23:58
  • 2
    It should be `std::unique_ptr` to make sure `delete[]` for array will be called. I would use a `std::vector` though, which is easier to use. – zett42 Nov 03 '18 at 02:10