You would think that retrieving version information from a program would be a basic and simple task. For example if you want to display your version number in an About box. For a long time I’ve stored version numbers in a resource (as they should be) but used a separate #define in the code, which is easy to access and display in an About box. Finally I got tired of this redundancy and dug up some old code I had (circa 1998!) and holy crap, it still works. And holy crap, the API hasn’t changed either.

The code was in C, and ugly, so I made a new class based on the old code. It has a static method to get the fixed portion of the version resource, and another method to get a string. one to get a string.  Here is the string version:

CString CMyVersion::GetStringItem (CString modulename, CString itemName)

{

CString result = "";

if (modulename.IsEmpty())

{

modulename = CCoreFile::GetProgramPath();

}

DWORD handle; // not used, will be set to 0.

DWORD size = ::GetFileVersionInfoSize (modulename, &handle);

if (size > 0)

{

VOID* block = ::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, size);

if (block != NULL)

{

if (::GetFileVersionInfo (modulename, 0, size, block))

{

// The pointer returned in buffer is freed automatically when block is freed.

// This assumes the english language block

itemName = "\\StringFileInfo\\040904E4\\" + itemName;

LPBYTE buffer;

UINT length;

if (::VerQueryValue (block, itemName, (LPVOID*)&buffer, &length))

{

result = CString(buffer);

}

}

::HeapFree(::GetProcessHeap(), 0, block);

}

}

return result;

}

Note the limitation, this method assumes you want an item in the English language version of the StringFileInfo block. Since I don’t foresee myself needing my version number in Swahili, I think this limitation will be fine.

To get the file or product version using this class:

CString fileVersion = CMyVersion::GetStringItem(modulename, "FileVersion");

CString productVersion = CMyVersion::GetStringItem(modulename, "ProductVersion");

Getting the fixed part of the version resource is similar:

BOOL

CMyVersion::GetFixedInfo (CString modulename, VS_FIXEDFILEINFO* info)

{

BOOL result = FALSE;

if (modulename.IsEmpty())

{

modulename = CCoreFile::GetProgramPath();

}

DWORD handle; // not used, will be set to 0.

DWORD size = ::GetFileVersionInfoSize (modulename, &handle);

if (size > 0)

{

VOID* block = ::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, size);

if (block != NULL)

{

if (::GetFileVersionInfo (modulename, 0, size, block))

{

// The pointer returned in buffer is freed automatically when block is freed.

LPBYTE buffer;

UINT length;

if (::VerQueryValue (block, "\\", (LPVOID*)&buffer, &length))

{

length = min(length, sizeof(*info));

::CopyMemory(info, buffer, length);

result = TRUE;

}

}

::HeapFree(::GetProcessHeap(), 0, block);

}

}

return result;

}

The Windows Version API certainly is robust, and supportive of multiple languages, but for goodness sake, didn’t the author realize that most of its usefulness would be in retrieving a version number? Why go through all of this nonsense for such a simple task?

(Sorry for the code formatting, one of these days I’ll get the formatting thing sorted out.)




Write a comment


Name




    
C++ Programming is based on WordPress platform, RSS tech , RSS comments design by Gx3.