Posts Tagged ‘Version Resource’

Version Info

Saturday, February 16th, 2008

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?