使用#定义方便控制版本号的宏

简介:

一个 VC Project 中,可能有很多地方需要用到版本号,比如 About 对话框、版本资源等。如果每次版本更改都一一去改变这些值,不但非常麻烦,而且有悖唯一原则。

巧妙地使用宏定义,可以很好地解决这个问题。

先来看看几个预处理操作符 (Preprocessor Operators):

Operator Action
Stringizing operator (#) Causes the corresponding actual argument to be enclosed in double quotation marks
Charizing operator (#@) Causes the corresponding argument to be enclosed in single quotation marks and to be treated as a character (Microsoft Specific)
Token-pasting operator (##) Allows tokens used as actual arguments to be concatenated to form other tokens

简单说,# 就是使参数用引号包住,形成字符串;#@ 使参数用单引号包住,形成一个字符;## 是粘结符。这几个操作符从语言上来说比较晦涩,仔细看看 MSDN 的例子,好好理解一下。

下面举例说一下怎么定义统一的版本宏。

假设工程中有资源脚本文件 Resource.rc,唯一的版本号码存放在 Define.h 里。其它需要用到版本号的 CPP 文件均包含此文件。

先看看 Define.h:

#define VER_Major    2
#define VER_Minor 2
#define VER_Release 137
#define VER_Build 1762
#define VER_Version MAKELONG(MAKEWORD(VER_Major, VER_Minor), VER_Release)

#define _Stringizing(v) #v
#define _VerJoin(a, b, c, d) _Stringizing(a.b.c.d)

#define STR_BuildDate TEXT(__DATE__)
#define STR_BuildTime TEXT(__TIME__)
#define STR_BuilDateTime TEXT(__DATE__) TEXT(" ") TEXT(__TIME__)
#define STR_Version TEXT(_VerJoin(VER_Major, VER_Minor, VER_Release, VER_Build))

假设有了上面的定义后,就可以方便地使用 VER_Major、VER_Minor、VER_Release、VER_Build 作为版本号数字;STR_Version 作为版本字符串 (上面的例子中 STR_Version 执行宏展开后是 TEXT("2.2.137.1763") 的 TCHAR 字符串)。任何 CPP 文件中可以直接使用这些宏定义。

资源脚本 Resource.rc 中,假设我们需要版本资源,可以首先在 Define.h 中再定义一些宏,比如:

#define STR_AppName    TEXT("CuteFoto")
#define STR_Author TEXT("Yonsm")
#define STR_Corporation TEXT("Yonsm.NET")
#define STR_Web TEXT("Yonsm.reg365.com")
#define STR_Email TEXT("Yonsm@163.com")
#define STR_WebUrl TEXT("http://") STR_Web
#define STR_EmailUrl TEXT("mailto:") STR_Email TEXT("?Subject=") STR_AppName


#ifdef _CHS
#define STR_Description TEXT("灵巧的批量扫描照片切割工具。")
#define STR_Copyright TEXT("版权所有 (C) 2002-2004 ") STR_Corporation TEXT(",保留所有权利。")
#else // _CHS
#define STR_Description TEXT("Picture cutting tool for batch-scanned photo.")
#define STR_Copyright TEXT("Copyright (C) 2002-2004 ") STR_Corporation TEXT(". All rights reserved.")
#endif // _CHS

这时,我们在 Resouurc.rc 中添加版本资源——注意,不要直接添加,否则会被 VS 更改成实际的值,这样就不能达到我们的目的了。一个好的解决方法是:

  1. 在 VS IDE 中双击 Resource.rc 转到 资源视图 中,右击 Resource.rc,选择“资源包括”,在“只读符号指令”中包含 Define.h:
    #define APSTUDIO_HIDDEN_SYMBOLS
    //……
    #include "Define.h"
    #include "Windows.h"
    //……
    #undef APSTUDIO_HIDDEN_SYMBOLS
  2. 在“编译时指令”中输入:
    LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
    #pragma code_page(DEFAULT)

    VS_VERSION_INFO VERSIONINFO
    FILEVERSION VER_Major, VER_Minor, VER_Release, VER_Build
    PRODUCTVERSION VER_Major, VER_Minor, VER_Release, VER_Build
    FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
    FILEFLAGS 0
    FILEOS VOS__WINDOWS32
    FILETYPE 0
    FILESUBTYPE VFT2_UNKNOWN
    BEGIN
    BLOCK "StringFileInfo"
    BEGIN
    BLOCK "040004e4"
    BEGIN
    VALUE "FileVersion", STR_Version
    VALUE "FileDescription", STR_Description
    VALUE "ProductName", STR_AppName
    VALUE "ProductVersion", STR_Version
    VALUE "CompanyName", STR_Corporation
    VALUE "LegalCopyright", STR_Copyright
    VALUE "Comments", "Powered by " STR_Author "."
    VALUE "OriginalFilename", STR_AppName EXT_Exe
    END
    END
    BLOCK "VarFileInfo"
    BEGIN
    VALUE "Translation", 0x0400, 0x04e4
    END
    END

OK,以后要更改版本号或程序信息,只要修改 Define.h 即可了。

继续……

Define.h 中假设 VER_Release/VER_Build 分别指 Release 号和 Build 号,如果让这两个值分别表示我们用 Release 方式编译的次数和总编译次数,多好:)为此我写了个小工具 BPP (Build++ 的意思):

首先把 BPP.exe 放在工程目录下,然后在 VC Project 属性中,Debug 方式:在“生成事件”->“预生成事件”->“命令行”中输入“BPP Define.h”,Release 方式:“BPP -Release Define.h”。这样,每次 VC 编译都会调用 BPP.exe 使 VER_Build 或 VER_Reelase 自增一。好酷酷吧……

目录
相关文章
|
8月前
|
编译器 C# 开发者
C# 10.0中的全局`using`指令:简化命名空间引用的新方式
【1月更文挑战第4天】本文介绍了C# 10.0中引入的全局`using`指令,该指令允许开发者在项目级别统一管理命名空间引用,从而消除源文件中重复的`using`语句。全局`using`指令通过减少冗余代码、提高可维护性和统一命名空间管理,为开发者带来了更高效的编码体验。文章详细解释了如何实现全局`using`指令,并探讨了其在实际项目中的优势和适用场景。
|
7月前
|
缓存 监控 程序员
Python中的装饰器是一种特殊类型的声明,它允许程序员在不修改原有函数或类代码的基础上,通过在函数定义前添加额外的逻辑来增强或修改其行为。
【6月更文挑战第30天】Python装饰器是无侵入性地增强函数行为的工具,它们是接收函数并返回新函数的可调用对象。通过`@decorator`语法,可以在不修改原函数代码的情况下,添加如日志、性能监控等功能。装饰器促进代码复用、模块化,并保持源代码整洁。例如,`timer_decorator`能测量函数运行时间,展示其灵活性。
53 0
|
8月前
|
API C# Windows
LabVIEW​​共享​变量生命周期
LabVIEW​​共享​变量生命周期
54 1
|
8月前
|
Java API 数据库
后台组件-常量定义
平台里有很多可配置的参数
|
8月前
|
存储 API
功能定义
功能定义.
243 1
功能定义
|
运维 Shell Linux
【运维知识高级篇】超详细的Shell编程讲解1(Shell作用+脚本书写方式+脚本执行方式+变量分类+变量配置文件+变量定义+Shell重要的位置变量+三种传参方式)
【运维知识高级篇】超详细的Shell编程讲解1(Shell作用+脚本书写方式+脚本执行方式+变量分类+变量配置文件+变量定义+Shell重要的位置变量+三种传参方式)
368 1
|
移动开发 小程序 JavaScript
uniapp进行条件编译的两种方法?小程序端和H5的代表值是什么
在 UniApp 中,可以使用条件编译来根据不同的平台(小程序、H5 等)进行不同的代码处理。有两种主要的方法来实现条件编译:使用 mp 属性和条件注释。
|
缓存 运维 监控
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
425 0
|
JavaScript 前端开发
vvue基础指令和基础属性
vue基础指令和基础属性
|
C++ Windows
[✔️]VS中查看设置项目宏Marcos
[✔️]VS中查看设置项目宏Marcos
98 0