Introduction
There are several good articles here about reading module version information (by shaman74 and Armen Hakobyan), also there are some about modifying RC files during the build process (by Srinivas Vaithianathan and gugulea).
But sometimes, one needs to modify the version information in a compiled executable(s) or DLL:
- Change product name, company name, comments, etc. when deploying multiple products under different names (different skins, branding, resources) but same code;
- Update DLL version numbers without having to modify dozens of RC files;
- Modify a self-extractable archive's (simple installers) resources to reflect the product name and the version information of the contained application.
Description
This library provides an easy way to read, modify, and save version information resource(s) (RT_VERSION
) in compiled executable modules (EXE, DLL, OCX, SCR, etc.).
CVersionInfo vi(strModulePath);
vi.SetFileVersion(4, 5, 0, 3,
TRUE );
vi["Comments"] = "We will stick to C++";
vi.Save();
Classes exported from VerLibInfo
CVersionInfo
- The main class; reads and writes complete version information resources to/from modules. Contains CStringFileInfo
and VS_FIXEDFILEINFO
. The VarFileInfo
structure is not a part of this object, because it is basically computed data. When saving modified version information, proper VarFileInfo
is calculated from the number of string tables and their language-codepage keys.
CStringFileInfo
- The wrapper for the StringFileInfo
structure (contains string tables for different translations of the version information).
CStringTable
- The wrapper for the string-table structure (contains the actual name-value pairs).
CVersionInfoString
- The wrapper for the string structure.
CVersionInfo reference
CVersionInfo();
CVersionInfo(const CString& strModulePath,
LPCTSTR lpszResourceId = NULL ,
WORD wLangId = 0xFFFF );
virtual ~CVersionInfo();
BOOL FromFile(const CString& strModulePath,
LPCTSTR lpszResourceId = NULL ,
WORD wLangId = 0xFFFF );
BOOL ToFile(const CString& strModulePath = "",
LPCTSTR lpszResourceId = NULL ,
WORD wLangId = 0xFFFF );
BOOL Save();
void Reset();
BOOL IsValid() const;
BOOL GetInfoBlockOrder() const;
void SetInfoBlockOrder(BOOL bRegularStringsFirst);
const CStringFileInfo& GetStringFileInfo() const;
CStringFileInfo& GetStringFileInfo();
const CString operator [] (const CString &strName) const;
CString &operator [] (const CString &strName);
const VS_FIXEDFILEINFO& GetFixedFileInfo() const;
VS_FIXEDFILEINFO& GetFixedFileInfo();
void SetFileVersion(WORD dwFileVersionMSHi,
WORD dwFileVersionMSLo,
WORD dwFileVersionLSHi,
WORD dwFileVersionLSLo,
BOOL bUpdateStringTables = TRUE);
void SetFileVersion(DWORD dwFileVersionMS,
DWORD dwFileVersionLS,
BOOL bUpdateStringTables = TRUE);
void SetProductVersion(WORD dwProductVersionMSHi,
WORD dwProductVersionMSLo,
WORD dwProductVersionLSHi,
WORD dwProductVersionLSLo,
BOOL bUpdateStringTables = TRUE);
void SetProductVersion(DWORD dwProductVersionMS,
DWORD dwProductVersionLS,
BOOL bUpdateStringTables = TRUE);
Sample usage
The attached file contains a sample project that utilizes the library (VerInfoLibTest). The test tool understands several command line parameters:
Test Application for Version Info Library
USAGE:
VerInfoLibTest.exe -system
Prints out version numbers of all DLLs in Windows system folder
VerInfoLibTest.exe -f <FileName>
Prints out version info string tables of a specified module
VerInfoLibTest.exe -u <FileName> <StringName> "<Value>"
Modifies the StringName value in the first String Table
in module version information
EXAMPLES:
VerInfoLibTest.exe -u mydll.dll CompanyName "New company name"
VerInfoLibTest.exe -u mydll.dll Comments "Updated comment"
VerInfoLibTest.exe -f mydll.dll
The code for "-system":
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
TCHAR szBuf[MAX_PATH];
::GetSystemDirectory(szBuf, MAX_PATH);
CString strSystemFolder = szBuf;
hFind = FindFirstFile(strSystemFolder + "\\*.dll", &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("Invalid File Handle. "
"Get Last Error reports %d\n",
GetLastError ());
}
else
{
do
{
CString strModulePath = strSystemFolder +
"\\" + FindFileData.cFileName;
const CVersionInfo vi(strModulePath);
if (vi.IsValid())
{
_tprintf(_T("%s\t%s\n"),
FindFileData.cFileName,
vi["FileVersion"]);
}
}
while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
The code for "-f <FileName>":
const CVersionInfo vi(strFilePath);
if (vi.IsValid())
{
POSITION posTable =
vi.GetStringFileInfo().GetFirstStringTablePosition();
while (posTable)
{
const CStringTable &st =
*vi.GetStringFileInfo().GetNextStringTable(posTable);
_tprintf(_T("String table %s\n-----")
_T("-------------------------\n"),
st.GetKey());
POSITION posString = st.GetFirstStringPosition();
while (posString)
{
const CVersionInfoString &vistr =
*st.GetNextString(posString);
_tprintf(_T("%s=%s\n"), vistr.GetKey(),
vistr.GetValue());
}
_tprintf(_T("------------------------------\n"));
}
}
else
{
_tprintf(_T("Failed to get module version")
_T(" information for %s\n"), strFilePath);
}
This will produce an output similar to:
C:\...eProject\Article1\Output\Release>
VerInfoLibTest.exe -f VerInfoLib.dll
String table 040904b0
------------------------------
Comments=
CompanyName=Denis Zabavchik
FileDescription=VerInfoLib DLL
FileVersion=1, 0, 0, 1
InternalName=VerInfoLib
LegalCopyright=Copyright (C) 2006
LegalTrademarks=
OriginalFilename=VerInfoLib.DLL
PrivateBuild=
ProductName=VerInfoLib Dynamic Link Library
ProductVersion=1, 0, 0, 1
SpecialBuild=
------------------------------
The code for updating a given string is very neat (-u <FileName> <StringName> "<Value>"):
if (!_tcscmp(argv[1], _T("-u")))
{
CString strFilePath(argv[2]);
CVersionInfo vi(strFilePath);
vi[argv[3]] = argv[4];
vi.Save();
}
Notes
The code compiles and works in VC6 and 2005 (both MBCS and UNICODE are supported). MFC is used for the container classes, maps etc. The code can be easily ported to be used without MFC.