文件描述信息即在文件图标上击右键,选择“属性”后弹出的对话框里那个“描述”字段的内容。如下图:
要对一个已生成的可执行文件的描述信息进行修改,可按如下步骤如下:
1. 利用GetFileVersionInfo函数获取版本信息数据块。
2. 利用VerQueryValue函数获取要修改字段的地址。
3. 根据上一步获取的地址,修改其内容为你所指定的内容。
4.利用UpdateResource函数将修改过的数据块更新到可执行文件。
关键的步骤为第二步:获取要修改字段的地址。
开始按照网页http://www.codeproject.com/Articles/6317/Updating-version-information-at-run-time所示的方法,用VerQueryValue得到地址,修改后却并不成功。检查修改的结果,最终确定VerQueryValue得到的地址并不是实际地址,为什么不是真实地址这个原因并不清楚。网上也没搜到相应内容。自己摸索着这个地址与信息块的长度有关联,于是根据这个长度修正地址,最终解决问题。
这里还要提醒下,信息块内的字符串内容都是以宽字符形式存储的。
以下列出相关代码。
首先是两个宽字符与标准字符转换的函数:
//*****************************************************************************
// 宽字符串转为标准字符串
// swSource:宽字符串 szDescription=保存标准字符串的缓冲区 nSize = 缓冲区大小
//*****************************************************************************
BOOL TransformStringWideToAnsi(LPCWSTR swSource, LPSTR szDescription, UINT nSize)
{
UINT nLength = WideCharToMultiByte(CP_ACP, NULL, swSource, -1, NULL, 0, NULL, NULL);
if((nLength<=0)||(nSize<nLength)) return FALSE;
WideCharToMultiByte(CP_ACP, NULL, swSource, -1, szDescription, nLength, NULL, NULL);
szDescription[nLength-1]=0;
return TRUE;
}
//*****************************************************************************
// 标准字符串转为宽字符串
// szSource:标准字符串 swDescription=保存宽字符串的缓冲区 nSize = 缓冲区大小
//*****************************************************************************
BOOL TransformStringAnsiToWide(LPCSTR szSource, LPWSTR swDescription, UINT nSize)
{
UINT nLength = MultiByteToWideChar(CP_ACP, 0, szSource, strlen(szSource), 0, 0);
if((nLength<=0)||(nSize<nLength)) return FALSE;
WCHAR *pDst=new WCHAR[nSize+1];
if (pDst==NULL)return NULL;
MultiByteToWideChar(CP_ACP, 0, szSource, strlen(szSource), swDescription, nLength);
swDescription[nLength]=0;
if(swDescription[0] == 0xFEFF)
{
for(UINT i=0; i<nLength; i++)
{
swDescription[i] = swDescription[i+1];
}
}
return TRUE;
}
相关结构定义:
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
};
struct VS_VERSIONINFO
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[1];
WORD wPadding1[1]; //以零填充szKey以对齐数据为32位(4个字节)
VS_FIXEDFILEINFO Value;
WORD wPadding2[1];
WORD wChildren[1];
};
修改字段内容的函数:
//*****************************************************************************
// 修改文件描述信息
// lpszAppFile=文件名 lpszKeyName=字段名 lpszDescription=字段内容
//*****************************************************************************
BOOL ModifyAppDescription(LPCSTR lpszAppFile, LPCSTR lpszKeyName, LPCTSTR lpszDescription)
{
BOOL fgRet = FALSE;
DWORD dwHandle, dwSize;
LPSTR lpFileName = (LPSTR)lpszAppFile;
//获取版本信息区大小
dwSize = ::GetFileVersionInfoSize(lpFileName, &dwHandle);
if(dwSize == 0) return FALSE;
//建立缓冲区,
LPBYTE lpBuffer = new BYTE[dwSize];
ZeroMemory(lpBuffer, dwSize);
do
{
//读取版本信息
if(!::GetFileVersionInfo(lpFileName, 0, dwSize, lpBuffer)) break;
//获取语言代码
UINT nSize;
LANGANDCODEPAGE *lpTranslate = NULL;
if(!::VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID *)(&lpTranslate), &nSize)) break;
//查询描述字段
CString strSubBlock;
LPTSTR pValueBuffer;
strSubBlock.Format(_T("\\StringFileInfo\\%04x%04x\\%s"), lpTranslate->wLanguage, lpTranslate->wCodePage, lpszKeyName);
if(!::VerQueryValue(lpBuffer, (LPTSTR)((LPCTSTR)strSubBlock), (LPVOID *)(&pValueBuffer), &nSize)) break; //查询并得到字段值的地址
//转换描述串为宽字符串
WCHAR swDescription[MAX_PATH];
TransformStringAnsiToWide(lpszDescription, swDescription, MAX_PATH);
//定位VS_VERSIONINFO结构体
VS_VERSIONINFO *pVerInfo;
pVerInfo = (VS_VERSIONINFO *)lpBuffer;
if(pVerInfo->wValueLength == 0) break;
if(!wcscmp(pVerInfo->szKey, (WCHAR *)"VS_VERSION_INFO")) break;
//修改描述
pValueBuffer -= (pVerInfo->wLength+4); //根据信息块长度修正地址(加的数字4估计是数据块结尾为4个0的结束标记)
nSize = wcslen((WCHAR *)pValueBuffer);
ZeroMemory(pValueBuffer, nSize*sizeof(WCHAR)); //清零
if(strlen(lpszDescription)<nSize) wcscpy((WCHAR *)pValueBuffer, swDescription);//填入新值
//更新到文件
HANDLE hResource = ::BeginUpdateResource(lpszAppFile, FALSE);
if(hResource == NULL) break;
if(!::UpdateResource(hResource, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), lpTranslate->wLanguage, lpBuffer, dwSize)) break;
fgRet = ::EndUpdateResource(hResource, FALSE);
}while(FALSE);
delete []lpBuffer;
return fgRet;
}
应用举例:ModifyAppDescription(“test.exe”, "FileDescription", "My God");