【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3281|回复: 7

[推荐]Windows API for 2000/XP实例精解(精彩连载)

[复制链接]
发表于 2006-6-30 16:20:37 | 显示全部楼层 |阅读模式
<TABLE cellSpacing=0 cellPadding=5 width="100%" border=0>

<TR>
<TD vAlign=top width=130>
<TABLE cellSpacing=5 cellPadding=0 width=180 align=center border=0>

<TR>
<TD align=middle><a href="http://act.it.sohu.com/book/data/book/62/62/62.jpg" target="_blank" ><IMG src="http://act.it.sohu.com/book/data/book/62/62/62.icon.gif" border=0></A> </TD></TR><!--<br>      <tr> <br>       <td height="20" align="center" ><img src='images/stars-0-0.gif' width="67" height="13" border=0 alt=读者评分></td><br>      </tr><br>      --></TABLE></TD>
<TD vAlign=top colSpan=3>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>

<TR>
<TD width="18%" height=20><STRONG>书名:</STRONG></TD>
<TD width="82%" height=20><STRONG><FONT face=宋体 color=#333333>Windows API for 2000/XP实例精解 </FONT></STRONG></TD></TR>
<TR>
<TD height=20><STRONG>作者:</STRONG></TD>
<TD height=20><FONT face=宋体 color=#333333>王强、周明、李定国 等 </FONT></TD></TR>
<TR>
<TD height=20><STRONG>来源:</STRONG></TD>
<TD height=20><a href="http://www.phei.com.cn/" target="_blank" ><FONT face=宋体 color=#333333>电子工业出版社</FONT></A><FONT face=宋体 color=#333333> </FONT></TD></TR>
<TR>
<TD height=20><STRONG>ISBN:</STRONG></TD>
<TD height=20><FONT face=宋体 color=#333333>7-5053-7701-9 </FONT></TD></TR>
<TR>
<TD height=20><STRONG>页数:</STRONG></TD>
<TD height=20><FONT face=宋体 color=#333333>545 </FONT></TD></TR>
<TR>
<TD height=20><STRONG>开本:</STRONG></TD>
<TD height=20><FONT face=宋体 color=#333333>16开 </FONT></TD></TR>
<TR>
<TD height=20><STRONG>出版时间:</STRONG></TD>
<TD height=20><FONT face=宋体 color=#333333>2002年8月 </FONT></TD></TR>
<TR>
<TD height=20><STRONG>定价:</STRONG></TD>
<TD height=20><FONT face=宋体 color=#333333>54元 </FONT></TD></TR>
<TR>
<TD colSpan=2 height=20>
<><STRONG></STRONG></P></TD></TR></TABLE></TD></TR></TABLE>
<>本书首先详细地阐述了在Windows 2000环境下使用API函数开发应用程序的机制、步骤和方法,并围绕典型实例对Win32 API函数的特性进行了具体说明。最后三章着重介绍了新一代操作系统Windows XP的一些新增API函数和使用这些函数开发应用程序的方法。本书语言通俗易懂,内容丰富翔实,突出了以实例为中心的特点,适合有一定的C和VC编程经验的中、高级开发人员学习使用,同时也可作为从事Windows应用程序开发的软件工程师参考用书。 </P>
<><a href="http://act.it.sohu.com/book/serialize.php?id=62" target="_blank" ><IMG src="http://act.it.sohu.com/book/images/new/yd.gif" border=0></A></P>
<DIV align=center><B>第1章 概述</B></DIV>
<><br></P>
<DIV align=center>1.1 Windows家族简介</DIV>
<DIV align=left><br>     <br>
<><FONT size=3>      IBM PC在1981年与世人见面时,当时名不见经传的Microsoft的创始人比尔·盖茨和保罗·艾伦就为它编写了一套基于命令行的操作系统。很快,MS-DOS随着PC一起流行,成为主流的操作系统。随着内存和其他有关硬件的成熟,图形界面可以从小型机向PC机转移,Microsoft在1983年11月发布了Windows,但在两年后(即1985年)才正式推出。由于软件本身的缺陷和硬件等种种原因,直到1990年5月,Windows 3.0发布后,Windows才开始逐渐取代MS-DOS,成为PC操作系统的主流。</FONT></P>
<H3><FONT size=3><FONT face=Arial><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">1.1.1</st1:chsdate>  Windows 3.x/NT/95/98</FONT></FONT></H3>
<><FONT size=3>      1992年4月发布的Microsoft Windows 3.1奠定了Windows作为PC操作系统霸主的地位。Windows 3.1中包括了很多新的特性,如多媒体(Multimedia)、对象链接和嵌入(OLE:Object Linking And Embedding)和通用对话框(Common Dialog)等。在Windows 3.1后,Microsoft还推出了一些Windows的新版本,如Windows 3.2,但这些都是基于16位的操作系统的,其根本改变还是发生在Windows NT推出之后。</FONT></P>
<><FONT size=3>       Windows NT在1993年发布,是支持Intel 386、486和Pentium微处理器的32位模式的第一个Windows版本。NT的含义是新技术(New Technology)。除了Intel处理器,它还可以移植到其他处理器上。Windows NT操作相对简单,运行比较稳定,安全性能较高,自问世以来,一直在服务器操作系统的市场上有着重要的位置。</FONT></P>
<><FONT size=3>       Windows 95是基于DOS内核的32位模式的操作系统,它的发布标志着Microsoft鼎盛时期的到来。Windows 95虽然缺少了Windows NT中的一些功能特性,但同样也对硬件配置降低了要求。Windows 95用户界面的友好性对广大的用户而言无疑是一个福音,在很短的时间内,它几乎在PC操作系统方面一统天下,并获得了空前的成功。</FONT></P>
<><FONT size=3>       Windows 98继承了Windows 95的优势,对性能和硬件支持有了进一步的提高。特别在顺应市场的要求方面,它与Internet和WWW(World Wide Web)的结合更加紧密。</FONT></P>
<H3><FONT face=Arial><FONT size=3><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">1.1.2</st1:chsdate>  Windows 2000</FONT></FONT></H3>
<><FONT size=3>       Windows 2000的中文版在<st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="20" Month="3" Year="2000">2000年3月20日</st1:chsdate>正式发售。Windows 2000平台操作系统采用NT的技术,并在其上做了大量的改进,使Windows 2000操作系统平台比此前的Windows操作系统平台更加可靠,更易扩展,更易部署,更易管理和更易使用。值得一提的是,Windows 2000还提供了对多国语言的支持。</FONT></P>
<P><FONT size=3>Windows 2000提供了“个性化”菜单,不断地监视并显示经常使用的菜单项目,隐藏那些不经常使用的程序选项,还会根据程序的使用频率对“开始”菜单中的程序项进行动态调整。所以,如果某个程序被用户频繁使用,它将逐渐上升到顶行。Windows 2000还提供了增强的网络管理,利用“网上邻居”左边Web页中的“添加网络组件”命令,可以为网络增加网络管理和监视工具。该工具的作用是监视网络设备的活动,并且向网络控制台工作站汇报情况。</FONT></P>
<P><FONT size=3>       Windows 2000家族有两大类平台(共四种操作系统):第一类是工作站平台Windows 2000 Professional;第二类是服务器平台。Windows 2000家族的服务器平台有如下三种:</FONT></P>
<P>●    <FONT size=3>Windows 2000 Server:除了包含Windows 2000 Professional的所有特性外,它还提供简单的网络管理服务。</FONT></P>
<P>●    <FONT size=3>Windows 2000 Advanced Server:除了包含Windows 2000 Server的所有特性外,它还提供更好的可扩展性和有效性,并支持更多的内存、处理器以及群集。</FONT></P>
<P>●    <FONT size=3>Windows 2000 Data Center Server:除了包含所有Windows 2000 Advanced Server的特性外,它还提供更多的内存和处理器的支持,适用于大型数据仓库和在线事务处理等重要应用。</FONT></P>
<H3><FONT face=Arial><FONT size=3><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">1.1.3</st1:chsdate>  Windows XP</FONT></FONT></H3>
<P><FONT size=3>       Windows XP于<st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="25" Month="10" Year="2001">2001年10月25日</st1:chsdate>正式发布,XP的意思是eXPerience,即体验。Windows XP给大家的感觉是耳目一新。尽管用户还可以在其中发现一些Windows 95~Windows 2000中用户界面的影子,但它确实与以前所使用的Windows看上去有很多不同。用户能够根据喜好来定制自己的系统界面,这在以前只能通过相关软件才能完成。如图1-1、图1-2所示展示了全新的操作界面。</FONT></P>
<P><FONT size=3>    与Windows 2000相同,Windows XP基于NT技术,是纯32位的操作系统,其功能更健壮、更稳定。除此之外,Windows XP与以前的版本相比,还提供了更快速的用户切换、更丰富的交流功能、更强的移动性、更好的帮助和支持以及更简捷的数码影像等。</FONT></P>
<P><FONT size=3>    Windows XP在网络特性上的增强有不少值得称道的方面。不少用户都知道Windows 2000中的脱机文件功能,Windows XP对其做了进一步优化,并可将脱机文件加密,使其更为安全。另外,“网络连接向导”也更为体贴,拨号连接的用户名与密码输入和在桌面上创建连接的快捷方式等操作都能在向导中直接完成。</FONT></P><v:shapetype><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype>
<P align=center><v:shape><v:imagedata><FONT size=3><IMG src="http://act.it.sohu.com/book/images/upload//62-1-1.jpg" align=baseline border=0></FONT></v:imagedata></v:shape><FONT size=3>                     </FONT><v:shape><v:imagedata><IMG src="http://act.it.sohu.com/book/images/upload//62-1-2.jpg" align=baseline border=0></v:imagedata></v:shape></P>
<H6 align=center><FONT size=2>图1-1  Windows XP开始菜单                             图1-2  Windows XP“我的电脑”界面</FONT></H6>
<P><FONT size=3>    Windows XP在兼容性和稳定性方面相对以前的版本有了很大的提高。在兼容性方面,不少用户都知道Windows 2000的一个弊病就是与不少应用软件(特别是游戏软件)不兼容。但是,在Windows XP中不存在这个问题,几乎在其他Windows系统中可以运行的软件都可以在Windows XP中运行。Windows XP还提供了兼容运行模式,可以骗过那些原来不能在Windows XP中运行的软件,使它们将当前系统误认为是Windows 9x/NT/ 2000,从而保证其顺利运行。在稳定性方面,Windows XP在Windows 2000的基础上采用了驱动程序回滚(安装设备新驱动程序出错后,恢复到以前正常的驱动程序)和系统还原(自动监视系统,在系统配置出错时,可恢复到以前完好的状态)功能,使整个系统更为稳定。现在,微软仍在不断改进Windows XP的兼容性和稳定性,用户可以通过网上升级或以后安装服务包(SP)来进行驱动升级和错误修正。</FONT></P>
<P><FONT size=3>    Windows XP的核心代码基于Windows 2000,所以从Windows NT 4.0/2000上进行升级安装是十分容易的。Windows XP提供了4个适用于不同用途的版本:个人版(支持1个CPU)、专业版(支持2个CPU)、服务器版(支持4个CPU)和高级服务器版(支持8个CPU)。</FONT></P>Microsoft在推出Windows XP后,正在紧锣密鼓地筹划下一个Windows版本。用不了多久,Windows的下一个版本Windows Longhorn将会与大家见面,紧接着还有Blackcomb。 <br></DIV>
 楼主| 发表于 2006-6-30 16:23:08 | 显示全部楼层
<br>     <br>   API(Application Programming Interface)的中文含义是应用编程接口。其实,它是程序员与Windows交互的最基本方式,包含了所有应用程序对构造操作系统的函数的调用,当然,其中也包含了相关的数据类型和结构。
<p>1.2.1  什么是API    在Windows系统中,API保持着一贯的一致性。也就是说,从Windows 1.0以来,系统就提供了API函数的调用。随着系统的不断升级,API函数也不断地得到扩充,高版本的系统对低版本系统的API函数都提供了支持。现在,API函数已经扩充到了几千个。
<p>   正如大家所知,API函数首先出现在16位的系统中,从Windows 1.0到Windows 3.1,提供的API函数都是基于16位体系结构的,被称为Win16。从Windows NT开始,以后所有的Windows操作系统都基于32位体系结构,API函数也相应地基于32位体系结构,被称为Win32。Windows API和它的语法中的最大变化来自于从16位体系结构向32位体系结构的转化过程。
<p>   在Windows出现时,当时流行的Intel微处理器(如Intel 8086、8088和286)都是16位的。但是,从Intel 386开始的微处理器设计成32位字长的中央处理器,因此与硬件相适应的32位操作系统的出现和普及是必然的。16位系统的API函数在32位系统中都得到了支持,以确保与旧应用程序的兼容。但提供支持的方式并不是完全相同的,因为Windows NT/2000/XP和Windows 95/98的工作方式截然不同。在Windows NT/2000/XP中,Win16函数的调用通过一个转换层被转化成Win32函数的调用,然后被操作系统处理。在Windows 95/98中,操作的步骤正好相反,所有的Win32函数在转换层被转化为Win16函数调用,然后由操作系统处理。
<p>   由于Windows系统的各个版本之间会有区别,每一个操作系统都有一些其他操作系统所不支持的功能特性,所以编写的应用程序会有兼容性的问题。因为绝大部分的API函数都是兼容的,所以只要在编写程序时考虑到兼容性的问题,就能写出在不同的Windows操作系统中都可以很好运行的程序。
<p>随着硬件的发展,64位微处理器的推出是必然的,Windows的后续版本中很有可能推出基于64位的操作系统。那么,API从32位平台向64位平台的转变又将是一次重大的转变。
<p>1.2.2  为什么程序员需要API    使用C语言和原始的API绝不是进行Windows程序设计的惟一方法。现在有很多选择,包括快速的开发工具,但这种方法提供的是最佳的性能、最强大的功能、最有效的控制和最紧凑的应用程序,能最大限度地发掘Windows系统的灵活性。通过运用Windows API函数编程,用户将对Windows系统内部的运行机制有更深入的了解。
<p>   使用C语言和原始API函数编写的程序经过编译后,可执行文件相对较小。 除了Windows DLL之外,不需要其他外部库的支持。
<p>即使使用其他开发工具,也经常会调用API函数,因为API函数直接针对Windows的底层,可以用简单的语句实现对系统功能的调用。几乎所有基于Windows平台的开发工具都用自己的语言对重要的API函数进行了重新编写和封装,以提供对这一功能的支持。所以,通过对原始的API进行分析和演练,可以帮助大家在其他开发工具中更好地理解和利用API函数。
<p>   在使用原始的API函数编程的过程中,可以控制Windows消息的发送和接收,灵活地调用各种系统功能,这对理解Windows的运行机制很有好处。在编程的过程中,程序员几乎拥有对程序执行的绝对控制权,这在其他开发环境下是很难做到的。
<p>   既然用原始API函数编程有很多有利之处,那么为什么在实际运用中并不会总选择它作为开发的工具呢?这是因为它有一个很明显的不足之处,即要为实现任何一个很小的功能而编写很多代码,这与开发的时间和效率要求是相违背的,况且用它实现高级的控制所需花费的精力将十分惊人。所以,只有在对代码的执行效率有严格的控制时,才会使用这种方法编程。本文的主要目的是讲解一种编程的方法,让大家更好地理解Windows的运行机制,在其他开发工具中更好地利用API函数。
<p>1.2.3  Windows XP API的新特性    随着Windows操作系统的每一次升级,API都会得到较大的扩充,Windows XP系统的升级也不例外。在Windows XP中增加较多的API函数是关于界面和图形的,Windows XP在界面方面号称是Windows 95以来改变最大的一次升级。在图形方面,由于GDI+(Graphics Device Interface +)的引入而提供的一系列功能强大的函数,使编写程序更容易,运行程序也更快捷。有关具体的函数,在以后的章节中会详细介绍。
<p>
 楼主| 发表于 2006-6-30 16:23:48 | 显示全部楼层
< align=left><br>     <br>1.3.1  概述    现在,已经了解了什么是API函数,下面用API函数编写第一个程序。如图1-3所示展示给大家的是一个再熟悉不过的窗口,在此窗口的中央写着  “Hello,You Are Welcome!”。当按下键盘上的任意一个键时,窗口显示的文本颜色将随机地发生改变。它是在Windows 2000中编译运行程序而得到的效果图。</P>
< align=center><IMG src="http://act.it.sohu.com/book/images/upload//62-1-3.jpg" align=baseline border=0></P>
<H6 align=center><FONT size=2>  图1-3  运行效果图</FONT></H6>
<p>
<p>  图1-3  运行效果图 1.3.2  应用程序实例在字符界面的模式下显示一个字符串只需用到很短的一段代码,如下所示:
<p>#include &lt;stdio.h&gt;
<p>int main()
<p>{
<p>printf(“Hello,You Are Welcome”);
<p>return 0;
<p>}
<p>   在Windows中,涉及到窗口创建和维护、文本的显示等,代码就变得有一点复杂了,但这一切还在可控制之中。
<p>   在Windows中,创建一个窗口实际上也是很简单的,只需调用一个API函数CreateWindow即可。复杂的是,这个函数所带的参数有11个,这些都是需要了解并且在创建过程中需要设定的。在此之前,还需要定义并注册一个窗口类,并为类的各个参数设定要用到的值。
<p>下面是图1-3所示的效果图的源代码。
<p>------------------------------------------------------------
<p>// Hello.c
<p>------------------------------------------------------------
<p>#include &lt;windows.h&gt;
<p>LPCTSTR lpszAppName=TEXT(“MyApp”);
<p>LPCTSTR lpszTitle=TEXT(“My Application”);
<p>   
<p>LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
<p>int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
<p>LPTSTR lpCmdLine, int nCmdShow)
<p>{
<p>    MSG msg;
<p>HWND hWnd;
<p>WNDCLASSE wc;
<p>// 注册主应用程序的窗口类
<p>wc.style=CS_HREDRAW|CS_VREDRAW;
<p>wc.lpfnWndProc=(WNDPROC)WndProc;      
<p>wc.cbClsExtra=0;                     
<p>wc.cbWndExtra=0;                     
<p>wc.hInstance=hInstance;              
<p>wc.hIcon=LoadIcon(NULL, IDI_APPLICATION);
<p>wc.hCursor=LoadCursor(NULL, IDC_ARROW);
<p>wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
<p>wc.lpszMenuName=lpszAppName;              
<p>wc.lpszClassName=lpszAppName;              
<p>if(!RegisterClass(&amp;wc))
<p>return(FALSE);
<p>// 创建主应用程序的窗口
<p>hWnd=CreateWindow(lpszAppName,  lpszTitle,WS_OVERLAPPEDWINDOW,
<p>CW_USEDEFAULT,0, CW_USEDEFAULT, 0,  
<p>NULL, NULL,  hInstance, NULL);               
<p>if (!hWnd)
<p>return(FALSE);
<p>
<p>ShowWindow(hWnd, nCmdShow);
<p>UpdateWindow(hWnd);         
<p>
<p>while(GetMessage(&amp;msg, NULL, 0, 0))   
<p>  {
<p>TranslateMessage(&amp;msg);
<p>DispatchMessage(&amp;msg);  
<p>   }
<p>return(msg.wParam);
<p>}
<p>--------------------------------------------------------------
<p>// 窗口过程函数
<p>--------------------------------------------------------------
<p>LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg,
<p>WPARAM wParam, LPARAM lParam)
<p>{
<p>  RECT rect;
<p>  HDC hdc;
<p>  PAINTSTRUCT ps;
<p>  static int uRed=0, uGreen=0, uBlue=0;
<p>
<p>  switch(uMsg)
<p>  {   
<p>case WM_PAINT :
<p>hdc=BeginPaint(hWnd, &amp;ps);
<p>GetClientRect(hWnd, &amp;rect);
<p>SetTextColor(hdc, RGB(uRed, uGreen, uBlue));
<p>DrawText (hdc, TEXT (“Hello, You Are Welcoming!”), -1, &amp;rect,
<p>DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
<p>EndPaint(hWnd, &amp;ps);
<p>     break;
<p>case WM_KEYDOWN :
<p>      uRed=rand() % 255;
<p>uGreen=rand() % 255;
<p>uBlue=rand() % 255;
<p>InvalidateRect(hWnd, NULL, TRUE);
<p>break;
<p>case WM_DESTROY :
<p>ostQuitMessage(0);
<p>break;
<p>default :
<p>return  DefWindowProc(hWnd, uMsg, wParam, lParam);
<p>    }
<p>return(0L);
<p>}
<p>
 楼主| 发表于 2006-6-30 16:26:32 | 显示全部楼层
< align=left><br></P>
<DIV align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px;><br>     <br></DIV>
<H3 align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3><FONT face=Arial><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">1.3.3</st1:chsdate>  </FONT>头文件的类型</FONT></H3>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>与传统的C程序一样,在程序的开始都会包含头文件,并在程序中会有对调用函数的申明。在每一个用C编写的Windows程序中,都会用到一个头文件WINDOWS.H。其实,WINDOWS.H只是一个包含文件,包含了其他的Windows头文件。当然,在这些被包含的头文件中也可能还包含着其他的Windows头文件。这些头文件中最重要的有如下几种。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>WINDEF.H:基本类型的定义。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>WINNT.H:支持Unicode的类型定义。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>WINGDI.H:图形设备接口的定义。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>WINUSER.H:用户接口的定义。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>WINBASE.H:内核函数的定义。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>WINSOCK.H和WINSOCK2.H:用于网络通信的套接字的定义。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>在这些头文件中,定义了Windows提供的所有数据类型、常数标识符、函数原型和数据结构等,都是Windows文档中最重要的部分。在Visual C++的Include子目录中可以找到所有的头文件。</FONT></P>
<H3 align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3><FONT face=Arial><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">1.3.4</st1:chsdate>  </FONT>函数和数据结构</FONT></H3>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 6pt?><FONT size=3>在C语言中有一个入口函数main,在Windows应用程序中同样也有一个入口函数WinMain,它的原型在WINBASE.H中声明,如下所示:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance,</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>LPSTR lpCmdLine, int nShowCmd);</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm 6pt><FONT size=3>其中,第一个参数被称为“实例句柄”,该句柄惟一地标识了该程序,其他Windows函数可以通过将该句柄作为参数来调用该程序;第二个参数只是为了与早期的版本相兼容,在32位Windows程序中,该概念已经不再被采用,所以总是设置为NULL;第三个参数用于运行程序的命令行,可以通过它将文件在程序启动时载入内存;第四个参数表示程序在运行时是以何种方式显示的(从正常、最大化和最小化中选一)。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>在程序Hello中,除了用到WinMain函数外,还用到了以下的API函数。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>LoadIcon:为程序加载图标以供使用。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>LoadCursor:为程序加载鼠标指针以供使用。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>GetStockObject:获取图形对象。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>RegisterClass:为主程序的窗口注册窗口类。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>ShowWindow:在屏幕上显示窗口。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>UpdateWindow:命令窗口刷新自身。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>GetMessage:从消息队列中获取消息。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>TranslateMessage:转换某些键盘消息。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>DispatchMessage:将消息发送给窗口过程。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>BeginPaint:开始在窗口的客户区绘制。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>GetClientWindow:获得窗口客户区的尺寸。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>SetTextColor:设置文本的颜色。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>DrawText:显示文本串。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>EndPaint:结束绘制。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>InvalidateRect:强制刷新指定的区域,程序Hello刷新整个窗口的客户区。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>PostQuitMessage:在消息队列中插入一条“退出”消息。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>DefWindowProc:执行默认的消息处理。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这些函数在头文件WINDOWS.H中都有原型的申明,具体的信息可以查阅MSDN(Microsoft Developer Network)中SDK平台的部分函数说明。除了用到的这些API函数外,还使用了在Windows头文件中定义的4个数据类型:MSG(消息结构)、WNDCLASS(窗口类结构)、PAINTSTRUCT(绘图结构)和RECT(矩形结构)。</FONT></P>
<H4 align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt 21.25pt?><FONT face=Arial>1. </FONT>消息结构</H4>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 6pt?><FONT size=3>消息结构定义一个用于发送的消息,其中包含消息的具体信息,在程序接收到消息后,根据其中包含的信息做出相应的处理。其结构声明如下:<o:p></o:p></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>typedef struct tagMSG {</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 147.0pt? 40.6pt><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    HWND hwnd;          </FONT>// 获得消息的窗口句柄</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 147.0pt? 40.6pt><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    UINT message;       </FONT>// 消息标志</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 147.0pt? 40.6pt><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    WPARAM wParam;      </FONT>// 消息的附加信息</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 147.0pt? 40.6pt><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    LPARAM lParam;      </FONT>// 消息的附加信息</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 147.0pt? 40.6pt><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    DWORD time;         </FONT>// 消息的发送时间</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 147.0pt? 40.6pt><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    POINT pt;           </FONT>// 当消息发送时,鼠标所处的屏幕位置</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>} MSG, *PMSG; </FONT></P>
<H4 align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt 21.25pt?><FONT face=Arial>2. </FONT>窗口类结构</H4>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 6pt?><FONT size=3>窗口总是在窗口类的基础上创建的,窗口类用来标识处理窗口消息的窗口过程。在一个窗口类的基础上可以创建多个窗口的实例,所以在程序创建窗口之前,必须先调用函数RegisterClass注册一个窗口类。该函数中只带有一个参数,它是一个指向类型为WNDCLASS的结构指针。其结构声明如下:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>typedef struct _WNDCLASS { </FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT face=Courier><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5">   UINT style;                 </FONT></FONT></FONT><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5">//   窗口类的风格 <o:p></o:p></FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5">   <FONT face=Courier>WNDPROC lpfnWndProc;        </FONT>//  指向窗口过程的指针<o:p></o:p></FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>   int  cbClsExtra;             //  </FONT>分派给窗口类的扩展的字节数</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>   int  cbWndExtra;             //  </FONT>分派给窗口实例的扩展的字节数</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>   HINSTANCE hInstance;        //  </FONT>窗口的实例句柄</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>   HICON hIcon;                //  </FONT>类图标的句柄</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>     HCURSOR hCursor;           //  </FONT>类鼠标指针的句柄</FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5">  <FONT face=Courier>   HBRUSH hbrBackground;</FONT>       //  刷新背景所用的画刷的句柄<o:p></o:p></FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm TEXT-INDENT: 0pt; tab-stops: 4.33? mso-char-indent-count: 183.75pt; 38.95pt;><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>LPCTSTR lpszMenuName;      </FONT>//  窗口类包含的菜单的名称<o:p></o:p></FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 0pt; tab-stops: 183.75pt?><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5">     <FONT face=Courier>LPCTSTR lpszClassName;     </FONT>//  窗口类名<o:p></o:p></FONT></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>} WNDCLASS, *PWNDCLASS; </FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm 6pt><FONT size=3>现在,结合程序Hello依次来看WNDCLASS结构中的各个域。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>第一个域语句:ws.style = CS_HREDRAW | CS_VREDRAW</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这条语句使用C的按位“或”操作符组合了两个“类风格”标识符。有关的标识符是在WINUSER.H中定义的,可以查看该文件中以CS为前缀的标识符定义集合。在本程序中,使用的这两个标识符的意义是当窗口水平方向尺寸(CS_HREDRAW)发生改变时和当窗口的垂直方向尺寸(CS_VREDRAW)发生改变时,窗口都要完全刷新。这一点在改变窗口的尺寸时,可以明显地看到。无论窗口如何变化,文本总是出现在窗口的中央(因为在客户区输出文本时,定义将其显示在窗口的中央,每一次窗口的刷新都要执行此操作)。 </FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>第二个域语句:ws.lpfnWndProc = (WNDPROC)WndProc</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这条语句的作用是将窗口类的窗口过程设置为WndProc,这是在本程序中定义的第二个函数,用来处理基于这个窗口类创建的所有窗口的全部消息。在类定义中,实际上使用的是一个指向函数的指针,通过该指针调用同名函数。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>第三和第四个域语句:wc.cbClsExtra = 0;和wc.cbWndExtra = 0 </FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这两条语句用于为程序预留空间,程序可以根据需要来使用它们。在本程序中没有使用到,所以赋值为零。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>第五个域语句:wc.hInstance = hInstance</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这条语句指定了程序的实例句柄,该句柄可以从WinMain函数的第一个参数处获得。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>第六个域语句:wc.hIcon = LoadIcon( NULL, IDI_APPLICATION )</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这条语句用于为所有基于这个窗口类建立的窗口设置一个图标。图标是一个小的位图图像,将出现在Windows任务栏中和窗口的标题栏的左端。用户可以定义自己的图标加载到程序中,也可以使用系统提供的图标。在本程序中,为简单起见,使用系统提供的应用程序的标准图标(ID为IDI_APPLICATION),使用函数LoadIcon将图标加载到应用程序中。该函数返回一个图表句柄。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>第七个域语句:wc.hCursor = LoadCursor(NULL, IDC_ARROW)</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这条语句表示窗口载入一个预定义命名为IDC_ARROW的鼠标光标(形状为箭头),并返回该光标的句柄。在Win32 API中定义了一系列的鼠标光标,具体内容可以参考MSDN文档中Platform SDK/Windows User Interface/LoadCursor等内容。当程序启动且鼠标的位置处于窗口的客户区时,鼠标变成箭头形状。另外,也可以自定义鼠标光标的形状。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 32.6pt? 0pt>●    <FONT size=3>第八个域语句:wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1)</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>这条语句指定了基于这个窗口类所创建的窗口的背景颜色。在Windows API中,用某一种颜色覆盖背景一般都需要用到画刷(brush),以指定的颜色来填充一个区域。在本程序中,使用了比窗口颜色稍亮的颜色作为画刷的颜色。在Windows中还定义了一些标准的画刷,称为“备用画刷”(stock brush)。利用GetStockObject函数可以调用一个备用画刷。例如,hBrush=GetStockObject(WHITE_ BRUSH),其中的WHITE_BRUSH就是一个标准的画刷。</FONT></P>
 楼主| 发表于 2006-6-30 16:27:10 | 显示全部楼层
<BR>1.3 Win32 API应用程序框架结构(3) <BR>     
<p>
<>●    第九个域语句:wc.lpszMenuName = lpszAppName</P>
<>这条语句指定窗口类的菜单,其中,lpszAppName指向存储菜单名字符串的指针。在本程序中没有用到菜单,所以该字段被设置为NULL。</P>
<>●    第十个域语句:wc.lpszClassName = lpszAppName</P>
<>最后一个域给出了窗口类的类名。在提供的程序中,类名和窗口类的菜单名相同。</P>3. 矩形结构
<>矩形结构相对简单,它定义了四个LONG域,前两个表示矩形左上点的横坐标和纵坐标(通常用X和Y表示)的值,后两个表示矩形右下点的X,Y值。其结构声明如下:</P>
<>typedef struct _RECT { </P>
<>         LONG left;      // 左上点的X坐标</P>
<>         LONG top;       // 左上点的Y坐标</P>
<>         LONG right;     // 右下点的X坐标</P>
<>         LONG bottom;    // 右下点的Y坐标</P>
<P>} RECT, *PRECT;</P>
<P>有关绘图结构的具体内容将在讲解GDI(图形设备接口,Graph Device Interface)时重点介绍。下一小节将具体介绍Windows消息机制,整个Windows是以消息(Message)作为传递信息的手段的消息机制可以说是Windows的灵魂。</P>1.3.5  消息机制 1. 消息循环
<P>在调用了UpdateWindows之后,窗口就会出现在显示器上,此时Windows就为程序维护一个“消息队列”。当Windows侦测到程序的用户键盘和鼠标输入数据时,就将此输入事件转化为一个“消息”,并将此消息放到程序的消息队列中。</P>
<P>程序通过执行被称为“消息循环”的代码从消息队列中取出消息。实现循环的程序代码如下:</P>
<P>while(GetMessage(&amp;msg, NULL, 0, 0))   </P>
<P>{</P>
<P>TranslateMessage(&amp;msg); </P>
<P>DispatchMessage(&amp;msg);  </P>
<P>}</P>
<P>其中,变量msg是类型为MSG的结构,在前一小节中已经介绍过这个结构的有关信息。消息循环首先从消息队列中取出一个消息,其方法如下所示:</P>
<P>GetMessage(&amp;msg, NULL, 0, 0);</P>
<P>它将取到的消息赋给一个指向名为msg的MSG结构的指针。第二、第三和第四个参数分别设置为NULL或者0,表示程序将接收它创建的所有窗口的所有消息。只要从消息队列中取出的消息的message域不为WM_QUIT(其值为0x0012),GetMessage就返回一个非零的值。</P>
<P>然后,进行一些键盘消息转换(在讲解有关键盘输入的章节中进行详细讨论),其方法是:</P>
<P>TranslateMessage( &amp;msg );</P>
<P>最后,消息又将被转回Windows,Windows会将消息发送给适当的窗口过程进行处理,即Windows调用窗口过程(在程序Hello中是WndProc函数),其方法是:</P>
<P>DispatchMessage(&amp;msg);</P>
<P>当处理完消息后,窗口过程又将控制返回给Windows,此时,Windows仍处在函数DispatchMessage的调用中。当得到返回后,Windows结束DispatchMessage函数的调用,重新开始调用GetMessage函数从消息队列中获取消息。</P>
<P>从以上可以看出,消息只是在窗口过程和Windows之间传递,程序并不会直接调用窗口过程。如果要从程序调用自己的窗口过程,就要用到SendMessage函数,这在后续的章节中会重点讨论。</P>
<P>并不是所有的消息都会进入消息队列,加入消息循环。一般来说,进队的消息基本上是用户输入的结果(包括鼠标输入和键盘输入)。另外,进队的消息还包括时钟消息(WM_TIMER)、刷新消息(WM_PAINT)和退出消息(WM_QUIT)等。不进队的消息一般来自调用特定的Windows函数。例如,调用CreateWindow时,将直接给窗口过程发送一个WM_CREATE的消息;调用ShowWindow时,将直接给窗口过程发送名为WM_SIZE和WM_SHOWWINDOW的消息。</P>
<P>消息的循环和处理十分复杂,但绝大部分的消息处理都由Windows完成,而且是有规律可循的。消息其实只是应用程序与Windows交互的媒介,存在于窗口过程和Windows之中。</P>2. 消息及消息处理
<P>窗口过程接收的每一个消息都是用数值标识的,也就是传递给窗口过程msg结构中的message参数。在Windows头文件WINUSER.H中,为每个消息参数定义以“WM”(Window Message)为前缀的标识符。当然,也可以在自己程序的头文件中定义自己的消息参数。</P>
<P>一般来说,Windows程序员都会选择使用switch和case的结构来确定窗口过程接收到的是什么消息。窗口过程在处理消息时,必须返回零,所有窗口过程不予处理的消息都应该被传给函数DefWindowProc处理。事实上, DefWindowProc并不是惟一处理其他消息的函数,在接触多文档时,还会碰到用于相似处理内容的函数。从函数DefWindowProc返回的值必须由窗口过程返回,函数只是将消息进行加工,具体工作还是要由Windows来完成。</P>
<P>在程序中,WndProc函数只处理三种消息:WM_PAINT,WM_KEYDOWN和WM_DESTROY。窗口过程的总体结构如下:</P>
<P>switch(uMsg)</P>
<P>{   </P>
<P>// 定义有关变量</P>
<P>case WM_PAINT :</P>
<P>// 处理WM_PAINT消息的过程</P>
<P>break;</P>
<P>case WM_KEYDOWN :</P>
<P>// 处理WM_KEYDOWN消息的过程</P>
<P>break;</P>
<P>case WM_DESTROY :</P>
<P>// 处理WM_DESTROY消息的过程</P>
<P>break;</P>
<P>default :</P>
<P>return(DefWindowProc(hWnd, uMsg, wParam, lParam));</P>
<P>}</P>
<P>return(0L);</P>
<P>在上面结构的定义中,利用“default :”来调用DefWindowProc函数为窗口过程不予处理的消息提供的默认的处理是必需的。 因为在窗口过程中,有很多很重要的工作都要Windows来完成。如果不能将这些消息及时地发送给Windows,则窗口的创建和维护就不会成功。用户可以将此函数去掉后再编译运行,就会发现其问题所在。</P>(1)WM_PAINT消息
<P>当客户区的一部分或者全部变为无效时,将由这个消息通知程序“刷新”该区域。在很多情况下,客户区会变得无效,下面介绍经常遇到的几种情况。</P>
<P>●    在创建窗口时,客户区将变得无效。</P>
<P>此时,整个客户区都是无效的。在程序运行函数UpdateWindow时,将发送第一个WM_PAINT的消息,指示窗口过程在客户区域画一些东西。</P>
<P>●    改变应用程序窗口的大小时,窗口的整个客户区将变得无效。</P>
<P>因为在定义窗口类的第一个域style时,曾经将标志设置为CS_HREDRAW和CS_VREDRAW,这一设置将指示Windows在窗口改变大小后,使整个窗口无效。此时,又将发送一个WM_PAINT的消息。</P>
<P>●    在移动窗口并发生窗口重叠时,窗口客户区将变得无效。</P>
<P>此时,Windows将不会保存本窗口中被另外一个窗口覆盖部分的客户区内容。此时,窗口客户区将变成无效,发送一个WM_PAINT的消息。</P>
<P>除了这些由程序接收到外部变化和自动刷新之外,还可以通过函数强制刷新客户区的一部分或者全部,将在下一个消息中介绍这种方法。</P>
<P>对消息WM_PAINT的处理,一般都从BeginPaint函数调用开始,其调用方法是:</P>
<P>hdc=BeginPaint(hWnd, &amp;ps);</P>
<P>结束消息WM_PAINT的处理,一般通过调用EndPaint函数完成,其调用方法是:</P>
<P>EndPaint(hWnd, &amp;ps);</P>
<P>在这两个调用中,第一个参数是程序的窗口句柄,第二个参数是指向类型为PAINTSTRUCT结构的指针。在调用函数BeginPaint成功时,程序将调用在窗口类中定义的背景画刷来将整个客户区刷新,并返回一个“设备环境句柄(hdc)”。所谓设备环境,是指物理输出设备(如显示器)及其设备驱动程序。在窗口的客户区画任何东西(包括文本和图形)都需要用到设备环境句柄。当程序调用了函数EndPaint后,就使设备环境句柄不再有效。</P><BR>
 楼主| 发表于 2006-6-30 16:29:30 | 显示全部楼层
<DIV  align=left>1.3 Win32 API应用程序框架结构(4)</DIV>
<DIV  align=left><BR>     </DIV>
<  align=left><FONT size=3>   在调用完BeginPaint后,WndProc接着调用GetClientRect函数,其调用方法是:</FONT></P>
<  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>GetClientRect(hWnd, &amp;rect);</FONT></P>
<  align=left><FONT size=3>   其中,第一个参数是窗口的句柄;第二个参数是指向RECT类型结构的指针。调用这个函数后,有关客户区大小的信息就被存储在变量rect中。其中,left和top一般为零,right和bottom设置为以像素点数形式保存的客户区域的宽度和高度。</FONT></P>
<  align=left><FONT size=3>函数SetTextColor用来为输出的文本着色,其调用方法是:</FONT></P>
<  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>SetTextColor(hdc, RGB(uRed, uGreen, uBlue));</FONT></P>
<  align=left><FONT size=3>   其中,第一个参数表示设备环境句柄;第二个参数表示用函数RGB表示的颜色。有关函数RGB的参数在创建窗口时都是0,综合起来获得的文本的颜色是黑色。当执行下一个要介绍的消息时,它的参数将发生改变。</FONT></P>
<  align=left><FONT size=3>函数DrawText的作用是在客户区输出文本,其调用方法如下:</FONT></P>
<  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>DrawText(hdc, TEXT(“Hello, You Are Welcome!”), -1, &amp;rect,DT_SINGLELINE| </FONT></P>
<  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>         DT_ CENTER|DT_VCENTER); </FONT></FONT></FONT></P>
<  align=left><FONT size=3>   其中,第一个参数表示从BeginPaint函数返回的设备环境句柄;第二个参数表示要输出的文本;第三个参数为-1,表示文本串要以字节0结束;第四个参数表示从GetClientRect处返回的客户区矩形的结构指针;第五个参数表示一系列位标识,指示文本必须显示在同一行上(DT_SINGLELINE),水平方向(DT_CENTER)和垂直方向(DT_VCENTER)都必须位于第四个参数描述的矩形(在程序Hello中是整个客户区)的中央。</FONT></P>
<P  align=left><FONT size=3>当客户区变得无效时,WndProc就会接收到一个新的WM_PAINT消息。此时,WndProc就会调用GetClientRect函数重新获得当时的窗口客户区的大小,通过调用SetTextColor重新设置文本的颜色,并在客户区的中央显示文本。</FONT></P>
<H5  align=left><FONT face=楷体_GB2312 size=3>(2)WM_KEYDOWN消息</FONT></H5>
<P  align=left><FONT size=3>   当系统侦测到用户键盘按键(除了一些系统键)信息时,就会产生一个WM_KEYDOWN的消息,并将该消息发送给WndProc。</FONT></P>
<P  align=left><FONT size=3>在对WM_KEYDOWN处理时,首先将调用函数rand,分别获得三个随机的整数:uRed = rand() % 255、uGreen = rand() % 255和uBlue = rand() % 255。这三个随机整数分别用来定义函数RGB中的红、绿、蓝三原色,以遵循函数RGB的定义。这三个被用做参数的变量的值均应当小于255,故采用了求余的方式。在定义三个变量时,为了保证它们在不同消息处理时的一贯性,所以采用的是静态变量的方式,例如:static int uRed=0,  uGreen=0, uBlue=0;。</FONT></P>
<P  align=left><FONT size=3>重新为作为参数的三个静态变量赋值后,就调用函数InvalidateRect,其调用方法是:</FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>InvalidateRect ( hWnd, NULL, TRUE ); </FONT></P>
<P  align=left><FONT size=3>   此函数的作用就是在程序中用代码的形式强制刷新指定的区域。此函数的第一个参数是窗口的句柄;第二个参数是指向要刷新的矩形结构的指针,如果被设置为NULL,则将刷新整个客户区;第三个参数是BOOL类型,当设置为TRUE时,客户区在调用BeginPaint函数时,将擦除指定的矩形或客户区并重新画图,如果设置为FALSE,则将不擦除指定的矩形或客户区而重新画图。在程序Hello中,将强制擦除整个客户区并重新画图。由于重新设置了显示客户区显示文本的颜色,所以在每按下一个键时,都将随机地改变窗口文本的颜色。其中的消息的传递过程如下:</FONT></P>
<P  align=left><FONT size=3></FONT> </P>
<P  align=left><FONT size=3>① DefWindowProc将侦测鼠标和键盘的输入,当侦测到一个键盘按键的信息时,就产生一个消息添加到Windows为该程序产生的消息队列中。</FONT></P>
<P  align=left><FONT size=3>② 当其前面的消息处理完后,处理此消息时,Windows将给WndProc发送一个WM_KEYDOWN的消息,WndProc接收到消息后,执行WM_KEYDOWN下的有关代码。</FONT></P>
<P  align=left><FONT size=3>③ 当执行到InvalidateRect时,又将WM_PAINT的消息加入消息队列中。</FONT></P>
<P  align=left><FONT size=3>④ 执行完WM_KEYDOWN下的有关代码后,将控制权交给Windows。</FONT></P>
<P  align=left><FONT size=3>⑤ Windows将从DispatchMessage函数中返回,并从新的消息队列中获取消息。</FONT></P>
<P  align=left><FONT size=3>⑥ 当获得WM_PAINT消息时,又将执行WM_PAINT下的有关代码。</FONT></P>
<H5  align=left><FONT face=楷体_GB2312 size=3>(3)WM_DESTORY消息</FONT></H5>
<P  align=left><FONT size=3>   这个消息指示Windows根据用户输入的命令来清除窗口。该消息在用户单击“Close”按钮或在程序的系统菜单(通过单击窗口图标或使用快捷键【Alt+Space】获得)上选择“Close”时发生。通过调用函数PostQuitMessage以标准的方式响应WM_DESTORY消息以退出消息循环,函数PostQuitMessage的调用方法如下:</FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>PostQuitMessage(0);</FONT></P>
<P  align=left><FONT size=3>   该函数将在程序的消息队列中插入一个WM_QUIT的消息。当GetMessage函数获得这个消息时,将返回零。这将导致本程序的WinMain函数退出消息循环,并终止程序的执行,返回msg.wParam。结构wParam是传递给PostQuitMessage函数的值,通常为零。然后,程序将退出消息队列。退出程序消息循环的过程如下:</FONT></P>
<P  align=left><FONT size=3>① 当用户选择了退出程序时,DefWindowProc将发送一个WM_SYSCOMMAND消息到窗口过程WndProc。</FONT></P>
<P  align=left><FONT size=3>② 经过消息队列后,WndProc又将这个消息传递给DefWindowProc。</FONT></P>
<P  align=left><FONT size=3>③ DefWindowProc处理后,发送一个WM_CLOSE的消息给窗口过程。</FONT></P>
<P  align=left><FONT size=3>④ 经过消息队列后,WndProc再次将这个消息传递给DefWindowProc。</FONT></P>
<P  align=left><FONT size=3>⑤ DefWindowProc处理后,调用DestoryWindow来响应WM_CLOSE消息,导致Windows给窗口过程发送一个WM_DESTORY消息。</FONT></P>
<P  align=left><FONT size=3>⑥ WndProc再调用PostQuitMessage,将一个WM_QUIT消息放入消息队列中,这样才导致程序的退出。</FONT></P>
<H3  align=left><FONT size=3><FONT face=Arial><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="30" Month="12" Year="1899">1.3.6</st1:chsdate>  </FONT>句柄、标识符和数据类型</FONT></H3>
<P  align=left><FONT size=3>   在Windows中,句柄的使用是十分频繁的,那什么是句柄呢?句柄是一个32位的数,代表一个对象。程序基本上是通过调用函数来获得句柄的。句柄的实际值对程序而言无关紧要,但重要的是,程序通过它来引用相应的对象。在Windows中,句柄的类型定义有很多种,下面是一些常用的句柄:</FONT></P>
<P  align=left>●    <FONT size=3>HANDLE:指向对象的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HBITMAP:指向位图的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HBRUSH:指向画刷的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HCURSOR:指向鼠标光标的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HDC:指向设备环境的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HFILE:指向文件的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HGLOBAL:指向全局内存块的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HMETAFILE:指向元文件的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HMODULE:指向模块的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HMENU:指向菜单的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HPEN:指向画笔的句柄。</FONT></P>
<P  align=left>●    <FONT size=3>HWND:指向窗口的句柄。</FONT></P>
<P  align=left><FONT size=3>   有关标识符的定义,前面已经简要介绍过了。现在所用到的和以后将要用到的标识符绝大部分都是在Windows头文件中定义的(自定义的除外)。其中,有些标识符由两个或三个字母组成并后跟下划线作为前缀,如下面一些标识符:</FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>CS_HREDRAW</FONT> <FONT face=Courier>CS_VREDRAW      DT_SINGLELINE</FONT> <FONT face=Courier>  DT_CENTER</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>DT_VCENTER</FONT> <FONT face=Courier>IDC_ARROW       IDI_APPLICATION</FONT> <FONT face=Courier>WM_PAINT</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>WM_KEYDOWN</FONT> <FONT face=Courier>WM_DESTORY</FONT></FONT></FONT></P>
<P  align=left><FONT size=3>   前缀用来表明其“身份”,即标明该标识符(其实都是数值常量)所属的类别。前缀和所表示的类别如表1-1所示。</FONT></P>
<P  align=left><FONT size=2><FONT face=Arial> </FONT>表<FONT face=Arial>1-1  </FONT>标识符前缀</FONT></P>
<DIV  align=left>
<TABLE  cellSpacing=0 cellPadding=0 border=1>

<TR>
<TD  width=84>
<P ><FONT size=1>前    缀<o:p></o:p></FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>类    别<o:p></o:p></FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>CS</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>窗口类风格选项</FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>CW</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>创建窗口选项</FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>DT</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>绘制文本选项</FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>IDI</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>图标的ID号</FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>IDC</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>光标的ID号</FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>MB</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>信息框选项</FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>SND</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>声音选项</FONT></P></TD></TR>
<TR>
<TD  width=84>
<P ><FONT size=1>WM</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>窗口消息选项</FONT></P></TD></TR>
<TR >
<TD  width=84>
<P ><FONT size=1>WS</FONT></P></TD>
<TD  width=232>
<P ><FONT size=1>窗口风格选项</FONT></P></TD></TR></TABLE></DIV>
<P  align=left><FONT size=3>在使用API编程的过程中,可以使用标准C语言中定义的所有数据类型。但除此之外,Windows还在其头文件中使用typedef和#define定义的一系列新的数据类型。例如:</FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define PCHAR char *</FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>typedef unsigned int UINT  </FONT></FONT></FONT></P>
<P  align=left><FONT size=3>在程序Hello中使用到的参数WPARAM和LPARAM的定义有一点不清楚。其实,在Win16中,WPARAM被定义为WORD,是一个16位的无符号整数,而LPARAM被定义为LONG,是一个32位有符号的整数。当API进入Win32时代时,WPARAM被定义为UINT,LPARAM依然被定义为LONG,两个参数都是32位的整数,但为了保持命名的一致性,依然沿用原来的命名方法。</FONT></P>
<P  align=left><FONT size=3>WndProc返回的类型LRESULT是一个简单的句柄LONG。在Windows头文件中,所有的函数都被指定为WINAPI类型。这个类型的定义如下:</FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define WINAPI _ _stdcall</FONT></P>
<P  align=left><FONT size=3>有趣的是,函数WndProc被指定的类型为CALLBACK,它的定义也是_ _stdcall。用不同的命名来定义一个相同的数据类型,旨在表明不同的调用规则。</FONT></P>
<DIV  align=left><BR><BR></DIV>
 楼主| 发表于 2006-6-30 16:33:19 | 显示全部楼层
<DIV align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px;><br>     <br></DIV>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>   Unicode字符是ASCII字符编码的扩展。在ASCII中,每个字符用7位表示,而Unicode是完全的16位编码字符形式。这样,就使Unicode可以把世界上所有的书写语言都在计算机中用字符的形式表示出来。Unicode影响到了计算机业的方方面面,其中对操作系统和基于其上的编程语言的影响最大。Unicode的出现动摇了ASCII字符在计算机中的支配地位,而Unicode最终取代ASCII是整个计算机界正在努力实现的目标。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>   在Windows操作系统中,基于NT内核的系统是从底层支持Unicode的,如Windows NT、Windows 2000和Windows XP等。Windows 98中只有一小部分支持Unicode。从编程语言的角度来看,传统的C语言通过对宽字符集的支持来支持Unicode。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>   由于在计算机中,每个字符被定义为8位,而Unicode要占16位,所以可以用双字符的字符集(DBCS:Double_Byte Character Set)来解决Unicode的表示问题。同时,又可以保持与ASCII字符集的兼容性。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>   在Unicode中,每一个字符的宽度不再是8位,而是16位。这就使Unicode在理论上可以表示65 536个不同的字符,完全可以包括世界上常用的任何文字语言符号,也包括数学和货币的符号。ISO 10646-1对Unicode代码的范围做了明确的规定,为不同的语言、数学及货币符号限定了所占用的空间。这样,在全球范围内就初步统一了文字符号在计算机中表示的问题。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>   在C语言中,涉及到的字符都只占一个字节,即Sizeof(char)返回为1。引入Unicode和宽字符的概念后,char数据类型没有改变。</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 6pt?><FONT size=3>在C语言中的宽字符是基于数据类型wchar_t上的,例如:</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>typedef unsigned short wchar_t;</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 6pt 0cm?><FONT size=3>   从上可以看出,wchar_t数据类型与无符号短整数类型相同,都是16位宽。用下面的语句可以定义一个宽字符的变量:</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>wchar_t x = ‘A’;</FONT></P>
< align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 6pt 0cm?><FONT size=3>   这个字符所占的字节数不再是1,而是2。另外,还可以用以下的语句定义一个指向宽字符串的指针:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>wchar_t *p = L” HELLO, WORLD!”</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 6pt 0cm?><FONT size=3>   其中,在第一个引号前面的大写字母L表示“long”。它将通知编译器该字符串是以宽字符保存的,也就是必须为每个字符准备两个字节的空间,整个字符串要占用的空间是26个字节(包括末尾有一个0所占的2个字节)。如果不怕麻烦,前一个语句可以这样写:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>wchar_t x = L‘A’;</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm 6pt><FONT size=3>   但事实上,这是没有必要的,因为数据类型已经告诉编译器这个字符要占用双字节空间。<o:p></o:p></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 6pt?><FONT size=3>   在Windows系统中,为了解决同一个源代码既可以按ASCII编译,又可以按Unicode编译的问题,就必须针对不同的环境给出解决方案。头文件TCHAR.H解决了这个问题。下面是其中的定义:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#ifdef UNICODE</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define _ _T(x) L # # x</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#else</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define _ _T(x) x</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#endif</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 6pt 0cm?><FONT size=3>   这样,只需对字符串加工即可让程序自己判断所处的系统环境,以采用不同的处理编译方式。定义字符串如下:<o:p></o:p></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>_ _T(“HELLO,WORLD”);</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 6pt 0cm?><FONT size=3>   另外,在TCHAR.H中还定义了以下两个相同的宏:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define _T(x) _ _T(x)</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define _TEXT(x) _ _T(x)</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm 6pt><FONT size=3>   可以根据需要使用哪一个宏,当然用户也可以定义自己的宏,但为了程序的通用性和可读性,不提倡这样做。<o:p></o:p></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 6pt?><FONT size=3>宽字符的表示问题解决了,但以往的库函数对宽字符是否支持呢?下面做一个实验,调用函数strlen来显示在前面定义的宽字符串的长度,例如:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>int nLength = strlen(p);</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 6pt 0cm?><FONT size=3>   但是,编译器通常会给出如下一条警告消息:<o:p></o:p></FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>‘function’: incompatible types – from ‘unsigned short *’ to ‘const char *’</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 6pt 0cm?><FONT size=3>   这表明数据类型产生了冲突,原有的库函数对宽字符并不支持。在这种情况下,惟一的办法是将含有字符串参数的函数全部重写。事实上,这件事情已经做到了。与strlen函数相对应并应用于宽字符的函数是wcslen,它在头文件STRING.H和WCHAR.H中均有声明。下面就可以用这个函数试一试,例如:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>int nLength = wcslen(p);</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm 6pt><FONT size=3>   编译通过了,运行得到的数据却比较费解,其结果是12,而不是24。原来,在使用宽字符时,字符串的长度是不变化的,变化的是字节的长度。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>在存储宽字符时,要用的存储空间是原来的两倍,而且宽字符运行库中的函数比常规的函数要大。出于种种原因的考虑,读者也许认为有必要建立两个版本的程序:一个用于处理ASCII字符串;另一个用于处理Unicode字符串。事实上这是没有必要的,因为Windows的库函数和头文件已经解决了这个问题。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0cm 6pt?><FONT size=3>在有关的函数库中,涉及字符串参数的函数都有两个定义:一个用于ASCII;另一个用于Unicode。例如,在USER32.DLL中,有两个关于信息框的函数:MessageBoxA和MessageBoxW。这两个函数的功能完全相同,都用于在指定的窗口内显示对话框。不同的只是前者用于ASCII,后者用于Unicode。在头文件WINUSER.H中有这样一段定义:</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#ifdef UNICODE</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define MessageBox MessageBoxW</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#else</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#define MessageBox MessageBoxA</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>#endif</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm 6pt><FONT size=3>   这段定义很明确地告诉用户可以使用MessageBox,不管到底调用了哪个函数,程序在运行时会根据系统是否支持Unicode和用户在使用该函数时参数定义是否用到Unicode来判断该调用哪一个函数。也就是说,在USER32.DLL中并不存在一个名为MessageBox的函数,它只是WINUSER.H中给出的一个入口点。在相关的动态链接库中,这样的函数还有很多,因为对宽字符函数的处理基本上都采用了这种方式。</FONT></P>
<P align=left ? 宋体: ; FONT-FAMILY: #990000; COLOR: 18px; 0pt? 0cm><FONT size=3>   有关Unicode的内容就介绍到这里,如果读者有兴趣,可以查阅有关专著。Unicode的最大作用莫过于它可以使所写的程序国际化,正如在前面讨论的,Unicode几乎为世界上的每一种文字语言都提供了可用的空间。 </FONT></P>
 楼主| 发表于 2006-6-30 16:36:06 | 显示全部楼层
<DIV  align=left>2.1 窗口过程与消息处理</DIV>
<DIV  align=left><BR>     </DIV>
<  align=left><FONT size=3>   每个窗口都有与之相对应的窗口过程。窗口过程能够确定其窗口的外观和行为特性,这是通过对进入到窗口过程中的窗口消息的处理完成的。在第1章中,已经讲过了窗口过程的例子,虽然它只处理几个简单的消息,但确实实现了一个标准的窗口。</FONT></P>
<  align=left><FONT size=3>   窗口过程总是与已注册的特定窗口类相关联的,一个应用程序可以有几个窗口类,基于每个窗口类都可以创建多个窗口(通过CreateWindow等函数创建)。也就是说,同一个窗口过程可能要处理几个窗口中产生的消息。但是,在多窗口的应用程序中,Windows怎样辨别消息队列中的消息该发给哪个窗口的窗口过程处理呢?</FONT></P>
<  align=left><FONT size=3>   在WinMain函数中创建窗口如下所示:</FONT></P>
<  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>hWnd = CreateWindow (LPCTSTR lpClassName , </FONT>//注册窗口类名 </FONT></FONT></P>
<  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>                        //</FONT>与窗口相关的其他参数<o:p></o:p></FONT></FONT></P>
<  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>                        )</FONT></FONT></FONT></P>
<  align=left><FONT size=3>   从以上代码可以看到,在创建窗口时,至少要完成两项工作:一项将窗口类及其相关联的窗口过程与新窗口关联起来,另一项是得到新窗口的句柄。这样,当新窗口中产生消息时,Windows的消息循环可以根据这个句柄找到相应的消息处理过程(窗口过程)。<o:p></o:p></FONT></P>
<  align=left><FONT size=3>下面介绍窗口过程的定义,读者就会更易明白Windows的这一处理过程。</FONT></P>
<  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>LRESULT CALLBACK WndProc( HWND hwnd,</FONT></P>
<  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>                          UINT message,</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>                      WPARAM wParam,</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>                      LPARAM lParam </FONT></FONT></FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>)</FONT></P>
<P  align=left><FONT size=3>注意:<FONT face=楷体_GB2312>窗口过程的hwnd参数指明了产生消息的窗口,其他几个参数则表明了消息信息。这与MSG结构的前四个域是相同的。</FONT></FONT></P>
<P  align=left><FONT size=3>   WndProc被声明为CALLBACK(回调函数),回调函数是输出函数中特殊的一种,能够在Windows环境下直接调用。一个应用程序至少有一个回调函数,因为在应用程序处理消息时,Windows会调用回调函数,即窗口过程。它对应于一个活动的窗口,回调函数必须向Windows注册,Windows实施相应的操作后就进行回调。</FONT></P>
<P  align=left><FONT size=3>   窗口过程的名字可以任意指定,只需与窗口类结构的lpfnWndProc域指定的名字相同即可。窗口过程函数体负责接收和处理由消息循环发送来的消息。通常,通过switch和case结构确定窗口过程对发送来的哪些消息进行处理,而不予处理的消息可以交给默认的窗口过程DefWindowProc来处理。典型的switch和case结构在第1章已经给出,通过嵌套此结构,可以获得更灵活且功能更强的窗口处理过程,如下面一段程序:</FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>Switch(iMsg)</FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>{</FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>case WM_SIZE:<o:p></o:p></FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5">         // 处理<FONT face=Courier>WM_SIZE</FONT>消息<o:p></o:p></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5">         <FONT face=Courier>return 0;</FONT></FONT></FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>case WM_COMMAND:</FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>        switch(LOWORD(wParam))</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>        {</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>        case IDM_FILE_NEW:</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>            // </FONT>处理<FONT face=Courier>IDM_FILE_NEW</FONT>消息</FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>            return 0;</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>        case IDM_FILE_CLOSE:</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>            // </FONT>处理<FONT face=Courier>IDM_FILE_CLOSE</FONT>消息</FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>            return 0;</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    }</FONT></FONT></FONT></P>
<P  align=left><FONT size=2><FONT style="BACKGROUND-COLOR: #e5e5e5"><FONT face=Courier>    break;</FONT></FONT></FONT></P>
<P  align=left><FONT style="BACKGROUND-COLOR: #e5e5e5" face=Courier size=2>}</FONT></P>
<P  align=left><FONT size=3>   上述程序是一个菜单消息处理窗口过程(在第5章中将做详细介绍)的片断,通过对消息的两个参数之一wParam(另一个为lParam)的使用,得到了更强大的消息处理能力。设计优秀的程序需要仔细分析窗口中产生的消息及其参数代表的含义,并对消息处理流程进行充分设计。</FONT></P>
<P  align=left><FONT size=3>   需要再次重申的是,Windows消息的wParam参数保存了与消息相关的信息,如产生消息的窗口句柄和ID号(以后都称为“标识符”);lParam参数则保存了一些与消息无关的信息,如消息产生时鼠标位置的坐标值等。另外需要注意的是,case语句完成后要返回零,以便窗口过程将控制返回到程序。</FONT></P>
<P  align=left><FONT size=3>   Windows的DefWindowProc是应用程序默认的消息处理过程,它为各类消息提供了最少的处理功能,以处理窗口过程不予处理的消息。一般来说,窗口过程中不予处理的消息一定要交给DefWindowProc函数处理,否则应用程序可能不会正常工作。</FONT></P>
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 04:43

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表