Click here to Skip to main content
15,861,125 members
Articles / .NET

Versioning Controlled Build

Rate me:
Please Sign up or sign in to vote.
4.90/5 (237 votes)
8 Dec 2013CPOL35 min read 2.2M   20.6K   779   1K
A Visual Studio add-in and command-line utility that automates versioning of .NET and VC++ projects
Image 1

Introduction

When a new project is created, Visual Studio generates an AssemblyInfo file inside it. This file, among other things, contains the AssemblyVersion attribute. Version information consists of four integer values: Major Version, Minor Version, Build Number, and Revision. The default pattern for version information generated by Visual Studio 2002/2003 is 1.0.*, i.e. Major Version is set to 1, Minor Version to 0, while Build Number and Revision are generated automatically. More specifically, during the build process, the Build Number is created from the number of days elapsed since January 1, 2000, whereas Revision is created from the current local time of the day. A similar rule applies for VB.NET projects and Managed VC++ projects, except that the project information files are named AssemblyInfo.vb and AssemblyInfo.cpp, respectively.

However, this automatism may sometimes be annoying. For example, if you want to assign the same version to several projects. Even if you rebuild all projects inside the same solution, they may obtain different Revisions. Moreover, if you want to rebuild an older revision from the versioning system, you will have to set the version manually.

Visual Studio 2005 generates the AssemblyVersion attribute in the form 1.0.0.0, by default (i.e. there is no wildcard in the version), and also adds the AssemblyFileVersion attribute. Note that the user can also include the AssemblyInformationalVersion attribute that is assigned to the Product version.

As suggested on George Shepherd's Windows Forms FAQ, a simple solution to synchronize versions among multiple projects is to extract version information into a single file and reference it from each project. However, that approach has one drawback: if an assembly is used in different solutions, you may end up having two different versions of actually the same assembly.

The purpose of this add-in is to help the user to manage and synchronize all these versions, especially for solutions that contain several projects. There is already a solution provided by Darriel Liu (Build Number Automation for Visual Studio .NET Projects) where he created a Visual Basic macro that modifies the AssemblyVersion, basically following the original approach by Microsoft. This solution is written in C#, and extends the original idea, providing GUI for more control, and enabling managing all three version types either independently or synchronized. It also provides a means of automatism to simplify versioning as much as possible.

Moreover, add-in supports Visual C++ resource file versions (FileVersion and ProductVersion) in unmanaged projects and setup project versions.

Last but not least, command line utility does not only provide batch counterpart of the add-in but additionally extends the functionality to Visual C++ 6.0 projects.

This article first provides basic information on versions and how they are managed in this tool. Implementation details follow, including a description of specific techniques used. The reader familiar with versioning and not interested in implementation details may skip to the final section that provides the basic instructions for users.

Contents

Background

This section deals in more detail with versions available in the .NET Framework, and describes the logic used in the tool.

The Three Version Musketeers

As already mentioned in the introduction, there are three types of versions supported by the .NET Framework: AssemblyVersion, AssemblyFileVersion, and AssemblyInformationalVersion, corresponding to AssemblyVersionAttribute, AssemblyFileVersionAttribute, and AssemblyInformationalAttribute, respectively. The actual values of attributes are defined in the AssemblyInfo file (Visual Studio 2005 and newer hide this file inside the Properties subfolder):

C#
// ...

[assembly: AssemblyVersion("1.1.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.2.1.0")]
// ... 

Note that the content sample given is for a C# AssemblyInfo file; for other languages, syntax differs somewhat.

As the reader probably knows, AssemblyVersion is stored in the metadata table of the assembly built. It is used to uniquely identify an assembly when referenced from other assemblies. Moreover, the CLR uses this version when binding to strongly named assemblies (more details may be found in the book, "Applied Microsoft .NET Framework Programming" by Jeff Richter). AssemblyFileVersion and AssemblyInformationalVersion are informational only (see e.g. "How to use Assembly Version and Assembly File Version" and "Assembly Versioning" articles). However, it is worth to notice that AssemblyFileVersion is used by Windows Installer when installing a file to a location that already contains a file with the same name (see "File Versioning Rules" article - thanks to si618 for pointing that out).

These values are incorporated into the assembly, and displayed on the Version tab of the compiled assembly properties window:

Image 2

The file version displayed at the top of the pane corresponds to the AssemblyFileVersion attribute, and the other two attributes are displayed inside the "Other version information" group box. If any of the attributes are missing in the AssemblyInfo file, a value of another available attribute is assigned. For example, if only the AssemblyVersion attribute is defined, then its value is used for the file and product versions. If no version is defined, values are defaulted to 0.0.0.0.

If you check the descriptions of the AssemblyVersionAttribute, AssemblyFileVersionAttribute, and AssemblyInformationalAttribute classes in the .NET Framework documentation, you may notice that each of them contains a Version property (in the AssemblyInformationalVersionAttribute class, the property is named InformationalVersion). This property is a string, which could mean that it may contain any valid string and is not restricted to a dot-separated list of four integers. However, if you try to change the version strings to another form, the compiler will issue a warning or an error. At least one integer (i.e. Major version) must be supplied. Therefore, the following strings are valid versions:

1
1.2
1.2.3
1.2.3.4

A single asterisk may be used in AssemblyVersion only as a wildcard for the Build and Revision, or Revision only:

1.2.*
1.2.3.*

Interestingly, although there is a class Version in the .NET Framework that is meant to represent the assembly version, it is not used by any of the above mentioned version classes.

Versions in the C++ Resource File

Although for managed C++ projects, an AssemblyInfo.cpp file (with the AssemblyVersion value) is created, its content is not displayed in the properties of the compiled code. As for unmanaged C++ applications, a resource file (*.rc) is used to store version information, instead:

C++
// ...

VS_VERSION_INFO VERSIONINFO
    FILEVERSION 1,0,0,1
    PRODUCTVERSION 1,0,0,1
    // ...

BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "041a04b0"
        BEGIN
            // ...

            VALUE "FileVersion", "1, 0, 0, 1"
            // ...

            VALUE "ProductVersion", "1, 0, 0, 1"
        END
    END
    // ...

END

As you can see, the file and product versions appear at least twice: below the VS_VERSION_INFO block, and inside the StringFileInfo block. Moreover, the StringFileInfo block may contain more than one block, each for a different language selected. Also note that separators in versions may vary, depending on the localization settings.

It should be pointed out that for managed C++ projects, the version information block is not generated automatically in the resource file, but the developer must add it, e.g. in the Resource View window, or manually edit the content of the resource file.

Version in the Setup Project

In contrast to other project types, setup projects have only Product Version. It may consist of up to three dot-separated integers, and is stored in the project file (with a .vdproj extension) itself (and not in a separate file):

// ...
"Product"
{
    "Name" = "8:Microsoft Visual Studio"
    "ProductName" = "8:SetupProject"
    "ProductCode" = "8:{1DC3B403-8041-43BD-BA39-588EDA4325E4}"
    "PackageCode" = "8:{C2627176-ED8C-40B0-B9E2-095D4612A21C}"
    "UpgradeCode" = "8:{1FD6C202-4297-4AAE-8C48-DDB81C44EC44}"
    // ...
    "ProductVersion" = "8:2.0.0"
    // ...
}

As you may notice, the number 8 followed by a colon precedes the Product Version value. This number only indicates the type of data to follow (8 stands for string).

When the product version of the setup is modified from the Visual Studio environment, the user is asked to modify ProductCode and PackageCode. These codes (given as GUIDs) are used to identify an application during subsequent installations or upgrades. So, the tool that modifies the Product Version should be able to create new GUIDs for both codes.

Logic Used in This Tool

The AssemblyInfo file is usually modified for the first time when a project is created: the developer enters information such as company name, copyright, and product description. After that, it is rarely modified, often only to change the version information. So, when a source code is modified after version change, the corresponding "file modified" timestamp will be more recent than the timestamp of the AssemblyInfo file.

When the user starts the tool from any of the four commands, the tool browses projects in the currently opened solution. For each file in a C#, VB.NET, VJ#, or VC++ project, the timestamp of when the file has last been saved is compared to the timestamp of the corresponding AssemblyInfo file. If there is a file with a more recent timestamp (which means that the source code has been modified after the previous version change), the project will be marked for version update. In the GUI, the project will be displayed with a check mark in the main application form with the next version proposed, the proposed version being created according to the tool settings. The user may change the selection or even modify the next version(s). After the build is triggered from the form, the application updates the assembly versions of all the selected projects and (re)builds the solution. Batch commands implement the same procedure, without interrupting for user intervention.

Depending on the configuration settings, the tool also includes Visual C++ resource files (that may contain ProductVersion and FileVersion ) in the numbering scheme: if a resource file contains version information, its timestamp is compared to the timestamps of all the files contained in the project. If the project (e.g. a managed C++ application) contains version info in both the AssemblyInfo and the resource files, the larger version is used as a reference.

It should be pointed out that if a Visual C++ project contains a resource file but no AssemblyInfo file, adding a new resource will always put the latest timestamp on the resource file, and the project will not be marked for version update. However, it is worth noting that adding a new resource usually modifies the resource.h header file that is saved immediately before the resource file. So, to circumvent (at least partially) the mentioned inconsistency, the reference timestamp (used to compare timestamps of other files in the project) is created from the resource file timestamp offset by one second.

Since setup projects consists of a single file, the timestamp comparison logic cannot be implemented for them - the user has to select these files for version update manually.

Using the Demo Project 

The download demo project is a VS2008 solution consisting of several distinct projects:

  1. Addin project that contains only one class implementing the IDTExtensibility2 and IDTCommandTarget interfaces in order to create the add-in. This class is the common entry point for add-ins that are registered through the registry (i.e. COM object registration) so that only single class needs to be registered.
  2. Implementation is the project for the main module that implements the add-in functionality.
  3. Buttons is the resource DLL with images used for toolbar buttons and menus.
  4. CommandLine is the main project for the command-line utility.
  5. Configurator project to start the configuration dialog as a separate application.
  6. Shared project contains classes common to add-in and command-line utilities.
  7. Test application which can be used to test the application prior to installing it as an add-in
  8. Setup which creates the installer for the tool.

Originally, the solution was created on VS2002 for .NET Framework 1.x. With version 2.0 of the add-in, support for VS2005 has been added, which has been later extended for recent versions of Visual Studio, as described in tool history. Creating add-in for multiple versions of Visual Studio required some rearrangements (as described later in the section Migration to .NET 2.0) and the project Implementation has been multiplied (ImplementationVS7, ImplementationVS8 and ImplementationVS9) to build the add-in for the new environments. Note that all Implementation projects share the same source code, using conditional compilation in order to distinguish parts of the code specific for different environments. 

The add-in initially used permanent command bars. Permanent command bars are created only once, when Visual Studio is run for the first time after add-in installation and Visual Studio saves their positions between sessions. Moreover, buttons and menu items for add-in commands can be copied and moved freely to other toolbars/menus. On the other hand, temporary command bars are created each time Visual Studio is started and destroyed each time Visual Studio is closed. The add-in must take care to save temporary toolbar and menu positions and their layouts. 

Since some third party add-ins caused VCB menus and toolbars to be multiplicated with each run of Visual Studio, additional implementation projects with temporary bars (ImplementationVSxTemporaryBars) and corresponding Setup have been added. Implementation projects share the majority of code so they include the same source files. 

Points of Interest 

The greatest challenge in the project was to utilize the VS.NET environment automation since it is rather poorly documented and hard to debug. Besides, several custom controls and unique solutions have been employed. Some of them are described in the following sections. 

Connecting to the Visual Studio Environment

The add-in established connection to Visual Studio Environment through the Connect class whose skeleton is automatically generated by the Add-in Wizard. The following methods of the class are used:

  • OnConnection:  
    • Receives reference to the application object which is actually the Visual Studio environment (EnvDTE) object, and stores it for further use by the tool.
    • Selects current thread UI culture from the VS environment (for optional localization of resources) and loads the corresponding localized resources.
    • Creates toolbar and menu for the add-in.
    • Stores references to Build and Cancel Build commands which are used to dynamically enable or disable the add-in tool commands.  
  • OnDisconnection: Stores the current configuration and removes the toolbar and the menubar.
  • OnStartupComplete: Updates the state of add-in commands.
  • QueryStatus: Disables and enables add-in commands (using the state of the Build and Cancel Build commands as reference); for example, the add-in is disabled when there is no solution open or when the VS environment is in the process of compiling or building.
  • Exec: Opens the GUI or executes one of the batch commands.

SolutionBrowser Classes 

The abstract SolutionBrowser is a base class for the "workhorse" VSSolutionBrowser, VS7SlnFileReader, VS8SlnFileReader and DswFileReader classes that manage project information. VSSolutionBrowser is used in add-in and utilizes Visual Studio .NET automation to browse the solution and gather all included project information. It handles project information, such as all project items relevant for version update, file save time comparisons, and VS environment settings. Command-line utility counterparts (VS7SlnFileReader, VS8SlnFileReader and DswFileReader) do the same job parsing corresponding solution (*.sln or *.dsw) files as well as included project files.

On tool startup, SolutionBrowser derived class browses the solution selected, and gathers information for each project: project type, full name (including path) of AssemblyInfo (and optionally, *.rc and *.vdproj) file(s) in which versions are stored, current values of all version types, and a flag indicating if the project has been modified since the last version update.

The AssemblyVersions class contains a set of ProjectVersions, each of them representing one of the version types. ProjectVersion is capable of comparing and incrementing versions as well as applying string patterns with wildcards. The ProjectInfo class contains project information actually displayed in the ListView. The AssemblyInfoStream, ResourceFileStream, and SetupVersionStream classes are derived from the abstract VersionStream class, and are responsible for retrieving and storing versions in the corresponding files.

Main Form

The MainForm class represents the main window containing three tabbed ProjectsListViews (derived from the ListView class) of all the projects, with their current and proposed next versions, with one listview for each type of version. To avoid the well known problem of TabControl flickering when it is being resized, a control derived from UserControl has been used.

The main window contains several buttons on the right-hand side of the ProjectsListView to manage project selection, as well as buttons to trigger save and build actions. It also contains a VersionUpDown edit box in which the user can manually define a new version pattern to apply to selected projects.

ProjectsListView

ProjectsListView is a custom drawn listview control. Custom drawing was required to allow dynamic changing of item appearance: items are displayed in different colors depending on version availability and validity, or are displayed grayed when the item is not checked. Excessive flickering has been reduced by implementing the technique described in the article, Flicker-free ListView in .NET - Part 2.

A control derived from TextBox is embedded into ProjectsListView to allow in-line editing of the "to be version", as described in the In-place editing of ListView subitems article. It should be noted that the embedded TextBox with the default value of the Multiline property (false) has a finite smallest size. This size is larger than the size of the listview cell, which makes the appearance of the in-line editing control awkward. To fix this, EmbeddedTextBox is made multiline, and the OnKeyPress method has been overridden in order to capture the Enter key and avoid skipping to the next line.

ProjectsListView also overrides the OnItemCheck method to prevent checking items that do not have a valid version.

VersionTextBox

The VersionUpDown control is a user control consisting of two controls: VersionTextBox and SpinButton. The VersionTextBox is a control which imposes a restriction on the user whereby when entering the version, only a sequence of four integers, asterisk or plus characters, delimited with dot characters, can be used. The SpinButton is derived from the VScrollBar class.

VersionTextBox is derived from the TextBox, and overrides some of the event handlers to ensure specific behavior. OnKeyPress has to be overridden to prevent the user from entering anything but digit or asterisk. Moreover, four sections of the version sequence are virtually split into four blocks, each having its own Tab stop. To establish this, the PreProcessMessage method had to be overridden to handle TAB, HOME, END, BACKSPACE, DELETE, and ARROW keys. 

To keep the internal tab order in synch with the dialog tab order (when the next control in the dialog is back-tabbed, the last block must be selected), two delegate instances are defined and added to the LostFocus events of the Next and Previous controls:

C#
override protected void OnParentVisibleChanged(EventArgs e)
{
    base.OnParentVisibleChanged(e);
    if (TopLevelControl != null)
    {
        Control nextControl = GetNextTabControl(Parent, true);
        if (nextControl != null)
            nextControl.LostFocus += new System.EventHandler(
            OnNextControlLostFocus);
        Control previousControl = GetNextTabControl(Parent, false);
        if (previousControl != null)
            previousControl.LostFocus += new System.EventHandler(
            OnPreviousControlLostFocus);
    }
}
// searches for the next control that has a tab stop

private Control GetNextTabControl(Control ctl, bool forward)
{
    do
    {
        ctl = TopLevelControl.GetNextControl(ctl, forward);
        if (ctl == null || ctl == this)
        return null;
    }
    while (ctl.TabStop == false);
    return ctl;
}
// selects the last block

private void OnNextControlLostFocus(object sender, EventArgs e)
{
    SelectionStart = Text.Length - 1;
}
// selects the first block

private void OnPreviousControlLostFocus(object sender, EventArgs e)
{
    SelectionStart = 0;
}

In order to prevent the selection to be extended across delimiting dots, it was necessary to override the OnMouseDown, OnMouseMove, and OnMouseUp event handlers. Also, by overriding the WndProc method, the "Select All" command has been restricted to a single block, whereas the context menu, undo operation, as well as all clipboard related operations have been disabled.

Other Classes of Interest

The WindowAdapter class is used to pass the VS environment main window as an owner window of MainForm and PromptUnsavedDocumentsDialog when they are displayed as modal forms. The PromptUnsavedDocumentsDialog mimics the dialog that pops up if "Build and Run Options" on the "Project and Solutions" page of the VS Environment options is set to "Prompt to save changes...". Namely, to prevent the popping up of this dialog when the add-in has already started (thus blocking its execution), the application will first check for the unsaved documents, then pop-up PromptUnsavedDocumentsDialog, if necessary, and finally temporarily disable the saving of open documents.

The MessageFilter class is used to handle the 'Application is busy' and 'Call was rejected by callee' errors which often appear when calling Visual Studio automation and may prevent add-in to start at all (c.f. Fixing 'Application is Busy' and 'Call was Rejected By Callee' Errors article).

The AssemblyInfoStream, ResourceFileStream, and SetupVersionStream classes (derived from the abstract VersionStream class) are used to read current and save new versions. Regular expressions are used to locate, extract, and save new versions.

Migration to .NET 2.0

In .NET 2.0, the Framework Class Library has changed a bit. For example, the command bars have been moved from Microsoft.Office to the Microsoft.VisualStudio.CommandBars assembly, and the use of EnvDTE80.DTE2 is preferred over the old EnvDTE.DTE class. Although functionalities of the classes used have not changed significantly (most of them have been extended), the fact that some classes are moved to the new Framework assemblies makes previous versions of the add-in useless for the new IDE without code modifications.

Since the functionality of the add-in remains the same, regardless of the .NET Framework change, the code could be simply recompiled with a few minor changes in the source code and the references to the .NET Framework assemblies updated. But in such an approach, compatibility with previous versions of the VS IDE would be lost. To leave the source code compatible with the previous .NET Frameworks, conditional compilation statements have been inserted wherever necessary. Actually, in all cases except one, it was sufficient to insert:

C#
#if VS8
using EnvDTE80;
using DTE = EnvDTE80.DTE2;
#endif

into every source file that used the DTE class.

Using the following conditional preprocessor directives has solved the problem of command bars being defined in different assemblies:

C#
#if VS7
using Microsoft.Office.Core;
#elif VS8
using Microsoft.VisualStudio.CommandBars;
#endif

To generate two distinct assemblies from the same source code, the corresponding project file has been duplicated, both projects containing exactly the same source code, but defining different conditional compilation constants (VS7 and VS8 for VS 200x and VS 2005/2008, respectively) and referencing different .NET Framework assemblies. Of course, to distinguish versions, the outputs were named differently: BuildAutoIncrementVS7 and BuildAutoIncrementVS8.

In order to use one installation set and to have only a single add-in registration for all IDE versions, the code was split into parts common to both Framework versions and those specific to each version. The common startup code detects which Framework is currently active, and loads the appropriate main assembly. By utilizing reflection, the main class that implements the IAddin interface is searched for in that assembly, and an instance of that class is created. The IAddin interface is defined in the Common assembly. A somewhat simplified code is provided below:

C#
int runtimeVersion = Environment.Version.Major;
Assembly assembly;
switch (runtimeVersion)
{
case 1:
    assembly = Assembly.Load("BuildAutoIncrementVS7");
    break;
case 2:
    assembly = Assembly.Load("BuildAutoIncrementVS8");
    break;
default:
    return;
}
// in the main assembly find the type that implements IAddin

// interface and create an instance of it

Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
    if (type.IsClass)
    {
         if (type.GetInterface("IAddin", true) != null)
         {
             ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
             m_addin = (IAddin)ci.Invoke(new object[0]);
         }
    }
}

Methods in the startup module just forward calls to the appropriate methods of the main implementation class.

Files under SourceSafe

The application is also able to handle code under SourceSafe control: it will automatically check out items if necessary. However, to fully exploit this automatism, please note that SourceSafe must be configured so that the date and time on local files are set to the modification date and time when checked out (c.f. figure below) and not to the default "Current" value:

Image 3

Also, you are advised to set "When checked-in items are edited" (in the Options dialog, Source Control category of the Visual Studio) to "Check-out automatically". Otherwise, you'll be prompted each time to checkout items manually. Moreover, in that case, it is pretty tricky to checkout items from the code since the call to the following method fails:

C#
public static bool CheckOutItem(string fileName, DTE dte)
{
    if (dte.SourceControl.IsItemUnderSCC(fileName) &&
        !dte.SourceControl.IsItemCheckedOut(fileName))
        return dte.SourceControl.CheckOutItem(fileName);
    return true;
}

To avoid such situations, the idea provided by Catalin Stavaru has been implemented: items in the Solution Browser of the VS environment are selected programmatically and then the check-out command is issued. Readers interested may find the implementation details in the SolutionExplorerCheckoutHelper class.

Using the Add-in

After the installation, a menu named VCB as well as a new Versioning Controlled Build toolbar (c.f. figure below) will be added. They contain four items, as described below:

Image 4
  1. Versioning Controlled Build will open a window like the one displayed at the top of this article. Projects ready for version update are automatically checked, but the user may modify versions at her/his wish.
  2. Build with Versions Updated will apply new versions to the modified projects and trigger the Build Solution command.
  3. Rebuild with Versions Updated will apply new versions to the modified projects and trigger the Rebuild Solution command.
  4. Save Updated Versions will save all the modified files first and then save the versions for modified projects.

Depending on the selection in "Build and Run Options" ("Options" - "Environment" - "Projects and Solutions") of the VS environment, the actions 1, 2, and 3 will save all currently opened files first. The user can assign a shortcut key to any of the above actions (this was a requirement by several users).

In addition, VCB menu contains four additional entries:

  1. Save Versions exports current versions to a file
  2. Print Versions prints current versions
  3. Configure starts the configuration dialog
  4. About pops-up information box

GUI

When a GUI command is started, the add-in browses the currently open solution for all the projects and displays their current versions, if available. It also proposes the next version, according to the increment schema defined in the tool settings. Items for which a code change has been detected are displayed in green, and are automatically marked for update. Items for which no code has been detected or for which no valid version information is found are initially displayed grayed.

Versions are displayed on three tabbed listviews, each listview for one of the version types: AssemblyVersion, AssemblyFileVersion (i.e., FileVersion), and AssemblyInformationalVersion (i.e., ProductVersion). Tabs can be switched by clicking the appropriate button above the listview or by using the Ctrl+Tab key combination.

The user can check/uncheck items at their wish (only items with a valid version can be checked) - all commands will be applied to checked items only. Please note that, depending on the configuration settings, it could happen that a project is checked in one listview but not in the other - in such cases, only the checked version is processed.

With the "Apply to all tabs" check box, the user can control if GUI commands are distributed to all listviews (i.e., to all version tabs) or are applied to the currently visible listview only. It overrides similar settings in the tool configuration.

Applying Version Pattern

The textbox below the listview contains a pattern that can be applied to checked items in the listview. On add-in start, this textbox contains the largest "to be version" proposed. However, the user can change it to any valid version. Moreover, it is possible to use asterisk (*) or plus (+) character followed by optional integer in the pattern. An asterisk on any version position (Major Version, Minor Version, Build Number, or Revision) prevents that position from being modified. This could be useful, e.g. when the user wants to increment the Minor Version of several or all projects simultaneously but leave individual Builds and Revisions as they are. The plus character will increment the corresponding version position by integer provided or by one if none is provided. For example, "1.0.*.+2" pattern sets Major and Minor version to 1 and 0, respectively, leaves Build unchanged and increments Revision by 2.

When the content of the textbox is modified, versions in the listview are compared to the version pattern. If the pattern could lead to a version that is lower than the project's current version, the project is displayed in red, serving as a visual warning for the user.

After pressing the Apply button, the pattern in the textbox is applied to all the checked items in the listview. Note that actual versions in files are not changed until the user clicks one of the "command" buttons, as described in Applying Changes subsection below.

Incrementing Major, Minor, Build, or Revision

A group of four buttons is provided to increment only one of the version components of the marked projects. Other version components will not be modified unless if so configured (c.f. Settings section below). A Minor component is always reset to 0 on Major change.

Modifying Versions Manually

For existing versions, it is possible to manually edit the proposed version: just click the version in the "to be version" column, or select the corresponding item and press the F2 button. The new version is validated, and only versions with at least two dot separated integers and an optional asterisk character are allowed.

Applying Changes

It should be pointed out that new versions are not actually saved as long as the Save, Build, or Rebuild buttons are clicked. Save button just saves new versions into the corresponding files, while Build and Rebuild buttons additionally issue corresponding commands to the Visual Studio environment.

Batch Commands

Batch commands are equivalent to Save, Build, and Rebuild All commands in the GUI, except that they are executed immediately, without user intervention. Versions for projects are incremented automatically according to the settings of the tool, as described below.

Command-Line Utility

Command line-utility supports VC++ 6.0 DSW files as well as VS2002/2003/2005/2008/2010/2012/2013 SLN files. It shares configuration settings with the add-in version, but user can override these settings with appropriate startup switches. Please check CommandLine.txt file included in the setup for a brief description and list of startup switches.

During command-line utility setup, corresponding menu with two items are added to Programs menu. "AutoVer" entry starts the command-line utility with /g switch, opening the same GUI as the add-in does.

Configuration

Settings are stored in the Configuration.xml file, in the user's ApplicationData folder. This file also stores the size of the main form and the widths of columns in the list view. A configuration file with default values is created when the user starts Visual Studio for the first time after the tool has been installed. Since it is created in the user's profile, each user can configure the tool independently.

The settings dialog consists of four tab pages described in the following sections.

General

Image 5

In the "General" tab page, the user can select which version (AssemblyVersion, AssemblyFileVersion, or AssemblyInformationalVersion) will be displayed in the main form on startup. Moreover, this default version will be the one processed by the "batch" commands corresponding to the last three buttons or menu items on the toolbar and menu, respectively. If "Apply changes to all version types" is checked, all version types will be processed independently, except when "For each project synchronize all version types" is checked. With "Allow arbitrary Informational Version" the user can manually enter freeform text (not conforming version pattern described at the beginning of the article) into corresponding listview entry as described in Modifying Versions Manually subsection. "Include VC++ resource files" includes processing of ProductVersion and FileVersion contained in the corresponding .RC files.

To include Visual Studio setup projects into processing, the "Include setup projects" option must be checked. There is also an option to automatically generate new ProductCode and PackageCode when the version of the setup project is modified.

Once again, it should be pointed out that since a setup project consists of a single .vdproj file, there is no way of checking for any changes, so the user must mark the setup project manually for version change.

Numbering Scheme

Image 6

The "Numbering scheme" tab page allows the user to fine-tune the automatic numbering scheme. Selecting the "By default, increment:" option, the user can choose which part of the version is incremented automatically. This could be useful for those who prefer to leave an asterisk for the Build and the Revision (as originally proposed by Microsoft) and increment the Minor only: the asterisk mask for the Build and the Revision will be left unchanged (except if the user selects one of the "Reset..." options below).

When the "Date & time based Build and Revision numbering" option is checked, the numbers for the Build and the Revision versions will be generated using the date and time rule mentioned at the beginning of this article, inserting actual integers instead of an asterisk. Numbers are generated every time on the tool startup, according to the current local date and time.

Reset options provide a finer control on what happens with less significant numbers when Major, Minor, or Build Versions are incremented. Note that the Minor Version number is always reset on Major increment.

If "Replace asterisk with component values" is left unchecked, asterisks in versions will not be replaced by integer values.

Appearance

Image 7

This tab allows the user to modify some display options: the coloring scheme used to highlight the listview items and how items appear in the listview. For color selection, a separate control presented elsewhere has been developed.

Batch Commands

Image 8

The Batch Commands tab provides additional control for batch commands. The user can also suppress the report dialog displayed when a batch command is executed. 

Folders 

Image 9

This tab contains the path to SourceSafe command-line (required by VCB command-line utility) and path to IIS root folder. These values are usually detected on VCB setup so user need not to modify them.

Export 

Image 10

This tab contains settings for printing versions and exporting them to file. It is possible to select versions and order in which they will be exported, define indentation depth (number of characters for exporting to file or line heights when printing). Also it is possible to select fonts for printer output. For CSV file output, there is an option to select separator; depending on localization settings comma character is not always recognized as a separator. 

Installation Notes 

If you have any previous versions of this tool installed, it is recommended to uninstall it first.

There are separate installation for add-in with permanent commandbars (BuildAutoIncrement.msi) and for add-in with temporary commandbars (BuildAutoIncrementTemporaryBars.msi) for all versions of Visual Studio (i.e. 2003, 2005, 2008, 2010, 2012 and 2013). 

Add-in cannot be installed on Express editions of Visual Studio since they do not allow add-ins. There are no prerequisites for the command-line tool, except that .NET 2.0 or later must be installed.

Credits 

I'd like to thank Don Bailes, Carl Mercier, David Smith, and many others for testing the add-in and helping me to fix the bugs. 

History 

  • ver. 1.0
    • Initial release (posted on 15th January, 2004).  
  • ver. 1.1
    • Support for VB.NET projects and some cosmetic changes in the UI. Note that the installer for this version will automatically remove the previous one.
  • ver. 1.2
    • Support for Managed VC projects added, text encoding set to default (enabling the use of extended characters), MessageFilter added to handle COM messages that often blocked the application, projects with missing AssemblyInfo file are displayed too, buttons to increment Major, Minor, or Build versions for selected projects added (Revision is incremented always by default), and a Save button that only saves updated AssemblyInfo files added.
  • ver. 1.3
    • Settings dialog added, settings are stored between sessions (c.f. "Settings" section above), and some bug fixes.
  • ver. 1.4
  • ver. 1.5
  • ver. 1.6
  • ver. 1.7
  • ver. 1.8
  • ver. 1.9
    • "Enterprise Templates Subprojects not shown" bug introduced with ver. 1.8. has been fixed.
  • ver. 2.0
    • Support for VS 2005 (please note that the add-in was tested on beta 2 version of VS 2005 only; I had no opportunity to test the add-in on the release version of the IDE yet). Additional option in Settings added to select which part of the version is incremented by default. Minor bug fixes. Solution rearranged to allow simultaneous builds for VS 2002/2003 and VS 2005.
  • ver. 2.1
    • Fixed installation problems from ver. 2.0, added separate tabs for AssemblyVersion, AssemblyFileVersion, and AssemblyInformationalVersion (i.e. product version). Note: this version works with VS2002/2003 and VS2005. However, in some cases, icons on the toolbar / menus of VS 2005, for some unknown reason, will not be displayed.
  • ver. 2.2
    • Code refactoring, minor bug fixes (e.g. space around version string problem), minor changes in GUI (scroll position synchronization between tabbed listviews, highlighting color configuration), implemented in-line editing of "to be version", report dialog added for batch commands, added support for setup projects.
  • ver. 2.3
    • Solution folders not displayed bug has been fixed; installation packages have been split (there is a setup for VS2002/2003/2005, and a separate setup for systems with VS2005 only); toolbars/menus have been made permanent, so users can modify the corresponding icons (in case they are not displayed in VS2005); projects in the listview are displayed in the same order as in the Solution Explorer (setup projects being placed at the end); projects in solution folders and in Enterprise Templates can be displayed indented (as selected in the Appearance tab of the Setup dialog). Known problems: conflict with some third party add-ins.
  • ver. 2.4
    • Command line-utility that supports VC++ 6.0 DSW files as well as VS2002/2003/2005 SLN files included into setup (please check CommandLine.txt file for a brief description);
    • Some code reorganization and refactoring, some minor bug-fixes.
  • ver. 2.5
  • ver. 3.0
  • ver. 3.1
    • Option to print current versions or save them to a text/CSV file added, Windows visual styles are now supported, some bug fixes.
      Note: If you have installed version 3.0 for VS2005/2008 on a system with VS 2008, because of a bug in its installation you have to follow the next procedure:
      1. Uninstall the previous version first
      2. Check if commands (not toolbar/menu) still exist in VS2008: Tools - Customize - Commands tab, in Categories list select Addins and see if it contains GUI, Build, Rebuild, Save, Configure and About entries. If any of them exists, run following command from Visual Studio 2008 command prompt:
        devenv /resetaddin BuildAutoIncrement.Connect
        This command will cleanup commands left.
      3. Run the new setup
  • Ver. 3.2
    • Supports Visual Studio 2010 projects
    • Merge module, Cab and Web setup projects supported
    • SourceSafe folder correctly identified on 64-bit systems
    • /V flag in command-line tool overrides configuration/defaults
  • Ver. 3.3
    • Two setups are available: BuildAutoIncrement.msi for add-in with permanent VCB toolbar/menu and BuildAutoIncrementTemporaryBars.msi for add-in with temporary VCB toolbar/menu. Please check readme.txt file in setup archive for more details.
    • Solved the problem of multiplying menu/toolbar items each time Visual Studio 2010 is started
    • F# projects are displayed and solution folder which contains F# project(s) is displayed correctly with all projects inside it
    • Setup, Merge module, CAB and Web setup projects versions displayed correctly
    • GUI opens normally when visual themes are disabled for Visual Studio
    • During uninstallation, an option dialog is shown which allows user to select if VCB menu and toolbar should be removed automatically. Please check readme.txt file in setup archive for more details.
    • Corrected issue with * noted by Michel Gerber 
    • Many thanks to Thomas Klähn, Stefano Leardini and Pierre Granger for helping me to identify multiplying/disappearing toolbar problem.
  • Ver. 3.4
    • Note: if you have a previous version installed, it is highly recommended to uninstall it first.
    • Supports Visual Studio 2012 and 2013 (tested on public preview)
    • Command-line utility supports .vcxproj (C++ project file format introduced with Visual Studio 2010)
    • Support for InstallShield LE included
    • Add-in for Visual Studio 2008/2009/2010/2012/2013 uses XML file based registration. Add-ins for Visual Studio 2003 and 2005 still use COM based registration.
  • Ver. 3.5
    • Problem with menu index fixed. 
    • Addin support for TFS brought back.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Croatia Croatia
Graduated at the Faculty of Electrical Engineering and Computing, University of Zagreb (Croatia) and received M.Sc. degree in electronics. For several years he was research and lecturing assistant in the fields of solid state electronics and electronic circuits, published several scientific and professional papers, as well as a book "Physics of Semiconductor Devices - Solved Problems with Theory" (in Croatian).
During that work he gained interest in C++ programming language and have co-written "C++ Demystified" (in Croatian), 1st edition published in 1997, 2nd in 2001, 3rd in 2010, 4th in 2014.
After book publication, completely switched to software development, programming mostly in C++ and in C#.
In 2016 coauthored the book "Python for Curious" (in Croatian).

Comments and Discussions

 
AnswerRe: Support VS 2012 (and VS 2013) Pin
Julijan Sribar28-Aug-13 9:29
Julijan Sribar28-Aug-13 9:29 
GeneralRe: Support VS 2012 Pin
baddaydaddy18-Aug-13 22:03
baddaydaddy18-Aug-13 22:03 
GeneralRe: Support VS 2012 Pin
onicron9-Sep-13 3:13
onicron9-Sep-13 3:13 
GeneralRe: Support VS 2012 Pin
Julijan Sribar9-Sep-13 3:45
Julijan Sribar9-Sep-13 3:45 
QuestionVS2008 and VS2010 Pin
seleas9-Jul-12 23:35
seleas9-Jul-12 23:35 
AnswerRe: VS2008 and VS2010 Pin
Julijan Sribar10-Jul-12 10:21
Julijan Sribar10-Jul-12 10:21 
GeneralRe: VS2008 and VS2010 Pin
seleas10-Jul-12 22:13
seleas10-Jul-12 22:13 
AnswerRe: VS2008 and VS2010 Pin
Julijan Sribar12-Jul-12 8:43
Julijan Sribar12-Jul-12 8:43 
Hello,

Please check this message[^] (replace 10.0 with 9.0 in registry keys stated) - maybe that could help.

Regards,

Julijan
GeneralRe: VS2008 and VS2010 Pin
seleas19-Jul-12 21:44
seleas19-Jul-12 21:44 
GeneralRe: VS2008 and VS2010 Pin
Julijan Sribar19-Jul-12 21:59
Julijan Sribar19-Jul-12 21:59 
QuestionThank you! Pin
cipher_nemo7-May-12 5:13
cipher_nemo7-May-12 5:13 
QuestionVS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
pomt9-Mar-12 7:47
pomt9-Mar-12 7:47 
AnswerRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
Julijan Sribar9-Mar-12 10:24
Julijan Sribar9-Mar-12 10:24 
GeneralRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
pomt9-Mar-12 11:20
pomt9-Mar-12 11:20 
GeneralRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
pomt9-Mar-12 11:54
pomt9-Mar-12 11:54 
AnswerRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
Julijan Sribar9-Mar-12 23:00
Julijan Sribar9-Mar-12 23:00 
GeneralRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
pomt9-Mar-12 23:21
pomt9-Mar-12 23:21 
GeneralRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
Aleks Kravetsker7-Mar-13 0:47
Aleks Kravetsker7-Mar-13 0:47 
AnswerRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
Julijan Sribar7-Mar-13 1:18
Julijan Sribar7-Mar-13 1:18 
GeneralRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
Don Walker27-Aug-13 9:47
professionalDon Walker27-Aug-13 9:47 
AnswerRe: VS 2010: NullReferenceException at BuildAutoIncrement.VCppProjectFileReader.GetIncludedFiles() Pin
Julijan Sribar28-Aug-13 4:55
Julijan Sribar28-Aug-13 4:55 
GeneralMy vote of 5 Pin
nicoverschu27-Feb-12 0:10
nicoverschu27-Feb-12 0:10 
QuestionThank you ! Pin
nicoverschu27-Feb-12 0:07
nicoverschu27-Feb-12 0:07 
QuestionOpposite problem - not appearing in VS2010 Pin
Ian Wall7-Feb-12 1:12
Ian Wall7-Feb-12 1:12 
AnswerRe: Opposite problem - not appearing in VS2010 Pin
Julijan Sribar7-Feb-12 12:29
Julijan Sribar7-Feb-12 12:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.