browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

版本号的战争

Posted by on 2011 年 03 月 04 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

先上张图,我曾为此图纠结了很久很久。

简单说来,我一直在寻找一种能够很方便地管理应用程序版本号的办法,使得应用程序窗口标题、关于对话框及其 exe 版本信息中能够显示同一个版本号。

当然,使窗口标题和关于对话框的字符串统一是很简单的,只需要一个宏就可以解决这个问题:

1
2
#define MANGACON_VERSTR         "1.3.4.170"
#define MANGACON_WNDCAPTION     _T("漫画控 v")_T(MANGACON_VERSTR)

然后,在不同的场合使用 MANGACON_WNDCAPTION 即可。

但 exe 的版本信息却不是能够这么玩的。比如,我手动修改 .rc 文件,包含含有 MANGACON_VERSTR 的头文件,并对版本信息资源做出如下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "Version.h"
 
VS_VERSION_INFO VERSIONINFO
 FILEVERSION MANGACON_RCVER
 PRODUCTVERSION MANGACON_RCVER
 FILEFLAGSMASK 0x17L
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x4L
 FILETYPE 0x1L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "080404b0"
        BEGIN
            VALUE "CompanyName", "Titi Stuio"
            VALUE "FileDescription", "漫画控"
            VALUE "FileVersion", MANGACON_RCVERSTR
            VALUE "InternalName", "MangaCon"
            VALUE "LegalCopyright", "Copyright (C) 2010"
            VALUE "OriginalFilename", "MangaCon.exe"
            VALUE "ProductName", "漫画控"
            VALUE "ProductVersion", MANGACON_RCVERSTR
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x804, 1200
    END
END

虽然编译是没有问题的,但是聪明过头的 Visual Studio 却总会热情地帮我们把这里边的宏全部展开。而且无可救药的是,我无法控制 Visual Studio 的这一行为。于是,我曾一度在工程的 Pre Build 事件中使用正则表达式工具或 Lua 脚本以重新写入我的版本号,以保证其一致性。

后来,我从 AutoBuild 插件中得到灵感,将版本信息资源放到一个单独的 version.rc2 文件中,以避免 IDE 对它的修改。并且,在 .rc 的 TEXTINCLUDE 节中加入对此 .rc2 的包含:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
 
1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END
 
2 TEXTINCLUDE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END
 
3 TEXTINCLUDE 
BEGIN
    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n"
    "#ifdef _WIN32\r\n"
    "LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED\r\n"
    "#pragma code_page(936)\r\n"
    "#endif //_WIN32\r\n"
    "#include ""res\\version.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
    "#endif\r\n"
    "\0"
END

之后,再把 3 TEXTINCLUDE 的一段展开在它应该被展开的位置上:

1
2
3
4
5
6
7
8
9
10
11
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#endif //_WIN32
#include "res\version.rc2"  // non-Microsoft Visual C++ edited resources
#endif

至此,这个比较令我满意的版本号管理方式就已经完成了。如果你觉得上述代码的片段不足以理解这个技巧,那么可以点这里下载完整的示例工程来进行参考。

订阅本站

2 Comments

  • At 2011.03.05 17:14, z said:

    保护一个手动编辑过的rc文件最好的办法就是不用可视化编辑器去保存。
    有个更简单的办法是将版本信息直接编译成res,然后连接。

    • At 2011.03.05 20:22, 李马 said:

      1. 在绝大多数情况下,我仍要借助与 IDE 提供的资源编辑器来设计 UI。
      2. 如果需要修改版本号,那么需要再编译一次 res,这便是另外的一步手续,容易遗忘。

      (Required)
      (Required, will not be published)