Version Build
An automated method to generate meaningful version numbers in a MS Devstudio project's version resources has been a surprisingly popular topic. After following leads to a variety of solutions, none that I came across quite do what I would like. Here is a solution that suits my needs, perhaps it will suit yours too.
The resource version number is a structure of two double word values, the Most Significant Value (MSV) and the Least Significant Value (LSV). Each value is broken into two parts, the high word and the low word. In a resource script, this is represented by something like "FILEVERSION 1,0,0,1" or "PRODUCTVERSION 1,0,0,1". The "1,0" is the high word/low word of the MSV. The "0,1" is the high word/low word of the LSV. There is also a string representation of the versions in the StringFileInfo block.
I find it desirable to to use the LSV to track incremental builds. Generally, marketing types like to dictate the MSV. So while I may be working on what I consider a Beta release, they want it stamped as version 2.1. But I digress.... :-)
The protocol I use for development versioning is to set the high word of the LSV to a value that indicates the year and day of the build. The low word counts the builds in the given day.
The way the high word is formulated is this: Using the ASCII decimal representation of the year, take the first digit ( e.g, 1998=1, 1999=1, 2000=2 ), multiply times 10, then add the last digit of the year (e.g., 1998=8, 1999=9, 2000=0), then multiply the sum by 1000 (e.g., 1998=18000, 1999=19000, 2000=20000). Now add the day of the year (e.g., Jan 1= 1, Jan 31=31, Feb 1=32). The high word for February 1, 1999 would therefore be 19032, the high word for December 25, 1998 would be 18356, while the high word for June 23, 2000 would be 20175.
The low word is started at 1 for the first build of the day, and incremented by 1 for each ensuing build.
Armed with this information, it is possible to go back in the source control application and find the version of the source that generated any given build. But of course it is tedious and demands more diligence than I can muster to reliably maintain the version by manual input. Thus I present this Devstudio macro that does all this for me, "VersionBuild".
When invoked, VersionBuild will attempt to locate the version resource. If successful, it will modify the FILEVERSION entry according to the protocol outlined above. If successful, VersionBuild will continue to build the project currently active.
By default, VersionBuild will synchronize the LSV of the PRODUCTVERSION as well as the StringFileInfo block's FileVersion and ProductVersion. There are two variables at the top of the macro, bPRODUCTVERSION and bStringFileInfo, which may be set appropriately to control which version types you want modified.
Sub VersionBuild()
'DESCRIPTION: Sets LSV of version number: Hi word = 1st digit of year + last digit of year + day of year; Lo word = 1 if new Hi word or previous + 1 if same Hi word
'Patrick Dell'Era
'patrickd@sirius.com
'
Dim i
Dim strHiWord
Dim strLoWord
Dim nHiWord, nOldHiWord
Dim LSV
Dim strTemp
Dim strMsg
Dim bPRODUCTVERSION, bStringFileInfo
' Set to True if you want the PRODUCTVERSION synchronized
bPRODUCTVERSION = True
' Set to True if you want the StringFileInfo block synchronized
bStringFileInfo = True
strMsg = "There was a problem modifying your version resource. Could not locate "
' Open the resource file as text
' NOTE: You will probably be informed that the resource is
' already opened in the resource editor. You'll need to confirm
' that you want to close that and open the file as text. Otherwise,
' we will return an error informing you that the resource file is
' not in the documents collection
' Trap errors for likely suspects
On Error Resume Next
' Attempt to open the document
Documents.Open (ActiveProject.Name + ".rc"), "Text"
If Err.Number <> 0 Then
MsgBox ("Error 0x" & Hex(Err.Number) & ": " & Err.Description)
Exit Sub
End If
' Try to bring it to the fore
Windows(ActiveProject.Name + ".rc").Active = True
If Err.Number <> 0 Then
MsgBox ("Error 0x" & Hex(Err.Number) & ": " & Err.Description)
Exit Sub
End If
' Seek out the version resource block
If ActiveDocument.Selection.FindText("VS_VERSION_INFO VERSIONINFO", dsMatchWord + dsMatchCase) = False Then
MsgBox strMsg + """VS_VERSION_INFO VERSIONINFO"""
Exit Sub
End If
' Seek the binary FILEVERSION entry
If ActiveDocument.Selection.FindText("FILEVERSION", dsMatchWord + dsMatchCase) = False Then
MsgBox strMsg + """FILEVERSION"""
Exit Sub
End If
' Skip first two entries for the MSV portion of the version
For i = 1 To 2
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #" + Trim(CStr(i)) + " in ""FILEVERSION""."
Exit Sub
End If
Next
' Move off comma
ActiveDocument.Selection.CharRight
' Select the entire number
ActiveDocument.Selection.WordRight dsExtend
' Copy the number string
strTemp = ActiveDocument.Selection.Text
' Convert the number string into an integer
nOldHiWord = CInt(strTemp)
' Get the current year as a string
strTemp = CStr(DatePart("yyyy", Now))
' Make the high word of the LSV equal to the first digit
' of the year ( 1998 = 1; 1999 = 1; 2000 = 2 ...) and
' the last digit of the year ( 1998 = 8; 1999 = 9; 2000 = 0 ...)
strHiWord = CStr(Left(strTemp, 1)) + CStr(Right(strTemp, 1))
' Convert the string into an integer value times 1000 to allow
' room for the day of the year value that is calculated next
nHiWord = CInt(strHiWord) * 1000
' Find out the day of the year for today
LSV = CInt(DatePart("y", Now))
' Add it to the previously calculated year-based value
nHiWord = nHiWord + LSV
' Preserve a copy of the value as a string
strHiWord = CStr(nHiWord)
' If the current value of the high word of the LSV is not the
' same as the newly calculated one, then replace the old with
' the new
If nHiWord <> nOldHiWord Then ' new day
strHiWord = CStr(nHiWord)
ActiveDocument.Selection = strHiWord
End If
' Let's find the low word of least significant value and adjust it
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #3" + " in ""FILEVERSION""."
Exit Sub
End If
' Move off the comma
ActiveDocument.Selection.CharRight
' Select the entire number
ActiveDocument.Selection.WordRight dsExtend
' If the high word of the LSV has changed, then we have begun a
' new day of compilation fun. So reset the low word to 1
If nHiWord <> nOldHiWord Then ' new day, restart counter
LSV = 1
Else
' Same day, new compilation, so increment the low word of
' the LSV
' Grab the number into a text string
strTemp = ActiveDocument.Selection.Text
' Convert it into an integer
LSV = CInt(strTemp)
' Increment the integer
LSV = LSV + 1
End If
' Convert the low word of the LSV into a string
strLoWord = CStr(LSV)
' Copy the string into the selected text
ActiveDocument.Selection = strLoWord
' NOTE: The following code will synchronize the PRODUCTVERSION, FileVersion, and ProductVersion
' entries of the resource file with the FILEVERSION. This is done with the same techniques.
' Set the bPRODUCTVERSION and bStringFileInfo values at the top of the macro appropriately.
If bPRODUCTVERSION Then
' Now seek out PRODUCTVERSION and synchronize
If ActiveDocument.Selection.FindText("PRODUCTVERSION", dsMatchWord + dsMatchCase) = False Then
MsgBox strMsg + """PRODUCTVERSION"""
Exit Sub
End If
For i = 1 To 2
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #" + Trim(CStr(i)) + " in ""PRODUCTVERSION""."
Exit Sub
End If
Next
ActiveDocument.Selection.CharRight
ActiveDocument.Selection.WordRight dsExtend
ActiveDocument.Selection = strHiWord
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #3" + " in ""PRODUCTVERSION""."
Exit Sub
End If
ActiveDocument.Selection.CharRight
ActiveDocument.Selection.WordRight dsExtend
ActiveDocument.Selection = strLoWord
End If
If bStringFileInfo Then
' Now seek out FileVersion in the string block and synchronize
If ActiveDocument.Selection.FindText("FileVersion", dsMatchWord + dsMatchCase) = False Then
MsgBox strMsg + """FileVersion"""
Exit Sub
End If
For i = 1 To 3
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #" + Trim(CStr(i)) + " in ""PRODUCTVERSION""."
Exit Sub
End If
Next
ActiveDocument.Selection.WordRight
ActiveDocument.Selection.WordRight dsExtend
ActiveDocument.Selection = strHiWord
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #4" + " in ""PRODUCTVERSION""."
Exit Sub
End If
ActiveDocument.Selection.WordRight
ActiveDocument.Selection.WordRight dsExtend
ActiveDocument.Selection = strLoWord
If bPRODUCTVERSION Then
' Now seek out ProductVersion in the string block and synchronize
If ActiveDocument.Selection.FindText("ProductVersion", dsMatchWord + dsMatchCase) = False Then
MsgBox strMsg + """ProductVersion"""
Exit Sub
End If
For i = 1 To 3
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #" + Trim(CStr(i)) + " in ""ProductVersion""."
Exit Sub
End If
Next
ActiveDocument.Selection.WordRight
ActiveDocument.Selection.WordRight dsExtend
ActiveDocument.Selection = strHiWord
If ActiveDocument.Selection.FindText(",") = False Then
MsgBox strMsg + "comma #4" + " in ""ProductVersion""."
Exit Sub
End If
ActiveDocument.Selection.WordRight
ActiveDocument.Selection.WordRight dsExtend
ActiveDocument.Selection = strLoWord
End If ' bPRODUCTVERSION
End If ' bStringFileInfo
'close RC file
ActiveDocument.Close
If Err.Number <> 0 Then
MsgBox ("Error 0x" & Hex(Err.Number) & ": " & Err.Description)
Exit Sub
End If
'build active project
ExecuteCommand "BuildToggleBuild"
End Sub
Date Posted: February 23, 1999