UpdateResource系列函数用法

来源:互联网 发布:淘宝助理打印模板在哪 编辑:程序博客网 时间:2024/05/19 14:19

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


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

BOOL WINAPI UpdateResource(  _In_      HANDLE hUpdate,  _In_      LPCTSTR lpType,  _In_      LPCTSTR lpName,  _In_      WORD wLanguage,  _In_opt_  LPVOID lpData,  _In_      DWORD cbData);

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


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

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

BOOL GetResourceFromFile(LPCTSTR lpszFile, LPCTSTR lpName, LPCTSTR lpType, LPBYTE lpOut){if( NULL == lpszFile || !PathFileExists(lpszFile) || NULL == lpName || NULL == lpType )return FALSE;BOOL bRet = FALSE;HMODULE hFile = LoadLibrary( lpszFile );if( NULL == hFile )return bRet;HRSRC hRsrc = FindResource( hFile, lpName, lpType );if( NULL == hRsrc )return bRet;HGLOBAL hGlobal = LoadResource( hFile, hRsrc );if( NULL == hGlobal )return bRet;LPBYTE lpBuffer = (LPBYTE)LockResource( hGlobal );if( NULL == lpBuffer)return bRet;DWORD dwSize = SizeofResource( hFile, hRsrc );memcpy( lpOut, lpBuffer, dwSize );bRet = TRUE;FreeLibrary( hFile );return bRet;}


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

BOOL UpdateDllFile(LPCTSTR lpszFile, LPBYTE pIniBuf, LPCTSTR lpType, LPCTSTR lpName){if( NULL == lpszFile || !PathFileExists(lpszFile) || NULL == pIniBuf || NULL == lpType || NULL == lpName )return FALSE;BOOL bRet = FALSE;DWORD dwBufSize = strlen( (char*)pIniBuf );DWORD dwSize = 0;DWORD dwHandle = 0;dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);if( 0 >= dwSize)return bRet;LPBYTE lpBuffer = new BYTE[dwSize];memset( lpBuffer, 0, dwSize );if (GetFileVersionInfo(lpszFile, dwHandle, dwSize, lpBuffer) != FALSE){HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);if( NULL != hResource ){UINT uTemp = 0;if (VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &uTemp) != FALSE){if( FALSE != UpdateResource( hResource, lpType, lpName, lpTranslate->wLanguage, (LPVOID)pIniBuf, dwBufSize) )if (EndUpdateResource(hResource, FALSE) != FALSE)bRet = TRUE;}}}return bRet;}

对了,资源类型如果是一个整形的话,一般用MAKEINTRESOURCE来转换。比如我自定义的资源类型为2000,传入lpType的时候就可以用MAKEINTRESOURCE(2000)。顺便提供下lpTranslate的定义:

struct{WORD wLanguage;WORD wCodePage;} *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。最后附下修改版本信息的源码吧:

BOOL UpdateDllFile(LPCTSTR lpszFile){if( NULL == lpszFile || !PathFileExists(lpszFile) )return FALSE;BOOL bRet = FALSE;DWORD dwHandle = 0;DWORD dwSize = 0;dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);if( 0 >= dwSize)return bRet;LPBYTE lpBuffer = new BYTE[dwSize];memset( lpBuffer, 0, dwSize );if (GetFileVersionInfo(lpszFile, dwHandle, dwSize, lpBuffer) != FALSE){HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);if (NULL != hResource){UINT uTemp;DWORD dwVer[4] = {0};if (VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID *)&lpTranslate, &uTemp) != FALSE){// 修改版本信息,给副版本号加1LPVOID lpFixedBuf = NULL;DWORD dwFixedLen = 0;if( FALSE != VerQueryValue( lpBuffer, _T("\\"), &lpFixedBuf, (PUINT)&dwFixedLen )){VS_FIXEDFILEINFO* pFixedInfo = (VS_FIXEDFILEINFO*)lpFixedBuf;pFixedInfo->dwFileVersionLS    = pFixedInfo->dwFileVersionLS + 0x1;pFixedInfo->dwProductVersionLS = pFixedInfo->dwProductVersionLS + 0x1;dwVer[0] = HIWORD(pFixedInfo->dwFileVersionMS);dwVer[1] = LOWORD(pFixedInfo->dwFileVersionMS);dwVer[2] = HIWORD(pFixedInfo->dwFileVersionLS);dwVer[3] = LOWORD(pFixedInfo->dwFileVersionLS);}// 修改版本的文本信息LPVOID lpStringBuf = NULL;DWORD dwStringLen = 0;TCHAR szTemp[MAX_PATH] = {0};TCHAR szVersion[MAX_PATH] = {0};_stprintf_s( szTemp, MAX_PATH - 1, _T("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTranslate->wLanguage, lpTranslate->wCodePage );_stprintf_s( szVersion, MAX_PATH - 1, _T("%d, %d, %d, %d"), dwVer[0], dwVer[1], dwVer[2], dwVer[3] );if( FALSE != VerQueryValue( lpBuffer, szTemp, &lpStringBuf, (PUINT)&dwStringLen ) )memcpy( lpStringBuf, szVersion, (_tcslen(szVersion) + 1) * sizeof(TCHAR) );memset( szTemp, 0, sizeof(szTemp) );_stprintf_s( szTemp, MAX_PATH - 1, _T("\\StringFileInfo\\%04x%04x\\ProductVersion"), lpTranslate->wLanguage, lpTranslate->wCodePage );if( FALSE != VerQueryValue( lpBuffer, szTemp, &lpStringBuf, (PUINT)&dwStringLen ) )memcpy( lpStringBuf, szVersion, (_tcslen(szVersion) + 1) * sizeof(TCHAR) );// 更新if (UpdateResource(hResource, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), lpTranslate->wLanguage, lpBuffer, dwSize) != FALSE){if (EndUpdateResource(hResource, FALSE) != FALSE)bRet = TRUE;}}}}if( lpBuffer )delete [] lpBuffer;return bRet;}

水平有限,请指正~~~~~




原创粉丝点击