Versioning a Native C/C++ Binary with Visual Studio

Last time in  Mapping Binaries in the Field to Source Code in the Repository we talked about the value of including version information in your binaries. Today I’m going to explain how to accomplish this in Visual Studio for a native C/C++ binary. I’m using 2010 Professional, but it should work on other versions as well.

The source code is available here.

Step 1: Add a Version Resource

  1. Right-click on your project
  2. Select Add->Resource
  3. Select Version
  4. Click New

This will give you two files: resource.h and <project_name>.rc. I generally rename the .rc file to be version.rc

Step 2: Updating Version.rc

Out of the box the version.rc file will have you define the values right there. I recommend that you instead define the values in a version.h file and use those defines in the version.rc file.

Edit the resource file in a text editor:

  1. In the Solution Explorer, Right-click on version.rc
  2. Select Open With
  3. Select C++ Source Code Editor
  4. Scroll down to the Version section

Here is a template Version section that I frequently use (and will build on below):

/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
 FILEVERSION        VER_FILE_VERSION
 PRODUCTVERSION     VER_PRODUCT_VERSION
 FILEFLAGSMASK      0x3fL
 FILEFLAGS          VER_FILEFLAGS
 FILEOS             VER_FILEOS
 FILETYPE           VER_FILETYPE
 FILESUBTYPE        0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "FileDescription",  VER_FILE_DESCRIPTION_STR "\0"
            VALUE "FileVersion",      VER_FILE_VERSION_STR "\0"
            VALUE "InternalName",     VER_INTERNAL_NAME_STR "\0"
            VALUE "LegalCopyright",   VER_COPYRIGHT_STR "\0"
            VALUE "OriginalFilename", VER_ORIGINAL_FILENAME_STR "\0"
            VALUE "ProductName",      VER_PRODUCTNAME_STR
            VALUE "ProductVersion",   VER_PRODUCT_VERSION_STR "\0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END

Step 3: Adding a Version Header

Next we create a file named version.h to provide a more convenient location to set the various version information. This is especially useful if you are sharing version information across multiple projects in a single solution. Here’s the information I generally start with mine:


#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)

#define VERSION_MAJOR               1
#define VERSION_MINOR               0
#define VERSION_REVISION            0
#define VERSION_BUILD               0

#define VER_FILE_DESCRIPTION_STR    "Description"
#define VER_FILE_VERSION            VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR        STRINGIZE(VERSION_MAJOR)        \
                                    "." STRINGIZE(VERSION_MINOR)    \
                                    "." STRINGIZE(VERSION_REVISION) \
                                    "." STRINGIZE(VERSION_BUILD)    \

#define VER_PRODUCTNAME_STR         "c_version_binary"
#define VER_PRODUCT_VERSION         VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR     VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR   VER_PRODUCTNAME_STR ".exe"
#define VER_INTERNAL_NAME_STR       VER_ORIGINAL_FILENAME_STR
#define VER_COPYRIGHT_STR           "Copyright (C) 2011"

#ifdef _DEBUG
  #define VER_VER_DEBUG             VS_FF_DEBUG
#else
  #define VER_VER_DEBUG             0
#endif

#define VER_FILEOS                  VOS_NT_WINDOWS32
#define VER_FILEFLAGS               VER_VER_DEBUG
#define VER_FILETYPE                VFT_APP

Step 4: Add the Necessary Include

The final step is to add the necessary include line to the version.rc file for the version.h file:

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#include "version.h"

#define APSTUDIO_READONLY_SYMBOLS

Results

Now when you build your application, all the version info above will be defined in the binary itself. Much of this information is available directly from the Details pane of the Properties window in Explorer.

Version Info
Version Info

Final Thoughts

Note that this information is static from build to build. You must change the version numbering yourself or use a script to auto-increment values. I’ll be discussing how to make the BUILD number automatically correspond to the revision info from the working copy of the source code using Mercurial or Subversion in an upcoming post.

Other Posts in this Series

  1. Mapping Binaries in the Field to Source Code in the Repository
  2. Versioning a Native C/C++ Binary with Visual Studio
  3. Versioning a .NET Assembly with Visual Studio
  4. Integrating the Mercurial Revision into the Version Automatically with Native C/C++
  5. Integrating the Mercurial Revision into the Version Automatically with .NET
  6. Integrating the Subversion Revision into the Version Automatically with Native C/C++
  7. Integrating the Subversion Revision into the Version Automatically with .NET

Comments

26 responses to “Versioning a Native C/C++ Binary with Visual Studio”

  1. Jeff Avatar
    Jeff

    Hi. I’m following this tutorial. Quick question about the version.rc file. When following Step #2, I should only modify the relevant portion of this file, correct? (the part sectioned off by the VERSION comment)

    Just so you know, you skipped step #3. Also, and maybe this is obvious, but I am brand new to Visual Studio. The file created will not necessarily be called version.rc. It will be NAME_OF_YOUR_PROJECT.rc

    Thanks for posting this series. This is exactly what I am looking for.

  2. ZachB Avatar

    @Jeff: Correct, for step 2 at that point you are only replacing the contents of the Version section, not the entire contents of the resource file.

    Whoops, I did skip #3! I’ve renumbered the sections, updated the first step to reflect that I renamed the .rc file to version.rc, and added a clarification for the text replacement in step 2.

    Thanks for the feedback, I’m glad someone has found this useful!

  3. Michael Khan Avatar

    Thanks for all the wonderful information available. Here’s one that might tickle your fancy.

    I use InstallAnywhere (2008) to create an installation file. We’re no longer paying for support, so they won’t talk to me. Is there a way to place version information into the setup.exe created by InstallAnywhere using Visual Studio? There appears to be a Version Information Editor that is supposed to be a part of Visual Studio, but I’m guessing it’s used in the context of a project, and not for the modification of an exe created by someone else.

    Appreciate your thoughts.

  4. ZachB Avatar

    Thanks for the feedback, I’m glad you found it useful!

    I’ve never used InstallAnywhere, but I assume you mean providing the setup.exe binary itself with version information like was discussed above. In otherwords, that you do NOT mean embedding version information into the installer package’s manifest which would a cause it to install into a different directory and such.

    If you mean the former, then the Version information is just a resource of the binary. What you could do is create the Version.rc you actually want in a dummy application. Then in a build step after the setup.exe is created, replace the resource in setup.exe with the one from the dummy.exe.

    For information on how to replace the resource, see Updating Resources. To easily view the embedded resource info (and a whole lot more) I recommend CFF Explorer

  5. Eveline Avatar

    My application is set for Unicode (a requirement).
    I need the string VER_FILE_VERSION_STR to be shown in my ‘About’ dialog.

    I use this in my dialog window initialization:

    SetWindowText( GetDlgItem( hDlg, V_F_VERS_STR ), TEXT( VER_FILE_VERSION_STR ) );

    where V_F_VERS_STR is the ID of the dialog item, where I want the string.
    That works perfect when I have this in my svn_version_h:

    #define VER_FILE_VERSION_STR ” dit is ook een string ”

    But with your code:

    #define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
    “.” STRINGIZE(VERSION_MINOR) \
    “.” STRINGIZE(VERSION_REVISION) \
    “.” STRINGIZE(VERSION_BUILD) \
    I get all kinds of errors about parameter conversions.
    What should I do better?
    Thanks in advance for any answer.

    1. ZachB Avatar

      Eveline,

      The problem most likely has to do with the strings in version.h being MBCS strings, not UNICODE strings. You can’t simply do TEXT( VER_FILE_VERSION_STR ) because VER_FILE_VERSION_STR is a concatenation of other strings so it will place the L in the wrong place. I don’t have any Win32 Windows applications handy to easily test the SetWindowText function call you are making, but I got similar errors using wprintf.

      A simple fix would be to convert all strings in version.h to unicode with L (like the “.” -> L”.”) and update the STRINGIZE function to be L#s rather than just #s. Since I have some projects that require MBCS and others that require UNICODE, I went ahead and adapted it to the TCHAR macros so the same code should work in either place. However, if you use include <tchar.h> into version.h, you’ll get some resource compiler warnings (RC4011) because we include version.h in version.rc. To get around that, I locally defined the _T macro within the version.h file for this example. I didn’t get to thoroughly test the code below, but it worked fine for both UNICODE and MBCS build configurations of my sample project using both printf and wprintf.

      – Zach

      #include "svn_version.h"
      
      #ifdef _UNICODE
      #define _T(x)      L ## x
      #else
      #define _T(x)      x
      #endif
      
      #define STRINGIZE2(s) _T(#s)
      #define STRINGIZE(s) STRINGIZE2(s)
      
      #define VERSION_MAJOR               1
      #define VERSION_MINOR               0
      #define VERSION_REVISION            0
      #define VERSION_BUILD               SVN_REVISION
      
      #if SVN_LOCAL_MODIFICATIONS
        #define VERSION_MODIFIER _T("M")
      #else
        #define VERSION_MODIFIER
      #endif
      
      #define VER_FILE_DESCRIPTION_STR    _T("Built ") STRINGIZE(SVN_TIME_NOW) _T(" from r") STRINGIZE(SVN_REVISION)
      #define VER_FILE_VERSION            VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
      #define VER_FILE_VERSION_STR        STRINGIZE(VERSION_MAJOR)            \
                                          _T(".") STRINGIZE(VERSION_MINOR)    \
                                          _T(".") STRINGIZE(VERSION_REVISION) \
                                          _T(".") STRINGIZE(VERSION_BUILD)    \
                                          VERSION_MODIFIER
      
      #define VER_PRODUCTNAME_STR         _T("c_svn_autoversion")
      #define VER_PRODUCT_VERSION         VER_FILE_VERSION
      #define VER_PRODUCT_VERSION_STR     VER_FILE_VERSION_STR
      
      #if LIBRARY_EXPORTS
        #define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR _T(".dll")
      #else
        #define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR _T(".exe")
      #endif
      #define VER_INTERNAL_NAME_STR       VER_ORIGINAL_FILENAME_STR
      
      #define VER_COPYRIGHT_STR           _T("Copyright (C) 2011")
      
      #ifdef _DEBUG
        #define VER_VER_DEBUG             VS_FF_DEBUG
      #else
        #define VER_VER_DEBUG             0
      #endif
      
      #define VER_FILEOS                  VOS_NT_WINDOWS32
      #define VER_FILEFLAGS               VER_VER_DEBUG
      
      #if LIBRARY_EXPORTS
        #define VER_FILETYPE              VFT_DLL
      #else
        #define VER_FILETYPE              VFT_APP
      #endif
      
  6. Eveline Avatar

    Dear Zach

    Thank you so much for your fast and excellent answer.

    I adapted your solution to my problem and it works as a charm!

    The compiler warned me about

    _T(x)
    being defined before, so I changed that to
    _Tx(x)

    I’m all set now, you made my Xmas holiday (I spent it completely wrestling with this problem) happy at last.
    I learned a lot from your website and I am still learning.
    Bless you!

    Eveline

    1. ZachB Avatar

      Awesome, I’m glad you found it helpful!

  7. Leonid Raiz Avatar
    Leonid Raiz

    Thanks for a very useful tutorial

  8. Dhanush Avatar

    Is it possible to have 2 Version files ?
    how can it be done

  9. Dhanush Avatar

    having two version files is possible for one .rc file

  10. Sagir Avatar
    Sagir

    The product version is getting changed in the dll files
    but the File version is not getting changed.

  11. ValyaS Avatar
    ValyaS

    Hi Zach,
    Thank you for the article. It looks promising, but this doesn’t work in newer Visual Studios 🙁
    Could you please suggest how to define version info for a native project in Visula Studio 2013?

    Thanks,
    Valentina

    1. ValyaS Avatar
      ValyaS

      Sorry, just found a simple way myself.
      Still, thank you.

  12. Lu Liu Avatar
    Lu Liu

    Hi Zach,

    we used the same method to version our DLL, however, I found this method of versioning did not work for the excel Add In that we built in VS. the excel Add In is XLL. Do you know why?

    Thanks!

    1. ZachB Avatar

      Unfortunately no, I do not know why.

  13. Djanni Avatar
    Djanni

    Hi,

    is it somehow possible to add a field to the details pane? If I add a Value in the version block I can see it in the resource view in visual studio, but I cant see it in the details pane when checking the properties of my .exe

    Thanks!

    1. ZachB Avatar

      I don’t believe so. I suspect that the properties shown in the details pane are controlled by the implementation in Window’s Explorer (explorer.exe) and that it may not support customer attributes, however I am not positive of this.

  14. Beulah Avatar
    Beulah

    HI,

    Thanks for this post. very useful. Clear and simple.

  15. hackerman Avatar
    hackerman

    In VS 2017 VFT_APP seems to be unknown, causing
    version.h(32): fatal error RC1004: unexpected end of file found

    Removing the line and adjusting version.rc will fix this as the cost of VER_FILETYPE being missing.

    1. Viacheslav Avatar
      Viacheslav

      Just press enter after the last line in the version.h file. (add a new line in the end)
      And the error will be solved.
      There is no need to delete VFT_APP constant.

  16. kk Avatar
    kk

    I’ve got the “unexpected end of file found” error too.
    Adding an empty line at the end of version.h fixed the error for me.
    Btw, I use VS 2019.

  17. adolfo Avatar
    adolfo

    Ok, you must end version.h content with a at last line.

    1. adolfo Avatar
      adolfo

      return *

  18. Muhammed_SYR Avatar
    Muhammed_SYR

    You just have to add a new blank line at the last of your header file, and rebuild, it will work ..

  19. mariano Francolino Avatar
    mariano Francolino

    hey there Im trying to use your code above and Im gettin RC1004 “Unexpected end of file found”, any ideas

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.