1. 程式人生 > >修改檔案版本資訊(PE檔案版本資訊、資源Version)

修改檔案版本資訊(PE檔案版本資訊、資源Version)

此處的檔案版本資訊,指:

也就是VS開發環境中的資源Version:

對於資訊的讀取,用C#實現起來很簡單:

System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(dllOrExeFilePathName);
fvi...

雖然C#獲取的資訊並不完整(當然,在大多數情況下這些資訊已經足夠)。
用資源修改工具或PE修改工具,可以對版本資訊進行修改。

由於一些原因,需要對一些dll和exe進行批量修改、反覆修改,並且將這些操作配置在VS2010的生成選項中(比如,選擇Debug配置,則版本資訊中的備註為“除錯”,選擇Release為“發行”)。

當然,在RC檔案中,也是可以使用巨集和預處理的:

VS_VERSION_INFO VERSIONINFO
 FILEVERSION 1,0,0,1
 PRODUCTVERSION 1,0,0,1
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x40004L
 FILETYPE 0x1L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "080404b0"
        BEGIN
            VALUE "CompanyName", "INFO"
#ifdef DEBUG
            VALUE "Comment", "除錯"
#else
            VALUE "Comment", "發行"
#endif
VALUE "FileDescription", "INFO" VALUE "FileVersion", "1.0.0.1" VALUE "InternalName", "INFO" VALUE "LegalCopyright", "INFO" VALUE "OriginalFilename", "INFO" VALUE "ProductName", "INFO" VALUE "ProductVersion", "1.0.0.1" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x804, 1200 END END

但問題在於,在IDE中一旦對資源進行了更改,則使用者新增的任何內容都會丟失;也就是說,資原始檔的內容是由IDE自動更新和維護的。

當然,這不是問題。我們可以使用編譯前事件,寫個小程式,根據配置修改rc檔案中的相關內容。這個實現比較簡單。

不過,本人採取了另外一種方法:使用編譯後事件,對已經生成的dll或exe注入相關內容。這樣做的好處是,對執行注入的程式稍加修改,就能批量處理任意數目、任意位置的dll和exe。

從網上逛了一圈,找到了一些示例,可惜的是,沒看到有完整的。於是自己寫了一個。

由於本人水平有限,加之時間有限,程式碼不大好,勿噴,歡迎改善之:

標頭檔案:

#pragma once

class CVersionUpdater
{
public:
	class CResourcePacker
	{
	public:
		CResourcePacker() : Resource(NULL), Size(0) {}
		~CResourcePacker() { Reset(); }

	public:
		void Reset();

		void AppendWord(WORD value_);
		void AppendWords(const WORD* value_, DWORD count_);
		void AppendWChar(WCHAR value_);
		void AppendWString(const WCHAR* value_);
		void AppendAlignment() ;
		void Append(const void* value_, DWORD size_);

		inline BYTE* GetResource() const { return this->Resource; }
		inline DWORD GetSize() const { return this->Size; }

	private:
		BYTE* Resource;
		DWORD Size;
	};
	class CResourceParser
	{
	public:
		CResourceParser(const BYTE* data_) : Data(data_),ParsedSize(0) {}

	public:
		WORD Word();
		WCHAR WChar();
		void Alignment();
		const BYTE* Move(long size_);
		long GetParsedSize() const { return this->ParsedSize; }

	private:
		const BYTE* Data;
		long ParsedSize;
	};

	struct structLangageAndCodePage 
	{
 		WORD Language;
 		WORD CodePage;
 	};

	class CStringTable : public structLangageAndCodePage
	{ 
	public:
		CStringTable();
		~CStringTable();

	public:
		inline const CString* GetComments() const { return this->Comments; }
		inline const CString* GetCompanyName() const { return this->CompanyName; }
		inline const CString* GetFileDescription() const { return this->FileDescription; }
		inline const CString* GetFileVersion() const { return this->FileVersion; }
		inline const CString* GetInternalName() const { return this->InternalName; }
		inline const CString* GetLegalCopyright() const { return this->LegalCopyright; }
		inline const CString* GetLegalTrademarks() const { return this->LegalTrademarks; }
		inline const CString* GetOriginalFilename() const { return this->OriginalFilename; }
		inline const CString* GetPrivateBuild() const { return this->PrivateBuild; }
		inline const CString* GetProductName() const { return this->ProductName; }
		inline const CString* GetProductVersion() const { return this->ProductVersion; }
		inline const CString* GetSpecialBuild() const { return this->SpecialBuild; }
		
		inline void SetComments(LPCTSTR value_) { this->Set(Comments, value_); }
		inline void SetCompanyName(LPCTSTR value_) { this->Set(CompanyName, value_); }
		inline void SetFileDescription(LPCTSTR value_) { this->Set(FileDescription, value_); }
		inline void SetFileVersion(LPCTSTR value_) { this->Set(FileVersion, value_); }
		inline void SetInternalName(LPCTSTR value_) { this->Set(InternalName, value_); }
		inline void SetLegalCopyright(LPCTSTR value_) { this->Set(LegalCopyright, value_); }
		inline void SetLegalTrademarks(LPCTSTR value_) { this->Set(LegalTrademarks, value_); }
		inline void SetOriginalFilename(LPCTSTR value_) { this->Set(OriginalFilename, value_); }
		inline void SetPrivateBuild(LPCTSTR value_) { this->Set(PrivateBuild, value_); }
		inline void SetProductName(LPCTSTR value_) { this->Set(ProductName, value_); }
		inline void SetProductVersion(LPCTSTR value_) { this->Set(ProductVersion, value_); }
		inline void SetSpecialBuild(LPCTSTR value_) { this->Set(SpecialBuild, value_); }
		
		void Set(CString*& which_, LPCTSTR value_);
		
		void Reset();
		void Pack(CResourcePacker& packer_) const;
		void Parse(const BYTE* data_);

	private:
		CString* Comments;
		CString* CompanyName;
		CString* FileDescription;
		CString* FileVersion;
		CString* InternalName;
		CString* LegalCopyright;
		CString* LegalTrademarks;
		CString* OriginalFilename;
		CString* PrivateBuild;
		CString* ProductName;
		CString* ProductVersion;
		CString* SpecialBuild;
	};
	class CStringFileInfo 
	{ 
	public:
		~CStringFileInfo();

	public:
		CArray<CStringTable*, CStringTable*> Children;

	public:
		void Reset();
		void Pack(CResourcePacker& packer_) const;
		void Parse(const BYTE* data_);
	};

	class CVar 
	{
	public:
		CArray<structLangageAndCodePage, structLangageAndCodePage&> Value;

	public:
		void Pack(CResourcePacker& packer_) const;
		void Parse(const BYTE* data_);
	};
	class CVarFileInfo
	{ 
	public:
		~CVarFileInfo();

	public:
		CArray<CVar*, CVar*> Children;

	public:
		void Reset();
		void Pack(CResourcePacker& packer_) const;
		void Parse(const BYTE* data_);
	};

	class CVersionInfo 
	{
	public:
		CVersionInfo();
		~CVersionInfo();

	public:
		VS_FIXEDFILEINFO FixedFileInfo;
		CStringFileInfo* StringFileInfo;
		CVarFileInfo* VarFileInfo;

	public:
		void Reset();
		void Pack(CResourcePacker& packer_) const;
		void Parse(const BYTE* data_);
	};

public:
	CVersionUpdater();
	~CVersionUpdater();

public:
	bool Open(const CString& exeOrDll);
	bool Update(WORD language_ = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)) const;
	
public:
	CVersionInfo* VersionInfo;

private:
	CString ExeOrDll;
};


原始檔:

#include "stdafx.h"
#include "VersionUpdater.h"

#pragma comment(linker, "/defaultlib:version.lib")


///////////////////////////////////////////////////////////////////////////
static WCHAR* SZKEY_VS_VERSION_INFO = L"VS_VERSION_INFO";
static WCHAR* SZKEY_STRINGFILEINFO = L"StringFileInfo";
static WCHAR* SZKEY_VARFILEINFO = L"VarFileInfo";
static WCHAR* SZKEY_TRANSLATION = L"Translation";

enum enumWType
{
	WTYPE_TEXT = 1,
	WTYPE_BINARY = 0,
};

static LPCTSTR StringKeys[] = 
{
	_T("Comments"),
	_T("CompanyName"),
	_T("FileDescription"),
	_T("FileVersion"),
	_T("InternalName"),
	_T("LegalCopyright"),
	_T("LegalTrademarks"),
	_T("OriginalFilename"),
	_T("PrivateBuild"),
	_T("ProductName"),
	_T("ProductVersion"),
	_T("SpecialBuild")
};
int IndexInStringKeys(WCHAR* key)
{
	int length = wcslen(key);
	for(int i=0; i<12; ++i)
	{
		if(_wcsnicmp(StringKeys[i], key, length) == 0) return i;
	}
	return -1;
}
typedef CString* PCString;
typedef CString** PPCString;


DWORD WStringValueLength(const CString& value_)
{
	return value_.GetLength();
}
void SetLength(BYTE* resource_, WORD length_)
{
	*reinterpret_cast<WORD*>(resource_) = length_;
}
WORD GetLength(const BYTE* resource_)
{
	return *reinterpret_cast<const WORD*>(resource_);
}

///////////////////////////////////////////////////////////////////////////
void CVersionUpdater::CResourcePacker::Reset()
{
	if(this->Resource) 
	{
		delete []this->Resource; 
		this->Resource = NULL; 
		this->Size = 0;
	}
}

void CVersionUpdater::CResourcePacker::AppendWord(WORD value_) { this->Append(&value_, sizeof(WORD)); }
void CVersionUpdater::CResourcePacker::AppendWords(const WORD* value_, DWORD count_) { this->Append(value_, sizeof(WORD)*count_); }
void CVersionUpdater::CResourcePacker::AppendWChar(WCHAR value_) { this->Append(&value_, sizeof(WCHAR)); }
void CVersionUpdater::CResourcePacker::AppendWString(const WCHAR* value_) { this->Append(value_, sizeof(WCHAR)*(wcslen(value_)+1)); }
void CVersionUpdater::CResourcePacker::AppendAlignment() 
{
	if(this->Size % 4 == 0) return;
	static BYTE aligmentsValues[3] = {0,0,0};
	DWORD aligments = 4 - (this->Size % 4);
	this->Append(aligmentsValues, aligments);
}
void CVersionUpdater::CResourcePacker::Append(const void* value_, DWORD size_)
{
	DWORD newSize = this->Size + size_;
	BYTE* newResource = new BYTE[newSize];
	if(this->Resource) memcpy(newResource, this->Resource, this->Size);
	memcpy(newResource+this->Size, value_, size_);
	delete []this->Resource;
	this->Resource = newResource;
	this->Size = newSize;
}

///////////////////////////////////////////////////////////////////////////
WORD CVersionUpdater::CResourceParser::Word()
{
	return *reinterpret_cast<const WORD*>(this->Move(sizeof(WORD)));
}
WCHAR CVersionUpdater::CResourceParser::WChar()
{
	return *reinterpret_cast<const WORD*>(this->Move(sizeof(WCHAR)));
}
void CVersionUpdater::CResourceParser::Alignment()
{
	if(this->ParsedSize % 4 == 0) return;
	DWORD alignments = 4 - (this->ParsedSize % 4);
	this->ParsedSize += alignments;
}
const BYTE* CVersionUpdater::CResourceParser::Move(long size_)
{
	const BYTE* v = (this->Data + this->ParsedSize);
	this->ParsedSize += size_;
	return v;
}

///////////////////////////////////////////////////////////////////////////
CVersionUpdater::CStringTable::CStringTable()
	: Comments(NULL)
	, CompanyName(NULL)
	, FileDescription(NULL)
	, FileVersion(NULL)
	, InternalName(NULL)
	, LegalCopyright(NULL)
	, LegalTrademarks(NULL)
	, OriginalFilename(NULL)
	, PrivateBuild(NULL)
	, ProductName(NULL)
	, ProductVersion(NULL)
	, SpecialBuild(NULL)
{
	Language = 0;
	CodePage = 0;
}
CVersionUpdater::CStringTable::~CStringTable() { Reset(); }

void CVersionUpdater::CStringTable::Set(CString*& which_, LPCTSTR value_)
{
	if(which_) delete which_;
	which_ = value_ ? (new CString(value_)) : NULL;
}

void CVersionUpdater::CStringTable::Reset()
{
	if(this->Comments) { delete this->Comments; this->Comments = NULL; }
	if(this->CompanyName) { delete this->CompanyName; this->CompanyName = NULL; }
	if(this->FileDescription) { delete this->FileDescription; this->FileDescription = NULL; }
	if(this->FileVersion) { delete this->FileVersion; this->FileVersion = NULL; }
	if(this->InternalName) { delete this->InternalName; this->InternalName = NULL; }
	if(this->LegalCopyright) { delete this->LegalCopyright; this->LegalCopyright = NULL; }
	if(this->LegalTrademarks) { delete this->LegalTrademarks; this->LegalTrademarks = NULL; }
	if(this->OriginalFilename) { delete this->OriginalFilename; this->OriginalFilename = NULL; }
	if(this->PrivateBuild) { delete this->PrivateBuild; this->PrivateBuild = NULL; }
	if(this->ProductName) { delete this->ProductName; this->ProductName = NULL; }
	if(this->ProductVersion) { delete this->ProductVersion; this->ProductVersion = NULL; }
	if(this->SpecialBuild) { delete this->SpecialBuild; this->SpecialBuild = NULL; }
}
void CStringTable_PackChild(CVersionUpdater::CResourcePacker& packer_, const CString& which_, const CString& value_)
{
	packer_.Reset();
	packer_.AppendWord(0);
	packer_.AppendWord(WStringValueLength(value_));
	packer_.AppendWord(WTYPE_TEXT);
	packer_.AppendWString((LPCTSTR)which_);
	packer_.AppendAlignment();
	packer_.AppendWString(value_);
	packer_.AppendAlignment();
	SetLength(packer_.GetResource(), packer_.GetSize());
}
void CStringTable_ParseChild(const BYTE* data_, PPCString* values)
{
	CVersionUpdater::CResourceParser parser(data_);
	parser.Word();
	WORD valueLength = parser.Word();
	enumWType wType = (enumWType)parser.Word();ASSERT(wType == WTYPE_TEXT);
	WCHAR* key = (WCHAR*)parser.Move(0);
	parser.Move(sizeof(WCHAR)*(wcslen(key)+1));
	parser.Alignment();

	*values[IndexInStringKeys(key)] = new CString((WCHAR*)parser.Move(0));
}
void CVersionUpdater::CStringTable::Pack(CResourcePacker& packer_) const
{
	packer_.Reset();
	packer_.AppendWord(0);
	packer_.AppendWord(0);
	packer_.AppendWord(WTYPE_TEXT);
	CString translate;
	translate.Format(_T("%04x%04x"), this->Language, this->CodePage);
	packer_.AppendWString(translate);
	packer_.AppendAlignment();

	PCString values[] = 
	{
		this->Comments,
		this->CompanyName,
		this->FileDescription,
		this->FileVersion,
		this->InternalName,
		this->LegalCopyright,
		this->LegalTrademarks,
		this->OriginalFilename,
		this->PrivateBuild,
		this->ProductName,
		this->ProductVersion,
		this->SpecialBuild
	};
	for(int i=0; i<12; ++i)
	{
		if(!values[i]) continue;
		CResourcePacker childPacker;
		CStringTable_PackChild(childPacker, StringKeys[i], *values[i]);
		packer_.Append(childPacker.GetResource(), childPacker.GetSize());
		packer_.AppendAlignment();
	}
	packer_.AppendAlignment();
	SetLength(packer_.GetResource(), packer_.GetSize());
}
void CVersionUpdater::CStringTable::Parse(const BYTE* data_)
{	 
	Reset();

	CResourceParser parser(data_);
	parser.Word();
	parser.Word();
	enumWType wType = (enumWType)parser.Word();ASSERT(wType == WTYPE_TEXT);
	int iLanguage, iCodePage;
	swscanf((WCHAR*)parser.Move(8*sizeof(WCHAR)), L"%04x%04x", &iLanguage, &iCodePage);
	this->Language = iLanguage;
	this->CodePage = iCodePage;
	parser.Alignment();

	PPCString values[] = 
	{
		&this->Comments,
		&this->CompanyName,
		&this->FileDescription,
		&this->FileVersion,
		&this->InternalName,
		&this->LegalCopyright,
		&this->LegalTrademarks,
		&this->OriginalFilename,
		&this->PrivateBuild,
		&this->ProductName,
		&this->ProductVersion,
		&this->SpecialBuild
	};

	long structLength = GetLength(data_);
	long parsedLength = parser.GetParsedSize();
	while(parsedLength < structLength)
	{
		CStringTable_ParseChild(data_ + parsedLength, values);
		parsedLength += GetLength(data_ + parsedLength);
		if(parsedLength % 4 != 0) parsedLength += 4 - (parsedLength % 4);
	}
}
///////////////////////////////////////////////////////////////////////////
CVersionUpdater::CStringFileInfo::~CStringFileInfo() { Reset(); }

void CVersionUpdater::CStringFileInfo::Reset()
{
	for(int i=0; i<=this->Children.GetUpperBound(); ++i)
	{
		delete this->Children.GetAt(i);
	}
	this->Children.RemoveAll();
}
void CVersionUpdater::CStringFileInfo::Pack(CResourcePacker& packer_) const
{	 
	packer_.Reset();
	packer_.AppendWord(0);
	packer_.AppendWord(0);
	packer_.AppendWord(WTYPE_TEXT);
	packer_.AppendWString(SZKEY_STRINGFILEINFO);
	packer_.AppendAlignment();

	for(int i=0; i<=this->Children.GetUpperBound(); ++i)
	{
		CStringTable* st = this->Children.GetAt(i);
		if(!st) continue;
		CResourcePacker childPacker;
		st->Pack(childPacker);
		packer_.Append(childPacker.GetResource(), childPacker.GetSize());
		packer_.AppendAlignment();
	}
	packer_.AppendAlignment();
	SetLength(packer_.GetResource(), packer_.GetSize());
}
void CVersionUpdater::CStringFileInfo::Parse(const BYTE* data_)
{	 
	Reset();

	CResourceParser parser(data_);
	parser.Word();
	parser.Word();
	enumWType wType = (enumWType)parser.Word();ASSERT(wType == WTYPE_TEXT);
	parser.Move(sizeof(WCHAR)*(wcslen(SZKEY_STRINGFILEINFO)+1));
	parser.Alignment();

	long structLength = GetLength(data_);
	long parsedLength = parser.GetParsedSize();
	while(parsedLength < structLength)
	{
		CStringTable* st = new CStringTable;
		st->Parse(data_ + parsedLength);
		this->Children.Add(st);
		parsedLength += GetLength(data_ + parsedLength);
		if(parsedLength % 4 != 0) parsedLength += 4 - (parsedLength % 4);
	}
}
///////////////////////////////////////////////////////////////////////////
void CVersionUpdater::CVar::Pack(CResourcePacker& packer_) const
{	 
	packer_.Reset();
	packer_.AppendWord(0);
	packer_.AppendWord(sizeof(structLangageAndCodePage)*(this->Value.GetCount()));
	packer_.AppendWord(WTYPE_BINARY);
	packer_.AppendWString(SZKEY_TRANSLATION);
	packer_.AppendAlignment();

	for(int i=0; i<=this->Value.GetUpperBound(); ++i)
	{
		const structLangageAndCodePage& v = this->Value.GetAt(i);
		packer_.Append(&v, sizeof(structLangageAndCodePage));
    	packer_.AppendAlignment();
	}
	packer_.AppendAlignment();
	SetLength(packer_.GetResource(), packer_.GetSize());
}
void CVersionUpdater::CVar::Parse(const BYTE* data_)
{	 
	CResourceParser parser(data_);
	parser.Word();
	WORD valueLength = parser.Word();
	enumWType wType = (enumWType)parser.Word();ASSERT(wType == WTYPE_BINARY);
	parser.Move(sizeof(WCHAR)*(wcslen(SZKEY_TRANSLATION)+1));
	parser.Alignment();

	long structLength = GetLength(data_);
	long parsedLength = parser.GetParsedSize();
	while(parsedLength < structLength)
	{
		this->Value.Add(*(structLangageAndCodePage*)(data_ + parsedLength));
		parsedLength += GetLength(data_ + parsedLength);
		if(parsedLength % 4 != 0) parsedLength += 4 - (parsedLength % 4);
	}
}
///////////////////////////////////////////////////////////////////////////
CVersionUpdater::CVarFileInfo::~CVarFileInfo() { Reset(); }

void CVersionUpdater::CVarFileInfo::Reset()
{
	for(int i=0; i<=this->Children.GetUpperBound(); ++i)
	{
		delete this->Children.GetAt(i);
	}
	this->Children.RemoveAll();
}
void CVersionUpdater::CVarFileInfo::Pack(CResourcePacker& packer_) const
{	 
	packer_.Reset();
	packer_.AppendWord(0);
	packer_.AppendWord(0);
	packer_.AppendWord(WTYPE_TEXT);
	packer_.AppendWString(SZKEY_VARFILEINFO);
	packer_.AppendAlignment();

	for(int i=0; i<=this->Children.GetUpperBound(); ++i)
	{
		CVar* v = this->Children.GetAt(i);
		if(!v) continue;
		CResourcePacker childPacker;
		v->Pack(childPacker);
		packer_.Append(childPacker.GetResource(), childPacker.GetSize());
		packer_.AppendAlignment();
	}
	packer_.AppendAlignment();
	SetLength(packer_.GetResource(), packer_.GetSize());
}
void CVersionUpdater::CVarFileInfo::Parse(const BYTE* data_)
{	 
	Reset();

	CResourceParser parser(data_);
	parser.Word();
	parser.Word();
	enumWType wType = (enumWType)parser.Word();ASSERT(wType == WTYPE_TEXT);
	parser.Move(sizeof(WCHAR)*(wcslen(SZKEY_VARFILEINFO)+1));
	parser.Alignment();

	long structLength = GetLength(data_);
	long parsedLength = parser.GetParsedSize();
	while(parsedLength < structLength)
	{
		CVar* v = new CVar;
		v->Parse(data_ + parsedLength);
		this->Children.Add(v);
		parsedLength += GetLength(data_ + parsedLength);
		if(parsedLength % 4 != 0) parsedLength += 4 - (parsedLength % 4);
	}
}
///////////////////////////////////////////////////////////////////////////
CVersionUpdater::CVersionInfo::CVersionInfo():StringFileInfo(NULL),VarFileInfo(NULL)
{
	memset(&this->FixedFileInfo, 0, sizeof(VS_FIXEDFILEINFO));
}
CVersionUpdater::CVersionInfo::~CVersionInfo() { Reset(); }

void CVersionUpdater::CVersionInfo::Reset()
{
	if(this->StringFileInfo) { delete this->StringFileInfo; this->StringFileInfo = NULL; }
	if(this->VarFileInfo) { delete this->VarFileInfo; this->VarFileInfo = NULL; }
}
void CVersionUpdater::CVersionInfo::Pack(CResourcePacker& packer_) const
{	 
	packer_.Reset();
	packer_.AppendWord(0);
	packer_.AppendWord(sizeof(VS_FIXEDFILEINFO));
	packer_.AppendWord(WTYPE_BINARY);
	packer_.AppendWString(SZKEY_VS_VERSION_INFO);
	packer_.AppendAlignment();
	packer_.Append(&this->FixedFileInfo, sizeof(VS_FIXEDFILEINFO));
	packer_.AppendAlignment();

	if(this->StringFileInfo)
	{
		CResourcePacker childPacker;
		this->StringFileInfo->Pack(childPacker);
		packer_.Append(childPacker.GetResource(), childPacker.GetSize());
		packer_.AppendAlignment();
	}
	if(this->VarFileInfo)
	{
		CResourcePacker childPacker;
		this->VarFileInfo->Pack(childPacker);
		packer_.Append(childPacker.GetResource(), childPacker.GetSize());
		packer_.AppendAlignment();
	}
	
	packer_.AppendAlignment();
	SetLength(packer_.GetResource(), packer_.GetSize());
}
void CVersionUpdater::CVersionInfo::Parse(const BYTE* data_)
{	 
	Reset();

	CResourceParser parser(data_);
	parser.Word();
	parser.Word();
	enumWType wType = (enumWType)parser.Word();ASSERT(wType == WTYPE_BINARY);
	parser.Move(sizeof(WCHAR)*(wcslen(SZKEY_VS_VERSION_INFO)+1));
	parser.Alignment();
	this->FixedFileInfo = *(VS_FIXEDFILEINFO*)parser.Move(sizeof(VS_FIXEDFILEINFO));
	parser.Alignment();

	const BYTE* next = parser.Move(sizeof(WORD)*3);
	LPCTSTR v = (LPCTSTR)parser.Move(0);

	if(_wcsnicmp(v, SZKEY_STRINGFILEINFO, wcslen(SZKEY_STRINGFILEINFO)) == 0)
	{
		this->StringFileInfo = new CStringFileInfo;
		this->StringFileInfo->Parse(next);
		parser.Move(GetLength(next) - sizeof(WORD)*3);
		next = parser.Move(sizeof(WORD)*3);
		v = (LPCTSTR)parser.Move(0);
	}
	if(_wcsnicmp(v, SZKEY_VARFILEINFO, wcslen(SZKEY_VARFILEINFO)) == 0)
	{
		this->VarFileInfo = new CVarFileInfo;
		this->VarFileInfo->Parse(next);
	}
}

///////////////////////////////////////////////////////////////////////////
CVersionUpdater::CVersionUpdater() : VersionInfo(NULL) {}
CVersionUpdater::~CVersionUpdater()
{
	if(this->VersionInfo)
	{
		delete this->VersionInfo;
		this->VersionInfo = NULL;
	}
}

bool CVersionUpdater::Open(const CString& exeOrDll)
{
	DWORD handle = 0;
	DWORD blockBytesCount = GetFileVersionInfoSize(exeOrDll, &handle);
	if(blockBytesCount == 0) return false;	

	BYTE* blockBytes = new BYTE[blockBytesCount];
	if(!GetFileVersionInfo(exeOrDll, NULL, blockBytesCount, blockBytes))
	{
		delete []blockBytes;
		return false;
	}

	CVersionInfo* versionInfo = new CVersionInfo;
	versionInfo->Parse(blockBytes);
	delete []blockBytes;

	if(this->VersionInfo) delete this->VersionInfo;
	this->VersionInfo = versionInfo;
	this->ExeOrDll = exeOrDll;

	return true;
}

bool CVersionUpdater::Update(WORD language_) const
{
	if(!this->VersionInfo) return false;

	HANDLE resource = BeginUpdateResource(this->ExeOrDll, FALSE);
	if(!resource) return false;

	CResourcePacker packer;
	this->VersionInfo->Pack(packer);

	if (!UpdateResource(resource, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), language_, packer.GetResource(), packer.GetSize())) return false;
	return EndUpdateResource(resource, FALSE) != FALSE;
}


使用示例:

	CVersionUpdater vu;
	if(vu.Open(_T("D:\\PWB\\chem2009\\Debug\\My.exe")))
	{
		if(vu.VersionInfo == NULL) vu.VersionInfo = new CVersionUpdater::CVersionInfo;
		if(vu.VersionInfo->StringFileInfo == NULL) vu.VersionInfo->StringFileInfo = new CVersionUpdater::CStringFileInfo;
		if(vu.VersionInfo->StringFileInfo->Children.GetUpperBound() < 0) vu.VersionInfo->StringFileInfo->Children.Add(new CVersionUpdater::CStringTable);
		for(int i=0; i<=vu.VersionInfo->StringFileInfo->Children.GetUpperBound(); ++i)
		{
			CVersionUpdater::CStringTable* st = vu.VersionInfo->StringFileInfo->Children.GetAt(i);
			//st->SetComments(_T(""));
			st->SetCompanyName(_T("My有限公司"));
// 			st->SetFileDescription(_T(""));
// 			st->SetFileVersion(_T(""));
// 			st->SetInternalName(_T(""));
			st->SetLegalCopyright(_T("My。保留所有權利。"));
// 			st->SetLegalTrademarks(_T(""));
// 			st->SetOriginalFilename(_T(""));
// 			st->SetPrivateBuild(_T(""));
// 			st->SetProductName(_T(""));
// 			st->SetProductVersion(_T(""));
// 			st->SetSpecialBuild(_T(""));
		}
	}
	if(vu.Update()) cout << "OK";
	else cout << "error";