Zach Burlingame
Programming, Computers, and Other Notes on Technology

Archive for the ‘Windows’ Category

Things to Consider When Publishing Mercurial Repositories

Wednesday, March 23rd, 2011

Shortcut: If you just want to know HOW I publish my repos locally and not all this babble on WHY, then jump to the post Installing Mercurial and Hosting Repositories with CentOS.

I’ve been using Mercurial as my VCS of choice now for about six months and quite frankly I love it. There were a number of pain points for me with Subversion (although I still use it almost every day) that Hg addressed. One of the items that regularly comes up when switching to a DVCS like Hg is “Where is the central repository?” By the pure nature of a DVCS, there is no requirement to have one. It is often useful however, to have a master or authoritative repository that other developers or clones (more on this later) can use to sync with.

Once you decide to have master a repo, the next question is “How do we access it?” With SVN this was typically accomplished through the use of HTTP with mod_dav or via svn+ssh. Mercurial comes with an utility called hgserve that will publish a repository for others to access, but it doesn’t provide any authentication methods so it’s really only viable on internal trusted networks. Fortunately, Mercurial also supports numerous other methods of publishing a repository. Additionally, there are a number of great repository hosting companies out there, including my personal favorites: BitBucket and Kiln.  I use BitBucket’s free service to host the source code used for posts on this blog and I use Kiln’s (which is so much more than just a source code hosting platform) free service for managing some personal projects.

With all these great free online services, why do I want another repository?

  1. Build Server – I run a TeamCity build server for a number of my personal projects and I would rather it work with a local repository than pull it’s data down from the Internet for every build.
  2. Backup – While the online services certainly have a more robust configuration overall than my little personal server, my data is but drop in their huge bucket. It means a LOT to me though, so having some up-to-date master copy that I control makes me sleep a bit better at night. Furthermore web companies go out of business overnight sometimes, and I don’t want to get caught with my data at the mercy of some company’s financials.
  3. Security – Not all of the things I want under version control do I want out on the Internet. Whether it be some personal project or versioning of my configuration data, it’s nice to have a local sandbox to keep these things in.
  4. Fun – I AM a developer after all – this stuff is fun!

There are 1,271,486 other articles out there on how to publish a Mercurial repository, why another?

I have several specific requirements in how I want to deploy my setup and there was no single source that seemed to address them all. This is more for my own documentation purposes than anything else, but I figured hey, there may be 0.7 other people out there who might benefit from it as well! These requirements are:

  1. User Authentication – I definitely want to require user authentication to get access to the repositories. This knocks out the built-in hgserve. (Yes, it’s running on my internal network, but I’m paranoid like that.)
  2. Multiple Committers – I don’t want to use the same user account for everyone who accesses the repository (including the build server) and it’s plausible that I may give friends access to specific projects that come up from time to time.
  3. No server user shell accounts just for access to repositories – I don’t want to have to create a full-blown shell account on a system just to give a user access to a repository. This knocks out SSH-only solutions.
  4. No stored passwords in hg clients for users with shell accounts on the server – For those of us (like me) who DO have shell accounts on the server, I don’t want to be caching a stored password on my client machines. I would much rather use something like public-key authentication in a case like this. This knocks out hgweb-only solutions.
  5. Support for multiple-repositories – I want a solution that supports publishing and managing access for multiple repositories with minimal effort.

Sidebar

Of note on point three – using an SSH-based solution – is that this is creates a special hell for you when you go to setup a TeamCity Continuous Integration server (or any Windows Service based agent that is accessing your repository in an authenticated manner). You either have to provide a username and password to TeamCity when setting up the VCS Root, which will also correspond to a user login on your server (no, thank you!) or setup public-key authentication. The problem arises when you go to setup public-key auth: How do you get TortoiseHg’s plink the key? It turns out you can but it involves jumping through some mighty hoops. First you have to generate your key, securely transfer it to your build server, convert it to PuTTY’s PPK format, place it and a mercurial.ini file in the correct SYSTEM account’s profile directory deep in the bowels of the Windows directory based on the bitness of your TeamCity install, use PsExec to run plink as the system account to accept the host key and not run into any other problems along the way. Ew.

The Hybrid-Solution

I settled on a hybrid of Apache hgweb and SSH to meet all of my requirements. For those users who already have shell accounts, I can use public-key authentication to both securely access the repositories and avoid having stored passwords on the client machines. For those users who don’t have shell accounts (like the service running the TeamCity build server) I can use HTTPS to provide authenticated access in either a read-only or read-write manner. I’ll provide steps on how to do this in the next post: Installing Mercurial and Hosting Repositories with CentOS.

Targeting Windows 2000/XP RTM/XP SP1 from Visual Studio 2010

Tuesday, March 15th, 2011

I’m currently working on a little native C application using the C-runtime libraries (CRT) to detect Windows power events. I ran into a problem when testing my application on Windows XP Professional 32-bit RTM (e.g. “Gold Release”, no service packs). When I attempt to run the application, I get the following error message:

Entry Point Not Found

Entry Point Not Found. The procedure entry point DecodePointer could not be located in the dynamic link library KERNEL32.dll.

Huh?!

After a little digging, it turns out the Microsoft rather quietly discontinued targeting the Windows 2000 and Windows XP RTM/SP1 platforms with Visual Studio 2010. The last release that will target these platforms is Visual Studio 2008.

There were various suggestions on how to workaround this issue including recompiling the CRT, implementing the missing functions in your own w2kcompat.lib, FASM/MASM assembly magic, and reverting to using Visual Studio 2008.  However all of these offered significant drawbacks for me. I do not want to be in the business of supporting a custom compiled version of the CRT. I don’t understand the assembly editing based solutions sufficiently to feel comfortable supporting them on x86 and x64 platforms in the field.

The workaround that works for me and that I ultimately used is to target the Visual Studio 2008 (VC 9.0) Platform Toolset from within my Visual Studio 2010 projects as suggested here and here. There were three key upsides for me with this solution:

  1. This seems like the most reasonable option to support in deployments. No custom builds and no assembly hacking.
  2. I can continue to use VS2k10 and all it’s goodness. (Well, almost. Any feature added in the VC10 runtime won’t be available. )
  3. This modification can be done on a per project (and actually, per Build Configuration) basis, so I don’t have to make system-wide changes to my VS install.

The major downside to this option is that it requires me to have Visual Studio 2008 installed, but this was something I was willing to live with.

One way to accomplish this workaround that was suggested is to place the path to the Visual Studio 2008 VC libs (e.g. “C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\lib” for 32-bit builds) first in the Additional Library Directories under the Linker options for your project. This messy because you have to do this for every configuration of every project in your solution that needs it and it varies for x86 versus x64 builds. Making matters worse is that the location of these files may vary from system to system, so what works for one developer’s machine may not work for another. Not ideal.

The cleaner and easier way to do this is to set the Platform Toolset in the project’s general properties pane. You still need to do this for each project as well as all configurations and all platforms. However, unlike the previous method, this one uses the same value across configurations and platforms and it’s portable across machines.

Setting the Platform Toolset in Visual Studio 2010

Setting the Platform Toolset in Visual Studio 2010

Suppress Unreferenced Parameter/Variable Warnings in Windows C/C++ Applications

Saturday, March 12th, 2011

I use warning level 4 (/W4) for all of my projects as well as “warnings as errors” (/WX) on Release builds. During development I often run into C4100 warnings for unreferenced parameters or variables that are either:

  1. Currently unused but will be used once development is complete
  2. Due to a specific required signature (e.g. for use in a Windows callback in an API) but that I don’t need

In the past I’ve just used a cast to suppress the warnings like this:

// Suppress C4100 Warnings for Unused Parameters
(void*) param1;
(void*) param2;

I came across a collection of handy macros today in WinNT.h (you should include <Windows.h>):

//
// Macros used to eliminate compiler warning generated when formal
// parameters or local variables are not declared.
//
// Use DBG_UNREFERENCED_PARAMETER() when a parameter is not yet
// referenced but will be once the module is completely developed.
//
// Use DBG_UNREFERENCED_LOCAL_VARIABLE() when a local variable is not yet
// referenced but will be once the module is completely developed.
//
// Use UNREFERENCED_PARAMETER() if a parameter will never be referenced.
//
// DBG_UNREFERENCED_PARAMETER and DBG_UNREFERENCED_LOCAL_VARIABLE will
// eventually be made into a null macro to help determine whether there
// is unfinished work.
//

#if ! defined(lint)
#define UNREFERENCED_PARAMETER(P)          (P)
#define DBG_UNREFERENCED_PARAMETER(P)      (P)
#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V)

Integrating the Subversion Revision into the Version Automatically with .NET

Monday, March 7th, 2011

In our final post in this series, we’ll be discussing how to integrate the Subversion information into the file version automatically with .NET. Building on these previous posts, I’ll be discussing how to do this for a .NET project using Visual Studio 2010 Professional and TortoiseSVN.

The source code for this post is available here.

Step 1: Add a Version Project

I find adding a specific Version project to the solution is beneficial. The reason is that we are generating common version info to be used across the entire solution, however the first project in the build order needs to be the one to generate this info. Depending on your project dependencies there may not be an obvious or good place to do this. By adding a Version project and making all other projects depend on it we have an easy place to generate the necessary files.

  1. Add a project named Version to your Solution
  2. Add a reference to Version from all the other projects in your Solution

Step 2: Add a GlobalAssemblyInfo Template

Create a file named GlobalAssemblyInfo.cs.tmpl in the Properties folder of the Version project. Copy the code below into the template and make any desired customizations to match your environment.

Notice the $WCNOW$, $WCNOW$ and $WCMODS?M:$ tokens. We’ll use these to place the necessary Subversion information in the file we generate using SubWCRev.exe.

// This file contains common AssemblyVersion data to be shared across all projects in this solution.
using System.Reflection;

[assembly: AssemblyCompany("Zach Burlingame")]
[assembly: AssemblyProduct("DotNetSVNAutoVersion")]
[assembly: AssemblyCopyright("Copyright © Zach Burlingame 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Revision
//      Build
[assembly: AssemblyVersion("1.0.0.$WCREV$")]
[assembly: AssemblyTitle("Built $WCNOW$ from r$WCREV$$WCMODS?M:$")] // This is visible as the "File Description" on the Details tab of the Explorer pane

NOTE: Originally I also had set the AssemblyFileVersion in the template as well. However, for .NET projects, placing string data in this attribute will generate a warning (like the one below), unlike the FileVersionStr in native projects.

[assembly: AssemblyFileVersion(“1.0.0.$WCREV$$WCMODS?M:$”)]
Warning 1 Assembly generation — The version ‘1.0.0.118M’ specified for the ‘file version’ is not in the normal ‘major.minor.build.revision’ format Version

Step 3: Using SubWCRev to Generate GlobalAssemblyInfo

Next we need to add a pre-build step to our Version project to generate the GlobalAssemblyInfo.cs file from the template using the TortoiseSVN tool called SubWCRev.

The extracted version info includes the revision number, the date time of the build and if there are any local modifications to the working copy. Note that in counter-intuitive fashion, the AssemblyTitle attribute is what sets the Description field when viewed from the Details tab of the Properties pane in Explorer. Meanwhile the AssemblyDescription field isn’t displayed at all and rather is only accessible through API calls against the binary. Why MS did this, I do not know…

  1. Right-click on the Version project
  2. Select Properties
  3. Select the Build Events tab
  4. In the Pre-build event command line box, enter:
    subwcrev.exe "$(SolutionDir)\" "$(ProjectDir)Properties\GlobalAssemblyInfo.cs.tmpl" "$(SolutionDir)Code\App\GlobalAssemblyInfo.cs"

Step 4: Add a link to the GlobalAssemblyInfo.cs file in each project

  1. In Visual Studio, right-click on a project
  2. Select Add->Existing Item
  3. Browse to GlobalAssemblyInfo.cs
  4. Select the file
  5. Click the drop-down arrow next to Add and select Add As Link
  6. Move the link to your Properties folder (optional, but keeps things neat)

Step 5: Update the AssemblyInfo.cs for each project

In order to avoid duplicate annotations for assembly information, you must remove entries from the AssemblyInfo.cs file that appear in the GlobalAssemblyInfo.cs file. In our example here, this is what we end up with:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyDescription("")]  // This is not visible on the Details tab of the Explorer pane

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("dad09178-814d-43f4-b76d-0fbe29a32544")]

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

Integrating the Mercurial Revision into the Version Automatically with .NET

Friday, February 25th, 2011

I’ve already shown how you can add the mercurial revision into the version automatically with native C/C++. However, there are some extra hurdles you have to jump to make this work for .NET. The problem is that you can’t use static variables or class data in the assembly attributes – you have to use constant literals or expressions. As a result, we can’t just generate a simple class and reference it in the AssemblyAttributes.

Again I’ll be building on the previous posts and discussing how to do this with Visual Studio 2010 Professional and Mercurial using TortoiseHg, this time for a .NET application. Other versions of Visual Studio should work similarly and other Mercurial packages will work as well, as long as they provide command-line tools that are in the path of your IDE. We’ll be using a GlobalAssemblyInfo file to share common assembly attributes across projects in the same solution as discussed here.

The source code for this post is available here.

Step 1: Add a Version Project

Although I didn’t do this for the native solution, I find adding a specific Version project to the solution is beneficial. The reason is that we are generating common version info to be used across the entire solution, however the first project in the build order needs to be the one to generate this info. Depending on your project dependencies there may not be an obvious or good place to do this. By adding a Version project and making all other projects depend on it we have an easy place to generate the necessary files.

  1. Add a project named Version to your Solution
  2. Add a reference to Version from all the other projects in your Solution

Step 2: Add a GlobalAssemblyInfo Template

Rather than generate the entire contents of the GlobalAssemblyInfo.cs file in the script, where it’s harder to find and edit when needed, we’ll use a template. Create a file named GlobalAssemblyInfo.cs.tmpl in the Properties folder of the Version project. Copy the code below into the template and make any desired customizations to match your environment.

Notice the $REVISION$, $CHANGESET$ and $LOCAL_MODIFICATIONS$ tokens. We’ll use these to place the necessary Mercurial information in the file we generate.

// This file contains common AssemblyVersion data to be shared across all projects in this solution.
using System.Reflection;

[assembly: AssemblyCompany("Zach Burlingame")]
[assembly: AssemblyProduct("DotNetHgAutoVersion")]
[assembly: AssemblyCopyright("Copyright © Zach Burlingame 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Revision
//      Build
[assembly: AssemblyVersion("1.0.0.$REVISION$")]
[assembly: AssemblyTitle("$CHANGESET$$LOCAL_MODIFICATIONS$")]   // This is visible as the "File Description" on the Details tab of the Explorer pane

Step 3: Using WSH to Generate Global Assembly

Next we need to add a file to our Version project named hg_version.jse. Personally, I like to add this file under the Properties filter of my project. Copy the code below in to the script file. This code does two things:

  1. Creates GlobalAssemblyInfo.cs
  2. Extracts the desired Mercurial version info from the working copy and places it in the header

The extracted version info includes the full node identity, the revision number and if there are any local modifications to the working copy. Note that in counter-intuitive fashion, the AssemblyTitle attribute is what sets the Description field when viewed from the Details tab of the Properties pane in Explorer. Meanwhile the AssemblyDescription field isn’t displayed at all and rather is only accessible through API calls against the binary. Why MS did this, I do not know…

var fso   = new ActiveXObject("Scripting.FileSystemObject");
var shell = new ActiveXObject("WScript.Shell");
var ForReading = 1, ForWriting = 2, ForAppending = 8;

var projectDir = "../../";

var hgRevNum               = shell.Exec("hg identify --num");
var rev                    = hgRevNum.StdOut.ReadAll();
var hg_revision            = String(rev).replace(/\n/g,"").replace(/\+/g,"");
var hg_local_modifications = '';

if( String(rev).replace(/\n/g, "").indexOf("+") != -1 )
{
   hg_local_modifications = '+';
}

var hgChangeset  = shell.Exec("hg parents --template \"{node}\"");
var changeset    = hgChangeset.StdOut.ReadAll();
var hg_changeset = String(changeset).replace(/\n/g,"");

var hgChangesetShort    = shell.Exec("hg parents --template \"{node|short}\"");
var changeset_short     = hgChangesetShort.StdOut.ReadAll();
var hg_changeset_short  = String(changeset_short).replace(/\n/g,"");

var tmplFile = fso.OpenTextFile( projectDir + 'Properties/GlobalAssemblyInfo.cs.tmpl', ForReading, false );
var strContents = tmplFile.ReadAll();
tmplFile.Close();

strContents = String(strContents).replace(/\$REVISION\$/g, hg_revision );
strContents = String(strContents).replace(/\$LOCAL_MODIFICATIONS\$/g, hg_local_modifications );
strContents = String(strContents).replace(/\$CHANGESET\$/g, hg_changeset );
strContents = String(strContents).replace(/\$SHORT_CHANGESET\$/g, hg_changeset_short )

var asmFile = fso.CreateTextFile( projectDir + '../GlobalAssemblyInfo.cs', ForWriting, true );
asmFile.Write( strContents );
asmFile.Close();

Step 4: Add a Pre-build Event

Add a pre-build event to the Version project to call the hg_version.jse script and generate GlobalAssemblyInfo.cs.

  1. Right-click on the Version project
  2. Select Properties
  3. Select the Build Events tab
  4. In the Pre-build event command line box, enter:
    cscript.exe “$(ProjectDir)\Properties\hg_version.jse”

Step 5: Add a link to the GlobalAssemblyInfo.cs file in each project

  1. In Visual Studio, right-click on a project
  2. Select Add->Existing Item
  3. Browse to GlobalAssemblyInfo.cs
  4. Select the file
  5. Click the drop-down arrow next to Add and select Add As Link
  6. Move the link to your Properties folder (optional, but keeps things neat)

Step 6: Update the AssemblyInfo.cs for each project

In order to avoid duplicate annotations for assembly information, you must remove entries from the AssemblyInfo.cs file that appear in the GlobalAssemblyInfo.cs file. In our example here, this is what we end up with:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyDescription("")]  // This is not visible on the Details tab of the Explorer pane

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("dad09178-814d-43f4-b76d-0fbe29a32544")]

Conclusion

And there you have it! Now when you build your solution, all your project assemblies will have the latest Mercurial version information included in their meta-data automatically.

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

Integrating the Mercurial Revision into the Version Automatically with Native C/C++

Tuesday, February 15th, 2011

Now that we’ve covered why we should include version information in our binaries and how to do that for native C/C++ and managed .NET projects, it’s time to up our game. One of the major shortfalls of the previous solutions is that the version information on the binary didn’t map one-to-one to revisions from source control. As a result, while you may be able to determine the version of a particular file, you can’t easily get to the corresponding source code, if at all. One solution to this is to include the source control revision information in the version so you know exactly what was used to build it. Here I’ll be building on the previous posts and discussing how to do this with Visual Studio 2010 Professional and Mercurial using TortoiseHg for a native C/C++ application. Other versions of Visual Studio should work similarly and other Mercurial packages will work as well, as long as they provide command-line tools that are in the path of your IDE. The steps can be easily modified for use with a .NET project based on the previous post.

Update 2011/02/17: Doing this for a .NET assembly is actually a bit trickier than I originally thought because you can’t use static variables or class data in the assembly attributes – you have to use constant literals or expressions. I’ll do a separate post on how to do this with a .NET project.

The basic concept of how this works is explained in the here. The source code for this post is available here.

Step 1: Using WSH to Generate a Version Header

The first step is to add a file to your project named hg_version.jse. Personally, I add this file under the Resource filter of my project. Copy the code below in to the script file. This code does two things:

  1. Creates hg_version.h
  2. Extracts the desired Mercurial version info from the working copy and places it in the header

The extracted version info includes the full node identity, the short node identity, the revision number, and if there are any local modifications to the working copy.

var fso   = new ActiveXObject("Scripting.FileSystemObject");
var shell = new ActiveXObject("WScript.Shell");

var outFile = fso.CreateTextFile("hg_version.h", true);

var hgRevNum               = shell.Exec("hg identify --num");
var rev                    = hgRevNum.StdOut.ReadAll();
var hg_revision            = String(rev).replace(/\n/g,"").replace(/\+/g,"");
var hg_local_modifications = 0
if( String(rev).replace(/\n/g, "").indexOf("+") != -1 )
{
   hg_local_modifications = 1;
}
outFile.WriteLine( "#define HG_REVISION               " + hg_revision );
outFile.WriteLine( "#define HG_LOCAL_MODIFICATIONS    " + hg_local_modifications );

var hgChangeset  = shell.Exec("hg parents --template \"{node}\"");
var changeset    = hgChangeset.StdOut.ReadAll();
var hg_changeset = String(changeset).replace(/\n/g,"");
outFile.WriteLine( "#define HG_CHANGESET              \"" + hg_changeset +"\"" );

var hgChangesetShort    = shell.Exec("hg parents --template \"{node|short}\"");
var changeset_short     = hgChangesetShort.StdOut.ReadAll();
var hg_changeset_short  = "#define HG_CHANGESET_SHORT        \"" + String(changeset_short).replace(/\n/g,"") + "\"";
outFile.WriteLine( hg_changeset_short );

outFile.Close();

Step 2: Update Version.h

The version.h file we created in a previous post needs to be updated to use the information from the generated header. The mercurial revision number is a human friendly integer and can be used directly in the file version. However, due to the nature of a DVCS it is not guaranteed to be globally unique (and it often won’t be on projects with multiple developers using common workflow patterns). The node identity however, does uniquely identify the changeset globally. We include this information in the file description field which maps the binaries one-to-one with the source code they were built with. It’s important to note that the identity field is not a 16-bit integer and thus cannot be used in the file version field directly. Finally, we want to know if the binary was built with local modifications to the working copy, which would complicate reproducing the build. As a result we append an ‘M’ to the end of the file version string if local modifications are present.

#include "hg_version.h"

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

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

#if HG_LOCAL_MODIFICATIONS
  #define VERSION_MODIFIER "M"
#else
  #define VERSION_MODIFIER
#endif

#define VER_FILE_DESCRIPTION_STR    HG_CHANGESET
#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)    \
                                    VERSION_MODIFIER

#define VER_PRODUCTNAME_STR         "c_hg_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 ".dll"
#else
  #define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".exe"
#endif
#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

#if LIBRARY_EXPORTS
  #define VER_FILETYPE              VFT_DLL
#else
  #define VER_FILETYPE              VFT_APP
#endif

Step 3: Add the Pre-build Step

Finally we need to add a pre-build step which will execute the hg_version.jse script, thus generating the hg_version.h file prior to the binary being built.

  1. Right-click on your project
  2. Select Properties
  3. Click Build Events
  4. Click Pre-Build Event
  5. In the Configuration drop-down, select All Configurations
  6. In the Command Line field, enter:
    cscript.exe hg_version.jse
  7. In the Description field, add a comment such as:
    Generate the hg_version.h file with the necessary repo identify info for versioning

NOTE:If you have multiple projects in the same solution that all need to use the same information from Mercurial you have a few choices. One is to put the hg_version.jse script in one project which all the other projects depend on and add a link to the hg_version.h file. Another option is to create a specific version project that all it does is generate the hg_version.h file and define common version information and then have every project in the solution depends on it so it’s executed first in the build order.

Results

Now when each time you build your projects, the latest Mercurial information of the working copy is automatically included in the file version information.

Version Info with Mercurial

Version Info with Mercurial

Final Thoughts

So there you have it, you can now automatically include all the necessary information from your Mercurial working copy in your build to map them one-to-one with the source code that was used. In an upcoming post I’ll discuss how to do this using Subversion as your VCS.

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

Versioning a .NET Assembly with Visual Studio

Friday, February 11th, 2011

We’re already discussed the value of including version information in your binaries. Last post we talked about Versioning a Native C/C++ Binary with Visual Studio. This time we are going to talk about how to do this with a .NET assembly with Visual Studio. I’ll be using C# and Visual Studio 2010 but the principals work in VB .NET and other versions of Visual Studio as well.

First of all, credit where credit is due. Many of the details below are based on this stackoverflow question.

The source code for this post is available here.

Step 1: It’s Already Done!

Whenever you create a new .NET project in Visual Studio a file named AssemblyInfo.cs is created for you under the Properties folder. The annotations in the AssemblyInfo.cs file define the version characteristics include those found in the file properties. By default you’ll get a file like this which sets the copyright to Microsoft, the version to a fixed 1.0.0.0 (more on that in a moment) and a title that matches the project name.

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("ClassLibrary1")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6e0a5113-8d8a-4177-8de4-1c18b5b2c446")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

You can make changes directly to this file however after you have several projects in the same solution, it can get rather tedious to manually update this duplicative information across all your assemblies.

Step 2: Add a Solution-wide GlobalAssemblyInfo File for Common Info

To make life a little simpler moving forward and in keeping with that whole DRY thing you can use a single file to hold all the assembly information that is common across multiple projects. I generally organize my source tree such that there is a top-level Code directory, with separate sub-directories for each project. Therefore I find it most convenient to place a file named GlobalAssemblyInfo.cs in the Code directory, peer to all my project directories. You can place the file wherever you want, however.

Place common version info inside such as:


// This file contains common AssemblyVersion data to be shared across all projects in this solution.
using System.Reflection;

[assembly: AssemblyCompany("Zach Burlingame")]
[assembly: AssemblyProduct("DotNetVersionAssembly")]
[assembly: AssemblyCopyright("Copyright © Zach Burlingame 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Revision
//      Build
//
// You can specify all the values or you can default the Revision and Build Numbers by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.*")]
//[assembly: AssemblyFileVersion("1.0.0.*")]

Step 3: Add a link to the GlobalAssemblyInfo.cs file in each project

  1. In Visual Studio, right-click on a project
  2. Select Add->Existing Item
  3. Browse to GlobalAssemblyInfo.cs
  4. Select the file
  5. Click the drop-down arrow next to Add and select Add As Link
  6. Move the link to your Properties folder (optional, but keeps things neat)

Step 4: Update the AssemblyInfo.cs for each project

In order to avoid duplicate annotations for assembly information, you must remove entries from the AssemblyInfo.cs file that appear in the GlobalAssemblyInfo.cs file. In our example here, this is what we end up with:


using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DotNetVersionAssembly")]
[assembly: AssemblyDescription("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("dad09178-814d-43f4-b76d-0fbe29a32544")]

Step 5: Auto-incrementing the build number

You might of noticed a couple of other changes I made in Step 3:

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Revision
//      Build
//
// You can specify all the values or you can default the Revision and Build Numbers by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.*")]
//[assembly: AssemblyFileVersion("1.0.0.*")]

By replacing build value with an asterisk, Visual Studio (and more specifically, MSBuild) will auto-increment that number every time you build. If you replace both the revision and the build value with a single asterisk it will cause both the revision and build number to auto-increment. This is helpful since the maximum value of any single field is 65535. By auto-incrementing both fields, the revision field is only incremented when the build value overflows, giving you in effect 4 billion unique version numbers for a given Major.Minor combination. If you overflow that, then for the love of pete increment your Major version already!

Also notice that I commented out the AssemblyFileVersion. The differences between the AssemblyVersion and AssemblyFileVersion are discussed here. The key in our example is that you can’t use asterisks to auto-increment the AssemblyFileVersion like you can the AssemblyVersion and you probably don’t want the two getting out-of-sync (at least in this versioning scheme). By not providing an AssemblyFileVersion, MSBuild will default to using the value from the AssemblyVersion.

Results

Now when you build your application, all the version info above will be defined in the assembly 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 while it is possible to auto-increment the build and revision number of the assemblies, those numbers don’t correspond to anything in source control. 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

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

Monday, February 7th, 2011

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

Mapping Binaries in the Field to Source Code in the Repository

Saturday, February 5th, 2011

The Scenario

Andrew from customer support walks down to your cubicle (wait, you have an office?! jealous.) and tells you that he has Joanne on the line from Widgets and Wrenches Unlimited. She says that your remote login software is crashing and they can’t access the server that controls the CNC machine which means they can’t make tools. One of the first things you are going to want to know, is “What version of the app are you running?”

Usually if it’s a product or mature application, there will be a straightforward way to get this information – an About page or the version name right in the application shortcut for instance. When it’s a smaller app or library, or when you need more specific information than “v1.2”  though, you might be up a creek. Numerous times I’ve run into this problem on an internal application where there is no installer, about page, or any other information on the version of the binary I’m looking at and what it’s origins might be.  Sometimes it’s as simple as “let’s just grab the latest version and try that”, but other times that’s not an option. My solution to this problem on many projects has been to include the version information in the binary or assembly itself. At the very least someone can view the Details tab on the Properties window in Explorer and get the info directly.  Best of all it works on all versions of Windows, even if the application won’t run.

A Solution

There are tons of different versioning schemes out there, but I tend to favor:

MAJOR.MINOR.REVISION.BUILD

Three things have been key for making this work for me:

  1. Make the least significant number (BUILD in my example above) correspond to the revision number from the source control repository.
  2. Note if the binary was built from a working copy with local modifications
  3. Make it happen automatically.

With these three things, we can take a binary and know exactly what revision we need to grab from source control to reproduce the problem. Before we release a binary to anyone, we can make sure it wasn’t built with local modifications (and thus potentially seriously complicating reproducing the problem). And since it all happens automatically, we don’t have to remember jump through any hoops. Yay!

How-To

The basic concept is that a pre-build step runs which grabs the version information from the source control tool for the working copy and generates an file which is included in our project. From there we include the information into our version scheme and then it’s just applied to a normal resource version file or AssemblyInfo.cs.

Another policy I try follow on my projects is having everything build on checkout with as minimal a development environment as possible (usually just Visual Studio and the source control tools). To that end, I try to avoid bringing a scripting engine like Python into the development environment just to allow a simple build script. So to accomplish that pre-build step, I use the Javascript engine for the Windows Script Host (WSH) which is built-in since Windows 98.

Over the next several posts, I’m going to explain how to accomplish this in Visual Studio. I’ll explain how to do it for a native C/C++ binary and a C# assembly as well as automating the BUILD number from Subversion and Mercurial.

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