📄 附录a0 建构环境.htm
字号:
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B
style="LINE-HEIGHT: 25px">chROUNDDOWN与chROUNDUP之内嵌范本函数(Template
Functions)<BR style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>chROUNDDOWN与chROUNDUP之内嵌范本函数只从下或从上循环一个值至最接近的特定倍数。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=101009>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">chBEGINTHREADEX巨集<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>本书中所有的多线程范例皆使用了_beginthreadex函数,该函数包含在Microsoft之C/C++
执行时期程序库中,以取代作业系统的CreateThread函数。使用_beginthreadex的原因在于它准备了新的线程,以使用C/C++
执行时期程序库函数,以及在线程返回时,确认经过线程的C/C++ 执行时期程序库资讯已被删除(请参阅《Programming
Applications for Microsoft Windows, Fourth
Edition》一书的第六章内容,以取得更多详细的资讯)。_beginthreadex函数的原型定义如下:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">unsigned long __cdecl _beginthreadex( <BR> void *, <BR> unsigned, <BR> unsigned (__stdcall *)(void *), <BR> void *, <BR> unsigned, <BR> unsigned *);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>虽然_beginthreadex函数的参数与CreateThread函数相同,然而其参数的资料型别并不相符。以下是CreateThread函数的原型定义:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(PVOID pvParam); <BR>HANDLE CreateThread( <BR> PSECURITY_ATTRIBUTES psa, <BR> DWORD cbStack, <BR> PTHREAD_START_ROUTINE pfnStartAddr, <BR> PVOID pvParam, <BR> DWORD fdwCreate, <BR> PDWORD pdwThreadId);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>Microsoft没有使用Windows资料型别来建立_beginthreadex函数的原型,因为Microsoft的C/C++
执行时期小组不想使用到作业系统上的任何从属关系。我赞同这个决定,然而,这也让_beginthreadex函数的使用变得更困难。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>实际上,Microsoft定义_beginthreadex函数原型时产生了二个问题。首先,用于功能的某些资料类型不和经由CreateThread功能使用之原始型别相匹配。例如,Windows之DWORD资料型别定义如下:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef unsigned long DWORD;</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>不但将此资料类型用在CreateThread的cbStack参数,也用于它的fdwCreate参数。问题是_beginthreadex的这二个参数定义为unsigned型别,实际上为unsigned
in型别。编译器认为unsigned int与unsigned
long不同,因此产生了一个警告讯息。因为_beginthreadex函数不是标准的C/C++
执行时期程序库,并且只有在选择呼叫CreateThread函数时才存在,我相信Microsoft应该使用此_beginthreadex原型的方法,以避免产生警告讯息:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">unsigned long __cdecl _beginthreadex( <BR> void *psa, <BR> unsigned long cbStack, <BR> unsigned (__stdcall *) (void *pvParam), <BR> void *pvParam, <BR> unsigned long fdwCreate, <BR> unsigned long *pdwThreadId);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>第二个问题只是第一个问题的小变化而已。_beginthreadex函数回传了一个unsigned
long值,表示对新建立之线程的handle。一个应用程序通常会在一个HANDLE型别之资料变数中储存此回传值,如下所示:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">HANDLE hThread = _beginthreadex(...);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>此程序代码会导致编译器产生一个警告讯息。要避免编译器产生警告讯息,您必须重新编写该行程序,以下展示一个范例:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">HANDLE hThread = (HANDLE) _beginthreadex(...);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>虽然如此,但是它非常不方便。为了使工作变得容易些,可在CmnHdr.h中定义了一个chBEGINTHREADEX巨集,让该巨集执行所有此类型的工作:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef unsigned (__stdcall *PTHREAD_START) (void *); <BR>#define chBEGINTHREADEX(psa, cbStack, pfnStartAddr, \ <BR> pvParam, fdwCreate, pdwThreadId) \ <BR> ((HANDLE)_beginthreadex( \ <BR> (void *) (psa), \ <BR> (unsigned) (cbStack), \ <BR> (PTHREAD_START) (pfnStartAddr), \ <BR> (void *) (pvParam), \ <BR> (unsigned) (fdwCreate), \ <BR> (unsigned *) (pdwThreadId)))</PRE></FONT></DIV></A><A
style="LINE-HEIGHT: 25px" name=101010>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">改善x86平台的DebugBreak函数<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>有时候当处理程序不在侦错工具下执行时,会想在程序代码中放置一个中断点,可以在Windows中经由一个线程呼叫DebugBreak函数来完成。此函数存在Kernel32.dll中,可让您指派一个侦错工具至处理程序。一旦侦错工具被指派后,指令指标会被放置在CPU指令集上,以产生一个中断点。此指令被Kernel32.dll内的DebugBreak函数所控制,所以要察看程序代码就必须跳出DebugBreak函数。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>在x86架构上,您会经由执行一个「int
3」的CPU指令来执行一个中断点,所以我重新将DebugBreak定义成此内嵌组合语言的指令。当我的DebugBreak巨集执行时,我不会呼叫至Kernel32.dll;中断点会正确地在我的程序代码中产生,而指令指标会被适当的放在下一个C/C++
语言叙述上。这个经过改进的DebugBreak巨集正好使事情变得更方便。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=101011>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">建立软件例外程序代码<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>当您要使用软件例外时,必须建立您拥有的32-bit例外程序代码。这些程序代码采用了一个特定的格式(在《Programming
Applications for Microsoft Windows, Fourth
Edition》一书之第二十四章中讨论)。为了使建立这些程序代码的工作变得较为容易,可以利用MAKESOFTWAREEXCEPTION巨集。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=101012>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">chMB巨集<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>chMB巨集只显示一个讯息方块,标题为呼叫处理程序之执行档的完整路径。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=101013>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">chASSERT和chVERIFY巨集<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>为了寻找范例应用程序的潜在问题,我在程序代码的各处放置了chASSERT巨集。chASSERT巨集会测试哪个运算式被为TRUE之x所确认,反之,则显示一个讯息方块指示该文件、行号以及执行失败的运算式。在应用程序的Release建置中,此巨集不会使执行档的大小膨胀。除了运算式在Release以及Debug建置中皆会被评估外,chVERIFY巨集几乎与chASSERT巨集相同。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=101014>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">chHANDLE_DLGMSG巨集<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>当您在使用讯息萃取器(Message
Cracker)对话方块时,不该从Microsoft之WindowsX.h标头档中使用HANDLE_MSG巨集,因为它并不回传TRUE或FALSE值以指示讯息是否已被对话方块程序处理。我的chHANDLE_DLGMSG巨集显示了视窗讯息的回传值并适当地处理使用于对话方块中的程序。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=101015>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">chSETDLGICONS巨集<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>因为多数的范例应用程序皆使用一个对话方块为它们的主视窗,您必须手动地修改对话方块图示以使它正确地显示在工作列上、工作转换视窗以及应用程序标题中。chSETDLGICONS巨集通常在对话方块接收一个WM_INITDIALOG讯息时被呼叫,以使图示被正确地设定。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=101016>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">确定主机系统支援Unicode<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>CmnHdr.h文件包含一个在《Programming Applications for Microsoft
Windows, Fourth
Edition》一书中使用的Unicode检查巨集,以确定主机系统支援Unicode。由于本书的范例应用程序需要在Windows
2000中执行,所以不需要此巨集。</FONT></P></A><A style="LINE-HEIGHT: 25px"
name=101017>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">OS版本检查之内嵌函数<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>CmnHdr.h文件包含二个在《Programming Applications for Microsoft
Windows, Fourth
Edition》一书中使用的内嵌函数,以检查主机系统的作业系统版本。由于本书的范例应用程序需要在Windows
2000中执行,所以不需要这些函数。</FONT></P></A><A style="LINE-HEIGHT: 25px"
name=101018>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">CsystemInfo之C++ 类别<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>这是一个非常简单的C++
类别,它包装了Windows的SYSTEM_INFO结构,并在一个类别实例被建构后初始此结构。许多范例应用程序皆在此结构中使用此成员;在一个C/C++
类别中包装该架构,并确保这些成员已被初始化以及一些程序代码的简化。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">CmnHdr.h <BR>/******************************************************************** <BR>模组:CmnHdr.h <BR>通告:Copyright (c)2000 Jeffrey Richter <BR>目的:Common标头文件,包含了便于使用之巨集以及本书所有应用程序使用的定义。 <BR> 请参阅附录A。 <BR>********************************************************************/ <BR>#pragma once // 每个编辑单元皆引入此标头档一次 <BR>///////////////////////////执行Windows子系统/////////////////////////// <BR>#pragma comment(linker, "/subsystem:Windows,5") <BR>///////////////////////////执行Windows 2000 //////////////////////////////// <BR>#pragma comment(linker, "/version:5") <BR>////////////////////////Windows版本建构选项///////////////////////// <BR>#define _WIN32_WINNT 0x0500 <BR>#define WINVER 0x0500 <BR>////////////////////////////Unicode建构选项///////////////////////////// <BR>// 若不在x86之CPU下编译,则使用Unicode编译 <BR>#ifndef _M_IX86 <BR>#define UNICODE <BR>#endif <BR>// 若不使用Unicode编译,请将以下这行做注解 <BR>#define UNICODE <BR>// 当使用了Unicode Windows函数,也使用了Unicode C-Runtime函数 <BR>#ifdef UNICODE <BR>#define _UNICODE <BR>#endif <BR>/////////////////////////包含Windows定义///////////////////////// <BR>#pragma warning(push, 4) <BR>#include <Windows.h> <BR>#include <TChar.h> <BR>/////////////核对适当的标头档////////////// <BR>#ifndef WT_EXECUTEINPERSISTENTIOTHREAD <BR>#pragma message("You are not using the latest Platform SDK header/library ") <BR>#pragma message("files.This may prevent the project from building correctly.") <BR>#pragma message("You may install the Platform SDK from the book’s CD-ROM or ") <BR>#pragma message("from <A href="http://msdn.microsoft.com/downloads/" target=_blank>http://msdn.microsoft.com/downloads/</A>") <BR>#endif <BR>//////////////允许程序代码在warning level 4中编译 /////////////// <BR>/* 曾被使用之非标准延伸「单一注解」 **/ <BR>#pragma warning(disable:4001) <BR>// 未被参考的正式参数 <BR>#pragma warning(disable:4100) <BR>// 注意:建立先行编译标头 <BR>#pragma warning(disable:4699) <BR>// 非内嵌的函数 <BR>#pragma warning(disable:4710) <BR>// 已被移除之未被参考的内嵌函数 <BR>#pragma warning(disable:4514) <BR>// 指派不能被产生的运算子 <BR>#pragma warning(disable:4512) <BR>// 将截断常数值转型 <BR>#pragma warning(disable:4310) <BR>/////////////////////////Pragma讯息协助程序巨集///////////////////////// <BR>/* <BR>当编译器看到一行如下的程序代码: <BR> #pragma chMSG(Fix this later) <BR>它会输出一行如下的讯息: <BR> c:\CD\CmnHdr.h(82):Fix this later <BR>您能轻易直接跳至此行并检查周围的程序代码。 <BR>*/ <BR>#define chSTR2(x) #x <BR>#define chSTR(x) chSTR2(x) <BR>#define chMSG(desc) message(__FILE__"(" chSTR((__LINE__)"):" ##desc) <BR>//////////////////////////////chINRANGE巨集//////////////////////////////// <BR>// 如果有一个数字在另外二个数字中间,此巨集会回传TRUE <BR>#define chINRANGE(low, Num, High)(((low) <= (Num)) && ((Num) <= (High))) <BR>////////////////////////////////chDIMOF巨集//////////////////////////////// <BR>// 此巨集计算阵列中的元件数 <BR>#define chDIMOF(Array) (sizeof(Array) / sizeof(Array[0])) <BR>/////////////////////////////chSIZEOFSTRING巨集//////////////////////////// <BR>// 此巨集计算一个字串所需的位元组数 <BR>#define chSIZEOFSTRING(psz) ((lstrlen(psz) + 1) * sizeof(TCHAR)) <BR>///////////////////chROUNDDOWN与chROUNDUP内嵌函数////////////////// <BR>// 此内嵌函数循环一个减少至最接近的倍数值 <BR>template <class TV, class TM> <BR>inline TV chROUNDDOWN(TV Value, TM Multiple){ <BR> return((Value / Multiple) * Multiple); <BR>} <BR>// 此内嵌函数循环一个减少至最接近的倍数值 <BR>template <class TV, class TM> <BR>inline TV chROUNDUP(TV Value, TM Multiple){ <BR> return(chROUNDDOWN(Value, Multiple) + <BR> (((Value % Multiple) > 0) ? Multiple : 0)); <BR>} <BR>/////////////////////////////chBEGINTHREADEX巨集/////////////////////////// <BR>// 此巨集函数呼叫C执行时期的 _beginthreadex函数。 <BR>// C执行时期程序库不需依赖任何Windows上的资料 <BR>// 如HANDLE的型别。这代表Windows程序设计师在使用 _beginthreadex时需要将这个值转型。 <BR> 这非常不方便,所以建立了一个巨集执行这个转型动作。 <BR>typedef unsigned (__stdcall *PTHREAD_START) (void *); <BR>#define chBEGINTHREADEX(psa, cbStack, pfnStartAddr, \ <BR> pvParam, fdwCreate, pdwThreadId) \ <BR> ((HANDLE)_beginthreadex( \ <BR> (void *) (psa), \ <BR> (unsigned) (cbStack), \ <BR> (PTHREAD_START) (pfnStartAddr), \ <BR> (void *) (pvParam), \ <BR> (unsigned) (fdwCreate), \ <BR> (unsigned *) (pdwThreadId))) <BR>//////////////////改善x86平台的DebugBreak/////////////////// <BR>#ifdef _X86_ <BR>#define DebugBreak() _asm { int 3 } <BR>#endif <BR>///////////////////////////软件例外巨集////////////////////////// <BR>// 建立您自己的软件例外程序代码之有用巨集 <BR>#define MAKESOFTWAREEXCEPTION(Severity, Facility, Exception)\ <BR> ((DWORD) ( \ <BR> /* 重要性程序代码 */ (Severity )| \ <BR> /* MS(0) 或Cust(1) */ (1 << 29)| \ <BR> /* 保留的(0) */ (0 << 28)| \ <BR> /* Facility程序代码 */ (Facility << 16)| \ <BR> /* 例外程序代码 */ (Exception << 0))) <BR>///////////////////////////Quick MessageBox巨集//////////////////////////// <BR>inline void chMB(PCSTR s){ <BR> char szTMP[256]; <BR> GetModuleFileNameA(NULL, szTMP, chDIMOF(szTMP)); <BR> HWND hwnd = GetActiveWindow(); <BR> MessageBoxA(hwnd, s, szTMP, <BR> MB_OK | ((hwnd == NULL ) ? MB_SERVICE_NOTIFICATION : 0)); <BR>} <BR>////////////////////////////Assert/Verify巨集///////////////////////////// <BR>inline void chMBANDDEBUG(PSTR szMsg){ chMB(szMsg); DebugBreak(); <BR>} <BR>// 放置一个判断执行失败的讯息方块 <BR>inline void chASSERTFAIL(LPCSTR file, int line, PCSTR expr){ <BR> char sz[256]; <BR> wsprintfA(sz, "File %s, line %d : %s", file, line, expr); <BR> chMBANDDEBUG(sz); <BR>} <BR>// 放置一个在侦错建置时判断执行失败的讯息方块 <BR>#ifdef _DEBUG <BR>#define chASSERT(x) if (!(x)) chASSERTFAIL(__FILE__, __LINE__, #x) <BR>#else <BR>#define chASSERT(x) <BR>#endif <BR>// 在建置侦错时放置一个执行失败的讯息方块 <BR>#ifdef _DEBUG <BR>#define chFAIL() chASSERTFAIL(__FILE__, __LINE__, "") <BR>#else <BR>#define chFAIL() <BR>#endif <BR>// 在侦错建置时判断,不要在建置正式版时移除此程序代码 <BR>#ifdef _DEBUG <BR>#define chVERIFY(x)chASSERT(x) <BR>#else <BR>#define chVERIFY(x)(x) <BR>#endif <BR>///////////////////////////chHANDLE_DLGMSG巨集///////////////////////////// <BR>// 正式的HANDLE_MSG巨集放置在WindowsX.h中,它并不会适当地执行对话方块,因为 <BR> DlgProc回传一个BOOL值,取代了LRESULT(像WndProcs一样)。 <BR>// 这个chHANDLE_DLGMSG巨集修正了这个问题: <BR>#define chHANDLE_DLGMSG(hwnd, message, fn) \ <BR> case (message): return (SetDlgMsgResult(hwnd, uMsg, \ <BR> HANDLE_##message((hwnd), (wParam), (lParam), (fn)))) <BR>////////////////////////对话方块图示设定巨集//////////////////////// <BR>// 设定对话方块的图示 <BR>inline void chSETDLGICONS(HWND hwnd, int idi){ <BR> SendMessage(hwnd, WM_SETICON, TRUE, (LPARAM) <BR> LoadIcon((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), <BR> MAKEINTRESOURCE(idi))); <BR> SendMessage(hwnd, WM_SETICON, FALSE, (LPARAM) <BR> LoadIcon((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), <BR> MAKEINTRESOURCE(idi))); <BR>} <BR>/////////////////////////////UNICODE检查巨集///////////////////////////// <BR>// 由于Windows 98不支援Unicode,如果在Windows 98上执行一个原生的Unicode建置时 <BR> ,显示一个错误并中止处理程序。 <BR>// 这是经由建立一个全域的C++ 物件完成的。它的建构者在Winmain/main前即已执行 <BR>#ifdef UNICODE <BR>class CUnicodeSupported { <BR>public: <BR> CUnicodeSupported(){ <BR> if (GetWindowsDirectoryW(NULL, 0) <= 0){ <BR> chMB("This application requires an OS that supports <BR> Unicode."); <BR> ExitProcess(0); <BR> } <BR> } <BR>}; <BR>// 「static」让连结器停止了当一个单一项目含有若干来源文件时,物件存在着若干实例 <BR> 的抱怨情形。 <BR>static CUnicodeSupported g_UnicodeSupported; <BR>#endif <BR>///////////////////////////OS版本检查巨集/////////////////////////// <BR>inline void chWindows9xNotAllowed() { OSVERSIONINFO vi = {sizeof(vi)}; GetVersionEx(&vi); <BR> if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { <BR> chMB("This application requires features not present in Windows 9x."); <BR> ExitProcess(0); <BR> } <BR>} <BR>inline void chWindows2000Required() { <BR> OSVERSIONINFO vi = { sizeof(vi) }; <BR> GetVersionEx(&vi); <BR> if ((vi.dwPlatformId != VER_PLATFORM_WIN32_NT) && (vi.dwMajorVersion < 5)){ <BR> chMB("This application requires features present in Windows 2000."); <BR> ExitProcess(0); <BR> } <BR>} <BR>//////////////////////////SYSTEM_INFO包装程序类别////////////////////////// <BR>class CSystemInfo :public SYSTEM_INFO { <BR>public: <BR> CSystemInfo() {GetSystemInfo(this); } <BR>}; <BR>///////////////////////////////// End of File /////////////////////////////////</PRE></FONT></DIV></A></DIV><BR><BR>
<P align=center><FONT color=#3e80d7 size=5><B><SPAN
style="BACKGROUND-COLOR: #d7d7d7">附录B 类别程序库(CLASS
LIBRARY)</SPAN></B></FONT></P>
<DIV language=javascript id=tab1
style="MARGIN-LEFT: 20px; LINE-HEIGHT: 25px"
ondragover="return tab1_ondragover()"><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>当在建立本书的范例应用程序时,为了让开发工作变得容易些,我设计了几个C++
类别。这些类别的原始码存放在随书光碟的ClassLib目录中。在这个附录中包含了以下这些类别。</FONT><A
style="LINE-HEIGHT: 25px" name=102001>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">Ensure Cleanup之C++
样板类别(EnsureCleanup.h)<BR style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -