《windows核心编程指南28.pdf》由会员分享,可在线阅读,更多相关《windows核心编程指南28.pdf(11页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、下载附录A 建 立 环 境读者要想建立本书中的示例程序,必须要对编译程序和链接程序的开关选项进行设置。笔者试图将这些设置方面的细节从示例程序中隔离出来,把所有这些设置放在一个头文件里。这个头文件就是C m m H d r.h,它包含在所有示例程序的源代码文件中。因为无法将所有的设置都放在这个头文件里,我们对每个示例程序的项目设置做了一些改变。对每个项目,我们显示Project Settings对话框,然后做下面所说的改变。在G e n e r a l栏,设定Output Files目录,这样所有最终的.e x e和.d l l文件都在一个目录之下。在C/C+栏,选择 Code Generati
2、on条目,并对 Use Run-Time Library字段选择Multithreaded DLL。这样就可以了。我只明确改变了两个设置,而接受了其他所有的默认设置。注意要对每个项目的D e b u g建立和R e l e a s e建立都做上述两个改变。我可以在源代码中设定所有其他的编译程序和链接程序的设置,当你在你的项目中使用这里的任何源代码模块时,这些设置都将起作用。A.1 CmmHdr.h头文件所有的示例程序都要包含 C m m H d r.h头文件,并且要在其他头文件之前包含。笔者编写的C m m H d r.h列在清单A-1里。这个文件给笔者带来不少便利。这个文件包含宏、链接程序指
3、令、还有一些其他所有示例程序公用的内容。当我想做某些实验时,我只需修改并重建(r e b u i l d)所有的示例程序。C m m H d r.h在所附光盘的根目录下。这个附录的其余部分将分别讨论 C m m H d r.h文件的每一节,解释每一节的基本原理,并描述在重建所有示例程序之前,如何及为什么要对这个文件进行修改。A.1.1 Wi n d o w s版本建立选项因为有些示例程序调用了 Microsoft Windows 2000中提供的新函数,本节定义 _ W I N 3 2 _W I N N T符号如下:这样做是因为新的Windows 2000函数在Wi n d o w s头文件中
4、被定义成下面这样的原型:第七部分附录676计计第七部分附录下载除非像我这样专门定义_ W I N 3 2 _ W I N N T(在包含Wi n d o w s.h之前),否则这些新函数的原型就没有被声明,当试图调用这些函数时,编译程序将产生错误。微软用 _ W I N 3 2 _ W I N N T符号来保护这些函数,以使程序员开发的应用程序能够运行在 Windows 98及Windows NT的多个版本上。A.1.2 Unicode建立选项笔者编写的所有这些示例程序既可按A N S I来编译,也可按U n i c o d e来编译。当针对x 8 6 C P U体系结构来编译这些程序时,A
5、N S I为默认选择,这样程序可以在 Windows 98上执行。但对其他C P U体系结构建立程序就要用U n i c o d e,这样程序可以占用较少的内存,并且执行得更快。为了对x 8 6体系结构建立U n i c o d e版本,只需将定义U N I C O D E的那一行代码的注释符去掉,并重建程序。通过在C m m H d r.h定义U N I C O D E宏,可以很容易地控制如何建立示例程序。关于U n i c o d e的详细内容,可参见第2章。A.1.3 窗口定义和第4级警告笔者在开发软件时,总是想保证代码的编译不受错误和警告的限制。我还喜欢在可能最高警告级上进行编译,这样
6、编译程序可以替我做大多数工作,甚至为我检查很小的细节。对于Microsoft C/C+编译程序,这将意味着我要使用第4级警告来建立示例程序。遗憾的是,微软的操作系统开发部在关于使用第4级警告做编译方面,与我没有共同的思想。其结果,当我使用第4级警告编译示例程序时,Wi n d o w s头文件中的许多行引起编译器产生警告。幸好,这些警告并不表示代码中有问题。大多数情况是由于 C语言中非传统的用法所引起的,这些用法依赖编译程序的扩展,几乎所有与Wi n d o w s兼容的编译程序厂商都实现了这些扩展。本节我确保警告级设定为 3,而且C m m H d r.h包含标准的 Wi n d o w s
7、.h头文件。当包含了Wi n d o w s.h时,在我编译其余代码时就设置第 4级警告。在第4级警告上,编译程序对那些我不认为有问题的内容发出“警告”,这样我通过使用#pragma warning指令显式地告诉编译程序忽略某些良性的警告错。A.1.4 Pragma消息帮助宏在我编写代码时,我喜欢让代码的某些部分能够立即运行起来,然后再完善它。为了提醒自己要特别注意某些代码,我习惯于加入下面这样一行代码:当编译程序对这一行进行编译时,它会输出一个字符串提醒我还需要再做一些工作。但这条消息不怎么有用。我决定寻找一种办法,让编译程序输出源代码文件的名字,以及 p r a g m a出现的行号。这样
8、,我不光知道要做一些工作,而且能够立刻确定在什么地方做。为了达到这个目的,需要使用一系列宏来修饰pragma message指令。可以这样使用c h M S G宏。当编译程序编译上面这一行代码时,会产生这样一行内容:使用Microsoft Visual Developer Studio,在输出窗口上双击这一行,将会自动定位到相应文件的确切位置上。还有一个方便之处,c h M S G宏不要求对文本串使用引号。A.1.5 chINRANGE和c h D I M O F宏我时常在编写程序时使用这两个方便有用的宏。第一个宏 c h I N R A N G E,用来查看一个数值是否在另外两个数值之间。第
9、二个宏 c h D I M O F,只是返回一个数组中元素的数目。这个宏是用s i z e o f操作符先计算整个数组的字节数,然后再用这个数除以数组中一个数据项所占的字节数,从而得出结果。A.1.6 chBEGINTHREADEX宏本书中的所有多线程示例程序都使用了微软的 CC+运行时函数库中的_ b e g i n t h r e a d e x函数,而不是操作系统的C r e a t e T h r e a d函数。我使用这个函数是因为_ b e g i n t h r e a d e x函数为新线程做好了准备,使新线程能够使用C/C+运行时函数库中的函数,而且还因为它保证在线程返回时清
10、除每个线程的C/C+运行时库信息(见第6章有关细节)。但遗憾的是_ b e g i n t h r e a d e x函数的原型是这样的。尽管_ b e g i n t h r e a d e x函数用的参数值同C r e a t e T h r e a d函数用的参数值是一样的,但二者的参数的数据类型都不相匹配。C r e a t e T h r e a d函数的原型是这样的:微软在建立_ b e g i n t h r e a d e x函数的原型时没有使用Wi n d o w s数据类型。这是因为微软的C/C+运行时库开发组不想对操作系统开发组有任何依赖。这使得_ b e g i n t
11、 h r e a d e x函数的使用更加困难。微软定义_ b e g i n t h r e a d e x函数原型的方式实际上存在着两个问题。首先,用于这个函数的一些数据类型同用于 C r e a t e T h r e a d函数的原始类型不相匹配。例如 Wi n d o w s数据类型D W O R D的定义是这样的:这个数据类型用于 C r e a t e T h r e a d函数的c b S t a c k参数以及 f d w C r e a t e参数。问题是函数_ b e g i n t h r e a d e x将这两个参数的原型定义为 u n s i g n e d,实际
12、意思是 unsigned int。编译程序将unsigned int看成是与unsigned long不同的东西,并且产生一个警告。_ b e g i n t h r e a d e x函数不属于标准的C/C+运行时函数库,只是作为调用 C r e a t e T h r e a d函数的替代手段而存在,所以微软应该按下面的形式来定义_ b e g i n t h r e a d e x的原型,这样就不会产生警告了:附录 A 建 立 环 境计计677下载678计计第七部分附录下载第二个问题是第一个问题的一个小变种。_ b e g i n t h r e a d e x函数返回一个unsigne
13、d long型的值,代表新建立线程的句柄。程序中通常用H A N D L E型数据变量来保存这个返回值:上面这行代码又使编译程序产生另一个警告错。为了避免编译程序警告,必须改写这一行代码,引入一个转换(c a s t):这又是一个不方便之处。为了方便起见,我在C m n H d r.h中定义了一个 c h B E G I N T H RE A D E X宏,替我执行所有这些转换:A.1.7 对x 8 6平台的调试断点改进即使进程没有在一个调试程序下运行,有时候我也想在我的程序代码中强制一个断点。在Wi n d o w s中要做这件事,可以让线程调用D e b u g B r e a k函数。这
14、个函数在k e r n e l 3 2.d l l中,可以使一个调试程序同进程挂接。当调试程序被挂接上时,指令指针就定位在引起断点的C P U指令上。这个指令包含在 k e r n e l 3 2.d l l中的D e b u g B r e a k函数里,所以为了看到我的源代码,我必须在D e b u g B r e a k函数之外单步执行。在x 8 6体系结构上,通过执行“i n t 3”C P U指令来做一个断点。所以,在x 8 6平台之上,我定义D e b u g B r e a k作为这个内联的汇编语言指令。当我的D e b u g B r e a k执行时,我不是在k e r n
15、e l 3 2.d l l中调用。断点发生在我的代码中,指令指针定位在下一个C/C+语句中。这样就方便多了。A.1.8 建立软件异常代码当处理软件异常时,必须建立你自己的3 2位异常代码。这些代码遵循特定的格式(见第 2 4章的讨论)。为了更容易地建立这些代码,我使用M A K E S O F T WA R E E X C E P T I O N宏。A.1.9 chMB宏c h M B宏只是显示一个消息框。消息框的标题是调用进程可执行代码的全路径名。A.1.10 chASSERT和c h V E R I F Y宏在我开发这些示例程序时,为了查找潜在的问题,我在整个代码中多处使用 c h A S
16、 S E RT宏。这个宏测试由x所标识的表达式是否为T R U E,如果不是,则显示一个消息框指出失败的文件、行和表达式。在程序的发行建立中,这个宏什么也不做。c h V E R I F Y宏与c h A S S E RT宏差不多,区别在于不论是调试建立(debug build)还是发行建立(release build),c h V E R I F Y都要对表达式进行测试。A.1.11 chHANDLE_DLGMSG宏当你通过对话框使用消息分流器时,不应该使用微软的Wi n d o w s X.h头文件中的H A N D L E _ M S G宏,因为这个宏并不能返回 T R U E或FA L
17、 S E来指出消息是否由对话框的过程来处理。我定义的c h H A N D L E _ D L G M S G宏会通知窗口消息的返回值,适当地处理返回值,以便在一个对话框过程中使用。A.1.12 chSETDLGICONS宏由于多数示例程序使用一个对话框作为主窗口,你必须手工改变对话框图标,以便让它正确地显示在 Ta s k b a r(任务条)、任务切换窗口和程序本身的标题上。当对话框接收到一个W M _ I N I T D I A L O G消息时,总要调用c h S E T D L G I C O N S宏,以正确设置图标。A.1.13 OS版本检查内联函数本书的大多数示例程序可运行在所
18、有平台上,但也有一些程序要求一些Windows 95和Windows 98所不支持的特性,有些程序要求一些只在 Windows 2000中提供的特性。每个程序在初始化时要检查宿主系统的版本,如果要求更适用的操作系统时,就显示一个通知。对那些不能在Windows 95和Windows 98上运行的程序,你会看到,在程序的_ t Wi n M a i n函数中有一个对Wi n d o w s 9 x N o t A l l o w e d函数的调用。对于要求Windows 2000的示例程序,你会看到在程序的_ t Wi n M a i n函中有一个对c h Wi n d o w s 2 0 0
19、0 R e q u i r e d函数的调用。A.1.14 确认宿主系统是否支持U n i c o d eWindows 98不能像Windows 2000那样完全支持U n i c o d e。实际上,调用U n i c o d e函数的程序不能在Windows 98上运行。但遗憾的是,如果调用一个为 U n i c o d e编译的程序,Wi n d o w s 9 8不会给出任何通知信息。对本书中的程序,这意味着这些程序从开始到结束,都不会有它们想执行的提示信息。这确实是一个难题。我需要有一种办法能够知道我的程序是对 U n i c o d e建立的,但可能在Windows 98系统上运
20、行。所以我建立了一个CUnicodeSupported C+类。这个类的构造函数只是检查宿主系统是不是对U n i c o d e有良好的支持,如果不是,就显示一个消息框,并且进程结束。读者会看到在C m n H d r.h中,我建立了这个类的一个全局的静态实例。当我的程序启动时,C/C+运行时库启动代码调用这个对象的构造函数。如果这个构造函数检测到操作系统完全支持U n i c o d e,构造函数返回而程序继续执行。通过建立这个类的全局实例,我不需要在每个示例程序的源代码模块中再增加特殊的代码。对于非 U n i c o d e的程序建立,不需要声明或实例化上述的C+类。让程序只管运行就是
21、。A.1.15 强制链接程序寻找(w)Wi n M a i n进入点函数本书以前版本的一些读者,将书中我的源代码模块添加到他们自己的 Vi s u a l C+项目中,但在建立项目时出现链接错误。问题的原因是他们创建了 Win32 Console Application项目,导附录 A 建 立 环 境计计679下载致链接程序去寻找(w)m a i n进入点函数。因为本书中所有示例程序都是 G U I程序,所以我的代码都有一个_ t Wi n M a i n进入点函数。这就是链接程序为什么要报错。我的回答是,他们应该删除原来的项目,用 Visual C+建立新的Win32 Application
22、项目(注意在项目类型中不能出现“C o n s o l e”一词),再将我的源代码加进去。链接程序寻找一个(w)Wi n M a i n进入点函数,而这在我的代码中已提供,项目应该能够建立。为了减少我收到的有关这个问题的电子邮件的数量,我在 C m n H d r.h中加入了一个p r a g m a,强制链接程序去寻找(w)Wi n M a i n进入点函数,即使是用Visual C+建立了一个Win32 ConsoleA p p l i c a t i o n项目。在第4章,我详细说明了Visual C+项目类型的有关内容,链接程序如何选择进入点函数,及如何重载链接程序的默认动作等。下面的清单A-1是Cmn Hdr.h 头文件。清单A-1 CmnHdr.h头文件680计计第七部分附录下载附录 A 建 立 环 境计计681下载682计计第七部分附录下载附录 A 建 立 环 境计计683下载684计计第七部分附录下载附录 A 建 立 环 境计计685下载