修改可执行文件描述信息

来源:互联网 发布:java生成utf8 xml文件 编辑:程序博客网 时间:2024/05/29 12:36

文件描述信息即在文件图标上击右键,选择“属性”后弹出的对话框里那个“描述”字段的内容。如下图:


要对一个已生成的可执行文件的描述信息进行修改,可按如下步骤如下:

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");


原创粉丝点击