|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionWhen a new project is created, Visual Studio generates an AssemblyInfo file inside it. This file, among other things, contains the 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 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 Moreover, add-in supports Visual C++ resource file 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
BackgroundThis section deals in more detail with versions available in the .NET Framework, and describes the logic used in the tool. The Three Version MusketeersAs already mentioned in the introduction, there are three types of versions supported by the .NET Framework: // ...
[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, These values are incorporated into the assembly, and displayed on the Version tab of the compiled assembly properties window:
The file version displayed at the top of the pane corresponds to the If you check the descriptions of the 1
1.2
1.2.3
1.2.3.4
A single asterisk may be used in 1.2.*
1.2.3.*
Interestingly, although there is a class Versions in the C++ Resource FileAlthough for managed C++ projects, an AssemblyInfo.cpp file (with the // ...
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 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 ProjectIn 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 Logic Used in This ToolThe 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 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 ProjectThe download demo project is a VS2003/VS2005 solution with several distinct projects:
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. This required some rearrangements (as described later in the section Migration to .NET 2.0) and the project Implementation has been duplicated (ImplementationVS8) to build the tool for the new environment. Note that Implementation and ImplementationVS8 share the same source code, using conditional compilation in order to distinguish parts of the code specific for different environments. Points of InterestThe 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 EnvironmentThe add-in established connection to Visual Studio Environment through the
SolutionBrowser ClassesThe abstract On tool startup, The Main FormThe The main window contains several buttons on the right-hand side of the ProjectsListView
A control derived from
VersionTextBoxThe
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 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 Other Classes of InterestThe The The Migration to .NET 2.0In .NET 2.0, the Framework Class Library has changed a bit. For example, the command bars have been moved from 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: #if VS8
using EnvDTE80;
using DTE = EnvDTE80.DTE2;
#endif
into every source file that used the Using the following conditional preprocessor directives has solved the problem of command bars being defined in different assemblies: #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 ( 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 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 SourceSafeThe 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:
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: 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 Using the Add-inAfter 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:
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:
GUIWhen 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: 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 PatternThe 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 RevisionA 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 ManuallyFor 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 ChangesIt 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 CommandsBatch 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 UtilityCommand line-utility supports VC++ 6.0 DSW files as well as VS2002/2003/2005/2008 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 ConfigurationSettings 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
In the "General" tab page, the user can select which version ( 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 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
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
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
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
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
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 NotesIf you have any previous versions of this tool installed, it is recommended to uninstall it first. There is a separate installation for all versions of Visual Studio .NET (i.e. 2002, 2003, 2005 and 2008) and a separate one for a system with VS2005/2008 only. The first one detects Visual Studio versions installed, and creates add-ins for all available versions. In some cases icons on the toolbar and menus of Visual Studio 2005 will not appear; nevertheless the tool is fully functional. If you experience any problem, please check if add-ins are allowed in Visual Studio settings. This tool cannot be installed on Express editions of Visual Studio since they do not allow add-ins. CreditsI'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
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||