In case you’ve missed the first 2 posts in this series, I’m discussing the concept of using Resouce files with Visual Basic 6.
In the first part, I talked about how to compile arbitrary information into a resource file and reference it from VB.
In Part 2, I discussed a technique for compiling a VersionInfo resource and writing it into your VB executable, thus replacing the incomplete VB provided VersionInfo resource.
In this installment, I wanted to share a little trick for defining the elements of the “Version number” in a resource (RC) file such that you only have to enter the version number once.
If you recall, I presented a sample RC file the last time, looking like this:
1 VERSIONINFO
FILEVERSION 1,2,3,4
PRODUCTVERSION 1,2,3,4
FILEOS 0x4
FILETYPE 0x1 //// 2 for dll, 1 for exe
{
BLOCK "StringFileInfo"
{
BLOCK "000004b0"
{
VALUE "CompanyName", "MyCompany"
VALUE "ProductName", "MyProduct"
VALUE "FileDescription", "MyFileDesc"
VALUE "LegalCopyright", "MyLegalCopyright"
VALUE "LegalTrademarks", "MyLegalTrademark"
VALUE "OriginalFilename", "MyOriginalFilename"
VALUE "ProductVersion", "1.2.3.4"
VALUE "FileVersion", "1.2.3.4"
VALUE "Comments", "MyComments"
VALUE "InternalName", "MyInternalName"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0000 0x04B0
}
}
If you’ll notice, there is one thing about this script that no lazy programmer worth a macro recorder would tolerate. The Version Number is duplicated several times, and what’s worse, in several different formats.
First, we have the FILEVERSION and PRODUCTVERSION entries, with comma separated numbers.
But then we also have the stringized version of those two elements, that must be specified as period separated elements within quotes.
I don’t have an alcohol fueled Code Sync 5000 robot to keep those numbers straight so I figured I’d just use macro substitution. Right. Turns out, the Resource compiler (RC.EXE) is a mighty fickel beast.
What I envisioned was a simple block to define the version number:
#define MAJOR 1
#define MINOR 0
#define REVISION 0
#define BUILD 116
and then use those definitions further down in the file, like so
FILEVERSION MAJOR,MINOR,REVISION,BUILD
and similiarly
VALUE “ProductVersion”, “MAJOR.MINOR.REVISION.BUILD”
But obviously, there’s a problem; actually, more than just one.
I won’t dwell on the details, but after much head scratching (polite euphimism), I ended up with this joyous concoction:
#define COMMAVER(mj,mn,rv,bl) mj,##mn,##rv,##bl
// Commaver yields x,y,z,a (necessary for the numeric versions)
#define PERIODVERPT2( mj ) #mj ""
#define PERIODVERPT3( mj,mn,rv,bl ) PERIODVERPT2( mj ) "." PERIODVERPT2( mn ) "." PERIODVERPT2( rv ) "." PERIODVERPT2( bl )
#define PERIODVER PERIODVERPT3( MAJOR,MINOR,REVISION,BUILD )
// PeriodVer yields x.y.z.a (necessary for the stringized versions)
// define the two numeric versions
// always make them the same
#define FILEVER COMMAVER(MAJOR,MINOR,REVISION,BUILD)
#define PRODUCTVER FILEVER
// define the two stringized version numbers, we just make them the same
#define STRFILEVER PERIODVER
#define STRPRODUCTVER PERIODVER
Then you can use them like so
....
FILEVERSION FILEVER
PRODUCTVERSION PRODUCTVER
....
VALUE "ProductVersion", STRPRODUCTVER
VALUE "FileVersion", STRFILEVER
Get clever with the #include directive and you can easily keep the version numbers of all the separately compiled VB components of your project synchronized and only have to set the version number in a single place.
If there’s a simpler way, I’d love to hear about it. But this works, and it keeps all my version numbers straight.