如何为已存在的.exe、.dll文件设置版本信息?

138
作为我们构建过程的一部分,我需要为所有已编译的二进制文件设置版本信息。其中一些二进制文件已经具有版本信息(在编译时添加),而另一些则没有。
我希望能够应用以下信息:
- 公司名称 - 版权声明 - 产品名称 - 产品描述 - 文件版本 - 产品版本
所有这些属性都由构建脚本指定,并且必须在编译后应用。这些是使用C++ Builder 2007编译的标准二进制文件(而不是程序集)。
我该怎么做?

ResourceHacker有什么用途?任务如何设置?如果任务是更新现有PE文件的版本,那么在什么问题下使用UpdateResource函数? - RbMm
试试这个:https://alternativeto.net/software/xn-resource-editor/,我认为有反向工程工具可以做到这一点。 - I_Al-thamary
15个回答

82
虽然不是批处理过程,但是 Visual Studio 也可以添加/编辑文件资源。只需使用“文件”->“打开”->“文件”选项打开.EXE 或 .DLL 文件即可。这非常方便,在构建后修复版本信息或将其添加到没有这些资源的文件中。

13
我尝试过这个方法,效果非常好。对于一个完全缺少版本信息的文件:在 Visual Studio 中打开 DLL 文件,选择“编辑”>“添加资源”>“版本”,并单击“新建”。接着,在新的“版本”选项卡中,修改“文件版本”、“产品版本”、“公司名称”等信息即可。保存文件后就完成了! - twasbrillig
2
@UweBaemayr。你引用的答案是我想问的同样问题,我们能否像我手动执行的那样自动化它呢?但是怎么做呢? - SteveScm
2
对于我的旧Delphi win32 dll,这并不起作用。尽管dll信息已正确更改,但在运行完整性检查时,您会意识到它已损坏。 - sthiers
4
在Windows 8和VS 2015上尝试了这个(添加版本信息),在Windows Explorer中一切都很好,但是可执行文件不再能够启动了。 - Liviu
1
使用Visual Studio可以在Visual Studio 2015上工作,但无法在2019上工作。 - Alenros
显示剩余4条评论

46
与许多其他答案不同,此解决方案使用完全免费的软件。
首先,创建一个名为 Resources.rc 的文件,像这样:
VS_VERSION_INFO VERSIONINFO
    FILEVERSION    1,0,0,0
    PRODUCTVERSION 1,0,0,0
{
    BLOCK "StringFileInfo"
    {
        BLOCK "040904b0"
        {
            VALUE "CompanyName",        "ACME Inc.\0"
            VALUE "FileDescription",    "MyProg\0"
            VALUE "FileVersion",        "1.0.0.0\0"
            VALUE "LegalCopyright",     "© 2013 ACME Inc. All Rights Reserved\0"
            VALUE "OriginalFilename",   "MyProg.exe\0"
            VALUE "ProductName",        "My Program\0"
            VALUE "ProductVersion",     "1.0.0.0\0"
        }
    }
    BLOCK "VarFileInfo"
    {
        VALUE "Translation", 0x409, 1200
    }
}

接下来,使用 GoRC 进行编译,生成一个 .res 文件,命令如下:
GoRC /fo Resources.res Resources.rc

(请参见下面我的GoRC.exe镜像评论)

然后使用Resource Hacker的CLI模式将其添加到现有的.exe中:

ResHacker -add MyProg.exe, MyProg.exe, Resources.res,,,

就是这样!


2
@CharlesB 我也注意到了,但链接是正确的。看起来有人忘记支付他们的网站托管费了! 这是二进制文件,我已将其镜像到我的公共Assembla帐户:https://www.assembla.com/code/danny-beckett/subversion/nodes/13/GoRC.exe - Danny Beckett
4
你也可以使用 Microsoft 资源编译器 来替代 GoRC。它可以在 Windows SDK 中获取。 - Holistic Developer
Resource Hacker 真是太棒了,我根据这个答案使用它,它非常出色,是一个伟大的程序。(与程序或制造商无关;-)) - user2109254
@UweKeim 我已经有一段时间没有使用过这个,但我非常确定它们是必需的。 - Danny Beckett
12
命令行似乎有一点变化:ResourceHacker.exe -open Source.dll -save Changed.dll -action addoverwrite -resource Version.res 另外,ResourceHacker可以自己编译.rc文件:ResourceHacker.exe -open Version.rc -save Version.res -action compile - Yusuf Tarık Günaydın

24

您也可以查看免费软件StampVer,它适用于Win32 exe/dll文件。
但是,只有当文件已经存在版本资源时,它才会更改文件和产品版本。如果没有版本资源,则无法添加版本资源。


22

rcedit 是相对较新的工具,很好地支持命令行:https://github.com/atom/rcedit

$ rcedit "path-to-exe-or-dll" --set-version-string "Comments" "This is an exe"
$ rcedit "path-to-exe-or-dll" --set-file-version "10.7"
$ rcedit "path-to-exe-or-dll" --set-product-version "10.7"

如果您正在使用Grunt,还有一个Grunt任务,而且还有一个NPM模块用JavaScript进行封装。


6
请注意,rcedit只能修改现有的资源,而不能插入新的资源。 - Bevan Collins
3
不能与7zip sfx压缩文件一起使用:/ 只是删掉了7zip压缩部分。 - Mgamerz
1
尝试过了,但在相同目录下仍然无法加载文件,似乎该工具可能依赖于主机配置。 - Arijoon
可以使用7zS.sfx驱动程序,其中第一部分包含了VERSIONINFO,可用于拼接自解压缩存档。虽然也可以手动将7zS.sfx重命名为7zS.exe并在Visual Studio中进行编辑,但由于每次构建版本号都会更改,因此最好使用批处理文件,并在其中使用rcedit语句进行设置。 - AndresRohrAtlasInformatik
3
在将此工具应用于您的二进制文件之前,请查看此错误:https://github.com/electron/rcedit/issues/51。此工具非常恶劣。 - Brun
1
损坏了我的二进制文件。 - Vasantha Ganesh

16

有许多工具被提到,由许多优秀的答案提供,我将选择其中一个。

Resource Hacker

我从[AngusJ]: Resource Hacker下载了最新版本(5.1.7)。所有所需信息都可以在该页面上找到(命令行选项、脚本等)。在接下来的演示中,我将操作两个可执行文件(实验鼠),它们(出于明显的原因)已复制到我的cwd中:

  • ResourceHacker.exe:我认为在其自身上操作会很有趣
  • cmake.exe:随机可执行文件,没有设置Version Info(安装在我的计算机上的v3.6.3的一部分)

在继续之前,我想提到ResourceHacker有一个有趣的终端输出,以下复制/粘贴片段可能会产生一些混乱。

1. 设置

这更像是一个初步步骤,以熟悉环境,展示没有奇怪的事情发生,...

e:\Work\Dev\StackOverflow\q000284258> sopr.bat
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> dir
 Volume in drive E is Work
 Volume Serial Number is 3655-6FED

 Directory of e:\Work\Dev\StackOverflow\q000284258

2019-01-28  20:09    <DIR>          .
2019-01-28  20:09    <DIR>          ..
2016-11-03  09:17         5,413,376 cmake.exe
2019-01-03  02:06         5,479,424 ResourceHacker.exe
2019-01-28  20:30               496 ResourceHacker.ini
               3 File(s)     10,893,296 bytes
               2 Dir(s)  103,723,261,952 bytes free

[prompt]> set PATH=%PATH%;c:\Install\x64\CMake\CMake\3.6.3\bin

[prompt]> .\cmake --help >nul 2>&1

[prompt]> echo %errorlevel%
0

[prompt]> .\ResourceHacker.exe -help

[prompt]>

==================================
Resource Hacker Command Line Help:
==================================

-help             : displays these abbreviated help instructions.
-help commandline : displays help for single commandline instructions
-help script      : displays help for script file instructions.




[prompt]> echo %errorlevel%
0

如您所见,可执行文件是正常的,它们可以很好地运行,以下是我们关心的它们的详细信息:

Img0-Initial

2. 资源

资源文件是包含资源的文本文件。一个资源(简化)包括:

  • 名称
  • 类型

更多详细信息请查看[MS.Docs]: 关于资源文件。有许多工具(在现有答案中提到)可以方便地编辑资源文件,例如:

  • VStudio 在启动新项目时创建默认文件
  • 可以手动创建此类文件
  • 但是,由于涉及到Resource Hacker,并且:

    • 它能够从现有可执行文件中提取资源
    • 它内嵌了资源(如上图所示)

    我将在此步骤中使用它(-action extract

接下来,为了将资源嵌入到一个.exe (.dll, ...)文件中,它必须被编译成二进制形式,并适合于PE格式。同样,有很多工具可以实现这一点,但你可能已经猜到了,我要坚持使用Resource Hacker (-action compile)。
[prompt]> :: Extract the resources into a file
[prompt]> .\ResourceHacker.exe -open .\ResourceHacker.exe -save .\sample.rc -action extract -mask VersionInfo,, -log con

[prompt]>

[28 Jan 2019, 20:58:03]

Current Directory:
e:\Work\Dev\StackOverflow\q000284258

Commandline:
.\ResourceHacker.exe  -open .\ResourceHacker.exe -save .\sample.rc -action extract -mask VersionInfo,, -log con

Open    : e:\Work\Dev\StackOverflow\q000284258\ResourceHacker.exe
Save    : e:\Work\Dev\StackOverflow\q000284258\sample.rc


Success!

[prompt]> :: Modify the resource file and set our own values
[prompt]>
[prompt]> :: Compile the resource file
[prompt]> .\ResourceHacker.exe -open .\sample.rc -save .\sample.res -action compile -log con

[prompt]>

[28 Jan 2019, 20:59:51]

Current Directory:
e:\Work\Dev\StackOverflow\q000284258

Commandline:
.\ResourceHacker.exe  -open .\sample.rc -save .\sample.res -action compile -log con

Open    : e:\Work\Dev\StackOverflow\q000284258\sample.rc
Save    : e:\Work\Dev\StackOverflow\q000284258\sample.res

Compiling: e:\Work\Dev\StackOverflow\q000284258\sample.rc
Success!

[prompt]> dir /b
cmake.exe
ResourceHacker.exe
ResourceHacker.ini
sample.rc
sample.res
在你的情况下保存和编辑资源文件并不是必要的,因为该文件已经存在,我只是为了演示目的而这样做。以下是修改后(编译之前)的资源文件。

sample.rc:

1 VERSIONINFO
FILEVERSION 3,1,4,1592
PRODUCTVERSION 2,7,1,8
FILEOS 0x4
FILETYPE 0x1
{
BLOCK "StringFileInfo"
{
    BLOCK "040904E4"
    {
        VALUE "CompanyName", "Cristi Fati\0"
        VALUE "FileDescription", "20190128 - SO q000284258 demo\0"
        VALUE "FileVersion", "3.1.4.1592\0"
        VALUE "ProductName", "Colonel Panic\0"
        VALUE "InternalName", "100\0"
        VALUE "LegalCopyright", "(c) Cristi Fati 1999-2999\0"
        VALUE "OriginalFilename", "ResHack\0"
        VALUE "ProductVersion", "2.7.1.8\0"
    }
}

BLOCK "VarFileInfo"
{
    VALUE "Translation", 0x0409 0x04E4  
}
}

3. 嵌入

这也可以通过 Resource Hacker (-action addoverwrite) 来完成。由于 .exe 文件已经被复制,我将直接在原地编辑它们的资源。

[prompt]> .\ResourceHacker.exe -open .\cmake.exe -save .\cmake.exe -res .\sample.res -action addoverwrite -mask VersionInfo,, -log con

[prompt]>

[28 Jan 2019, 21:17:19]

Current Directory:
e:\Work\Dev\StackOverflow\q000284258

Commandline:
.\ResourceHacker.exe  -open .\cmake.exe -save .\cmake.exe -res .\sample.res -action addoverwrite -mask VersionInfo,, -log con

Open    : e:\Work\Dev\StackOverflow\q000284258\cmake.exe
Save    : e:\Work\Dev\StackOverflow\q000284258\cmake.exe
Resource: e:\Work\Dev\StackOverflow\q000284258\sample.res

  Added: VERSIONINFO,1,1033

Success!

[prompt]> copy ResourceHacker.exe ResourceHackerTemp.exe
        1 file(s) copied.

[prompt]> .\ResourceHackerTemp.exe -open .\ResourceHacker.exe -save .\ResourceHacker.exe -res .\sample.res -action addoverwrite -mask VersionInfo,, -log con

[prompt]>

[28 Jan 2019, 21:19:29]

Current Directory:
e:\Work\Dev\StackOverflow\q000284258

Commandline:
.\ResourceHackerTemp.exe  -open .\ResourceHacker.exe -save .\ResourceHacker.exe -res .\sample.res -action addoverwrite -mask VersionInfo,, -log con

Open    : e:\Work\Dev\StackOverflow\q000284258\ResourceHacker.exe
Save    : e:\Work\Dev\StackOverflow\q000284258\ResourceHacker.exe
Resource: e:\Work\Dev\StackOverflow\q000284258\sample.res

  Modified: VERSIONINFO,1,1033

Success!

[prompt]> del /f /q ResourceHackerTemp.*

[prompt]> dir
 Volume in drive E is Work
 Volume Serial Number is 3655-6FED

 Directory of e:\Work\Dev\StackOverflow\q000284258

2019-01-28  21:20    <DIR>          .
2019-01-28  21:20    <DIR>          ..
2016-11-03  09:17         5,414,400 cmake.exe
2019-01-03  02:06         5,479,424 ResourceHacker.exe
2019-01-28  21:17               551 ResourceHacker.ini
2019-01-28  20:05             1,156 sample.rc
2019-01-28  20:59               792 sample.res
               5 File(s)     10,896,323 bytes
               2 Dir(s)  103,723,253,760 bytes free

如您所见,我必须使用一些技巧(gainarie),因为我不能(至少我认为我不能)在使用时修改.exe

4. 测试

这是一个可选的阶段,以确保:

  • 可执行文件仍然可以工作(它们在过程中没有被搞砸)
  • 资源已经被添加/更新
[prompt]> .\cmake --help >nul 2>&1

[prompt]> echo %errorlevel%
0

[prompt]> .\ResourceHacker.exe -help

[prompt]>

==================================
Resource Hacker Command Line Help:
==================================

-help             : displays these abbreviated help instructions.
-help commandline : displays help for single commandline instructions
-help script      : displays help for script file instructions.




[prompt]> echo %errorlevel%
0

以及他们的详细信息

Img1-Final


非常好的回答。不幸的是,ResourceHacker已不再维护,并且在尝试编辑大型EXE文件时会耗尽内存(我在尝试打开3GB的exe时收到了错误)。 - Lews Therin
@LewsTherin:最新版本(回答中也使用了该版本)是2019/01发布的,因此我认为它已经得到了很好的维护。问题在于它是32位的。您可以联系作者请求一个64位版本(我认为既然他们已经有了代码,构建一个64位版本不会很难)。 - CristiFati
@LewsTherin 只是出于好奇,你是怎么得到一个3GB的可执行文件的?是一款所有资源都嵌入为资源(加载速度较慢)的游戏吗? - Lothar
@Lothar 当时我正在本地化一个自定义的C++应用程序的EXE。 - Lews Therin

15

这个问题的解决方案可以是这样吗?

verpatch /va foodll.dll %VERSION% %FILEDESCR% %COMPINFO% %PRODINFO% %BUILDINFO%

完整源代码可以在这里获取


Verpatch似乎为我创建了一个错误的产品版本资源(使用/va /pv选项)。该版本在Windows资源管理器中显示正确,但是在使用VerQueryValue检索时,最后一个字符丢失了。为了修复错误的资源,我做了以下操作:(1)在Resource Hacker中加载DLL。(2)查看版本资源。(3)编译(修改一些内容然后将其改回以启用按钮)。 (4)保存。 - dan-gph
verpatch在我的开发环境中对DLL的x64和x86版本都运行得很好,但在apveyor构建项目中,它仅适用于x64,对x86 dll没有任何作用--也没有错误!有什么提示可能发生了什么? 我可以在appveyor日志中看到verpatch命令正在执行,没有错误,但某种方式未能替换dll,并且最终未能带有版本戳;对于x64,在所有情况下都正常工作。 请有线索的人? - ovi
@Ovi-Wan Kenobi:我不知道apveyor是什么,但根据你的描述,它看起来更像是一个apveyor的问题。最坏的情况是,如果可能的话,准备在apveyor环境中进行一些调试?... - filofel

12

我没有使用任何额外的工具。我只是将以下文件添加到我的Win32应用程序项目中。

一个头文件,定义了一些常量,我们可以在资源文件和程序代码中重复使用它们。我们只需要维护一个文件。 感谢Qt团队向我展示了如何在Qt项目上实现它,现在它也适用于我的Win32应用程序。

----[version.h]----

#ifndef VERSION_H
#define VERSION_H

#define VER_FILEVERSION             0,3,0,0
#define VER_FILEVERSION_STR         "0.3.0.0\0"

#define VER_PRODUCTVERSION          0,3,0,0
#define VER_PRODUCTVERSION_STR      "0.3.0.0\0"

#define VER_COMPANYNAME_STR         "IPanera"
#define VER_FILEDESCRIPTION_STR     "Localiza archivos duplicados"
#define VER_INTERNALNAME_STR        "MyProject"
#define VER_LEGALCOPYRIGHT_STR      "Copyright 2016 ipanera@gmail.com"
#define VER_LEGALTRADEMARKS1_STR    "All Rights Reserved"
#define VER_LEGALTRADEMARKS2_STR    VER_LEGALTRADEMARKS1_STR
#define VER_ORIGINALFILENAME_STR    "MyProject.exe"
#define VER_PRODUCTNAME_STR         "My project"

#define VER_COMPANYDOMAIN_STR       "www.myurl.com"

#endif // VERSION_H

----[MyProjectVersion.rc]----

#include <windows.h>
#include "version.h"

VS_VERSION_INFO VERSIONINFO
FILEVERSION     VER_FILEVERSION
PRODUCTVERSION  VER_PRODUCTVERSION
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904E4"
        BEGIN
            VALUE "CompanyName",        VER_COMPANYNAME_STR
            VALUE "FileDescription",    VER_FILEDESCRIPTION_STR
            VALUE "FileVersion",        VER_FILEVERSION_STR
            VALUE "InternalName",       VER_INTERNALNAME_STR
            VALUE "LegalCopyright",     VER_LEGALCOPYRIGHT_STR
            VALUE "LegalTrademarks1",   VER_LEGALTRADEMARKS1_STR
            VALUE "LegalTrademarks2",   VER_LEGALTRADEMARKS2_STR
            VALUE "OriginalFilename",   VER_ORIGINALFILENAME_STR
            VALUE "ProductName",        VER_PRODUCTNAME_STR
            VALUE "ProductVersion",     VER_PRODUCTVERSION_STR
        END
    END

    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1252
    END
END

2
只是好奇,你是如何防止Windows在每次更改对话框或修改项目中的任何资源时覆盖你的.rc文件的?我已经看到了一些类似这样的文章,如果你再也不需要更改会导致IDE自动生成的资源,那么它似乎可以起作用。 - shawn1874
@shawn1874 -- 在自动添加的 resource.h 文件中包含 #include <windows.h> 行。该文件不会重新生成(请注意,在 .rc 文件顶部指示它是生成的代码,并且可以在设计师中进行修改)。 - CJBS
1
@CJBS 这并没有回答问题。虽然这可能有效,但它并没有解释发布的答案如何工作。在发布的答案中,user3016543直接在.rc文件中包含version.h。有几种处理.rc文件覆盖的方法,我知道如何做。我只是质疑这个特定答案的显示方式,因为它对我来说看起来不正确。 - shawn1874
我猜那个方法对他有效,因为涉及的组件没有对话框组件,所以文件不会经常或从未被重新生成。然而,在一个带有MFC对话框资源的Windows应用程序中,情况就不同了。 - shawn1874
1
谢谢你提醒我这个技巧,我第一次看到它是在WinBatch Extender SDK附带的资源文件中。已经很久没有用到它了,以至于我忘记了大部分细节。你的解释让我想起了所有的内容。 - David A. Gray

11
有一个名为ChangeVersion的工具[1],它是一款命令行界面的软件,支持.EXE、.DLL和.RES文件。 它可以根据版本掩码更新文件版本和产品版本,添加/更改/删除版本键字符串,并调整文件标志(调试、特殊、私有等)。 此外,它还可以更新项目文件(.bdsproj | .bpr | .bpk | .dproj),添加/更改主应用程序图标并使用配置的ini文件。 该工具支持Windows Vista操作系统,易于集成到持续构建环境中。
完全披露:我认识写这个工具的人,曾经与他一起工作。但这也意味着我知道他制作高质量的软件 ;)

[1]链接失效了,似乎在download.cnet.com上有备份版本。


@Gareth 我添加了一个镜像链接。另一方面,我怀疑这个答案没有任何工作参考价值。 - Wolf
5
第二个链接显示的工具已过期,提示信息为:“更改版本 v2012.9.6.0 - (C)2007-2012 The-Software-Box.com。此试用版已过期”。 - Preet Sangha
2
在命令行中运行它时,它会显示 "Change Version v2012.9.6.0 - (C)2007-2012 The-Software-Box.com 该试用版本已过期"。 - NoName

9

verpatch很好用,但是不能处理Unicode字符...
试试ResourceLib


6

上面@DannyBeckett的回答对我帮助很大,

我把以下内容放入批处理文件中,并将其放置在ResourceHacker.exe和我要操作的EXE所在的相同文件夹中,它的效果非常好。 [您可以根据自己的需要进行编辑]

    @echo off
    :start1
    set /p newVersion=Enter version number [?.?.?.?]:
    if "%newVersion%" == "" goto start1
    :start2
    set /p file=Enter EXE name [for 'program.exe' enter 'program']:
    if "%file%" == "" goto start2
    for /f "tokens=1-4 delims=." %%a in ('echo %newVersion%') do (set ResVersion=%%a,%%b,%%c,%%d)
    (
    echo:VS_VERSION_INFO VERSIONINFO
    echo:    FILEVERSION    %ResVersion%
    echo:    PRODUCTVERSION %ResVersion%
    echo:{
    echo:    BLOCK "StringFileInfo"
    echo:    {
    echo:        BLOCK "040904b0"
    echo:        {
    echo:            VALUE "CompanyName",        "MyCompany\0"
    echo:            VALUE "FileDescription",    "TestFile\0"
    echo:            VALUE "FileVersion",        "%newVersion%\0"
    echo:            VALUE "LegalCopyright",     "COPYRIGHT © 2019 MyCompany\0"
    echo:            VALUE "OriginalFilename",   "%file%.exe\0"
    echo:            VALUE "ProductName",        "Test\0"
    echo:            VALUE "ProductVersion",     "%newVersion%\0"
    echo:        }
    echo:    }
    echo:    BLOCK "VarFileInfo"
    echo:    {
    echo:        VALUE "Translation", 0x409, 1200
    echo:    }
    echo:}
    ) >Resources.rc     &&      echo setting Resources.rc
    ResourceHacker.exe -open resources.rc -save resources.res -action compile -log CONSOLE
    ResourceHacker -open "%file%.exe" -save "%file%Res.exe" -action addoverwrite -resource "resources.res"  -log CONSOLE
    ResourceHacker.exe -open "%file%Res.exe" -save "%file%Ico.exe" -action addskip -res "%file%.ico" -mask ICONGROUP,MAINICON, -log CONSOLE
    xCopy /y /f "%file%Ico.exe" "%file%.exe"
    echo.
    echo.
    echo your compiled file %file%.exe is ready
    pause

[顺便提一下,我也使用了资源编辑器来编译res文件,而不是GoRC]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接