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

一个 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(" 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 自增一。好酷酷吧……

时间: 2025-01-21 03:54:29

使用#定义方便控制版本号的宏的相关文章

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

一个 VC Project 中,可能有很多地方需要用到版本号,比如 About 对话框.版本资源等.如果每次版本更改都一一去改变这些值,不但非常麻烦,而且有悖唯一原则.       巧妙地使用宏定义,可以很好地解决这个问题.       先来看看几个预处理操作符 (Preprocessor Operators): Operator Action Stringizing operator (#) Causes the corresponding actual argument to be encl

Kernel 中的 GPIO 定义和控制

最近要深一步用到GPIO口控制,写个博客记录下Kernel层的GPIO学习过程!   一.概念      General Purpose Input Output (通用输入/输出)简称为GPIO,或 总线扩展器.也就是芯片的引脚,当微控制器或芯片组没有足够的I/O端口,或当系统需要采用远端串行通信或控制时,GPIO产品能够提供额外的控制和监视功能.通常在ARM里,所有I/O都是通用的, 每个GPIO端口包含8个管脚,如PA端口是PA0-PA7,而且GPIO口至少有两个寄存器,即"通用IO控制寄

OC中的宏 和 C中的预编译宏定义

1.先来几个常用的: [csharp] view plain copy // 是否高清屏   #define isRetina ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 960), [[UIScreen mainScreen] currentMode].size) : NO)   // 是否模拟器   #define isSimulator (

Objective-C 宏定义详细介绍_IOS

喜欢读一些开源项目源码的人,总是会发现,大神的代码中总是有那么一些简短而高效的宏定义,点击进去一看,发现晦涩难懂,别说学习了,有时候理解都是一种困难,但是宏定义本身并没有那么难,但是写出一个好的宏当然还是需要丰富的经验和技术,接下来就说一说宏定义,看懂大神的宏是第一步,偶尔写一个也是装逼的好办法- 定义: 宏定义分为两种:一种是对象宏(object-like macro)另一种就是函数宏(function-like macro) 根据名字也可以理解到,对象宏就是用来定义一个量,通过这个宏可以拿到

【原创】Stringification 在二级宏定义中的使用

        最近在研究 Redis-2.6.12 的源码时,重新对一处宏展开的用法进行了梳理,记录如下:  在 zmalloc.h 中有如下定义,  ? 1 2 3 /* Double expansion needed for stringification of macro values. */ #define __xstr(s) __str(s) #define __str(s) #s        在注释中出现了一个专有名词" stringification ",经查阅,网络

C宏定义的小结

实现代码实例 程序代码: #include <stdio.h> #include <stdlib.h> #include <sys/types.h> /***** cplusplus *****/ #if 0 #include <iostream> using namespace std; #endif // 得到指定地址上的一个字节或字 #define MEM_B(x) (*((byte *)(x))) #define MEM_W(x) (*((word

C语言宏定义使用技巧

写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等.下面列举一些成熟软件中常用得宏定义-- 1,防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif 2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植. typedef unsigned char boolean: /* Boolean value type. */ typedef unsigned l

C:宏定义

使用宏时,用圆括号括住每个参数,并括住宏的整体定义:一般来说,在宏中不要使用自增或自减运算符. [1]最值 #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 求两者间的较小者 #define MAX(x, y) (((x) > (y)) ? (x) : (y)) 求两者间的较大者 #define MAX3(x,y,z) MAX(MAX(x,y),z) 求三者间的较大者 [2]移位 #define SHIFT(value, n) (((n) > 0)

VC预处理指令与宏定义

一个经典的例子 使用预处理与宏定义最经典的例子莫过于加在一个头文件中以避免头文件被两次编译.试想这种的情况,有一个文件headerfile.h 它被包含在headerfile1.h中,同时在headerfile2.h 中也被包含了,现在有一个CPP文件,implement.cpp 包含了headerfile1.h 和headerfile2.h: #include "headerfile1.h" #include "headerfile2.h" 假设headerfil