windows.h分析

windows.h与windef.h

vc++ 2009-03-15 11:14:58 阅读566 评论0 字号:

今天在用到了一个求最大值的max函数的时候,需要include一个头文件,查找了一下msdn,上面说应该添加windef.h头文件,结果编译的时候却报错了。我也搞不懂是为什么啦,上网查一下,说包含windows.h就可以了。这样是调通了。查看了一下windows.h,的确在这个头文件里又是包含了windef.h的,查了一下windef.h,这里面有的的确确是定义了max的,有点糊涂了。但是网上说最好还是包含windows.h,不管了就先这样吧,以后慢慢再说吧。以下是查到的一些网上的资料(来自http://blog.csdn.net/fengningning/archive/2008/04/19/2306650.aspx),有时间再看。

 

关于有没有必要解构“这么一个”头文件,作为初学者,我实在没有太多的见解要发表。我在Microsoft Visual Studio .NET 2005中打开的这个只有260多行(实际占用的行数可能更少)的文件,是所有(我知道用“所有”这个词似乎不大严谨,但据我所知——是的)Windows程序必须先包含的文件,既然是“必须”的,也就是无法规避的,那么又有什么理由阻止我去解构它呢?

 
刚开头的一段注释是对该头文件的描述:
/*++ BUILD Version: 0001    Increment this if a change has global effects
 
Copyright (c) 1985-1997, Microsoft Corporation
 
Module Name:
 
 
    windows.h
 
Abstract:
 
    Master include file for Windows applications.
 
--*/
这个文件似乎没有经历过重大的变化,至今仍是第一个版本。“Increment this if a change has global effects”,意思大概是“如果某个变化有全局性的影响,就将该变化增添至这个头文件”。话本身是没有歧义的,可转而一想,换做是我,我肯定不会擅作主张来修改这个文件的——道理很简单,这样做会导致代码移植更加复杂,还有其他一些不利因素。那么,这句话大概是微软开发人员对“自己人”说的罢。而摘要部分说:“Master include file for windows applications”,就不用多做解释了。
 
#ifndef _WINDOWS_
#define _WINDOWS_
这种宏定义应该是最常见的了,一个作用是防止重复包含。
 
#ifndef WINVER
#define WINVER 0x0400
#else    
#if defined(_WIN32_WINNT) && (WINVER < 0x0400) && (_WIN32_WINNT > 0x0400)
#error WINVER setting conflicts with _WIN32_WINNT setting
#endif
#endif
WINVER这个宏与Windows版本相关,也就是该宏变量取不同值时对应不同的Windows版本,Platform SDK文档中的相关说明如下:
Windows Server 2003                                 WINVER>=0x0502
Windows XP                                             WINVER>=0x0501
Windows 2000                                           WINVER>=0x0500
Windows NT 4.0                                        WINVER>=0x0400
Windows Me                                             WINVER>=0x0500
Windows 98                                              WINVER>=0x0410
Windows 95                                              WINVER>=0x0400
(如何查看自己Windows操作系统的版本号呢?下面提供其中一种方法:调出任务管理器->帮助—>关于任务管理器,在Windows XP中如上操作可以查得版本号是5.1,而在Windows server 2003中是5.2,Windows 2000中则是5.0。哈哈,确实如此,和Platform SDK文档中的描述是一致的!)_WIN32_WINNT这个宏其实也代表版本号,因此如果你同时定义了这个宏,却又与WINVER的定义不一致,那么,编译器就提示错误“WINVER setting conflicts with _WIN32_WINNT”。
 
#if (WINVER >= 0x0500)
#pragma message ("")
#pragma message ("NOTE: WINVER has been defined as 0x0500 or greater which enables")
#pragma message ("Windows NT 5.0 and Windows 98 features. When these headers were released,")
#pragma message ("Windows NT 5.0 beta 1 and Windows 98 beta 2.1 were the current versions.")
#pragma message ("")
#pragma message ("For this release when WINVER is defined as 0x0500 or greater, you can only")
#pragma message ("build beta or test applications. To build a retail application,")
#pragma message ("set WINVER to 0x0400 or visit http://www.microsoft.com/msdn/sdk")
#pragma message ("to see if retail Windows NT 5.0 or Windows 98 headers are available.")
#pragma message ("")
#pragma message ("See the SDK release notes for more information.")
#pragma message ("")
#endif
如果定义的WINVER>=0x0500,即要求最低的Windows版本是Windows NT 5.0(Windows 2000)和Windows 98,此时编译器在进行编译时会提示以#pragma message定义的一系列信息作为提示。
 
#ifndef _INC_WINDOWS
#define _INC_WINDOWS
 
#if defined (_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
 
/* If defined, the following flags inhibit definition
 *     of the indicated items.
 *
 * NOGDICAPMASKS     - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
 * NOVIRTUALKEYCODES - VK_*
 * NOWINMESSAGES     - WM_*, EM_*, LB_*, CB_*
 *  NOWINSTYLES       - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
 * NOSYSMETRICS      - SM_*
 * NOMENUS           - MF_*
 * NOICONS           - IDI_*
 * NOKEYSTATES       - MK_*
 * NOSYSCOMMANDS     - SC_*
 * NORASTEROPS       - Binary and Tertiary raster ops
 * NOSHOWWINDOW      - SW_*
 * OEMRESOURCE       - OEM Resource values
 * NOATOM            - Atom Manager routines
 * NOCLIPBOARD       - Clipboard routines
 * NOCOLOR           - Screen colors
 * NOCTLMGR          - Control and Dialog routines
 * NODRAWTEXT        - DrawText() and DT_*
 * NOGDI             - All GDI defines and routines
 * NOKERNEL          - All KERNEL defines and routines
 * NOUSER            - All USER defines and routines
 * NONLS             - All NLS defines and routines
 * NOMB              - MB_* and MessageBox()
 * NOMEMMGR          - GMEM_*, LMEM_*, GHND, LHND, associated routines
 * NOMETAFILE        - typedef METAFILEPICT
 * NOMINMAX          - Macros min(a,b) and max(a,b)
 * NOMSG             - typedef MSG and associated routines
 * NOOPENFILE        - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
 * NOSCROLL          - SB_* and scrolling routines
 * NOSERVICE         - All Service Controller routines, SERVICE_ equates, etc.
 * NOSOUND           - Sound driver routines
 * NOTEXTMETRIC      - typedef TEXTMETRIC and associated routines
 * NOWH              - SetWindowsHook and WH_*
 * NOWINOFFSETS      - GWL_*, GCL_*, associated routines
 * NOCOMM            - COMM driver routines
 * NOKANJI           - Kanji support stuff.
 * NOHELP            - Help engine interface.
 * NOPROFILER        - Profiler interface.
 * NODEFERWINDOWPOS - DeferWindowPos routines
 * NOMCX             - Modem Configuration Extensions
 */
接下来的所有内容都是用来定义另外一些需要包含的头文件的,当然也包含了其他信息。
_MSC_VER这个宏定义了编译器的版本,相关信息如下:
C   Compiler   version   6.0                                               600  
        C/C++   compiler   version   7.0                                          700  
        Visual   C++,   Windows,   version   1.0                                800  
        Visual   C++,   32-bit,   version   1.0                            800  
        Visual   C++,   Windows,   version   2.0                          900  
        Visual   C++,   32-bit,   version   2.x                               900  
        Visual   C++,   32-bit,   version   4.0                            1000  
        Visual   C++,   32-bit,   version   5.0                            1100  
        Visual   C++,   32-bit,   version   6.0                             1200  
这个宏是必须定义的 #pragma once指示编译器在编译过程中最多包含一次该头文件。
有意思的是下面一大段注释,说明了当定义了_MSC_VER这个宏,并且它的版本号>=1020,那么接下来所列出的一系列标志是不能够被定义的。
 
#if defined(RC_INVOKED) && !defined(NOWINRES)
 
#include <winresrc.h>
 
#else
 
#if defined(RC_INVOKED)
/* Turn off a bunch of stuff to ensure that RC files compile OK. */
#define NOATOM
#define NOGDI
#define NOGDICAPMASKS
#define NOMETAFILE
#define NOMINMAX
#define NOMSG
#define NOOPENFILE
#define NORASTEROPS
#define NOSCROLL
#define NOSOUND
#define NOSYSMETRICS
#define NOTEXTMETRIC
#define NOWH
#define NOCOMM
#define NOKANJI
#define NOCRYPT
#define NOMCX
#endif
 
#if !defined(_68K_) && !defined(_MPPC_) && !defined(_PPC_) && !defined(_ALPHA_) && !defined(_MIPS_) && !defined(_X86_) && defined(_M_IX86)
#define _X86_
#endif
 
#if !defined(_68K_) && !defined(_MPPC_) && !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_MRX000)
#define _MIPS_
#endif
 
#if !defined(_68K_) && !defined(_MPPC_) && !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_ALPHA)
#define _ALPHA_
#endif
 
#if !defined(_68K_) && !defined(_MPPC_) && !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_PPC)
#define _PPC_
#endif
 
#if !defined(_68K_) && !defined(_MPPC_) && !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_M68K)
#define _68K_
#endif
 
#if !defined(_68K_) && !defined(_MPPC_) && !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_MPPC)
#define _MPPC_
#endif
 
#ifndef _MAC
#if defined(_68K_) || defined(_MPPC_)
#define _MAC
#endif
#endif
 
#ifndef RC_INVOKED
#if      ( _MSC_VER >= 800 )
#pragma warning(disable:4001)
#pragma warning(disable:4201)
#pragma warning(disable:4214)
#pragma warning(disable:4514)
#endif
#include <excpt.h>
#include <stdarg.h>
#endif /* RC_INVOKED */
这一段有些长,但因为是一体的,所以放在一起分析是必然的。
宏RC_INVOKED似乎是这一段的核心,就从它开始。RC(资源编译器)定义了这个宏,使得你能够有选择地编译资源头文件的不同部分。为什么会有这种需要呢?当你考虑选择用C编译器还是用RC编译器来编译的资源头文件的时候,你就必须直面这个问题。因为RC所支持的定义语句只是C编译器的一个子集,因此,如果选择用RC来编译,那么就该注意不能用RC所不支持的语法来编写资源头文件。
NO_WINRES这个宏实在winresrc.h这个头文件里定义的,而winresrc.h这个文件里的内容实在是很少:
#ifndef _WINRESRC_
#define _WINRESRC_
 
#include <winuser.rh>
#include <commctrl.rh>
#include <dde.rh>
#include <winnt.rh>
#include <dlgs.h>
#include <winver.h>
 
#endif
呵呵,看过之后,不难理解了。
接下来的一些定义 #if !defined(_68K_) && !defined(_MPPC_) ……是和平台相关的,由于大多数人(包括我在内)可能只会在一种硬件平台下如X86,所以这些定义大可不必太过计较的。
如果没有定义RC_INVOKED并且_MSC_VER(编译器的版本号)>=800的话就禁用几个与编译器版本相关的几个警告信息。如果没有定义RC_INVOKED这个宏,还要包含excpt.h和stdarg.h这两个头文件(excpt .h是一个未文档化的头文件,包含了关于SEH(结构化异常处理)的一些定义;stdarg.h为具有多个参数的函数定义了ANSI类型的宏),那么,在这种情况下为什么要包含这两个头文件呢?Platform SDK中是这样解释的:“RC不支持一些ANSI C型的预定义宏(如__DATE__, __FILE__, __LINE__, __STDC__, __TIME__, __TIMESTAMP__等)”,而excpt.h和stdarg.h这两个头文件确实定义了一些ANSI C型的宏,因此,为避免编译出错,只有在不使用RC的情况下(也就是不定义RC_INVOKED这个宏)才包含这些头文件。
 
#include <windef.h>
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
这几个是windows.h中包含的几个最重要的和最基本的头文件:
windef.h——基本型态定义
winbase.h——Kernel函数
wingdi.h——图形设备接口函数
winuser.h——使用者接口函数
 
#ifdef _MAC
DECLARE_HANDLE(HKEY);
typedef HKEY *PHKEY;
#endif

你可能感兴趣的:(windows,Microsoft,include,compiler,编译器,X86)