【delphi】修改exe文件版本信息程序(RT_VERSION)

对于已经编译生成好的exe文件,可否修改文件的版本信息呢?答案是肯定的,微软提供了修改exe文件版本信息的API。

一、查看文件版本信息

在exe文件的图标上鼠标右键菜单选择【属性】,然后选择【详细信息】

就可以看到exe文件的相关版权、版本信息。

二、版本信息包括的项目如下

Delphi 复制代码
TRT_VERSION = packed record
     FileVersion_High      : DWORD;     //文件版本 VS_FIXEDFILEINFO
     FileVersion_Low       : DWORD;     //文件版本 VS_FIXEDFILEINFO
     ProductVersion_High   : DWORD;     //产品版本 VS_FIXEDFILEINFO
     ProductVersion_Low    : DWORD;     //产品版本 VS_FIXEDFILEINFO

     LangID           : Word;       //0x0409
     CodePage         : Word;       //0x04E4

     CompanyName      : string;     //公司名称
     FileDescription  : string;
     FileVersion      : string;     //文件版本
     InternalName     : string;     //内部名称
     LegalCopyright   : string;
     LegalTrademarks  : string;
     OriginalFilename : string;
     ProgramID        : string;
     ProductName      : string;
     ProductVersion   : string;     //产品版本
     Comments         : string;     //注释

     SpecialBuild     : string;    //特殊版本,一般不使用
     PrivateBuild     : string;    //私有版本,一般不使用,为空

     Assembly_Version : string;     //DeepL中有用
  end;

三、使用到的函数对象

Delphi 复制代码
//操作exe文件版本信息的对象
TEXE_Version = class
  private

    // 辅助函数
    class procedure WriteWideStringWithNull(Stream: TStream; const S: string);
    class procedure WriteWord(Stream: TStream; W: Word);
    class procedure WriteDWord(Stream: TStream; D: DWORD);
    class procedure AlignStream4(Stream: TStream);


    // Build VS_FIXEDFILEINFO structure (binary, little-endian)
    class procedure WriteFixedFileInfo(Stream: TStream; rt_Version : TRT_VERSION;  FileFlagsMask, FileFlags, FileOS, FileType, FileSubtype: DWORD);

    // Build a StringTable child block: a sequence of key/value pairs
    class procedure WriteStringTable(Stream: TStream; rt_Version : TRT_VERSION);

    // Build VarFileInfo block with Translation (LANGID + CodePage)
    class procedure WriteVarFileInfo(Stream: TStream; LangID, CodePage: Word);

    // Build top-level VERSIONINFO block and return binary as TBytes
    class function BuildVersionInfoBinary(const rt_Version: TRT_VERSION): TBytes;

    // 将版本信息写入到exe文件中
    class function Update_ExeVersion(const ExeFileName : string; LangID : Word; versionBytes : TBytes) : Boolean;
  public
     { 辅助函数:将版本字符串转换为VS_FIXEDFILEINFO需要的DWORD对  文本:1.0.0.2  }
    class procedure VersionStrToDWords(const Version: string; out VerMS, VerLS: DWORD);
    class function DWordsToVersionStr(VerMS, VerLS: DWORD): string;


    //读取exe文件的版本信息  2025-11-05 测试 OK
    class function Read_exe_Version(exeFile : string; out rt_Version : TRT_VERSION; out errmsg : string) : Boolean;
    //写入exe文件的版本信息
    class function Write_exe_Version(exeFile : string; rt_Version : TRT_VERSION; out errmsg : string) : Boolean;

    //保存 RT_VERSION 二进制流为文件
    class function SaveRTVersionResource(const ExeFileName, OutputFileName: string): Boolean;
end;

1. 读取exe文件版本信息

使用函数:TEXE_Version.Read_exe_Version(ExeFileName,myRT_VERSION,errmsg)

Delphi 复制代码
class function TEXE_Version.Read_exe_Version(exeFile: string;
  out rt_Version: TRT_VERSION; out errmsg : string): Boolean;
var
  hFile: DWORD;
  dwSize: DWORD;
  pData: ^Byte;
  pValue: PChar;
  dwValueSize: DWORD;
  LangID: PByte;
  pFixInfo : PByte;
  LangCode: string;
begin
  Result := False;
  //初始化变量 rt_Version
  FillChar(rt_Version, SizeOf(TRT_VERSION), 0);

  //如果文件不存在
  if not FileExists(exeFile) then
    begin
      errmsg := 'exe文件不存在!';
      Exit;
    end;


  // 获取版本信息大小
  dwSize := GetFileVersionInfoSize(PChar(exeFile), hFile);
  if dwSize = 0 then
    begin
      errmsg := '当前exe文件版本内容为空错误或者格式不正确!';
      Exit;
    end;

  // 分配内存并读取版本信息
  GetMem(pData, dwSize);
  try
    if GetFileVersionInfo(PChar(exeFile), hFile, dwSize, pData) then
      begin
        // 获取 VS_FIXEDFILEINFO 中的版本信息
        if VerQueryValue(pData, '\', Pointer(pFixInfo), dwValueSize) then
          begin
            Move((pFixInfo +  8)^,rt_Version.FileVersion_High,4);
            Move((pFixInfo + 12)^,rt_Version.FileVersion_Low,4);
            Move((pFixInfo + 16)^,rt_Version.ProductVersion_High,4);
            Move((pFixInfo + 20)^,rt_Version.ProductVersion_Low,4);
          end
        else
          begin
            errmsg := '获取版本信息中VS_FIXEDFILEINFO出现错误!';
            Exit(False);
          end;
        // 获取语言ID
        if VerQueryValue(pData, '\VarFileInfo\Translation', Pointer(LangID), dwValueSize) then
          begin
            //获取语言代码等
            Move(LangID[0],rt_Version.LangID,2);
            Move(LangID[2],rt_Version.CodePage,2);
            // 构建语言代码页路径
            LangCode := Format('\StringFileInfo\%.2x%.2x%.2x%.2x\',
                              [LangID[1], LangID[0], LangID[3], LangID[2]]);
            // 获取版本信息字符串值
            if VerQueryValue(pData, PChar(LangCode + 'CompanyName'), Pointer(pValue), dwValueSize) then
              rt_Version.CompanyName := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'FileDescription'), Pointer(pValue), dwValueSize) then
              rt_Version.FileDescription := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'FileVersion'), Pointer(pValue), dwValueSize) then
              rt_Version.FileVersion := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'InternalName'), Pointer(pValue), dwValueSize) then
              rt_Version.InternalName := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'LegalCopyright'), Pointer(pValue), dwValueSize) then
              rt_Version.LegalCopyright := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'LegalTrademarks'), Pointer(pValue), dwValueSize) then
              rt_Version.LegalTrademarks := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'OriginalFilename'), Pointer(pValue), dwValueSize) then
              rt_Version.OriginalFilename := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'ProgramID'), Pointer(pValue), dwValueSize) then
              rt_Version.ProgramID := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'ProductName'), Pointer(pValue), dwValueSize) then
              rt_Version.ProductName := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'ProductVersion'), Pointer(pValue), dwValueSize) then
              rt_Version.ProductVersion := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'Comments'), Pointer(pValue), dwValueSize) then
              rt_Version.Comments := StrPas(pValue);

            if VerQueryValue(pData, PChar(LangCode + 'SpecialBuild'), Pointer(pValue), dwValueSize) then
              rt_Version.SpecialBuild := StrPas(pValue);
            if VerQueryValue(pData, PChar(LangCode + 'PrivateBuild'), Pointer(pValue), dwValueSize) then
              rt_Version.PrivateBuild := StrPas(pValue);

             if VerQueryValue(pData, PChar(LangCode + 'Assembly Version'), Pointer(pValue), dwValueSize) then
              rt_Version.Assembly_Version := StrPas(pValue);

            errmsg := '正确获取到版本信息!';
            Exit(True);
            //else
            //  RaiseLastOSError;
          end
        else
          begin
           errmsg := '获取版本信息中的语言标志出现错误!';
           Exit(False);
          end;
      end
    else
      begin
        errmsg := '获取版本信息出现错误!';
        Exit(False);
      end;
  finally
    FreeMem(pData);
  end;
end;

2. 写入exe文件版本信息

使用函数:TEXE_Version.Write_exe_Version(ExeFileName,myRT_VERSION,errmsg)

Delphi 复制代码
class function TEXE_Version.Write_exe_Version(exeFile: string;
  rt_Version: TRT_VERSION; out errmsg: string): Boolean;
var
  versionBytes : TBytes;
  dwSize       : DWORD;
  hFile        : THandle;
begin
  Result := False;
  //1. 检查文件有效性
  //如果文件不存在
  if not FileExists(exeFile) then
    begin
      errmsg := 'exe文件不存在!';
      Exit;
    end;


  // 获取版本信息大小
  dwSize := GetFileVersionInfoSize(PChar(exeFile), hFile);
  if dwSize = 0 then
    begin
      errmsg := '当前exe文件版本内容为空错误或者格式不正确!';
      Exit;
    end;

  //2. 构造 版本信息数据流
  versionBytes := BuildVersionInfoBinary(rt_Version);
  //3. 备份原来的文件
  CopyFile(PChar(exeFile),PChar(exeFile + '.bak'), False);
  //4. 将版本信息写入到 exefile 文件中
  Result := Update_ExeVersion(exeFile, rt_Version.LangID, versionBytes);
end;

四、工具及源程序下载

1. 可执行程序下载

2. 源代码下载(收费)