How to get version info from resources?

3

I have the Version Info in resources declared:

100 VERSIONINFO
FILEVERSION 1,0,0,2
PRODUCTVERSION 1,0,0,2
FILEOS VOS_NT
FILETYPE VFT_APP
{
    BLOCK "StringFileInfo"
    {
        BLOCK "000004b0"
        {
            VALUE "FileDescription", "My application"
            VALUE "FileVersion", "1.0.0.2"
            VALUE "InternalName", "app.exe"
            VALUE "LegalCopyright", "Copyright ©  2012 by David."
            VALUE "OriginalFilename", "app.exe"
            VALUE "ProductName", "app"
            VALUE "ProductVersion", "1.0.0.2"
            VALUE "Assembly Version", "1.0.0.2"
        }
    }

    BLOCK "VarFileInfo"
    {
        VALUE "Translation", 0x0000 0x04B0
    }
}

I am getting Version Info this way:

HRSRC hResInfo;
HGLOBAL hResData;
LPCVOID pRes;
UINT uLen;
VS_FIXEDFILEINFO *lpFfi;

hResInfo = FindResource(hInst, MAKEINTRESOURCE(100), RT_VERSION);
MessageBox(0, "FindResource", 0,0);

hResData = LoadResource(hInst, hResInfo);
MessageBox(0, "LoadResource", 0,0);

pRes = LockResource(hResData);
MessageBox(0, "LockResource", 0,0);

VerQueryValue(pRes, "\\" ,(LPVOID*)&lpFfi, &uLen);
MessageBox(0, "VerQueryValue", 0,0);

FreeResource(hResData);

DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;

DWORD dwLeftMost     = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft   = LOWORD(dwFileVersionMS);
DWORD dwSecondRight  = HIWORD(dwFileVersionLS);
DWORD dwRightMost    = LOWORD(dwFileVersionLS);

In function VerQueryValue is an error, because program breaks (MessageBox with text "VerQueryValue" doesn't show) and Visual C++ shows me the following message:

First-chance exception at 0x77bf15a5 in ProxyCU.exe: 0xC0000005: Access violation writing location 0x00483192.

How to repair this code?

Regards, David

winapi
visual-c++
resources
asked on Stack Overflow Dec 18, 2012 by David

2 Answers

15

VerQueryValue() cannot access version info from the original resource directly. You must make a copy of the resource in memory, then pass that memory to VerQueryValue() instead. The reason is because VerQueryValue() is designed to work with GetFileVersionInfo(), which requires a user-allocated block of writable memory and performs certain fixups within that memory. Accessing the VS_FIXEDFILEINFO struct does not require the fixups, but the memory block must still be writable. You cannot pass the original resource directly to VerQueryValue() because it is read-only memory.

Try this instead:

HRSRC hResInfo;
DWORD dwSize;
HGLOBAL hResData;
LPVOID pRes, pResCopy;
UINT uLen;
VS_FIXEDFILEINFO *lpFfi;

hResInfo = FindResource(hInst, MAKEINTRESOURCE(100), RT_VERSION);
dwSize = SizeofResource(hInst, hResInfo);
hResData = LoadResource(hInst, hResInfo);
pRes = LockResource(hResData);
pResCopy = LocalAlloc(LMEM_FIXED, dwSize);
CopyMemory(pResCopy, pRes, dwSize);
FreeResource(hResData);

VerQueryValue(pResCopy, TEXT("\\"), (LPVOID*)&lpFfi, &uLen);

DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;

DWORD dwLeftMost     = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft   = LOWORD(dwFileVersionMS);
DWORD dwSecondRight  = HIWORD(dwFileVersionLS);
DWORD dwRightMost    = LOWORD(dwFileVersionLS);

LocalFree(pResCopy);

UPDATE: this only works if you access the VS_FIXEDFILEINFO struct only. If you need to access any other values, you must use GetFileVersionInfo(). Per Raymond Chen's blog:

The first parameter to VerQueryValue really must be a buffer you obtained from GetFileVersionInfo

The documentation says that the first parameter to VerQueryValue must be a buffer returned by the GetFileVersionInfo function for a reason. The buffer returned by GetFileVersionInfo is an opaque data block specifically formatted so that VerQueryValue will work. You're not supposed to look inside that buffer, and you certainly can't try to "obtain the data some other way". Because if you do, VerQueryValue will look for something in a buffer that is not formatted in the manner the function expects.

answered on Stack Overflow Dec 18, 2012 by Remy Lebeau • edited Oct 20, 2020 by Remy Lebeau
0

The above would create a heap corruption error message in debug mode, such as "Free Heap block b753e70 modified at b753ed4 after it was freed". Someone has posted this problem many years ago at http://microsoft.public.win32.programmer.kernel.narkive.com/mqoHgVwM/verqueryvalue-bug. It is still hapenning today. One can make the message disappear by making dwSize sufficiently large, such as multiplying it by 4.

answered on Stack Overflow May 26, 2016 by YS Yang

User contributions licensed under CC BY-SA 3.0