I've always wanted to do this so I'm finally doing it for benefit of everyone.
I've got the raw version resource format figured out. Here's an application that will dump the contents of a version resource.
I'll be posting some new code later that will allow you to edit and re-form the version resource so you can use it with UpdateResource().
You're gonna have to chew slowly to digest this.
Code:
//NOTE: link with version.lib
#include <windows.h>
#include <memory>
#include <iostream>
#include <iomanip>
using namespace std;
// if x isn't DWORD aligned, this will evaluate to next highest DWORD
// boundry, otherwise evaluates to x
#define ALIGN_UP32(x) ((((DWORD)(x)) + 3) & 0xFFFFFFFC)
// cast x to a DWORD
#define DW(x) ((DWORD)(x))
// is ptr within the range: [base, base+size]
#define PTR_WITHIN(ptr, base, size) \
((DW(ptr) >= DW(base)) && (DW(ptr) < (DW(base) + DW(size))))
//-----------------------------------------------------------------------------
// VersionInfoBase - base class for all structures representing resource
// memory layout
//-----------------------------------------------------------------------------
template<typename child_t>
struct VersionInfoBase
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[1];
// Tests if the given pointer points into this structures
bool IsValidPtr(PVOID ptr)
{
return PTR_WITHIN(ptr, &wLength, wLength);
}//IsValidPtr
// Get the next adjacent version info structure. We can put this in the
// base class since the wLength field holds the size of the structure.
child_t* GetNext()
{
return (child_t*)ALIGN_UP32((DWORD)&wLength + wLength);
}//GetNext
// This method is only valid for String_data_t and Var_data_t
WCHAR* GetValuePtr()
{
return (WCHAR*)ALIGN_UP32(szKey + wcslen(szKey) + 1);
}//GetValuePtr
};//VersionInfoBase
//-----------------------------------------------------------------------------
// String (version information) structures
//-----------------------------------------------------------------------------
// String memory layout type
struct String_data_t : public VersionInfoBase<String_data_t>
{
//WCHAR szKey[1] == name of string resource
};//String_t;
// String instance type
struct String_t
{
String_data_t *data;
WCHAR *Value;
String_t(String_data_t *d)
: data(d), Value(d->GetValuePtr()) {}
};//String_t
//-----------------------------------------------------------------------------
// StringTable structures
//-----------------------------------------------------------------------------
// StringTable memory layout type
struct StringTable_data_t : public VersionInfoBase<StringTable_data_t>
{
//WCHAR szKey[9] == hex string of lang_id:code_page (040904B0)
// Get a pointer to the first String child structure
// Use IsValidPtr() and GetNext() to iterate over all String child
// structures.
String_data_t* GetChildrenPtr()
{
return (String_data_t*)ALIGN_UP32(szKey + 9);
}//GetChildrenPtr
};//StringTable_data_t;
// StringTable instance type
struct StringTable_t
{
StringTable_data_t *data;
String_t str;
StringTable_t(StringTable_data_t *d)
: data(d), str(d->GetChildrenPtr()) {}
};//StringTable_t
//-----------------------------------------------------------------------------
// StringFileInfo structures
//-----------------------------------------------------------------------------
// StringFileInfo memory layout type
struct StringFileInfo_data_t : public VersionInfoBase<StringFileInfo_data_t>
{
//WCHAR szKey[15] == "StringFileInfo"
// Is this a valid a valid memory layout for a StringFileInfo struct?
bool IsValid() {return wcsncmp(szKey, L"StringFileInfo", 14) == 0;}
// Get a pointer to the first StringTable child structure
// Use IsValidPtr() and GetNext() to iterate over all StringTable child
// structures.
StringTable_data_t* GetChildrenPtr()
{
return (StringTable_data_t*)ALIGN_UP32(szKey + 15);
}//GetChildrenPtr
};//StringFileInfo_data_t;
// StringFileInfo instance type
struct StringFileInfo_t
{
StringFileInfo_data_t *data;
StringTable_t strtbl;
StringFileInfo_t(StringFileInfo_data_t *d)
: data(d), strtbl(d->GetChildrenPtr()) {}
};//StringFileInfo_t
//-----------------------------------------------------------------------------
// Var structures
//-----------------------------------------------------------------------------
// Var memory layout type
struct Var_data_t : public VersionInfoBase<Var_data_t>
{
//WCHAR szKey[12] == "Translation"
// Is this a valid a valid memory layout for a VarFileInfo struct?
bool IsValid() {return wcsncmp(szKey, L"Translation", 11) == 0;}
};//Var_data_t
// Var instance type
struct Var_t
{
Var_data_t *data;
DWORD *value;
Var_t(Var_data_t *d)
: data(d), value((DWORD*)d->GetValuePtr()) {}
};//Var_t
//-----------------------------------------------------------------------------
// VarFileInfo structures
//-----------------------------------------------------------------------------
// VarFileInfo memory layout type
struct VarFileInfo_data_t : public VersionInfoBase<VarFileInfo_data_t>
{
//WCHAR szKey[12] == "VarFileInfo"
// Is this a valid a valid memory layout for a VarFileInfo struct?
bool IsValid() {return wcsncmp(szKey, L"VarFileInfo", 11) == 0;}
// Get a pointer to the first Var child structure
// Use IsValidPtr() and GetNext() to iterate over all Var child
// structures.
Var_data_t* GetChildrenPtr()
{
return (Var_data_t*)ALIGN_UP32(szKey + 12);
}//GetChildrenPtr
};//VarFileInfo_data_t
// VarFileInfo instance type
struct VarFileInfo_t
{
VarFileInfo_data_t *data;
Var_t var;
VarFileInfo_t(VarFileInfo_data_t *d)
: data(d), var(d->GetChildrenPtr()) {}
};//VarFileInfo_t
//-----------------------------------------------------------------------------
// VS_VERSIONINFO structures
//-----------------------------------------------------------------------------
// VS_VERSIONINFO memory layout type
struct VS_VERSIONINFO_data_t : public VersionInfoBase<VS_VERSIONINFO_data_t>
{
WCHAR pad_szKey[15]; // [1]+[15] == "VS_VERSION_INFO"
WORD Padding1[1]; // assumes this is DWORD aligned
VS_FIXEDFILEINFO Value[1]; // may be "empty", check wValueLength
// Is this a valid a valid memory layout for a VS_VERSIONINFO struct?
bool IsValid() {return wcsncmp(szKey, L"VS_VERSION_INFO", 15) == 0;}
// Get a pointer to the first StringFileInfo child structure
// Use IsValidPtr() and GetNext() to iterate over all StringFileInfo child
// structures.
StringFileInfo_data_t* GetChildrenPtr()
{
return (StringFileInfo_data_t*)ALIGN_UP32((DWORD)Value + (DWORD)wValueLength);
}//GetChildrenPtr
};//VS_VERSIONINFO_data_t
// VS_VERSIONINFO instance type
struct VS_VERSIONINFO_t
{
VS_VERSIONINFO_data_t *data;
StringFileInfo_t sfi;
VS_VERSIONINFO_t(PVOID d)
: data(reinterpret_cast<VS_VERSIONINFO_data_t*>(d)),
sfi(data->GetChildrenPtr()) {}
bool IsValid() {return data->IsValid();}
bool IsValidPtr(PVOID ptr) {return data->IsValidPtr(ptr);}
};//VS_VERSIONINFO_t
//-----------------------------------------------------------------------------
// Prints the data for a structure derived from VersionInfoBase
template <typename vs_data_t>
void print_vs_struct(vs_data_t *data, int tab)
{
char indent[32];
int len = tab * 3;
memset(indent, ' ', len);
indent[len] = '\0';
cout << indent << "wLength = " << data->wLength << endl
<< indent << "wValueLength = " << data->wValueLength << endl
<< indent << "wType = " << data->wType << endl << indent;
wcout << L"szKey = " << data->szKey << endl;
}//print_vs_struct
// Helper macro used by print_ffi_struct()
#define print_ffi_member(member) \
cout << " " << setw(19) << #member << "= 0x" << hex << setw(8) \
<< setfill('0') << ffi->member << setfill(' ') << endl
// Print the data members of the given VS_FIXEDFILEINFO
void print_ffi_struct(VS_FIXEDFILEINFO *ffi)
{
cout << "BEGIN VS_FIXEDFILEINFO" << endl;
ios::fmtflags f = cout.setf(ios::left);
print_ffi_member(dwSignature);
print_ffi_member(dwStrucVersion);
print_ffi_member(dwFileVersionMS);
print_ffi_member(dwFileVersionLS);
print_ffi_member(dwProductVersionMS);
print_ffi_member(dwProductVersionLS);
print_ffi_member(dwFileFlagsMask);
print_ffi_member(dwFileFlags);
print_ffi_member(dwFileOS);
print_ffi_member(dwFileType);
print_ffi_member(dwFileSubtype);
print_ffi_member(dwFileDateMS);
print_ffi_member(dwFileDateLS);
cout.flags(f);
cout << "END VS_FIXEDFILEINFO" << endl;
}//print_ffi_struct
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int main()
{
char filename[] = "C:\\WINNT\\system32\\USER32.DLL";
DWORD dummy;
DWORD ver_sz = GetFileVersionInfoSize(filename, &dummy);
if (ver_sz == 0)
{
cerr << "GetFileVersionInfoSize() failed, error = " << GetLastError() << endl;
return 1;
}//if
BYTE *ver_info = new BYTE[ver_sz];
auto_ptr<BYTE> vi_ap(ver_info); // for auto deletion
if (!GetFileVersionInfo(filename, 0, ver_sz, ver_info))
{
cerr << "GetFileVersionInfo() failed, error = " << GetLastError() << endl;
return 2;
}//if
// construct a memory layout over the raw data (this is a good place to
// "step-into" using your debugger)
VS_VERSIONINFO_t vsvi(ver_info);
// show the VS_FIXEDFILEINFO structure if there is one
if (vsvi.data->wValueLength != 0)
{
print_ffi_struct(vsvi.data->Value);
}//if
// loop through all the StringFileInfo structures in VS_VERSIONINFO
StringFileInfo_data_t *sfi = vsvi.sfi.data;
while (vsvi.IsValidPtr(sfi))
{
if (!sfi->IsValid())
{
// VS_VERSIONINFO can have children of type StringFileInfo and
// VarFileInfo (usually StringFileInfo comes first)
break;
}//if
cout << "BEGIN StringFileInfo" << endl;
print_vs_struct(sfi, 1);
// loop through all the StringTable structures in this StringFileInfo
StringTable_data_t *strtbl = sfi->GetChildrenPtr();
while (sfi->IsValidPtr(strtbl))
{
cout << " BEGIN StringTable" << endl;
print_vs_struct(strtbl, 2);
// loop through all the String structures in this StringTable
String_data_t *str = strtbl->GetChildrenPtr();
while (strtbl->IsValidPtr(str))
{
cout << " BEGIN String" << endl;
print_vs_struct(str, 3);
cout << " Value = ";
if (str->wValueLength == 0) // may be empty string
cout << "<EMPTY>" << endl;
else
wcout << str->GetValuePtr() << endl;
cout << " END String" << endl;
str = str->GetNext();
}//while
cout << " END StringTable" << endl;
strtbl = strtbl->GetNext();
}//while
cout << "END StringFileInfo" << endl;
sfi = sfi->GetNext();
}//while
// see if there is a valid VarFileInfo child in VS_VERSIONINFO
VarFileInfo_data_t *vfi = (VarFileInfo_data_t*)sfi;
if (vfi->IsValid())
{
cout << "BEGIN VarFileInfo" << endl;
print_vs_struct(vfi, 1);
// loop through all the Var structures in this VarFileInfo
Var_data_t *var = vfi->GetChildrenPtr();
while (vfi->IsValidPtr(var))
{
cout << " BEGIN Var" << endl;
print_vs_struct(var, 2);
cout << " Value = ";
int len = var->wValueLength >> 2;
DWORD *p = (DWORD*)var->GetValuePtr();
for (int n = 0; n < len; n++)
cout << "0x" << hex << p[n] << ",";
cout << endl << " END Var" << endl;
var = var->GetNext();
}//while
cout << "END VarFileInfo" << endl;
}//if
return 0;
}//main
gg