rwandering.net
The blogged wandering of Robert W. AndersonUsing UpdateVersion with Resource Scripts
Introduction
At release build time, my company updates our version numbers using the UpdateVersion utility by Mike Gunderloy, Scott Hanselman, and Matt Griffith. This works fine for managed assemblies, but it doesn’t work for versioning unmanaged Win32 DLLs using the resource script. In this article, I show one way to populate the resource script with version numbers from another source.
A new version file
First I created a text file (resourceVersions.txt) to include assembly attributes as would be found in managed code. This file gets added to the project. I am using this format to be compatible with the UpdateVersion utility. It also has the side-benefit that version-related search (and replace) are the same across managed and unmanaged projects. This new file looks like this:
// This file is the source for the resourceVersions.h target // The full AssemblyVersion is set here [assembly : AssemblyVersion("1.2.0.0")] // The full AssemblyFileVersion is set in the release process [assembly : AssemblyFileVersion("1.2.0.0")]
Note that I use UpdateVersion to change the build and revision numbers in the AssemblyFileVersion during release-build time — that is why the two numbers above are the same.
Fixing the default resource script
The resource script that is generated by the IDE has a version section that looks something like this:
/////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,645,0 PRODUCTVERSION 1,0,645,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "Description here" VALUE "FileVersion", "1, 0, 645, 0" VALUE "InternalName", "Name" VALUE "LegalCopyright", "Copyright (C) 2005" VALUE "OriginalFilename", "Name.dll" VALUE "ProductName", " Product Name" VALUE "ProductVersion", "1, 0, 645, 0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END
Note that the version numbers (Product and File) appear in multiple places. My next step was to move the version numbers (both as numbers and as strings) into a header file (i.e., resourceVersions.h):
// this is an auto-generated file and should not be in source control! // Change these versions in resourceVersions.txt! #define ASSEMBLY_VERSIONSTRING "1.2.0.0" #define ASSEMBLY_MAJOR 1 #define ASSEMBLY_MINOR 2 #define ASSEMBLY_BUILD 0 #define ASSEMBLY_REVISION 0 #define FILE_VERSIONSTRING "1.2.0.0" #define FILE_MAJOR 1 #define FILE_MINOR 2 #define FILE_BUILD 0 #define FILE_REVISION 0
And I changed the hard-coded values in the resource script to these constants (with an include on top):
#include "resourceVersions.h" VS_VERSION_INFO VERSIONINFO FILEVERSION FILE_MAJOR, FILE_MINOR, FILE_BUILD, FILE_REVISION PRODUCTVERSION ASSEMBLY_MAJOR, ASSEMBLY_MINOR, ASSEMBLY_BUILD, ASSEMBLY_REVISION FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "Description here" VALUE "FileVersion", FILE_VERSIONSTRING VALUE "InternalName", "Name" VALUE "LegalCopyright", "Copyright (C) 2005" VALUE "OriginalFilename", "Name.dll" VALUE "ProductName", " Product Name" VALUE "ProductVersion", ASSEMBLY_VERSIONSTRING END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END
Auto-generating resourceVersions.h
The next step is to use a nant task to generate the header file. The version numbers are retrieved from resourceVersions.txt by capturing text using regular expressions. Following is a complete nant project file that will accomplish this task:
<?xml version="1.0" ?> <project name="Solution Build Example" default="rebuild" xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd"> <!-- target to make resourceVersions.h from resourceVersions.txt --> <target name="makeResourceVersions"> <loadfile property="resourceVersions" file="resourceVersions.txt" /> <!-- get the assemblyVersion and FileVersion --> <regex pattern="AssemblyVersion\(\042(?'assemblyVersion'(?'avMajor'[0-9]+)\.(?'avMinor'[0-9]+)\.(?'avBuild'[0-9]+)\.(?'avRev'[0-9]+))" input="${resourceVersions}" /> <regex pattern="AssemblyFileVersion\(\042(?'fileVersion'(?'fvMajor'[0-9]+)\.(?'fvMinor'[0-9]+)\.(?'fvBuild'[0-9]+)\.(?'fvRev'[0-9]+))" input="${resourceVersions}" /> <!-- echo --> <echo message="Found AssemblyVersion ${assemblyVersion}, ${avMajor}.${avMinor}.${avBuild}.${avRev}"/> <echo message="Found AssemblyFileVersion ${fileVersion}, ${fvMajor}.${fvMinor}.${fvBuild}.${fvRev}"/> <!-- write the new file --> <echo file="resourceVersions.h" message="// this is an auto-generated file and should not be in source control!" /> <echo file="resourceVersions.h" message="// Change these versions in resourceVersions.txt!" append="true"/> <!-- assembly (product) versions --> <echo file="resourceVersions.h" message='#define ASSEMBLY_VERSIONSTRING "${assemblyVersion}"' append="true"/> <echo file="resourceVersions.h" message="#define ASSEMBLY_MAJOR ${avMajor}" append="true"/> <echo file="resourceVersions.h" message="#define ASSEMBLY_MINOR ${avMinor}" append="true"/> <echo file="resourceVersions.h" message="#define ASSEMBLY_BUILD ${avBuild}" append="true"/> <echo file="resourceVersions.h" message="#define ASSEMBLY_REVISION ${avRev}" append="true"/> <!-- file versions --> <echo file="resourceVersions.h" message='#define FILE_VERSIONSTRING "${fileVersion}"' append="true"/> <echo file="resourceVersions.h" message="#define FILE_MAJOR ${fvMajor}" append="true"/> <echo file="resourceVersions.h" message="#define FILE_MINOR ${fvMinor}" append="true"/> <echo file="resourceVersions.h" message="#define FILE_BUILD ${fvBuild}" append="true"/> <echo file="resourceVersions.h" message="#define FILE_REVISION ${fvRev}" append="true"/> </target> </project>
Integrating into Visual Studio
The final step is to integrate the generation of the include file into your Visual Studio project. This ought to work in VS2003, though I have only confirmed it in VS2005. Simply do the following:
1. Add the resourceVersions.txt file to your project.
2. Give it the following custom build line: nant makeResourceVersions
Conclusion
Once you follow these steps, you should be able to treat your managed and unmanaged versioning identically. Please let me know if you have any comments (or even corrections).