原文地址:http://blog.ehomy.net/archives/94
最近在在把一些程序从VC6迁移到VS2008,由此而关注到了Winodws版本的定义问题。
关于版本定义的关键无外乎为程序头文件中对于#define WINVER 和 #define _WIN32_WINNT 的使用,具体为:
#define WINVER 0xXXXX #define _WIN32_WINNT 0xXXXX
该定义一般用于标示程序对运行环境的要求,另外在某些头文件中也有这样的宏定义。如果版本匹配的话就会在编译的时候将这些内容编译,否则就不编译。
定义正确的Windows版本,不仅关系到程序的正确编译,同时也关系到程序的正确运行;在升级的过程中,我就碰到了程序编译正确但运行出错的问题。实例稍候再续。
版本的定义关系到被编译到程序中的内容,这里主要是指系统提供的功能代码。Windows各个版本的功能虽然大差不差,但特定于某个系统功能还是存在的,于是关系到这些功能的API代码也就有所不一样。当我们在程序中定义了错误的系统版本,被编译进程序的内容便可能包含当前系统不支持的代码片段,这样的程序即使可能正确编译通过,但在运行的时候,由于在当前系统中找不到相应的内容资源,从而发生错误。这一点熟悉动态链接库(DLL)的人都很清楚,其实该问题就是和系统动态链接库有关。
Example:
下面为一段获取系统信息提示框的字体信息的代码片段:(编译环境从VC6迁移至VS2008,运行系统为Windows XP)
// Retrieves the message font info NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(NONCLIENTMETRICS); VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)); // Creates the font according to the message font info m_Font.CreateFontIndirect(&(ncm.lfMessageFont));
程序在VC6下编译运行都正确,迁移至VS2008后,编译正确,但运行时出错。原因是SystemParametersInfo调用失败,这和其传入的参数有关,根本在于 NONCLIENTMETRICS 这个结构体变量的定义。
在新的 Windows SDK 6.0 中,其定义如下:
typedef struct tagNONCLIENTMETRICSA { UINT cbSize; int iBorderWidth; int iScrollWidth; int iScrollHeight; int iCaptionWidth; int iCaptionHeight; LOGFONTA lfCaptionFont; int iSmCaptionWidth; int iSmCaptionHeight; LOGFONTA lfSmCaptionFont; int iMenuWidth; int iMenuHeight; LOGFONTA lfMenuFont; LOGFONTA lfStatusFont; LOGFONTA lfMessageFont; #if(WINVER >= 0x0600) int iPaddedBorderWidth; #endif /* WINVER >= 0x0600 */ } #ifdef UNICODE #define NONCLIENTMETRICSW NONCLIENTMETRICS #else #define NONCLIENTMETRICSA NONCLIENTMETRICS #endif
注意最后一个成员的定义条件,其指明了,该成员只能应用于 WINVER >= 0×0600 的系统环境(这里指明了系统为Vista)。
考虑到我迁移程序的时候,是直接利用VS2008将VC6程序转化的方式,然后按VS2008新建项目的StdAfx.h文件内容更新了原来的StdAfx.h头文件,并添加了VS2008项目才有的targerver.h头文件。
根据targetver.h头文件里的下列定义:
#ifndef WINVER // 指定要求的最低平台是 Windows Vista。 #define WINVER 0x0600 // 将此值更改为相应的值,以适用于 Windows 的其他版本。 #endif #ifndef _WIN32_WINNT // 指定要求的最低平台是 Windows Vista。 #define _WIN32_WINNT 0x0600 // 将此值更改为相应的值,以适用于 Windows 的其他版本。 #endif
我的程序便使用了新的Windows SDK版本的定义。于是编译的时候,NONCLIENTMETRICS 的最后一个成员便编译进了程序,由于系统DLL是动态加载的,所以程序在此可以正确编译。但是在运行的过程中,当前XP系统的DLL不支持该成员(新增的成员,在该系统下为不可用),这里表现为来自系统API的SystemParametersInfo函数,找不到匹配该系统预定义的NONCLIENTMETRICS 结构体参数,从而导致程序在运行时出错。
解决方法:
考虑当前系统的版本,添加合适的版本预定义,以程序在当前系统的正确运行。
如上述程序可以在项目的StdAfx.h头文件中添加如下预定义:
#define WINVER 0x0500 #define _WIN32_WINNT 0x0500
PS:0×0500 表示Windows 2000,0×0501为Windows XP,0×0502为Windows Server 2003,0×0600 为 Windows Vista。
以上问题并不复杂,主要是对Windows程序中关于版本定义问题的一些了解,以求得在以后的程序中涉及到该类问题,诸如程序移植等等,有一个明确的认识!
相关推荐
#define MAXLEN 201 #define LEN 1 #define SPEED1 50 #define SPEED2 100 #define SPEED3 200 #define FOOD1_S1 5 #define FOOD1_S2 10 #define FOOD1_S3 15 #define FOOD2_S1 10 #define FOOD2_S2 20 #define FOOD...
#define用法集锦 1.简单的define定义 #define MAXTIME 1000 一个简单的MAXTIME 就定义好了,它代表1000,如果在程序里面写 if(i){.........} 编译器在处理这个代码之前会对MAXTIME 进行处理替换为1000。 这样的定义...
题目:宏#define命令练习(1) 1.程序分析:2.程序源代码:#include "stdio.h"#define TRUE 1#define FALSE 0#define SQ(x) (x)*(x)void main(){int num;int again=1;printf("\40: Program will stop if input value ...
主要是#ifndef和#define的用法说明,并举例说明便于理解。
#define 问题 用法陷阱
const #define inline的用法及区别
#ifndef #define #endif的用法
介绍#define和typedef的区别于使用
1602液晶显示的底层驱动c程序,#define DataDir P4DIR #define DataPort P4OUT #define Busy 0x80 #define CtrlDir P5DIR #define CLR_RS P5OUT&=~BIT5; //RS = P5.5 #define SET_RS P5OUT|=BIT5; #define CLR...
用C语言实现的 预编译器中——#include和#define 操作
#define XBYTE ((unsigned char volatile xdata *) 0) 定义 XBYTE 为 指向 xdata 地址空间unsigned char 数据类型的指针,指针值为0 这样,可以直接用XBYTE[0xnnnn]或*(XBYTE+0xnnnn)访问外部RAM了。
使用场合:拼接两个宏,一个是传入的宏。但是传入的宏不会被替换,...#define DEFINE(X) DEFINE_(X) //再次定义 #define PARAM DEFINE(OBJECT) void fun() { // DEFINE_(OBJECT)=100; 这个操作是拒绝的,它就是直接拼
NULL 博文链接:https://jacky-dai.iteye.com/blog/868385
The #define Directive You can use the #define directive to give a meaningful name to a constant in your program. The two forms of the syntax are: Syntax #define identifier token-stringopt #...
介绍C++/C 宏定义(define)中# ## 的含义, 并以C++代码举例说明
写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等。下面列举一些成熟软件中常用得宏定义……
#define是预处理指令 typedef是在编译时处理的 typedef与#define的区别
#indef 与#define 区别于用法,很详细的解数哦!
#define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASTABLE -1 #define OVERFLOW -2 其次,需要定义线性表的初始大小以及线性表满后所需要的增加量。分别用LIST_INIT_SIZE和LISTINCREMENT...
#define DIR_LENGTH 1024 /*路径最长可达100字节*/ #define MAX_WRITE 1024*128 /*写入文字可达128k字节*/ #define MEM_D_SIZE 1024*1024 /*1M磁盘空间*/ #define DISKSIZE 1024 /*磁盘快的大小 1K*/ #define MSD 5...