WIN32汇编语言教程:第05章 使用资源 · 5.6 版本信息资源(2)
版本信息资源ID的取值必须为1,如果不为1则属性页上的“版本”信息是无法显示出来的。(笔者也不明白为什么必须为1还要定义这个ID,像stringtable一样没有ID不就完事了?)
可以定义的固定属性有:
● FILEVERSION——定义文件版本号,可以定义4个16位版本号xx.xx.xx.xx。
● PRODUCTVERSION——定义产品版本号,可以定义4个16位版本号xx.xx.xx.xx。
● FILEFLAGSMASK——指定FILEFLAGS属性中哪些位有效。
● FILEFLAGS—文件标志,是一些标志位的组合:VS_FF_PATCHED,VS_FF_DEBUG,VS_FF_PRIVATEBUILD,VS_FF_INFOINFERRED,VS_FF_PRERELEASE和VS_FF_SPECI- ALBUILD。
● FILEOS—定义适用的操作系统,可以定义为VOS_UNKNOWN,VOS_DOS,VOS_NT,VOS_WINDOWS16,VOS_WINDOWS32,VOS_DOS_WINDOWS16,VOS_DOS_WINDOWS32 或VOS_NT_WINDOWS32。
● FILETYPE—定义文件类型,可以是VFT_UNKNOWN,VFT_APP,VFT_DLL,VFT_ DRV,VFT_FONT,VFT_VXD或VFT_STATIC_LIB。
● FILESUBTYPE——定义文件的子类型。当文件类型是VFT_DRV(驱动程序)的时候,这里可以是VFT2_UNKNOWN,VFT2_DRV_COMM,VFT2_DRV_PRINTER,VFT2_DRV_ KEYBOARD,VFT2_DRV_LANGUAGE,VFT2_DRV_DISPLAY,VFT2_DRV_MOUSE,VFT2_DRV_NETWORK,VFT2_DRV_SYSTEM,VFT2_DRV_INSTALLABLE或VFT2_ DRV_SOUND;当文件类型是VFT_FONT(字体)的时候,这里可以是VFT2_UNKNOWN,VFT2_FONT_RASTER,VFT2_FONT_VECTOR或VFT2_FONT_TRUETYPE。
在固定属性定义完成以后,需要定义一些块声明,块声明有两种:变量型的信息块和字符串类型的信息块,变量类型的信息块定义如下:
BLOCK "VarFileInfo" BEGIN VALUE "Translation", 语言ID,字符集ID ...... END
语言ID的常用值有Ox0404(繁体中文)、Ox0409(美国英语)和Ox0804(简体中文),字符集ID的常用值有0(7位ASCII)、950(台湾GB5)和1200(Unicode)。一般使用Ox804, Ox4b0来定义,也就是简体中文和Unicode(Ox4b0=1200)。其他还有很多取值,读者可以查看Rc.exe的帮助文件。
变量类型信息块用来表示VERSIONINFO资源中定义有哪些语言和字符集的字符串类型信息块。如上例中有一句VALUE "Translation",Ox804,Ox4b0表示对应有一个名为“080404b0”的字符串类型的信息块。
字符串信息块的定义语句为:
BLOCK "StringFileInfo" BEGIN BLOCK "语言集" BEGIN VALUE "字符串名称", "字符串" ...... END END
语言集就是变量类型中定义的,其名称一定要是将语言ID和字符集ID组合成一个8位的16进制的格式,以上例文件来说明,当变量类型的信息块种定义Ox804,Ox4b0时,语言集名称就是“080404b0”,在语言集块的定义中,还可以定义多条字符串型的版本信息,这些版本信息的字符串名有12种,如表5.9所示。
表5.9 版本信息字符串类型
字符串名称 | 属性页位置 | 说明 |
Comments | 备注 | 有关程序的附加说明信息 |
CompanyName | 公司 | 开发产品的公司 |
FileDescription | 描述 | 有关文件的简单描述 |
FileVersion | 文件版本 | 如1.50、5.0.RC2等字符串型的版本信息 |
InternalName | 内部名称 | |
LegalCopyright | 版权 | 文件的所有版权信息 |
LegalTrademarks | 合法商标 | 文件的所有注册商标信息 |
OriginalFilename | 源文件名 | 原始文件名,从这里可以得知文件是否被改名 |
PrivateBuild | 个人用内部版本说明 | 作者私人信息 |
ProductName | 产品名称 | 文件所属的产品名称 |
ProductVersion | 产品版本 | 文件所属的产品的版本号 |
SpecialBuild | 特殊内部版本说明 | 特殊说明 |
定义版本信息字符串的时候要注意,所有的字符串必须是以NULL结尾的串,所以要在字符串尾加上\0,如例子程序所示:
VALUE "Comments", "Here is Comments\0"
VALUE "CompanyName", "Here is CompanyName\0"
...
5.6.2 在程序中检测版本信息
Win32 API中有3个版本信息函数:GetFileVersionSize,GetFileVersionInfo 和 VerQueryValue,它们驻留在VERSION.DLL文件中,如果在源程序中使用它们,注意要加上include Version.inc以及includelib Version.lib语句。
用这3个函数获取版本信息的方法是:
首先调用GetFileVersionInfoSize函数检测文件中有没有版本信息资源:
invoke GetFileVersionInfoSize,addr szFile,NULL
其中szFile是要检测的PE文件名字符串,该函数的返回值是版本信息资源的长度,如果返回0,则表示文件不是PE文件或没有定义版本信息资源。
如果检测到文件中有版本信息资源,那么可以将版本信息资源读取到一个缓冲区中,缓冲区的长度必须足够容纳上一步返回的资源长度,方法是:
invoke GetFileVersionInfo,addr szFile,NULL,sizeof dbVerInfo,addr dbVerInfo
其中dbVerInfo为一个足够大的缓冲区。该函数会把整个版本信息资源拷贝到这个缓冲区中。
拷贝到缓冲区种的信息有它自己的格式,必须用VerQueryValue去“解码”,解码固定属性的方法是:
invoke VerQueryValue,addr dbVerInfo,addr szRoot,addr lpBuffer,addr dwLen
第一个参数指向前一步返回的版本信息资源数据,第二个参数指向一个字符串:“\”,第三和第四个参数指向dw类型的变量lpBuffer和dwLen,返回到lpBuffer中的是指向一个VS_FIXEDFILEINFO结构的指针,这个结构中有定义的固定属性内容。
如果要获取字符串类型信息块中的版本信息,那就比较复杂一点了,必须首先知道语言集的名称,所以先要获取版本信息资源中变量类型信息块的内容,方法是:
invoke VerQueryValue,addr dbVerInfo,addr szVarInfo,addr lpBuffer,addr dwLen mov eax,lpBuffer mov eax,[eax] ror eax,16
szVarInfo是一个字符串:“\VarFileInfo\Translation”,这时函数在lpBuffer中返回语言集变量指针的指针,所以要先mov eax,lpBuffer,再用eax作指针用mov eax,[eax]得到语言集变量。语言集变量的高16位是字符集ID,低16位是语言ID,可以使用ror eax,16来调换高低位,以我们的例子为例,现在eax中的值就是080404b0h了!
接下来就可以获取字符串版本信息了,先将语言集的值通过wsprintf函数转换成“080404b0”的形式,然后拼装成“\StringFileInfo\080404b0\字符串名称”形式的字符串,中间的“字符串名称”可以是表5.9中的12种名称之一,最后调用下面的语句(假定拼装好的字符串地址为szString):
invoke VerQueryValue,addr dbVerInfo,addr szString,addr lpBuffer,addr dwLen
执行后lpBuffer中会得到一个指针,指向版本信息字符串定义的内容,这就是我们最后需要的东西!重复这个步骤可以得到所有12种字符串版本信息。
读者可以在所附光盘的Chapter05\ShowVersionInfo目录中找到一个ShowInfo程序,它可以获取PE文件中的版本信息资源并显示出来,详细的代码请参考该目录中的文件,主文件ShowInfo.asm是界面程序,版本信息资源的代码在GetVersionInfo.inc文件中,由于篇幅有限,源程序在这里就不列出来了。
上页:第05章 使用资源 · 5.5 字符串资源/5.6 版本信息资源(1) 下页:第05章 使用资源 · 5.7 二进制资源和自定义资源