`
dazhilao
  • 浏览: 240436 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

【转】关于 #define WINVER

阅读更多

原文地址: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程序中关于版本定义问题的一些了解,以求得在以后的程序中涉及到该类问题,诸如程序移植等等,有一个明确的认识!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics