Versioning in Windows

Environment: Visual Studio 6.0. Uses STL.

Windows has a built-in version concept, and it's a good idea to make use of this by version stamping all your binary modules. By doing this, you gain the following advantages:

  • Users can easily identify the version of your program that they are using.
  • When you load a module, you can verify its version much more reliably with a version stamp than using a date stamp.
  • Some Windows components, such as the Windows Installer, use the version stamp to secure against overriding a newer module with an older one.

A module in this article refers to either an executable or a dll.

Why Is a Version Stamp Better than a Date Stamp?

Because a date stamp gets changed and updated after build time. For instance, if your application gets written to a CD, the date stamp is whatever the burner software assigns at write time. If a user downloads a module from the Internet or extracts it from a zip file, the date stamp marks the time the file was created through one of these actions. Various utilities also touch the date stamp. You could potentially have a newer build from older sources. In short, there is no correlation between the date stamp and the sources comprising the build.

A version stamp, on the other hand, can tell you exactly when that module was built. It also can capture some other information, such as what the original filename was, in case the module gets renamed. It contains company and legal information as well.

Version Stamp Anatomy

The main part of the version stamp is the version itself. There are four parts to the version. A sample version looks like this:

A version resource in Windows has twelve fields altogether. Examples are "CompanyName," "FileDescription," and "LegalCopyright." There are two version fields, one for the file and one for the product. These often will be the same, but can be different when you release patches for a product. For instance, say your product consists of an executable and two DLLs. If you release a version of the product, and later release an update to one of the DLLs, that module will have a different file version number from the others.

Assigning a Build Number

There are different philosophies on how to assign build numbers. One approach, described in the Microsoft Support Article On Auto Incrementing Build Numbers, is to increase the build number every time the build script executes. The advantage to this approach is that each build is guaranteed to have a unique build number. The disadvantage is that there is no correlation between a build number and when the build was performed. This is more than a hypothetical situation because builds are performed rarely at the beginning of the development cycle, more frequently towards the end.

Another approach is to make the build number be determined by when the build was done. A typical way to do this is by counting the number of days from a given day—for instance, the project's start—to the day of the build. The advantage to this approach is that for any given version, a support rep or engineer can determine when that build was done. The disadvantage is that multiple builds on the same day will get the same build number.

Personally, I prefer the latter approach. After building software for twelve years, I have run into having to perform separate builds on the same day twice. (Performing the same build more than once should result in the same build number). In neither case was it a big problem. Checking in a version of the Resource Script with zero as the build number, then having the official build script assign the number each time, also allows users, engineers, and others to distinguish between official builds and private builds done by developers.


Adding a version stamp to any module, whether a DLL or executable, is simple. A version stamp is a type of resource. To add the version information, use "Insert/Resource," and choose the bottom entry in the resource type list: Version. This will insert a default version stamp. In your resource script, it will be called "VS_VERSION_INFO;" do not change this name.

A user can examine the version information from the Explorer. By right-clicking the module, choosing "Properties" from the context menu, and then clicking the "Version" tab, the version stamp is presented in the properties window.

If a module does not have a version stamp, the "Version" tab does not appear in the Explorer properties dialog.

Following is a sample of the version resource in the RC file. It corresponds to the version properties window displayed below. You would rarely need to edit the version resource directly.

  FILEVERSION    1,1,0,249
#ifdef _DEBUG
  FILEOS 0x40004L
    BLOCK "StringFileInfo"
        BLOCK "040904b0"
            VALUE "Comments", "\0"
            VALUE "CompanyName", "Hewlett-Packard Company\0"
            VALUE "FileDescription", "HPVersioner\0"
            VALUE "FileVersion", "1, 1, 0, 249\0"
            VALUE "InternalName", "HPVersioner\0"
            VALUE "LegalCopyright", "Copyright ) 2003\0"
            VALUE "LegalTrademarks", "\0"
            VALUE "OriginalFilename", "HPVersioner.exe\0"
            VALUE "PrivateBuild", "\0"
            VALUE "ProductName", "HPVersioner -- Commandline
                                  Version Markup Utility\0"
            VALUE "ProductVersion", "1, 1, 0, 249\0"
            VALUE "SpecialBuild", "\0"
    BLOCK "VarFileInfo"
        VALUE "Translation", 0x409, 1200

To use this resource from your code, you access a VS_FIXEDFILEINFO structure. You don't get this by the normal FindResource()/LoadResource() API functions. Instead, use GetFileVersionInfo() and VerQueryValue(). To load the version information from a file, use the following lines:

    DWORD dwLen, dwUseless;
    LPTSTR lpVI;
    std::string companyName;
    UINT verMajor;

    dwLen = GetFileVersionInfoSize((LPTSTR)szFile, &dwUseless);
    if (dwLen==0)
        return 0;

    lpVI = (LPTSTR) GlobalAlloc(GPTR, dwLen);
    if (lpVI)
        DWORD dwBufSize;
        BOOL bRet = FALSE;
        WORD* langInfo;
        UINT cbLang;
        TCHAR tszVerStrName[128];
        LPVOID lpt;
        UINT cbBufSize;

        GetFileVersionInfo((LPTSTR)szFile, NULL, dwLen, lpVI);

        if (VerQueryValue(lpVI, _T("\\"),
            (LPVOID *) &lpFFI, (UINT *) &dwBufSize))

            //We now have the VS_FIXEDFILEINFO in lpFFI
            verMajor = HIWORD(lpFFI->dwFileVersionMS);
        //Get the Company Name.
        //First, to get string information, we need to get
        //language information.
        VerQueryValue(lpVI, _T("\\VarFileInfo\\Translation"),
                      (LPVOID*)&langInfo, &cbLang);
        //Prepare the label -- default lang is bytes 0 & 1
        //of langInfo
        wsprintf(tszVerStrName, _T("\\StringFileInfo\\
                 langInfo[0], langInfo[1], _T("CompanyName"));
        //Get the string from the resource data
        if (VerQueryValue(lpVI, tszVerStrName, &lpt, cbBufSize))
            companyName.assign((LPTSTR)lpt);    //*must* save this


Notice that we don't have to clean up after each call to VerQueryValue(). We delete the lpVI pointer at the end. This also invalidates all the string values, so we must save the strings into other variables before we free lpVI.

Wrapper Class and HPVersioner Utility

Attached to this article are two useful downloads.

The first is a Version update utility, HPVersioner. It will find a VS_VERSION_INFO structure in your RC file and update it with the build number du jour. It follows the time-based approach, as described above. For information on the syntax and usage of HPVersioner, download the utility zip file and look at Readme.txt.

The other download is the sources for HPVersioner. This includes a class, CVersionInfo, that provides easy access to a version stamp. A CVersionInfo object can populate itself from a string (of the form ""), an HMODULE, a VS_FIXEDFILEINFO, another CVersionInfo, and so forth. If instantiated from an HMODULE or a file, it populates three strings from the version stamp: ProductName, CompanyName, and LegalCopyright. Other strings will be easy to add.

The CVersionInfo constructor that takes a string will parse the string as a version info, such as "". This will not populate ProductName, CompanyName, or LegalCopyright. To load version info from a file, use the method SetFromFilename().

We generally expect version numbers to appear separated by the period, such as "" In the RC file, the version numbers are separated by comma, as in "1,2,1,23." For this reason, CVersionInfo has the capability to render itself in either format. The former is called AsString(); the latter is AsResource().

CVersionInfo contains assignment and comparison operators. This allows you to easily manipulate and compare versions of modules. You can also use the CVersionInfo class to easily display version stamp information in your About box or Splash screen.

Sample usage of the CVersionInfo class:

    HINSTANCE hmodDll = LoadLibrary(_T("MyAppMod.dll"));

    if (hmodDll)
        CVersionInfo verApp(GetModuleHandle(NULL));
        CVersionInfo verModule(hmodDll);

        //Don't use the module if it's older than the app
        if (verModule < verApp)
            hmodDll = NULL;


Adding a version stamp to your modules is easy, and will allow you to perform robust versioning checks, display data about your modules to the user, and keeps the system informed about the sequence of your releases.


Download HPVersioner utility - 27 Kb
Download source - 9 Kb

About the Author

Henri Hein

Granite Tower
Granite Tower Software
See also my article: Auto-Testing Internet Explorer Browser Control


  • This article already been published by Paul DeLaSia on MSDN

    Posted by Legacy on 10/27/2003 12:00am

    Originally posted by: Imran

    Nothing much to offer or gain from this article this method already explained in MSDN site far more details, by Paul DeLaSia. I wonder why people keep repeating some else work under their name?

  • Additional Version Information

    Posted by Legacy on 10/24/2003 12:00am

    Originally posted by: Blake Miller

    This is not a criticism, only additonal information about version resources that is not always obvious from the SDK documentation.

    1. You do always have the option to add additional strings and binary data to a version information resource. The ones discussed here are merely the defaults usually encountered.

    2. The translation table can have more than one entry. There can be string and binary version information in a file consisting of multiple languages. Pulling the first language is a good start, but they should all be checked for the best fit for the language of the local user or of the operating system, or else the version resource should have an entry for a 'language neutral' translation.

    3. You can use #defines and include files to obtain aliases for version resource values. If you have a large project containing multiple modules, you can alias product versions and other such 'global' settings, so that you do not have to constantly touch all version resource files.

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date