C++外部程序修改exe文件属性信息

Windows平台可执行文件(execute文件)属性中会有版本信息,包含文件说明、文件版本、版权等信息。本文主要目的是将设置版本信息的方法公开化。

首先我们要清楚Windows下的可执行文件格式属于PE文件格式标准,PE文件标准支持内嵌资源,就是将一个外部文件内嵌到可执行文件中,这样程序启动时只需从自身内部找到这块资源加载就可以了,而不需依赖其他外部的磁盘文件。

PE文件支持的内嵌资源都有两个必须的标识:一个是资源类型,一个是资源名称。因此只要知道内嵌资源的这两个标识就能找到对应的资源。可执行文件的版本信息就是以内嵌资源的方式保存在文件中。

  • 资源类型和资源名称可以是数字也可以是字符串。
  • 系统已知资源都是以数字来命名的(比如图标资源、版本资源、Manifest资源)。
  • 建议自定义资源都用字符串来命名,避免与系统资源冲突。

微软提供了一组通用API接口,用来获取和设置可执行文件的内嵌资源,请看下面详细介绍。

版本数据获取

获取PE文件的版本信息数据有两种获取方法:

  1. 通用内嵌资源获取方式
  2. 专用API获取方式

通用内嵌资源获取方式

通过下面接口可以获取Windows可执行文件中的任何通用资源。

#include <io.h>
#include <string>

std::string GetPEResource(const char* exepath, const char* type,
                          const char* name, int language = 0)
{
   
    std::string r = "";

    if (!exepath)
        return r;

    //判定文件是否存在
    if (_access(exepath, 0) != 0)
        return r;

    //加载可执行文件
    HMODULE hexe = LoadLibrary(exepath);
    if (!hexe)
        return r;

    //查找资源
    HRSRC src = FindResourceEx(hexe, type, name, language);
    if (src)
    {
   
        HGLOBAL glb = LoadResource(hexe, src);
        int sz = SizeofResource(hexe, src);
        r = std::string((char *)LockResource(glb), sz);
        UnlockResource(glb);
        FreeResource(glb);
    }

    //释放可执行文件
    FreeLibrary(hexe);

    return r; //返回一个完整的、标准的版本信息数据
}

通过对 GetPEResource 接口进行简单调用即可获取PE文件中的版本数据。
文件的版本信息以内嵌资源的方式保存在可执行文件中,它的资源类型是RT_VERSION(16),资源名称是 MAKEINTRESOURCE(VS_VERSION_INFO)(1)。

std::string rc = GetPEResource( "C:\\测试文件.exe", RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), 0);

专用API获取方式

微软提供了另外一种专门用于获取文件版本信息的API接口,示例代码如下:

#include <io.h>
#include <string>

std::string GetPEVersionInfo(const char* exepath)
{
   
    std::string r = "";

    if (!exepath)
        return r;

    if (_access(exepath, 0) != 0)
        return r;

    DWORD sz = GetFileVersionInfoSize(exepath, 0);
    r.resize(sz, 0);
    return GetFileVersionInfo(exepath, 0, sz, (void*)r.c_str()) ? r : "";
}

通过调用此接口,也可正常获取文件中的版本信息数据。但此接口返回的缓冲区是自带备份的,并非标准版本数据。举个例子:假如某exe文件的版本数据大小是N字节,那么调用 GetPEVersionInfo 接口返回的缓冲区大小则是N * 2 + 4字节,前N字节数据为标准的版本数据,中间4字节用 ‘F’ ‘E’ ‘2’ 'X’字符填充,后N个字节用0填充。

版本数据解析

版本数据是格式是一个名叫 VS_VERSIONINFO 的结构体,在msdn上可搜到这个结构体的相关描述。该结构可以认为由三部分构成。
第一部分是一个 VS_FIXEDFILEINFO 对象,包含简要版本信息。
第二部分是一个 VarFileInfo 对象,该部分可能不存在。
第三部分是一个 StringFileInfo 对象,该部分可能不存在。

VS_FIXEDFILEINFO 对象存放在 VS_VERSIONINFO 结构中的 Value 字段中,
VarFileInfo 对象和 StringFileInfo 对象(若存在的话)存放在 VS_VERSIONINFO 结构中的 Children 字段中。

typedef struct {
   
  WORD             wLength; // VS_VERSIONINFO 结构的长度(以字节为单位)
  WORD             wValueLength; // Value成员的长度(以字节为单位)。 如果没有与当前版本结构关联的 Value 成员,则此值为零。
  WORD             wType; // 版本资源中的数据的类型。 如果版本资源为文本数据,则此成员为 1; 如果版本资源为二进制数据,则为0。
  WCHAR            szKey; // 标识字符串: “VS_VERSION_INFO”
  WORD             Padding1; // 包含在32位边界上 对齐 Value 成员所需的 0 , 使后面字段按4字节对齐。
  VS_FIXEDFILEINFO Value; // 与此 VS_VERSIONINFO 结构关联的数据。 wValueLength 成员指定此成员的长度;如果 wValueLength 为零,则不存在此成员。
  WORD             Padding2; // 在32位边界上对齐 Children 成员所需的 0 。 这些字节不包含在 wValueLength 中。 
  WORD             Children; // 零个或一个 StringFileInfo 结构的数组,以及零个或一个 VarFileInfo 结构。
} VS_VERSIONINFO;
typedef struct tagVS_FIXEDFILEINFO {
     
  DWORD dwSignature; // 文件填充信息标识,固定值0xFEEF04BD 
  DWORD dwStrucVersion; // 该结构的32位二进制版本号,高16位是主版本号,低16位是副版本号  
  DWORD dwFileVersionMS; // 该文件二进制版本号的高32bits  
  DWORD 
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值