UpdateResource系列函数用法

  1. 最近用到了需要实时更新exe和dll中的资源文件,网上查了很多资料,做一些总结,方便下次使用。  


UpdateResource这个函数主要用于添加、删除或者替换PE文件中的资源,它的原型为

  1. BOOL WINAPI UpdateResource(  
  2.   _In_      HANDLE hUpdate,  
  3.   _In_      LPCTSTR lpType,  
  4.   _In_      LPCTSTR lpName,  
  5.   _In_      WORD wLanguage,  
  6.   _In_opt_  LPVOID lpData,  
  7.   _In_      DWORD cbData  
  8. );  

我用两个例子来讲解下这个替换的使用,一个是更新自定义资源文件,一个是用的比较多的就是更新版本信息。


更新自定义资源文件,首先是对资源文件的读取,然后就是写入。读取的时候先通过LoadLibrary得到文件的HMODULE,然后通过FindResource获取到文件中的资源信息,FindResource需要提供HMODULE和资源的类型以及名字,这个一般在资源的头文件中有定义,通过exeScope也可查到,比如ABC   PNG   “abc.png”,这一行中,ABC就是名字,而PNG就是类型,而”abc.png“是你实际的文件名。FindResource得到一个HRSRC的句柄后,就可以通过LoadResource来载入这个资源文件,接着LockResource可以提供上一步的结果缓存指针,然后大家就可以将这段缓存保存下来,进行自己的处理,这样就得到了PE文件中的自定义资源的内容。当然,在保存的时候如果用memcpy的话,需要提供资源缓存的大小,可以通过SizeofResource这个函数来获取大小。其实,系统定义的文件也可以这样做,只是将类型名改为系统的就行了,比如BMP,STRING等等。

下面是我写的读取文件的函数,请指正:

  1. BOOL GetResourceFromFile(LPCTSTR lpszFile, LPCTSTR lpName, LPCTSTR lpType, LPBYTE lpOut)  
  2. {  
  3.     if( NULL == lpszFile || !PathFileExists(lpszFile) || NULL == lpName || NULL == lpType )  
  4.         return FALSE;  
  5.   
  6.     BOOL bRet = FALSE;  
  7.   
  8.     HMODULE hFile = LoadLibrary( lpszFile );  
  9.     if( NULL == hFile )  
  10.         return bRet;  
  11.   
  12.     HRSRC hRsrc = FindResource( hFile, lpName, lpType );  
  13.     if( NULL == hRsrc )  
  14.         return bRet;  
  15.   
  16.     HGLOBAL hGlobal = LoadResource( hFile, hRsrc );  
  17.     if( NULL == hGlobal )  
  18.         return bRet;  
  19.   
  20.     LPBYTE lpBuffer = (LPBYTE)LockResource( hGlobal );  
  21.     if( NULL == lpBuffer)  
  22.         return bRet;  
  23.   
  24.     DWORD dwSize = SizeofResource( hFile, hRsrc );  
  25.     memcpy( lpOut, lpBuffer, dwSize );  
  26.     bRet = TRUE;  
  27.   
  28.     FreeLibrary( hFile );  
  29.   
  30.     return bRet;  
  31. }  


写入资源文件也比较简单。先通过GetFileVersionInfoSize得到资源文件的大小,然后根据大小开辟一段缓存,通过GetFileVersionInfo来填充这段缓存,接着调用BeginUpdateResource来得到资源的句柄,这样就可以开始更新了。但是更新之前还需要获取当前的语言版本,这步不能少,所以用VerQueryValue来传入“\\VarFileInfo\\Translation”就可以得到语言版本。VerQueryValue可以查询三种信息,我们一会就会讲到。得到语言版本后,就可以UpdateResource来更新资源了,最后需要再调用EndUpdateResource来结束更新。还是附上源码参考:

  1. BOOL UpdateDllFile(LPCTSTR lpszFile, LPBYTE pIniBuf, LPCTSTR lpType, LPCTSTR lpName)  
  2. {  
  3.     if( NULL == lpszFile || !PathFileExists(lpszFile) || NULL == pIniBuf || NULL == lpType || NULL == lpName )  
  4.         return FALSE;  
  5.   
  6.     BOOL bRet = FALSE;  
  7.     DWORD dwBufSize = strlen( (char*)pIniBuf );  
  8.     DWORD dwSize = 0;  
  9.     DWORD dwHandle = 0;  
  10.   
  11.     dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);  
  12.     if( 0 >= dwSize)  
  13.         return bRet;  
  14.   
  15.     LPBYTE lpBuffer = new BYTE[dwSize];  
  16.     memset( lpBuffer, 0, dwSize );  
  17.   
  18.     if (GetFileVersionInfo(lpszFile, dwHandle, dwSize, lpBuffer) != FALSE)  
  19.     {  
  20.         HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);  
  21.         if( NULL != hResource )  
  22.         {  
  23.             UINT uTemp = 0;  
  24.             if (VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &uTemp) != FALSE)  
  25.             {  
  26.                 if( FALSE != UpdateResource( hResource, lpType, lpName, lpTranslate->wLanguage, (LPVOID)pIniBuf, dwBufSize) )  
  27.                     if (EndUpdateResource(hResource, FALSE) != FALSE)  
  28.                         bRet = TRUE;  
  29.             }  
  30.         }  
  31.     }  
  32.   
  33.     return bRet;  
  34. }  

对了,资源类型如果是一个整形的话,一般用MAKEINTRESOURCE来转换。比如我自定义的资源类型为2000,传入lpType的时候就可以用MAKEINTRESOURCE(2000)。顺便提供下lpTranslate的定义:
  1. struct  
  2. {  
  3.     WORD wLanguage;  
  4.     WORD wCodePage;  
  5. } *lpTranslate;  


下面讲下更新PE文件中版本信息。版本信息主要有两个,一个是数字形式的,一个是字符串形式的。以版本号为例,最开始我更新的时候只注意到了数字形式,修改了之后发现有些信息还是原来的,后来才查到还需要修改字符串形式,否则显示的仍然是原来的版本号。我下面也只讲下版本号的修改,其他都是一样的。

首先获取数字形式的版本号。之前还是需要先GetFileVersionInfoSize和GetFileVersionInfoSize来得到资源,并BeginUpdateResource获取资源句柄,这些可以参考上面的代码。然后得到语言版本,也是上面有的代码,VerQueryValue并传入“\\VarFileInfo\\Translation”。对于数字的版本号,我们可以通过VerQueryValue并传入“\\”来获取,这个时候我们将得到的缓存转换为VS_FIXEDFILEINFO* 形式的指针,就可以得到版本信息了。这个VS_FIXEDFILEINFO结构体里面dwFileVersionMS和dwFileVersionLS信息是文件版本号,dwProductVersionLS和dwProductVersionMS是产品版本号,MS是主版本号,LS是副版本号。更改之后再调用UpdateResource传入缓存指针就可以了。

另外一个就是字符串形式的版本号。字符串的获取是通过VerQueryValue传入“\\StringFileInfo\\语言版本\\需要的信息”来获取的,里面的“语言版本“需要已16进制格式化上面的lpTranslate结构体后得到。"需要的信息"是你想要查询的,这个在VerQueryValue的介绍里面也有,用exeScope打开一个PE文件,就可以查到,附图:



这里面可以看到语言版本是080404b0,我们如果想得到文件版本信息,则传入\\StringFileInfo\\080404b0\\FileVersionName,如果是产品版本号,则是\\StringFileInfo\\080404b0\\ProduceVersion,等等,就不一一举例了。

得到我们想要的字符串信息的缓存之后,很好办了,直接替换这段缓存,然后UpdateResource回去就可以了。最后记得EndUpdateResource。最后附下修改版本信息的源码吧:

  1. BOOL UpdateDllFile(LPCTSTR lpszFile)  
  2. {  
  3.     if( NULL == lpszFile || !PathFileExists(lpszFile) )  
  4.         return FALSE;  
  5.   
  6.     BOOL bRet = FALSE;  
  7.     DWORD dwHandle = 0;  
  8.     DWORD dwSize = 0;  
  9.   
  10.     dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);  
  11.     if( 0 >= dwSize)  
  12.         return bRet;  
  13.   
  14.     LPBYTE lpBuffer = new BYTE[dwSize];  
  15.     memset( lpBuffer, 0, dwSize );  
  16.   
  17.     if (GetFileVersionInfo(lpszFile, dwHandle, dwSize, lpBuffer) != FALSE)  
  18.     {  
  19.         HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);  
  20.         if (NULL != hResource)  
  21.         {  
  22.             UINT uTemp;  
  23.             DWORD dwVer[4] = {0};  
  24.   
  25.             if (VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &uTemp) != FALSE)  
  26.             {  
  27.                 // 修改版本信息,给副版本号加1  
  28.                 LPVOID lpFixedBuf = NULL;  
  29.                 DWORD dwFixedLen = 0;  
  30.                 if( FALSE != VerQueryValue( lpBuffer, _T("\\"), &lpFixedBuf, (PUINT)&dwFixedLen ))  
  31.                 {  
  32.                     VS_FIXEDFILEINFO* pFixedInfo = (VS_FIXEDFILEINFO*)lpFixedBuf;  
  33.   
  34.                     pFixedInfo->dwFileVersionLS    = pFixedInfo->dwFileVersionLS + 0x1;  
  35.                     pFixedInfo->dwProductVersionLS = pFixedInfo->dwProductVersionLS + 0x1;  
  36.   
  37.                     dwVer[0] = HIWORD(pFixedInfo->dwFileVersionMS);  
  38.                     dwVer[1] = LOWORD(pFixedInfo->dwFileVersionMS);  
  39.                     dwVer[2] = HIWORD(pFixedInfo->dwFileVersionLS);  
  40.                     dwVer[3] = LOWORD(pFixedInfo->dwFileVersionLS);  
  41.                 }  
  42.   
  43.                 // 修改版本的文本信息  
  44.                 LPVOID lpStringBuf = NULL;  
  45.                 DWORD dwStringLen = 0;  
  46.                 TCHAR szTemp[MAX_PATH] = {0};  
  47.                 TCHAR szVersion[MAX_PATH] = {0};  
  48.   
  49.                 _stprintf_s( szTemp, MAX_PATH - 1, _T("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTranslate->wLanguage, lpTranslate->wCodePage );  
  50.                 _stprintf_s( szVersion, MAX_PATH - 1, _T("%d, %d, %d, %d"), dwVer[0], dwVer[1], dwVer[2], dwVer[3] );  
  51.   
  52.                 if( FALSE != VerQueryValue( lpBuffer, szTemp, &lpStringBuf, (PUINT)&dwStringLen ) )  
  53.                     memcpy( lpStringBuf, szVersion, (_tcslen(szVersion) + 1) * sizeof(TCHAR) );  
  54.   
  55.                 memset( szTemp, 0, sizeof(szTemp) );  
  56.                 _stprintf_s( szTemp, MAX_PATH - 1, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"), lpTranslate->wLanguage, lpTranslate->wCodePage );  
  57.   
  58.                 if( FALSE != VerQueryValue( lpBuffer, szTemp, &lpStringBuf, (PUINT)&dwStringLen ) )  
  59.                     memcpy( lpStringBuf, szVersion, (_tcslen(szVersion) + 1) * sizeof(TCHAR) );  
  60.   
  61.                 // 更新  
  62.                 if (UpdateResource(hResource, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), lpTranslate->wLanguage, lpBuffer, dwSize) != FALSE)  
  63.                 {  
  64.                     if (EndUpdateResource(hResource, FALSE) != FALSE)  
  65.                         bRet = TRUE;  
  66.                 }  
  67.             }  
  68.         }  
  69.     }  
  70.   
  71.     if( lpBuffer )  
  72.         delete [] lpBuffer;  
  73.   
  74.     return bRet;  

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值