Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
626 views
in Technique[技术] by (71.8m points)

winapi - How to get version info from resources?

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...