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: 2.1.3.37.

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.

Usage

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.

VS_VERSION_INFO VERSIONINFO
  FILEVERSION    1,1,0,249
  PRODUCTVERSION 1,1,0,249
  FILEFLAGSMASK  0x3fL
#ifdef _DEBUG
  FILEFLAGS 0x1L
#else
  FILEFLAGS 0x0L
#endif
  FILEOS 0x40004L
  FILETYPE 0x1L
  FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            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"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END

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;
        VS_FIXEDFILEINFO* lpFFI;
        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\\
                                      %04x%04x\\%s"),
                 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

        //Cleanup
        GlobalFree((HGLOBAL)lpVI);
    }

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 "1.0.2.17"), 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 "1.0.2.17". 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 "1.2.1.23." 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)
        {
            FreeLibrary(hmodDll);
            hmodDll = NULL;
        }
    }

Conclusion

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.

Downloads

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

Comments

  • Beats by Dre sportslige stilfuldt – men ikke sponsor-brand – hovedtelefoner pÃ¥ spil

    Posted by wherewanzi on 06/05/2013 08:57pm

    [url=http://beatsbydrdredanmark.weebly.com/]Beats by dre danmark[/url] Beats enkel sammen med skiftes i sammen med frigivet eventuelle udskiftelige pandebånd er nået smertefri sammen med sat på mod stillet af blot beats by dremagneter. Dybest set vælter enhver pandebånd på grund af en indehaver toppen inden for headsets sammen med tilføje en anden. Progressionen modtage en smule af med en minimal sammen med før du kender det hele, vil du have et helt andet sæt af moderigtigt koordinerede headsets. Brug hvad vores firma er næsten garanteret er helt sikkert pude-soft kunstlæder høre kopper kaffe ud over et pandebånd, at leveres i en god samling for farvestoffer sammen med sorter disse virkelig er nødt til at føle, udseende sammen med tone enhver utroligt perfekt under forretningen. [url=http://www.nyebeatsbydrdre.350.com/]Nye beats by dr dre[/url] Det er officielt. Bortset fra at lade løs sin første sæt hovedtelefoner efter Monster for de Executive typer, Beats Electronics har sat sine seværdigheder på nabbing den bærbare Bluetooth audio krone fra Jawbone er Jambox . Du husker dette rammer FCC lidt siden, men i dag er Dr. er officielt klar til at tilbyde dig det er bod for on-the-go trådløs lyd med dens 200 $ Pill, en NFC-udstyrede bærbare Bluetooth 2,1 højttaler. Kommer i dit valg rød, sort eller hvid, er den cylindriske system, fyldt med en kvartet af 1-tommer drivere, og understøtter codecs, herunder Apt-X og AAC. En intern batteri siges at give omkring syv timers lytning på omkring 75-procent volumen (80 decibel), og enheden kan oplades via sin Micro-USB-indgang. Især en auto-sluk-funktionen slår apparatet fra efter 30 minutter, hvis ingen lyd streames til det. Som du ville forvente, at p-piller har en fremadvendte om bord mic til brug som en højttalertelefon, fysiske lydstyrkeknapper og power knap, samt en 3,5 mm indgang, hvis du gerne vil spille sans Bluetooth. Vi er også glade for at bemærke, at den diminutive system også har en 3,5 udgang, hvis du gerne vil sende lyden ud til en anden lyd ware. P-piller kommer med en 3,5 mm til 3,5 mm kabel, en USB til Micro-USB-kabel til opladning med en inkluderet væg adapter og endelig en kuffert etui, der kan hægtes på en pose. [url=http://kbhretelefonerbillig.webstarts.com/]Køb høretelefoner billig[/url] Det er officielt. Bortset fra at lade løs sin første sæt hovedtelefoner efter Monster for de Executive typer, Beats Electronics har sat sine seværdigheder på nabbing den bærbare Bluetooth audio krone fra Jawbone er Jambox . Du husker dette rammer FCC lidt siden, men i dag er Dr. er officielt klar til at tilbyde dig det er bod for on-the-go trådløs lyd med dens 200 $ Pill, en NFC-udstyrede bærbare Bluetooth 2,1 højttaler. Kommer i dit valg rød, sort eller hvid, er den cylindriske system, fyldt med en kvartet af 1-tommer drivere, og understøtter codecs, herunder Apt-X og AAC. En intern batteri siges at give omkring syv timers lytning på omkring 75-procent volumen (80 decibel), og enheden kan oplades via sin Micro-USB-indgang. Især en auto-sluk-funktionen slår apparatet fra efter 30 minutter, hvis ingen lyd streames til det. Som du ville forvente, at p-piller har en fremadvendte om bord mic til brug som en højttalertelefon, fysiske lydstyrkeknapper og power knap, samt en 3,5 mm indgang, hvis du gerne vil spille sans Bluetooth. Vi er også glade for at bemærke, at den diminutive system også har en 3,5 udgang, hvis du gerne vil sende lyden ud til en anden lyd ware. P-piller kommer med en 3,5 mm til 3,5 mm kabel, en USB til Micro-USB-kabel til opladning med en inkluderet væg adapter og endelig en kuffert etui, der kan hægtes på en pose.

    Reply
  • SÃ¥dan laver du krøller med dit GHD glattejern

    Posted by motherdhmm on 05/30/2013 06:04am

    [url=http://www.buy-beatsdrdre.com/category/new-beats-dr-dre-headphones]Beats By Dr Dre[/url] Bliv en køber dille. På grund af dette, ofte forekommer falsk, så flere og flere mennesker køber ægte ghd glattejern. Vores butik, selv om salget af ghd håret sort. Men vi er regelmæssige ghd glattejern produkter. Fandt du ikke bringe alle former for falske brand skader. Vores produkt kort med det fysiske kort, er nøjagtig det samme. For at sikre sande og pålidelige produkter. Og vi sælger billige ghd glattejern, 7 * 24 online-funktioner, kan du købe på ethvert tidspunkt. Så længe du har valgt den ønskede type, udfylde personlige oplysninger, osv. relaterede emner, kan produktet blive leveret direkte til din ventende hænder. Venligst købe ghd glattejern produkter følelser før, se på vores privacy policy, Om os, transport, FAQ og mere relevante politikker, vil dette hjælpe dig til at købe vores produkter. Tak for dit samarbejde. [url=http://www.blog.cheapbeatsbydre.co.nz/]beats by dre[/url] overalt i verden, du lettere kan anvende. Så længe du køber ghd glattejern tilbyder gratis forsendelse, så ghd håret hjem skal være [url=http://www.blog.cheapbeatsbydre.co.nz/]beats by dre nz[/url] Kvinder kan virkelig godt lide at følge moden ghd glattejern, og da deres religion er meget praktisk. Ghd store spor, og enhver tid af året i de nye forslag. ghd glattejern, som er meget populært i dag. Ønsker du at vide den reelle diskonteringssats? I virkeligheden, kun 50% vil "spare dig for en masse, ikke? Der er mange udmærkede ghd glattejern beskæftige sig med dette, kan du ændre farve og stil, der er altid en masse mennesker som i Danmark

    Reply
  • 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?
    

    Reply
  • 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.

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

Top White Papers and Webcasts

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

  • On-Demand Webcast APIs can be a great source of competitive advantage. The practice of exposing backend services as APIs has become pervasive, however their use varies widely across companies and industries. Some companies leverage APIs to create internal, operational and development efficiencies, while others use them to drive ancillary revenue channels. Many companies successfully support both public and private programs from the same API by varying levels of access to different constituents. Nearly all …

Most Popular Programming Stories

More for Developers

RSS Feeds