﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-C++ Programmer's Cookbook-随笔分类-Windows API</title><link>http://www.cppblog.com/mzty/category/298.html</link><description>&lt;br/&gt;  
&lt;br/&gt;
&lt;a href = "http://www.cppblog.com/mzty/archive/2007/03/02/19109.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C++ 基础}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/08/13/29922.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C++ 高级}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/04/16/22064.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C#界面，C++核心算法}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/03/04/19163.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{设计模式}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "
http://www.cppblog.com/mzty/archive/2007/03/04/19167.html"&gt;&lt;font size = 5 color ="#FF0000"&gt;{C#基础}&lt;font/&gt;&lt;/a&gt;





</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 13:34:32 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 13:34:32 GMT</pubDate><ttl>60</ttl><item><title>windows消息机制</title><link>http://www.cppblog.com/mzty/archive/2006/11/24/15619.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 24 Nov 2006 05:08:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/11/24/15619.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/15619.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/11/24/15619.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/15619.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/15619.html</trackback:ping><description><![CDATA[
		<p>一 Windows中有一个系统消息队列，对于每一个正在执行的Windows应用程序,系统为其建立一个“消息队列”，即应用程序队列，用来存放该程序可能创建的各种窗口的消息。应用程序中含有一段称作“消息循环”的代码，用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。</p>
		<p>
				<img height="211" alt="o_windowsmessage2.jpg" src="http://www.cppblog.com/images/cppblog_com/mzty/2021/o_windowsmessage2.jpg" width="450" border="0" />
				<br />
				<br />二 Windows为当前执行的每个Windows程序维护一个「消息队列」。在发生输入事件之后，Windows将事件转换为一个「消息」并将消息放入程序的消息队列中。程序通过执行一块称之为「消息循环」的程序代码从消息队列中取出消息：<br />while(GetMessage (&amp;msg, NULL, 0, 0))        <br />{        <br />    TranslateMessage (&amp;msg) ;        <br />    DispatchMessage (&amp;msg) ;        <br />}</p>
		<p>msg变量是型态为MSG的结构，型态MSG在WINUSER.H中定义如下：<br />typedef struct tagMSG        <br />{        <br />    HWND   hwnd ;        <br />    UINT   message ;        <br />    WPARAM wParam ;        <br />    LPARAM lParam ;        <br />    DWORD  time ;        <br />    POINT  pt ;        <br />}        <br />MSG, * PMSG ;<br />      <br />POINT数据型态也是一个结构，它在WINDEF.H中定义如下：<br />typedef struct tagPOINT        <br />{        <br />    LONG  x ;        <br />    LONG  y ;        <br />}        <br />POINT, * PPOINT;<br />TranslateMessage(&amp;msg); 将msg结构传给Windows，进行一些键盘转换。（关于这一点，我们将在第六章中深入讨论。）<br />DispatchMessage(&amp;msg);又将msg结构回传给Windows。然后，Windows将该消息发送给适当的窗口消息处理程序，让它进行处理。这也就是说，Windows将呼叫窗口消息处理程序。在HELLOWIN中，这个窗口消息处理程序就是WndProc函数。处理完消息之后，WndProc传回到Windows。此时，Windows还停留在DispatchMessage呼叫中。在结束DispatchMessage呼叫的处理之后，Windows回到HELLOWIN程序中，并且接着从下一个GetMessage呼叫开始消息循环。<br />        <br />三 队列化消息与非队列化消息<br />    <br />消息能够被分为「队列化的」和「非队列化的」。队列化的消息是由Windows放入程序消息队列中的。在程序的消息循环中，重新传回并分配给窗口消息处理程序。非队列化的消息在Windows呼叫窗口时直接送给窗口消息处理程序。也就是说，队列化的消息被「发送」给消息队列，而非队列化的消息则「发送」给窗口消息处理程序。任何情况下，窗口消息处理程序都将获得窗口所有的消息--包括队列化的和非队列化的。窗口消息处理程序是窗口的「消息中心」。</p>
		<p>队列化消息基本上是使用者输入的结果，以击键（如WM_KEYDOWN和WM_KEYUP消息）、击键产生的字符（WM_CHAR）、鼠标移动（WM_MOUSEMOVE）和鼠标按钮（WM_LBUTTONDOWN）的形式给出。队列化消息还包含时钟消息（WM_TIMER）、更新消息（WM_PAINT）和退出消息（WM_QUIT）。</p>
		<p>非队列化消息则是其它消息。在许多情况下，非队列化消息来自呼叫特定的Windows函数。例如，当WinMain呼叫CreateWindow时，Windows将建立窗口并在处理中给窗口消息处理程序发送一个WM_CREATE消息。当WinMain呼叫ShowWindow时，Windows将给窗口消息处理程序发送WM_SIZE和WM_SHOWWINDOW消息。当WinMain呼叫UpdateWindow时，Windows将给窗口消息处理程序发送WM_PAINT消息。键盘或鼠标输入时发出的队列化消息信号，也能在非队列化消息中出现。例如，用键盘或鼠标选择了一个菜单项时，键盘或鼠标消息就是队列化的，而说明菜单项已选中的WM_COMMAND消息则可能就是非队列化的。</p>
		<p>四 SendMessage()与PostMessage()之间的区别是什么？<br />它们两者是用于向应用程序发送消息的。PostMessagex()将消息直接加入到应用程序的消息队列中，不等程序返回就退出；而SendMessage()则刚好相反，应用程序处理完此消息后，它才返回。我想下图能够比较好的体现这两个函数的关系：<br /><br /><img height="407" alt="o_postmessage.gif" src="http://www.cppblog.com/images/cppblog_com/mzty/2021/o_postmessage.gif" width="609" border="0" /></p>
		<p>
				<br />五 函数peekmessage和getmessage的区别？</p>
		<p>两个函数主要有以下两个区别:<br />1.GetMessage将等到有合适的消息时才返回,而PeekMessage只是撇一下消息队列。<br />2.GetMessage会将消息从队列中删除,而PeekMessage可以设置最后一个参数wRemoveMsg来决定是否将消息保留在队列中。<br /></p>
<img src ="http://www.cppblog.com/mzty/aggbug/15619.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-11-24 13:08 <a href="http://www.cppblog.com/mzty/archive/2006/11/24/15619.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows消息大全 </title><link>http://www.cppblog.com/mzty/archive/2006/11/24/15618.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 24 Nov 2006 05:00:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/11/24/15618.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/15618.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/11/24/15618.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/15618.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/15618.html</trackback:ping><description><![CDATA[
		<p style="MARGIN: 8px; LINE-HEIGHT: 150%">
		</p>
		<table style="FLOAT: right; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
						</tr>
				</tbody>
		</table>消息，就是指Windows发出的一个通知，告诉应用程序某个事情发生了。例如，单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。消息本身是作为一个记录传递给应用程序的，这个记录中包含了消息的类型以及其他信息。例如，对于单击鼠标所产生的消息来说，这个记录中包含了单击鼠标时的坐标。这个记录类型叫做TMsg， 
<p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%"></p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">它在Windows单元中是这样声明的： 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">type 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">TMsg = packed record 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">hwnd: HWND; / /窗口句柄 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">message: UINT; / /消息常量标识符 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">wParam: WPARAM ; // 32位消息的特定附加信息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">lParam: LPARAM ; // 32位消息的特定附加信息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">time: DWORD; / /消息创建时的时间 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">pt: TPoint; / /消息创建时的鼠标位置 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">end; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%"></p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">消息中有什么？ 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">是否觉得一个消息记录中的信息像希腊语一样？如果是这样，那么看一看下面的解释： 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">hwnd 32位的窗口句柄。窗口可以是任何类型的屏幕对象，因为Win32能够维护大多数可视对象的句柄(窗口、对话框、按钮、编辑框等)。 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">message 用于区别其他消息的常量值，这些常量可以是Windows单元中预定义的常量，也可以是自定义的常量。 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">wParam 通常是一个与消息有关的常量值，也可能是窗口或控件的句柄。 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">lParam 通常是一个指向内存中数据的指针。由于W P a r a m、l P a r a m和P o i n t e r都是3 2位的， 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">因此，它们之间可以相互转换。 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%"></p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NULL = $0000; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CREATE = $0001; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序创建一个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DESTROY = $0002; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个窗口被销毁 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOVE = $0003; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">移动一个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SIZE = $0005; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">改变一个窗口的大小 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ACTIVATE = $0006; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个窗口被激活或失去激活状态； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SETFOCUS = $0007; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">获得焦点后 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_KILLFOCUS = $0008; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">失去焦点 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ENABLE = $000A; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">改变enable状态 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SETREDRAW = $000B; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">设置窗口是否能重画 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SETTEXT = $000C; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息来设置一个窗口的文本 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETTEXT = $000D; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息来复制对应窗口的文本到缓冲区 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETTEXTLENGTH = $000E; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">得到与一个窗口有关的文本的长度（不包含空字符） 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PAINT = $000F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">要求一个窗口重画自己 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CLOSE = $0010; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个窗口或应用程序要关闭时发送一个信号 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_QUERYENDSESSION = $0011; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户选择结束对话框或程序自己调用ExitWindows函数 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_QUIT = $0012; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">用来结束程序运行或当程序调用postquitmessage函数 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_QUERYOPEN = $0013; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户窗口恢复以前的大小位置时，把此消息发送给某个图标 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ERASEBKGND = $0014; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当窗口背景必须被擦除时（例在窗口改变大小时） 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SYSCOLORCHANGE = $0015; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当系统颜色改变时，发送此消息给所有顶级窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ENDSESSION = $0016; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当系统进程发出WM_QUERYENDSESSION消息后，此消息发送给应用程序， 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">通知它对话是否结束 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SYSTEMERROR = $0017; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SHOWWINDOW = $0018; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当隐藏或显示窗口是发送此消息给这个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ACTIVATEAPP = $001C; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发此消息给应用程序哪个窗口是激活的，哪个是非激活的； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_FONTCHANGE = $001D; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当系统的字体资源库变化时发送此消息给所有顶级窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_TIMECHANGE = $001E; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当系统的时间变化时发送此消息给所有顶级窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CANCELMODE = $001F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息来取消某种正在进行的摸态（操作） 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SETCURSOR = $0020; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">如果鼠标引起光标在某个窗口中移动且鼠标输入没有被捕获时，就发消息给某个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOUSEACTIVATE = $0021; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当光标在某个非激活的窗口中而用户正按着鼠标的某个键发送此消息给当前窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CHILDACTIVATE = $0022; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息给MDI子窗口当用户点击此窗口的标题栏，或当窗口被激活，移动，改变大小 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_QUEUESYNC = $0023; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息由基于计算机的训练程序发送，通过WH_JOURNALPALYBACK的hook程序 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">分离出用户输入消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETMINMAXINFO = $0024; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息发送给窗口当它将要改变大小或位置； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PAINTICON = $0026; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送给最小化窗口当它图标将要被重画 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ICONERASEBKGND = $0027; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息发送给某个最小化窗口，仅当它在画图标前它的背景必须被重画 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NEXTDLGCTL = $0028; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息给一个对话框程序去更改焦点位置 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SPOOLERSTATUS = $002A; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">每当打印管理列队增加或减少一条作业时发出此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DRAWITEM = $002B; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当button，combobox，listbox，menu的可视外观改变时发送 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息给这些空件的所有者 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MEASUREITEM = $002C; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当button, combo box, list box, list view control, or menu item 被创建时 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息给控件的所有者 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DELETEITEM = $002D; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当the list box 或 combo box 被销毁 或 当 某些项被删除通过LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_VKEYTOITEM = $002E; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息有一个LBS_WANTKEYBOARDINPUT风格的发出给它的所有者来响应WM_KEYDOWN消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CHARTOITEM = $002F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息由一个LBS_WANTKEYBOARDINPUT风格的列表框发送给他的所有者来响应WM_CHAR消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SETFONT = $0030; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当绘制文本时程序发送此消息得到控件要用的颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETFONT = $0031; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息得到当前控件绘制文本的字体 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SETHOTKEY = $0032; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息让一个窗口与一个热键相关连 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETHOTKEY = $0033; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息来判断热键与某个窗口是否有关联 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_QUERYDRAGICON = $0037; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息发送给最小化窗口，当此窗口将要被拖放而它的类中没有定义图标，应用程序能返回一个图标或光标的句柄，当用户拖放图标时系统显示这个图标或光标 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_COMPAREITEM = $0039; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息来判定combobox或listbox新增加的项的相对位置 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETOBJECT = $003D; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_COMPACTING = $0041; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">显示内存已经很少了 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_WINDOWPOSCHANGING = $0046; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息给那个窗口的大小和位置将要被改变时，来调用setwindowpos函数或其它窗口管理函数 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_WINDOWPOSCHANGED = $0047; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息给那个窗口的大小和位置已经被改变时，来调用setwindowpos函数或其它窗口管理函数 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_POWER = $0048;（适用于16位的windows） 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当系统将要进入暂停状态时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_COPYDATA = $004A; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个应用程序传递数据给另一个应用程序时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CANCELJOURNAL = $004B; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当某个用户取消程序日志激活状态，提交此消息给程序 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NOTIFY = $004E; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当某个控件的某个事件已经发生或这个控件需要得到一些信息时，发送此消息给它的父窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_INPUTLANGCHANGEREQUEST = $0050; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户选择某种输入语言，或输入语言的热键改变 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_INPUTLANGCHANGE = $0051; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当平台现场已经被改变后发送此消息给受影响的最顶级窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_TCARD = $0052; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当程序已经初始化windows帮助例程时发送此消息给应用程序 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_HELP = $0053; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息显示用户按下了F1，如果某个菜单是激活的，就发送此消息个此窗口关联的菜单，否则就 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送给有焦点的窗口，如果当前都没有焦点，就把此消息发送给当前激活的窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_USERCHANGED = $0054; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户已经登入或退出后发送此消息给所有的窗口，当用户登入或退出时系统更新用户的具体 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">设置信息，在用户更新设置时系统马上发送此消息； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NOTIFYFORMAT = $0055; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">公用控件，自定义控件和他们的父窗口通过此消息来判断控件是使用ANSI还是UNICODE结构 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">在WM_NOTIFY消息，使用此控件能使某个控件与它的父控件之间进行相互通信 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CONTEXTMENU = $007B; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户某个窗口中点击了一下右键就发送此消息给这个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_STYLECHANGING = $007C; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当调用SETWINDOWLONG函数将要改变一个或多个 窗口的风格时发送此消息给那个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_STYLECHANGED = $007D; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当调用SETWINDOWLONG函数一个或多个 窗口的风格后发送此消息给那个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DISPLAYCHANGE = $007E; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当显示器的分辨率改变后发送此消息给所有的窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETICON = $007F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息发送给某个窗口来返回与某个窗口有关连的大图标或小图标的句柄； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SETICON = $0080; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息让一个新的大图标或小图标与某个窗口关联； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCCREATE = $0081; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当某个窗口第一次被创建时，此消息在WM_CREATE消息发送前发送； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCDESTROY = $0082; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息通知某个窗口，非客户区正在销毁 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCCALCSIZE = $0083; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当某个窗口的客户区域必须被核算时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCHITTEST = $0084;//移动鼠标，按住或释放鼠标时发生 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCPAINT = $0085; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息给某个窗口当它（窗口）的框架必须被绘制时； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCACTIVATE = $0086; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息发送给某个窗口 仅当它的非客户区需要被改变来显示是激活还是非激活状态； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_GETDLGCODE = $0087; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息给某个与对话框程序关联的控件，widdows控制方位键和TAB键使输入进入此控件 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">通过响应WM_GETDLGCODE消息，应用程序可以把他当成一个特殊的输入控件并能处理它 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCMOUSEMOVE = $00A0; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当光标在一个窗口的非客户区内移动时发送此消息给这个窗口 //非客户区为：窗体的标题栏及窗 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">的边框体 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCLBUTTONDOWN = $00A1; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当光标在一个窗口的非客户区同时按下鼠标左键时提交此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCLBUTTONUP = $00A2; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户释放鼠标左键同时光标某个窗口在非客户区十发送此消息； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCLBUTTONDBLCLK = $00A3; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户双击鼠标左键同时光标某个窗口在非客户区十发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCRBUTTONDOWN = $00A4; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户按下鼠标右键同时光标又在窗口的非客户区时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCRBUTTONUP = $00A5; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户释放鼠标右键同时光标又在窗口的非客户区时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCRBUTTONDBLCLK = $00A6; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户双击鼠标右键同时光标某个窗口在非客户区十发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCMBUTTONDOWN = $00A7; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户按下鼠标中键同时光标又在窗口的非客户区时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCMBUTTONUP = $00A8; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户释放鼠标中键同时光标又在窗口的非客户区时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NCMBUTTONDBLCLK = $00A9; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户双击鼠标中键同时光标又在窗口的非客户区时发送此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_KEYFIRST = $0100; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_KEYDOWN = $0100; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//按下一个键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_KEYUP = $0101; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//释放一个键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CHAR = $0102; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//按下某键，并已发出WM_KEYDOWN， WM_KEYUP消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DEADCHAR = $0103; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用translatemessage函数翻译WM_KEYUP消息时发送此消息给拥有焦点的窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SYSKEYDOWN = $0104; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户按住ALT键同时按下其它键时提交此消息给拥有焦点的窗口； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SYSKEYUP = $0105; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户释放一个键同时ALT 键还按着时提交此消息给拥有焦点的窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SYSCHAR = $0106; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函数翻译后提交此消息给拥有焦点的窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SYSDEADCHAR = $0107; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函数翻译后发送此消息给拥有焦点的窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_KEYLAST = $0108; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_INITDIALOG = $0110; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">在一个对话框程序被显示前发送此消息给它，通常用此消息初始化控件和执行其它任务 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_COMMAND = $0111; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户选择一条菜单命令项或当某个控件发送一条消息给它的父窗口，一个快捷键被翻译 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SYSCOMMAND = $0112; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户选择窗口菜单的一条命令或当用户选择最大化或最小化时那个窗口会收到此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_TIMER = $0113; //发生了定时器事件 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_HSCROLL = $0114; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个窗口标准水平滚动条产生一个滚动事件时发送此消息给那个窗口，也发送给拥有它的控件 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_VSCROLL = $0115; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个窗口标准垂直滚动条产生一个滚动事件时发送此消息给那个窗口也，发送给拥有它的控件 WM_INITMENU = $0116; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个菜单将要被激活时发送此消息，它发生在用户菜单条中的某项或按下某个菜单键，它允许程序在显示前更改菜单 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_INITMENUPOPUP = $0117; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个下拉菜单或子菜单将要被激活时发送此消息，它允许程序在它显示前更改菜单，而不要改变全部 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MENUSELECT = $011F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户选择一条菜单项时发送此消息给菜单的所有者（一般是窗口） 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MENUCHAR = $0120; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当菜单已被激活用户按下了某个键（不同于加速键），发送此消息给菜单的所有者； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ENTERIDLE = $0121; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个模态对话框或菜单进入空载状态时发送此消息给它的所有者，一个模态对话框或菜单进入空载状态就是在处理完一条或几条先前的消息后没有消息它的列队中等待 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MENURBUTTONUP = $0122; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MENUDRAG = $0123; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MENUGETOBJECT = $0124; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_UNINITMENUPOPUP = $0125; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MENUCOMMAND = $0126; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CHANGEUISTATE = $0127; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_UPDATEUISTATE = $0128; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_QUERYUISTATE = $0129; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CTLCOLORMSGBOX = $0132; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">在windows绘制消息框前发送此消息给消息框的所有者窗口，通过响应这条消息，所有者窗口可以通过使用给定的相关显示设备的句柄来设置消息框的文本和背景颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CTLCOLOREDIT = $0133; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个编辑型控件将要被绘制时发送此消息给它的父窗口；通过响应这条消息，所有者窗口可以通过使用给定的相关显示设备的句柄来设置编辑框的文本和背景颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CTLCOLORLISTBOX = $0134; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个列表框控件将要被绘制前发送此消息给它的父窗口；通过响应这条消息，所有者窗口可以通过使用给定的相关显示设备的句柄来设置列表框的文本和背景颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CTLCOLORBTN = $0135; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个按钮控件将要被绘制时发送此消息给它的父窗口；通过响应这条消息，所有者窗口可以通过使用给定的相关显示设备的句柄来设置按纽的文本和背景颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CTLCOLORDLG = $0136; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个对话框控件将要被绘制前发送此消息给它的父窗口；通过响应这条消息，所有者窗口可以通过使用给定的相关显示设备的句柄来设置对话框的文本背景颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CTLCOLORSCROLLBAR= $0137; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个滚动条控件将要被绘制时发送此消息给它的父窗口；通过响应这条消息，所有者窗口可以通过使用给定的相关显示设备的句柄来设置滚动条的背景颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CTLCOLORSTATIC = $0138; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个静态控件将要被绘制时发送此消息给它的父窗口；通过响应这条消息，所有者窗口可以通过使用给定的相关显示设备的句柄来设置静态控件的文本和背景颜色 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOUSEFIRST = $0200; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOUSEMOVE = $0200; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">// 移动鼠标 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_LBUTTONDOWN = $0201; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//按下鼠标左键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_LBUTTONUP = $0202; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//释放鼠标左键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_LBUTTONDBLCLK = $0203; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//双击鼠标左键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_RBUTTONDOWN = $0204; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//按下鼠标右键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_RBUTTONUP = $0205; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//释放鼠标右键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_RBUTTONDBLCLK = $0206; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//双击鼠标右键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MBUTTONDOWN = $0207; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//按下鼠标中键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MBUTTONUP = $0208; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//释放鼠标中键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MBUTTONDBLCLK = $0209; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">//双击鼠标中键 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOUSEWHEEL = $020A; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当鼠标轮子转动时发送此消息个当前有焦点的控件 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOUSELAST = $020A; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PARENTNOTIFY = $0210; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当MDI子窗口被创建或被销毁，或用户按了一下鼠标键而光标在子窗口上时发送此消息给它的父窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ENTERMENULOOP = $0211; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息通知应用程序的主窗口that已经进入了菜单循环模式 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_EXITMENULOOP = $0212; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息通知应用程序的主窗口that已退出了菜单循环模式 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_NEXTMENU = $0213; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SIZING = 532; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户正在调整窗口大小时发送此消息给窗口；通过此消息应用程序可以监视窗口大小和位置也可以修改他们 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CAPTURECHANGED = 533; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">发送此消息 给窗口当它失去捕获的鼠标时； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOVING = 534; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户在移动窗口时发送此消息，通过此消息应用程序可以监视窗口大小和位置也可以修改他们； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_POWERBROADCAST = 536; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息发送给应用程序来通知它有关电源管理事件； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DEVICECHANGE = 537; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当设备的硬件配置改变时发送此消息给应用程序或设备驱动程序 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_STARTCOMPOSITION = $010D; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_ENDCOMPOSITION = $010E; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_COMPOSITION = $010F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_KEYLAST = $010F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_SETCONTEXT = $0281; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_NOTIFY = $0282; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_CONTROL = $0283; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_COMPOSITIONFULL = $0284; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_SELECT = $0285; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_CHAR = $0286; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_REQUEST = $0288; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_KEYDOWN = $0290; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_IME_KEYUP = $0291; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDICREATE = $0220; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息给多文档的客户窗口来创建一个MDI 子窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDIDESTROY = $0221; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息给多文档的客户窗口来关闭一个MDI 子窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDIACTIVATE = $0222; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息给多文档的客户窗口通知客户窗口激活另一个MDI子窗口，当客户窗口收到此消息后，它发出WM_MDIACTIVE消息给MDI子窗口（未激活）激活它； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDIRESTORE = $0223; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序 发送此消息给MDI客户窗口让子窗口从最大最小化恢复到原来大小 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDINEXT = $0224; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序 发送此消息给MDI客户窗口激活下一个或前一个窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDIMAXIMIZE = $0225; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息给MDI客户窗口来最大化一个MDI子窗口； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDITILE = $0226; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序 发送此消息给MDI客户窗口以平铺方式重新排列所有MDI子窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDICASCADE = $0227; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序 发送此消息给MDI客户窗口以层叠方式重新排列所有MDI子窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDIICONARRANGE = $0228; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序 发送此消息给MDI客户窗口重新排列所有最小化的MDI子窗口 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDIGETACTIVE = $0229; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序 发送此消息给MDI客户窗口来找到激活的子窗口的句柄 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDISETMENU = $0230; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序 发送此消息给MDI客户窗口用MDI菜单代替子窗口的菜单 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ENTERSIZEMOVE = $0231; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_EXITSIZEMOVE = $0232; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DROPFILES = $0233; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MDIREFRESHMENU = $0234; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOUSEHOVER = $02A1; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_MOUSELEAVE = $02A3; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CUT = $0300; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息给一个编辑框或combobox来删除当前选择的文本 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_COPY = $0301; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息给一个编辑框或combobox来复制当前选择的文本到剪贴板 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PASTE = $0302; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息给editcontrol或combobox从剪贴板中得到数据 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CLEAR = $0303; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息给editcontrol或combobox清除当前选择的内容； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_UNDO = $0304; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">程序发送此消息给editcontrol或combobox撤消最后一次操作 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_RENDERFORMAT = $0305； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%"></p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_RENDERALLFORMATS = $0306; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DESTROYCLIPBOARD = $0307; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当调用ENPTYCLIPBOARD函数时 发送此消息给剪贴板的所有者 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DRAWCLIPBOARD = $0308; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当剪贴板的内容变化时发送此消息给剪贴板观察链的第一个窗口；它允许用剪贴板观察窗口来 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">显示剪贴板的新内容； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PAINTCLIPBOARD = $0309; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区需要重画； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_VSCROLLCLIPBOARD = $030A; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_SIZECLIPBOARD = $030B; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区域的大小已经改变是此消息通过剪贴板观察窗口发送给剪贴板的所有者； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_ASKCBFORMATNAME = $030C; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">通过剪贴板观察窗口发送此消息给剪贴板的所有者来请求一个CF_OWNERDISPLAY格式的剪贴板的名字 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_CHANGECBCHAIN = $030D; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个窗口从剪贴板观察链中移去时发送此消息给剪贴板观察链的第一个窗口； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_HSCROLLCLIPBOARD = $030E; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息通过一个剪贴板观察窗口发送给剪贴板的所有者 ；它发生在当剪贴板包含CFOWNERDISPALY格式的数据并且有个事件在剪贴板观察窗的水平滚动条上；所有者应滚动剪贴板图象并更新滚动条的值； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_QUERYNEWPALETTE = $030F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息发送给将要收到焦点的窗口，此消息能使窗口在收到焦点时同时有机会实现他的逻辑调色板 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PALETTEISCHANGING= $0310; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当一个应用程序正要实现它的逻辑调色板时发此消息通知所有的应用程序 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PALETTECHANGED = $0311; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息在一个拥有焦点的窗口实现它的逻辑调色板后发送此消息给所有顶级并重叠的窗口，以此来改变系统调色板 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_HOTKEY = $0312; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">当用户按下由REGISTERHOTKEY函数注册的热键时提交此消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PRINT = 791; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">应用程序发送此消息仅当WINDOWS或其它应用程序发出一个请求要求绘制一个应用程序的一部分； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PRINTCLIENT = 792; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_HANDHELDFIRST = 856; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_HANDHELDLAST = 863; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PENWINFIRST = $0380; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_PENWINLAST = $038F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_COALESCE_FIRST = $0390; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_COALESCE_LAST = $039F; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_FIRST = $03E0; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_INITIATE = WM_DDE_FIRST + 0; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE客户程序提交此消息开始一个与服务器程序的会话来响应那个指定的程序和主题名； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_TERMINATE = WM_DDE_FIRST + 1; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE应用程序（无论是客户还是服务器）提交此消息来终止一个会话； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_ADVISE = WM_DDE_FIRST + 2; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE客户程序提交此消息给一个DDE服务程序来请求服务器每当数据项改变时更新它 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_UNADVISE = WM_DDE_FIRST + 3; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE客户程序通过此消息通知一个DDE服务程序不更新指定的项或一个特殊的剪贴板格式的项 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_ACK = WM_DDE_FIRST + 4; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息通知一个DDE（动态数据交换）程序已收到并正在处理WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_DATA, WM_DDE_ADVISE, WM_DDE_UNADVISE, or WM_DDE_INITIAT消息 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_DATA = WM_DDE_FIRST + 5; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE服务程序提交此消息给DDE客户程序来传递个一数据项给客户或通知客户的一条可用数据项 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_REQUEST = WM_DDE_FIRST + 6; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE客户程序提交此消息给一个DDE服务程序来请求一个数据项的值； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_POKE = WM_DDE_FIRST + 7; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE客户程序提交此消息给一个DDE服务程序，客户使用此消息来请求服务器接收一个未经同意的数据项；服务器通过答复WM_DDE_ACK消息提示是否它接收这个数据项； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_EXECUTE = WM_DDE_FIRST + 8; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">一个DDE客户程序提交此消息给一个DDE服务程序来发送一个字符串给服务器让它象串行命令一样被处理，服务器通过提交WM_DDE_ACK消息来作回应； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_DDE_LAST = WM_DDE_FIRST + 8; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_APP = $8000; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">WM_USER = $0400; 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">此消息能帮助应用程序自定义私有消息； 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">///////////////////////////////////////////////////////////////////// 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">通知消息(Notification message)是指这样一种消息，一个窗口内的子控件发生了一些事情，需要通知父窗口。通知消息只适用于标准的窗口控件如按钮、列表框、组合框、编辑框，以及Windows 95公共控件如树状视图、列表视图等。例如，单击或双击一个控件、在控件中选择部分文本、操作控件的滚动条都会产生通知消息。 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">按扭 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">B N _ C L I C K E D //用户单击了按钮 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">B N _ D I S A B L E //按钮被禁止 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">B N _ D O U B L E C L I C K E D //用户双击了按钮 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">B N _ H I L I T E //用户加亮了按钮 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">B N _ PA I N T按钮应当重画 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">B N _ U N H I L I T E加亮应当去掉 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">组合框 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ C L O S E U P组合框的列表框被关闭 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ D B L C L K用户双击了一个字符串 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ D R O P D O W N组合框的列表框被拉出 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ E D I T C H A N G E用户修改了编辑框中的文本 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ E D I T U P D AT E编辑框内的文本即将更新 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ E R R S PA C E组合框内存不足 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ K I L L F O C U S组合框失去输入焦点 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ S E L C H A N G E在组合框中选择了一项 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ S E L E N D C A N C E L用户的选择应当被取消 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ S E L E N D O K用户的选择是合法的 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">C B N _ S E T F O C U S组合框获得输入焦点 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">编辑框 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ C H A N G E编辑框中的文本己更新 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ E R R S PA C E编辑框内存不足 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ H S C R O L L用户点击了水平滚动条 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ K I L L F O C U S编辑框正在失去输入焦点 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ M A X T E X T插入的内容被截断 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ S E T F O C U S编辑框获得输入焦点 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ U P D AT E编辑框中的文本将要更新 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">E N _ V S C R O L L用户点击了垂直滚动条消息含义 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">列表框 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">L B N _ D B L C L K用户双击了一项 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">L B N _ E R R S PA C E列表框内存不够 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">L B N _ K I L L F O C U S列表框正在失去输入焦点 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">L B N _ S E L C A N C E L选择被取消 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">L B N _ S E L C H A N G E选择了另一项 
</p><p style="MARGIN: 5px; TEXT-INDENT: 26px; LINE-HEIGHT: 150%">L B N _ S E T F O C U S列表框获得输入焦点 </p><img src ="http://www.cppblog.com/mzty/aggbug/15618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-11-24 13:00 <a href="http://www.cppblog.com/mzty/archive/2006/11/24/15618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《windows核心编程》之精华</title><link>http://www.cppblog.com/mzty/archive/2006/09/25/12952.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Mon, 25 Sep 2006 10:23:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/25/12952.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12952.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/25/12952.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12952.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12952.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">学习《</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">核心编程》<br /><br /></span>
				<span lang="EN-US">
						<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>
						<o:p>        －－如果发现有什么理解的不正确的，欢迎指出，共同学习，共同进步哦！</o:p>
				</span>
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
				</span>
		</p>
		<span lang="EN-US">
				<o:p> </o:p>
		</span>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">字符集，一切软件的基础，单字集（用</span>
				<span lang="EN-US">1</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个字节表示一个字符），双字节字符集（</span>
				<span lang="EN-US">DBCS，</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">并不是用</span>
				<span lang="EN-US">2</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个字节表示一个字符哦，而是用</span>
				<span lang="EN-US">1</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个，</span>
				<span lang="EN-US">2</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个，或多个字节的混合来表示字符），宽字节字符集（</span>
				<span lang="EN-US">unicode</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用</span>
				<span lang="EN-US">2</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个字节来表示一个字符）。对</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">操作系统来说，</span>
				<span lang="EN-US">windows 98</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">内核用</span>
				<span lang="EN-US">ANSI</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span>
				<span lang="EN-US">windows ME </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用</span>
				<span lang="EN-US">unicode</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span>
				<span lang="EN-US">windows 2000</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以后的版本也用</span>
				<span lang="EN-US">unicode</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，对于我们在</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">上开发，</span>
				<span lang="EN-US">windows2000</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以后的版本，我们即可以开发</span>
				<span lang="EN-US">ANSI</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">版本，也可以开发</span>
				<span lang="EN-US">unicode</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">版本，他们都能够很好的运行，但是重效率和软件的国际化来看的化，最后使用</span>
				<span lang="EN-US">unicode</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行编码。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">内核对象，被系统和应用程序用来管理各种资源，我们可以使用</span>
				<span lang="EN-US">API</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来管理和使用内核对象，但是不能直接修改内核对象的数据结构，内核对象由内核所拥有，内核知道某个内核对象有没有被使用等，内核对象被广泛的使用在进程，线程。。。中用来管理。（内核即操作系统的本质，核心所在，进行系统的管理）</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进程，包含用来管理进程的内核对象和用来加载</span>
				<span lang="EN-US">exe</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和数据等的地址空间。当一个</span>
				<span lang="EN-US">exe</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开始运行时，它即对应一个进程，</span>
				<span lang="EN-US">exe</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">main</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（）也即是进程入口函数，但是在进入</span>
				<span lang="EN-US">main</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（）之前还有</span>
				<span lang="EN-US">c</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span>
				<span lang="EN-US">c</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">＋＋运行库的初始化。当创建一个进程时，就产生了一个唯一的实例句柄，它就是</span>
				<span lang="EN-US">winmain</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（）函数中要传入的实例句柄，另外在主进程（可没有非主进程的啊，但也可以认为主进程的子进程是非主进程，因为系统不保存父子进程的关系，他们可以看作是相互独立的）中可以创建它的子进程，用来对多个需要共同管理的线程进行管理。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作业，作业是进程的容器，可以统一地对一组进程增加一些额外的限制。有时候建立单个进程的作业也是有意义的，因为可以对单一进程施加一些进程本身所没有的属性。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">线程，线程在进程中被创建，在创建进程时，默认的主线程即被创建。操作系统是用线程来完成任务的，因为进程不直接获得操作系统的时间，线程可以认为是操作系统的最小的处理单位。在多线程编程中，首先要注意的就是线程的同步问题，还有线程池的使用。且最好不要使用全局或静态变量。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">纤程，比线程更小的单位，纤程是用户对线程进行分割，然后自定义算法实行对纤程的调用，系统的内核并不知道线程。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span lang="EN-US">Windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">内存结构，每个进程都有它自己的虚拟内存，</span>
				<span lang="EN-US">32</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">位机，虚拟内存位</span>
				<span lang="EN-US">4G</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，但是这</span>
				<span lang="EN-US">4G</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">并不都可以被用户使用，它包含</span>
				<span lang="EN-US">NULL</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">指针，</span>
				<span lang="EN-US">dos</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">兼容区，文件映射区，系统核心区，能被用户使用的只有</span>
				<span lang="EN-US">2G</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。当然现在</span>
				<span lang="EN-US">64</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">位的机子可不是</span>
				<span lang="EN-US">2G</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">哦。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">虚拟内存，</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行内存管理的方法之一，最适合用来管理大型对象和结构数组，也即相当于</span>
				<span lang="EN-US">RAM</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（即物理内存）的二级缓存，系统先到</span>
				<span lang="EN-US">RAM</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">找，如找不到就到虚拟内存（页文件）找，找到了就加载到</span>
				<span lang="EN-US">RAM</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中，然后执行。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-size: 10.5pt; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">内存映射文件，</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的第二中内存管理方法，最适合用来管理大型数据流和单机上的数据共享。</span>
				<span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: Arial">与虚拟内存一样，内存映射文件可以用来保留一个地址空间的区域，并将物理存储器提交给该区域。它们之间的差别是，物理存储器来自一个已经位于磁盘上的文件，而不是系统的页文件。一旦该文件被映射，就可以访问它，就像整个文件已经加载内存一样。系统还使用内存映射文件，以便加载和执行</span>
				<span lang="EN-US" style="COLOR: black; FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">. e x e</span>
				<span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: Arial">和</span>
				<span lang="EN-US" style="COLOR: black; FONT-FAMILY: Arial; mso-bidi-font-size: 10.5pt">D L L</span>
				<span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: Arial">文件。</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-size: 10.5pt; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">u<span style="FONT: 7pt 'Times New Roman'">       </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 10.5pt">堆栈，</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 10.5pt">的第三中内存管理方法，最适合管理大量的小对象，例如链表等，线程，进程都有自己的堆栈，默认的大小位</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">1M</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 10.5pt">，也可以修改。<br /><br /><br />最后是DLL高级和SEH的使用。<br /><br /></span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">主要参考：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">《</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">核心编程》</span>
				<span lang="EN-US">
						<span style="mso-spacerun: yes">  </span>
						<span style="mso-tab-count: 1">    </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">机械工业出版社</span>
				<span lang="EN-US">
						<span style="mso-spacerun: yes">  </span>jeffrey richter</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">著</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">《</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">系统编程》</span>
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">人民邮电出版社</span>
				<span lang="EN-US">
						<span style="mso-spacerun: yes">  </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">求是科技</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">《</span>
				<span lang="EN-US">windows2000</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">编程技术内幕》</span>
				<span lang="EN-US">
						<span style="mso-spacerun: yes">   </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">机械工业出版社</span>
		</p>
<img src ="http://www.cppblog.com/mzty/aggbug/12952.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-25 18:23 <a href="http://www.cppblog.com/mzty/archive/2006/09/25/12952.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程－－SEH（结构异常处理）</title><link>http://www.cppblog.com/mzty/archive/2006/09/22/12824.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 22 Sep 2006 06:52:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/22/12824.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12824.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/22/12824.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12824.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12824.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 主要参考：http://blog.csdn.net/hbrr224/archive/2006/05.aspxSEH 的工作原理。         Windows 程序设计中最重要的理念就是消息传递，事件驱动。当GUI应用程序触发一个消息时，系统将把该消息放入消息队列，然后去查找并调用窗体的消息处理函数(CALLBACK)，传递的参数当然就是这个消息。我们同样可以把异常也当作是一种消息，应用程序发生...&nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2006/09/22/12824.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/12824.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-22 14:52 <a href="http://www.cppblog.com/mzty/archive/2006/09/22/12824.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程－－DLL高级</title><link>http://www.cppblog.com/mzty/archive/2006/09/22/12823.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 22 Sep 2006 06:11:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/22/12823.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12823.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/22/12823.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12823.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12823.html</trackback:ping><description><![CDATA[
		<p>
				<strong>
						<font face="Arial" color="#0000ff">DLL的进入点函数</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">一个D L L可以拥有单个进入点函数。系统在不同的时间调用这个进入点函数，这个问题将在下面加以介绍。这些调用可以用来提供一些信息，通常用于供D L L进行每个进程或线程的初始化和清除操作。如果你的D L L不需要这些通知信息，就不必在D L L源代码中实现这个函数。例如，如果你创建一个只包含资源的D L L，就不必实现该函数。如果确实需要在D L L中接受通知信息，可以实现类似下面的进入点函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad)
{
   switch(fdwReason) 
   {
      case DLL_PROCESS_ATTACH:
         //The DLL is being mapped into the process's address space.
         break;

      case DLL_THREAD_ATTACH:
         //A thread is being created.
         break;

      case DLL_THREAD_DETACH:
         //A thread is exiting cleanly.
         break;

      case DLL_PROCESS_DETACH:
         //The DLL is being unmapped from the process's address space.
         break;
   }
   return(TRUE);  // Used only for DLL_PROCESS_ATTACH
}</pre>
		</div>
		<p>
				<font face="Arial" size="2">注意函数名D l l M a i n是区分大小写的。</font>
		</p>
		<p>
				<font size="2">
						<font face="Arial">
								<font style="LINE-HEIGHT: 25px" color="#000000">参数h i n s t D l l包含了D L L的实例句柄。与( w ) Wi n M a i n函数的h i n s t E x e参数一样，这个值用于标识D L L的文件映像被映射到进程的地址空间中的虚拟内存地址。通常应将这个参数保存在一个全局变量中，这样就可以在调用加载资源的函数（如D i a l o g B o x和L o a d S t r i n g）时使用它。最后一个参数是f I m p L o a d，如果D L L是隐含加载的，那么该参数将是个非0值，如果D L L是显式加载的，那么它的值是0。</font>
						</font>
				</font>
		</p>
		<p>
				<font size="2">
						<font face="Arial">
								<font style="LINE-HEIGHT: 25px" color="#000000">参数f d w R e a s o n用于指明系统为什么调用该函数。该参数可以使用4个值中的一个。这4个值是： D L L _ P R O C E S S _ AT TA C H、D L L _ P R O C E S S _ D E TA C H、D L L _ T H R E A D _ AT TA C H或D L L _ T H R E A D _ D E TA C H。这些值将在下面介绍。</font>
						</font>
				</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">注意必须记住，D L L使用D l l M a i n函数来对它们进行初始化。当你的D l l M a i n函数执行时，同一个地址空间中的其他D L L可能尚未执行它们的D l l M a i n函数。这意味着它们尚未初始化，因此你应该避免调用从其他D L L中输入的函数。此外，你应该避免从D l l M a i n内部调用L o a d L i b r a r y ( E x )和F r e e L i b r a r y函数，因为这些函数会形式一个依赖性循环。</font>
		</p>
		<p>
				<font size="2">
						<font face="Arial">
								<strong>
										<font color="#0000ff">DLL_PROCESS_ATTACH通知</font>
								</strong>
								<br />
						</font>
				</font>
				<font size="2">
						<font face="Arial">
								<font style="LINE-HEIGHT: 25px" color="#000000">当D L L被初次映射到进程的地址空间中时，系统将调用该D L L的D l l M a i n函数，给它传递参数f d w R e a s o n的值D L L _ P R O C E S S _ AT TA C H。只有当D L L的文件映像初次被映射时，才会出现这种情况。如果线程在后来为已经映射到进程的地址空间中的D L L调用L o a d L i b r a r y ( E x )函数，那么操作系统只是递增D L L的使用计数，它并不再次用D L L _ P R O C E S S _ AT TA C H的值来调用D L L的D l l M a i n函数。</font>
								<br />
						</font>
				</font>
				<font style="LINE-HEIGHT: 25px" color="#000000">
						<font face="Arial">当处理D L L _ P R O C E S S _ AT TA C H时，D L L应该执行D L L中的函数要求的任何与进程相关的初始化。例如， D L L可能包含需要使用它们自己的堆栈（在进程的地址空间中创建）的函数。<br /><br /><strong><font color="#0000ff">DLL_PROCESS_DETACH通知</font></strong><br /></font>
						<font style="LINE-HEIGHT: 25px" color="#000000">
								<font face="Arial">D L L从进程的地址空间中被卸载时，系统将调用D L L的D l l M a i n函数，给它传递f d w R e a s o n的值D L L _ P R O C E S S _ D E TA C H。当D L L处理这个值时，它应该执行任何与进程相关的清除操作。例如， D L L可以调用H e a p D e s t r o y函数来撤消它在D L L _ P R O C E S S _ D E TA C H通知期间创建的堆栈。<br /><br /><strong><font color="#0000ff">DLL_THREAD_ATTACH通知</font></strong><br /></font>
								<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000">当在一个进程中创建线程时，系统要查看当前映射到该进程的地址空间中的所有D L L文件映像，并调用每个文件映像的带有D L L _ T H R E A D _ AT TA C H值的D l l M a i n函数。这可以告诉所有的D L L执行每个线程的初始化操作。新创建的线程负责执行D L L的所有D l l M a i n函数中的代码。只有当所有的D L L都有机会处理该通知时，系统才允许新线程开始执行它的线程函数。<br /></font>
						</font>
				</font>
		</p>
		<p>
				<font face="Arial" size="2">
						<strong>
								<font color="#0000ff" size="3">DLL_THREAD_DETACH通知</font>
						</strong>
						<br />让线程终止运行的首选方法是使它的线程函数返回。这使得系统可以调用E x i t T h r e a d来撤消该线程。E x i t T h r e a d函数告诉系统，该线程想要终止运行，但是系统并不立即将它撤消。相反， 它要取出这个即将被撤消的线程， 并让它调用已经映射的D L L 的所有带有D L L _ T H R E A D _ D E TACH 值的D l l M a i n函数。这个通知告诉所有的D L L执行每个线程的清除操作。</font>
				<br />
				<br />
				<strong>
						<font face="Arial" color="#0000ff">DllMain与C/C++运行期库</font>
				</strong>
				<br />
				<font face="Arial" size="2">当编写一个D L L时，你需要得到C / C + +运行期库的某些初始帮助。例如，如果你创建的D L L包含一个全局变量，而这个全局变量是个C + +类的实例。在你顺利地在D l l M a i n函数中使用这个全局变量之前，该变量必须调用它的构造函数。这是由C / C + +运行期库的D L L启动代码来完成的。当你的D L L文件映像被映射到进程的地址空间中时，系统实际上是调用_ D l l M a i n C RTS t a r t u p函数，而不是调用D l l M a i n函数。<br /><br /><font size="3"><strong><font color="#0000ff">延迟加载DLL</font></strong><font face="Times New Roman"> （但是怎么延迟那？^_^）</font></font></font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">Microsoft Visual C++ 6.0提供了一个出色的新特性，它能够使D L L的操作变得更加容易。这个特性称为延迟加载D L L。延迟加载的D L L是个隐含链接的D L L，它实际上要等到你的代码试图引用D L L中包含的一个符号时才进行加载。延迟加载的D L L在下列情况下是非常有用的：</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 如果你的应用程序使用若干个D L L，那么它的初始化时间就比较长，因为加载程序要将所有需要的D L L映射到进程的地址空间中。解决这个问题的方法之一是在进程运行的时候分开加载各个D L L。延迟加载的D L L能够更容易地完成这样的加载。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 如果调用代码中的一个新函数，然后试图在老版本的系统上运行你的应用程序，而该系统中没有该函数，那么加载程序就会报告一个错误，并且不允许该应用程序运行。你需要一种方法让你的应用程序运行，然后，如果（在运行时）发现该应用程序在老的系统上运行，那么你将不调用遗漏的函数。<br /></font>
				<br />
				<strong>
						<font face="Arial" color="#0000ff">函数转发器</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">函数转发器是D L L的输出节中的一个项目，用于将对一个函数的调用转至另一个D L L中的另一个函数。<br /><strong><font color="#0000ff" size="3"> DLL转移</font></strong><br />M i c r o s o f t给Windows 2000增加了一个D L L转移特性。这个特性能够强制操作系统的加载程序首先从你的应用程序目录中加载文件模块。只有当加载程序无法在应用程序目录中找到该文件时，它才搜索其他目录。<font style="LINE-HEIGHT: 25px" color="#000000" size="2">为了强制加载程序总是首先查找应用程序的目录，要做的工作就是在应用程序的目录中放入一个文件。该文件的内容可以忽略，但是该文件必须称为A p p N a m e . l o c a l。</font><font style="LINE-HEIGHT: 25px" color="#000000" size="2">例如，如果有一个可执行文件的名字是S u p e r A p p . e x e ，那么转移文件必须称为S u p e r A p p . e x e . l o c a l。<font style="LINE-HEIGHT: 25px" color="#000000" size="2">在系统内部， L o a d L i b r a r y ( E x )已经被修改，以便查看是否存在该文件。如果应用程序的目录中存在该文件，该目录中的模块就已经被加载。如果应用程序的目录中不存在这个模块，L o a d L i b r a r y ( E x )将正常运行。</font><font style="LINE-HEIGHT: 25px" color="#000000" size="2">对于已经注册的C O M对象来说，这个特性是非常有用的。它使应用程序能够将它的C O M对象D L L放入自己的目录，这样，注册了相同C O M对象的其他应用程序就无法干扰你的操作。<br /></font></font></font>
		</p>
		<p>
				<br />
				<br />
				<br />zz</p>
<img src ="http://www.cppblog.com/mzty/aggbug/12823.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-22 14:11 <a href="http://www.cppblog.com/mzty/archive/2006/09/22/12823.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程－－DLL基本</title><link>http://www.cppblog.com/mzty/archive/2006/09/21/12801.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 21 Sep 2006 10:00:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/21/12801.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12801.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/21/12801.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12801.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12801.html</trackback:ping><description><![CDATA[
		<font face="Arial" size="2">
				<br />Windows API 中的所有函数都包含在D L L中：<br /><br /> K e r n e l 3 2 . d l l，它包含用于管理内存、进程和线程的各个函数；<br /> U s e r 3 2 . d l l，它包含用于执行用户界面任务（如窗口的创建和消息的传送）的各个函数；<br /> G D I 3 2 . d l l，它包含用于画图和显示文本的各个函数。<br /> A d v A P I 3 2 . d l l包含用于实现对象安全性、注册表操作和事件记录的函数；<br /> C o m D l g 3 2 . d l l包含常用对话框（如File Open和File Save）；<br /> C o m C t l 3 2 . D L L则支持所有的常用窗口控件。<br /><br />使用DLL的优点：<br /><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们扩展了应用程序的特性。由于D L L能够动态地装入进程的地址空间，因此应用程序能够在运行时确定需要执行什么操作，然后装入相应的代码，以便根据需要执行这些操作。例如，当一家公司开发了一种产品，想要让其他公司改进或增强该产品的功能时，那么就可以使用D L L。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们可以用许多种编程语言来编写。可以选择手头拥有的最好的语言来编写D L L。也许你的应用程序的用户界面使用Microsoft Visual Basic编写得最好，但是用C + +来处理它的商用逻辑更好。系统允许Visual Basic程序加载C++ DLL、Cobol DLL和Fortran DLL等。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们简化了软件项目的管理。如果在软件开发过程中不同的工作小组在不同的模块上工作，那么这个项目管理起来比较容易。但是，应用程序在销售时附带的文件应该尽量少一些。我知道有一家公司销售的产品附带了1 0 0个D L L——每个程序员最多有5个D L L。这样，应用程序的初始化时间将会长得吓人，因为系统必须打开1 0 0个磁盘文件之后，程序才能执行它的操作。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们有助于节省内存。如果两个或多个应用程序使用同一个D L L，那么该D L L的页面只要放入R A M一次，所有的应用程序都可以共享它的各个页面。C / C + +运行期库就是个极好的例子。许多应用程序都使用这个库。如果所有的应用程序都链接到这个静态库，那么s p r i n t f、s t r c p y和m a l l o c等函数的代码就要多次存在于内存中。但是，如果所有这些应用程序链接到DLL C/C++运行期库，那么这些函数的代码就只需要放入内存一次，这意味着内存的使用将更加有效。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们有助于资源的共享。D L L可以包含对话框模板、字符串、图标和位图等资源。多个应用程序能够使用D L L来共享这些资源。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们有助于应用程序的本地化。应用程序常常使用D L L对自己进行本地化。例如，只包含代码而不包含用户界面组件的应用程序可以加载包含本地化用户界面组件的D L L。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们有助于解决平台差异。不同版本的Wi d n o w s配有不同的函数。开发人员常常想要调用新的函数（如果它们存在于主机的Wi n d o w s版本上的话）。但是，如果你的源代码包含了对一个新函数的调用，而你的应用程序将要在不能提供该函数的Wi n d o w s版本上运行，那么操作系统的加载程序将拒绝运行你的进程。即使你实际上从不调用该函数，情况也是这样。如果将这些新函数保存在D L L中，那么应用程序就能够将它们加载到Wi n d o w s的老版本上。当然，你仍然可以成功地调用该函数。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 它们可以用于一些特殊的目的。Wi n d o w s使得某些特性只能为D L L所用。例如，只有当D L L中包含某个挂钩通知函数的时候，才能安装某些挂钩（使用S e t Wi n d o w s H o o k E x和S e t Wi n E v e n t H o o k来进行安装）。可以通过创建必须在D L L中生存的C O M对象来扩展Windows Explorer的外壳程序。对于可以由We b浏览器加载的、用于创建内容丰富的We b页的A c t i v e X控件来说,情况也是一样.<br /><br /><a class="" title="DLL的显示和隐试的使用方法" href="/mzty/archive/2006/07/24/10419.html" target="">DLL的显示和隐试的使用方法</a> <br /><br /><br /><br />一些经验：<br />一般使用<font color="#f70938">extern "C" _declspec(dllexport)导出变量，函数等，一般不导出类，为了何其他的兼容。。。。。。。。。</font><br /></font></p></font>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">
				<p>
						<font style="LINE-HEIGHT: 25px" color="#000000" size="2">e x t e r n“C”用于c＋＋编译为能够让c兼容的，即保证函数名不被修改。<br />若要使用与其他编译器供应商的工具链接的M i c r o s o f t的工具创建一个可执行模块，必须告诉M i c r o s o f t的编译器输出没有经过改变的函数名。可以用两种方法来进行这项操作。第一种方法是为编程项目建立一个. d e f文件，并在该. d e f文件中加上类似下面的E X P O RT S节：</font>
				</p>
				<p>
				</p>
				<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
						<pre>EXPORTS
   MyFunc</pre>
				</div>
				<p>
						<br />如果想避免使用. d e f文件，可以使用第二种方法输出未截断的函数版本。在D L L的源代码模块中，可以添加下面这行代码：</p>
		</font>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>#pragma comment(linker, "/export:MyFunc=_MyFunc@8")</pre>
		</div>（MyFunc wei函数名字）<br /><br /><img src ="http://www.cppblog.com/mzty/aggbug/12801.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-21 18:00 <a href="http://www.cppblog.com/mzty/archive/2006/09/21/12801.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程－－内存堆栈</title><link>http://www.cppblog.com/mzty/archive/2006/09/21/12798.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 21 Sep 2006 08:24:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/21/12798.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12798.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/21/12798.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12798.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12798.html</trackback:ping><description><![CDATA[
		<p>
				<font face="Arial" size="2">对内存进行操作的第三个机制是使用堆栈。堆栈可以用来分配许多较小的数据块。例如，若要对链接表和链接树进行管理，最好的方法是使用堆栈，堆栈的优点是，可以不考虑分配粒度和页面边界之类的问题，集中精力处理手头的任务。堆栈的缺点是，分配和释放内存块的速度比其他机制要慢，并且无法直接控制物理存储器的提交和回收。</font>
				<br />
				<font face="Arial" size="2">从内部来讲，堆栈是保留的地址空间的一个区域。开始时，保留区域中的大多数页面没有被提交物理存储器。当从堆栈中进行越来越多的内存分配时，堆栈管理器将把更多的物理存储器提交给堆栈。物理存储器总是从系统的页文件中分配的，当释放堆栈中的内存块时，堆栈管理器将收回这些物理存储器。</font>
				<br />
				<br />
				<font style="BACKGROUND-COLOR: #ff1493">线程的堆栈：</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">每当创建一个线程时，系统就会为线程的堆栈（每个线程有它自己的堆栈）保留一个堆栈空间区域，并将一些物理存储器提交给这个已保留的区域。按照默认设置，系统保留1 MB的地址空间并提交两个页面的内存。但是，这些默认值是可以修改的，方法是在你链接应用程序时设定M i c r o s o f t的链接程序的/ S TA C K选项：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>/STACK:reserve[,commit]</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">当创建一个线程的堆栈时，系统将会保留一个链接程序的/ S TA C K开关指明的地址空间区域。<br /><font size="3"><strong><font color="#0000ff">进程的默认堆栈</font></strong><font face="Times New Roman"></font></font></font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">当进程初始化时，系统在进程的地址空间中创建一个堆栈。该堆栈称为进程的默认堆栈。按照默认设置，该堆栈的地址空间区域的大小是1 MB。但是，系统可以扩大进程的默认堆栈，使它大于其默认值。当创建应用程序时，可以使用/ H E A P链接开关，改变堆栈的1 M B默认区域大小。由于D L L没有与其相关的堆栈，所以当链接D L L时，不应该使用/ H E A P链接开关。/ H E A P链接开关的句法如下：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>/HEAP:reserve[,commit]</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">许多Wi n d o w s函数要求进程使用其默认堆栈。特别是widows提供的API。对默认堆栈的访问是顺序进行的。换句话说，系统必须保证在规定的时间内，每次只有一个线程能够分配和释放默认堆栈中的内存块。如果两个线程试图同时分配默认堆栈中的内存块，那么只有一个线程能够分配内存块，另一个线程必须等待第一个线程的内存块分配之后，才能分配它的内存块。一旦第一个线程的内存块分配完，堆栈函数将允许第二个线程分配内存块。这种顺序访问方法对速度有一定的影响。如果你的应用程序只有一个线程，并且你想要以最快的速度访问堆栈，那么应该创建你自己的独立的堆栈，不要使用进程的默认堆栈。</font>
				<br />
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">单个进程可以同时拥有若干个堆栈。这些堆栈可以在进程的寿命期中创建和撤消。但是，默认堆栈是在进程开始执行之前创建的，并且在进程终止运行时自动被撤消。不能撤消进程的默认堆栈。每个堆栈均用它自己的堆栈句柄来标识，用于分配和释放堆栈中的内存块的所有堆栈函数都需要这个堆栈句柄作为其参数。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">可以通过调用G e t P r o c e s s H e a p函数获取你的进程默认堆栈的句柄：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>HANDLE GetProcessHeap();</pre>
		</div>
		<p>
				<strong>
						<font color="#0000ff">为什么要创建辅助堆栈</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">除了进程的默认堆栈外，可以在进程的地址空间中创建一些辅助堆栈。由于下列原因，你可能想要在自己的应用程序中创建一些辅助堆栈：</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 保护组件。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 更加有效地进行内存管理。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 进行本地访问。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 减少线程同步的开销。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 迅速释放。</font>
		</p>
		<p>
				<strong>
						<font color="#0000ff">保护组件<br /></font>
				</strong>通过创建多个独立的堆栈，是数据隔离，且相互独立的操作。<br /><strong><font color="#0000ff">更有效的内存管理</font></strong></p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">通过在堆栈中分配同样大小的对象，就可以更加有效地管理堆栈。就是把大小相同的对象放在一个堆栈中进行分配。<br /></font>
				<strong>
						<font color="#0000ff">进行本地访问</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">每当系统必须在R A M与系统的页文件之间进行R A M页面的交换时，系统的运行性能就会受到很大的影响。如果经常访问局限于一个小范围地址的内存，那么系统就不太可能需要在R A M与磁盘之间进行页面的交换。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">所以，在设计应用程序的时候，如果有些数据将被同时访问，那么最好把它们分配在互相靠近的位置上。<br /><strong><font color="#0000ff">减少线程同步的开销</font></strong></font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">正如下面就要介绍的那样，按照默认设置，堆栈是顺序运行的，这样，如果多个线程试图同时访问堆栈，就不会使数据受到破坏。但是，堆栈函数必须执行额外的代码，以保证堆栈对线程的安全性。如果要进行大量的堆栈分配操作，那么执行这些额外的代码会增加很大的负担，从而降低你的应用程序的运行性能。当你创建一个新堆栈时，可以告诉系统，只有一个线程将访问该堆栈，因此额外的代码将不执行。（就是用多个堆栈来减少同步的性能消耗）<br /><strong><font color="#0000ff">迅速释放堆栈</font></strong></font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">最后要说明的是，将专用堆栈用于某些数据结构后，就可以释放整个堆栈，而不必显式释放堆栈中的每个内存块。例如，当Windows Explorer遍历硬盘驱动器的目录层次结构时，它必须在内存中建立一个树状结构。如果你告诉Windows Explorer刷新它的显示器，它只需要撤消包含这个树状结构的堆栈并且重新运行即可（当然，假定它将专用堆栈用于存放目录树信息）。对于许多应用程序来说，这是非常方便的，并且它们也能更快地运行。</font>
		</p>
		<p>
				<strong>
						<font face="Arial" color="#0000ff">如何创建辅助堆栈</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">你可以在进程中创建辅助堆栈，方法是让线程调用H e a p C r e a t e函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>HANDLE HeapCreate(
   DWORD fdwOptions,
   SIZE_T dwInitialSize,
   SIZE_T dwMaximumSize);</pre>
		</div>
		<p>
				<font face="Arial" size="2">当试图从堆栈分配一个内存块时， H e a p A l l o c函数（下面将要介绍）必须执行下列操作：</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">1) 遍历分配的和释放的内存块的链接表。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">2) 寻找一个空闲内存块的地址。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">3) 通过将空闲内存块标记为“已分配”分配新内存块。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">4) 将新内存块添加给内存块链接表。</font>
		</p>
		<p>
				<strong>
						<font face="Arial" color="#0000ff">从堆栈中分配内存块</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">若要从堆栈中分配内存块，只需要调用H e a p A l l o c函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>PVOID HeapAlloc(
   HANDLE hHeap,
   DWORD fdwFlags,
   SIZE_T dwBytes);</pre>
		</div>
		<p>
				<strong>
						<font face="Arial" color="#0000ff">改变内存块的大小</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">常常需要改变内存块的大小。有些应用程序开始时分配的内存块比较大，然后，当所有数据放入内存块后，再缩小内存块的大小。有些应用程序开始时分配的内存块比较小，后来需要将更多的数据拷贝到内存块中去时，再设法扩大它的大小。如果要改变内存块的大小，可以调用H e a p R e A l l o c函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>PVOID HeapReAlloc(
   HANDLE hHeap,
   DWORD fdwFlags,
   PVOID pvMem,
   SIZE_T dwBytes);</pre>
		</div>
		<p>
				<strong>
						<font face="Arial" color="#0000ff">了解内存块的大小</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">当内存块分配后，可以调用H e a p S i z e函数来检索内存块的实际大小：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>SIZE_T HeapSize(
   HANDLE hHeap,
   DWORD fdwFlags,
   LPCVOID pvMem);</pre>
		</div>
		<p>
				<strong>
						<font face="Arial" color="#0000ff">释放内存块</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">当不再需要内存块时，可以调用H e a p F r e e函数将它释放：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>BOOL HeapFree(
   HANDLE hHeap,
   DWORD fdwFlags,
   PVOID pvMem);</pre>
		</div>
		<p>
				<strong>
						<font face="Arial" color="#0000ff">撤消堆栈</font>
				</strong>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">如果应用程序不再需要它创建的堆栈，可以通过调用H e a p D e s t r o y函数将它撤消：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>BOOL HeapDestroy(HANDLE hHeap);</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">调用H e a p D e s t r o y函数可以释放堆栈中包含的所有内存块，也可以将堆栈占用的物理存储器和保留的地址空间区域重新返回给系统。如果该函数运行成功， H e a p D e s t r o y返回T R U E。如果在进程终止运行之前没有显式撤消堆栈，那么系统将为你将它撤消。但是，只有当进程终止运行时，堆栈才能被撤消。如果线程创建了一个堆栈，当线程终止运行时，该堆栈将不会被撤消。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">在进程完全终止运行之前，系统不允许进程的默认堆栈被撤消。如果将进程的默认堆栈的句柄传递给H e a p D e s t r o y函数，系统将忽略对该函数的调用。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">由于进程的地址空间中可以存在多个堆栈，因此可以使用G e t P r o c e s s H e a p s函数来获取现有堆栈的句柄：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>DWORD GetProcessHeaps(
   DWORD dwNumHeaps,
   PHANDLE pHeaps);</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">若要调用G e t P r o c e s s H e a p s函数，必须首先分配一个H A N D L E数组，然后调用下面的函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>HANDLE hHeaps[25];
DWORD dwHeaps = GetProcessHeaps(25, hHeaps);
if(dwHeaps &gt; 5) 
{
   //More heaps are in this process than we expected.
} 
else
{
   //hHeaps[0] through hHeap[dwHeaps - 1]
   //identify the existing heaps.
}</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">注意，当该函数返回时，你的进程的默认堆栈的句柄也包含在堆栈句柄的数组中。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">H e a p Va l i d a t e函数用于验证堆栈的完整性：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>BOOL HeapValidate(
   HANDLE hHeap,
   DWORD fdwFlags,
   LPCVOID pvMem);</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">调用该函数时，通常要传递一个堆栈句柄，一个值为0的标志（唯一的另一个合法标志是H E A P _ N O _ S E R I A L I Z E），并且为p v M e m传递N U L L。然后，该函数将遍历堆栈中的内存块以确保所有内存块都完好无损。为了使该函数运行得更快，可以为参数p v M e m传递一个特定的内存块的地址。这样做可使该函数只检查单个内存块的有效性。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">若要合并地址中的空闲内存块并收回不包含已经分配的地址内存块的存储器页面，可以调用下面的函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>UINT HeapCompact(
   HANDLE hHeap,
   DWORD fdwFlags);
</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">通常情况下，可以为参数f d w F l a g s传递0，但是也可以传递H E A P _ N O _ S E R I A L I Z E。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">下面两个函数H e a p L o c k和H e a p U n l o c k是结合在一起使用的：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>BOOL HeapLock(HANDLE hHeap);
BOOL HeapUnlock(HANDLE hHeap);</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">这些函数是用于线程同步的。当调用H e a p L o c k函数时，调用线程将成为特定堆栈的所有者。如果其他任何线程调用堆栈函数（设定相同的堆栈句柄），系统将暂停调用线程的运行，并且在堆栈被H e a p U n l o c k函数解锁之前不允许它醒来。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">H e a p A l l o c、H e a p S i z e和H e a p F r e e等函数在内部调用H e a p L o c k和H e a p U n l o c k函数来确保对堆栈的访问能够顺序进行。自己调用H e a p L o c k或H e a p U n l o c k这种情况是不常见的。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">最后一个堆栈函数是H e a p Wa l k：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>BOOL HeapWalk(
   HANDLE hHeap,
   PPROCESS_HEAP_ENTRY pHeapEntry);</pre>
		</div>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">该函数只用于调试目的。它使你能够遍历堆栈的内容。可以多次调用该函数。</font>
				<br />
				<br />zz<br /><br /><br /></p>
<img src ="http://www.cppblog.com/mzty/aggbug/12798.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-21 16:24 <a href="http://www.cppblog.com/mzty/archive/2006/09/21/12798.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程－－内存映射文件</title><link>http://www.cppblog.com/mzty/archive/2006/09/21/12790.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 21 Sep 2006 05:26:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/21/12790.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12790.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/21/12790.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12790.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12790.html</trackback:ping><description><![CDATA[
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">与虚拟内存一样，内存映射文件可以用来保留一个地址空间的区域，并将物理存储器提交给该区域。它们之间的差别是，物理存储器来自一个已经位于磁盘上的文件，而不是系统的页文件。一旦该文件被映射，就可以访问它，就像整个文件已经加载内存一样。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">内存映射文件可以用于3个不同的目的：</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">• 系统使用内存映射文件，以便加载和执行. e x e和D L L文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">• 可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I / O操作，并且可以不必对文件内容进行缓存。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">• 可以使用内存映射文件，使同一台计算机上运行的多个进程能够相互之间共享数据。Wi n d o w s确实提供了其他一些方法，以便在进程之间进行数据通信，但是这些方法都是使用内存映射文件来实现的，这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。<br /><br /><font size="3"><strong><font color="#0000ff">内存映射的可执行文件和DLL文件</font></strong><font face="Times New Roman"></font></font></font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">当线程调用C r e a t e P r o c e s s时，系统将执行下列操作步骤：</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">1) 系统找出在调用C r e a t e P r o c e s s时设定的. e x e文件。如果找不到这个. e x e文件，进程将无法创建，C r e a t e P r o c e s s将返回FA L S E。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">2) 系统创建一个新进程内核对象。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">3) 系统为这个新进程创建一个私有地址空间。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">4) 系统保留一个足够大的地址空间区域，用于存放该. e x e文件。该区域需要的位置在. e x e文件本身中设定。按照默认设置， . e x e文件的基地址是0 x 0 0 4 0 0 0 0 0（这个地址可能不同于在6 4位Windows 2000上运行的6 4位应用程序的地址），但是，可以在创建应用程序的. e x e文件时重载这个地址，方法是在链接应用程序时使用链接程序的/ B A S E选项。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">5) 系统注意到支持已保留区域的物理存储器是在磁盘上的. e x e文件中，而不是在系统的页文件中。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">当. e x e文件被映射到进程的地址空间中之后，系统将访问. e x e文件的一个部分，该部分列出了包含. e x e文件中的代码要调用的函数的D L L文件。然后，系统为每个D L L文件调用L o a d L i b r a r y函数，如果任何一个D L L需要更多的D L L，那么系统将调用L o a d L i b r a r y函数，以便加载这些D L L。每当调用L o a d L i b r a r y来加载一个D L L时，系统将执行下列操作步骤，它们均类似上面的第4和第5个步骤：</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">1) 系统保留一个足够大的地址空间区域，用于存放该D L L文件。该区域需要的位置在D L L文件本身中设定。按照默认设置， M i c r o s o f t的Visual C++ 建立的D L L文件基地址是0 x 1 0 0 0 0 0 0 0（这个地址可能不同于在6 4位Windows 2000上运行的6 4位D L L的地址）但是，你可以在创建D L L文件时重载这个地址，方法是使用链接程序的/ B A S E选项。Wi n d o w s提供的所有标准系统D L L都拥有不同的基地址，这样，如果加载到单个地址空间，它们就不会重叠。 </font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">2) 如果系统无法在该D L L的首选基地址上保留一个区域，其原因可能是该区域已经被另一个D L L或. e x e占用，也可能是因为该区域不够大，此时系统将设法寻找另一个地址空间的区域来保留该D L L。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">3) 系统会注意到支持已保留区域的物理存储器位于磁盘上的D L L文件中，而不是在系统的页文件中。<br /><br /></font>
				<font style="LINE-HEIGHT: 25px" color="#000000" size="2">如果由于某个原因系统无法映射. e x e和所有必要的D L L文件，那么系统就会向用户显示一个消息框，并且释放进程的地址空间和进程对象。<br />当所有的. e x e和D L L文件都被映射到进程的地址空间之后，系统就可以开始执行. e x e文件的启动代码。当. e x e文件被映射后，系统将负责所有的分页、缓冲和高速缓存的处理。<br /><strong><font color="#0000ff">在可执行文件或DLL的多个实例之间共享静态数据</font></strong> （通过定义共享的节） 
<p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">全局数据和静态数据不能被同一个. e x e或D L L文件的多个映像共享，这是个安全的默认设置。但是，在某些情况下，让一个. e x e文件的多个映像共享一个变量的实例是非常有用和方便的。例如，Wi n d o w s没有提供任何简便的方法来确定用户是否在运行应用程序的多个实例。但是，如果能够让所有实例共享单个全局变量，那么这个全局变量就能够反映正在运行的实例的数量。<br /></font><strong><font color="#0000ff"> 内存映射数据文件</font></strong></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">操作系统使得内存能够将一个数据文件映射到进程的地址空间中。因此，对大量的数据进行操作是非常方便的。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">为了理解用这种方法来使用内存映射文件的功能，让我们看一看如何用4种方法来实现一个程序，以便将文件中的所有字节的顺序进行倒序。</font></p><p><b><font color="#0000ff" size="3">方法1：一个文件，一个缓存</font></b></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">第一种方法也是理论上最简单的方法，它需要分配足够大的内存块来存放整个文件。该文件被打开，它的内容被读入内存块，然后该文件被关闭。文件内容进入内存后，我们就可以对所有字节的顺序进行倒序，方法是将第一个字节倒腾为最后一个字节，第二个字节倒腾为倒数第二个字节，依次类推。这个倒腾操作将一直进行下去直到文件的中间位置。当所有的字节都已经倒腾之后，就可以重新打开该文件，并用内存块的内容来改写它的内容。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">这种方法实现起来非常容易，但是它有两个缺点。首先，必须分配一个与文件大小相同的内存块。如果文件比较小，那么这没有什么问题。但是如果文件非常大，比如说有2 G B大，那该怎么办呢？一个3 2位的系统不允许应用程序提交那么大的物理内存块。因此大文件需要使用不同的方法。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">第二，如果进程在运行过程的中间被中断，也就是说当倒序后的字节被重新写入该文件时进程被中断，那么文件的内容就会遭到破坏。防止出现这种情况的最简单的方法是在对它的内容进行倒序之前先制作一个原始文件的拷贝。如果整个进程运行成功，那么可以删除该文件的拷贝。这种方法需要更多的磁盘空间。</font></p><p><b><font color="#0000ff" size="3"> 方法2：两个文件，一个缓存</font></b></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">在第二种方法中，你打开现有的文件，并且在磁盘上创建一个长度为0的新文件。然后分配一个比较小的内部缓存，比如说8 KB。你找到离原始文件结尾还有8 KB的位置，将这最后的8 KB读入缓存，将字节倒序，再将缓存中的内容写入新创建的文件。这个寻找、读入、倒序和写入的操作过程要反复进行，直到到达原始文件的开头。如果文件的长度不是8 KB的倍数，那么必须进行某些特殊的处理。当原始文件完全处理完毕之后，将原始文件和新文件关闭，并删除原始文件。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">这种方法实现起来比第一种方法要复杂一些。它对内存的使用效率要高得多，因为它只需要分配一个8 KB的缓存块，但是它存在两个大问题。首先，它的处理速度比第一种方法要慢，原因是在每个循环操作过程中，在执行读入操作之前，必须对原始文件进行寻找操作。第二，这种方法可能要使用大量的硬盘空间。如果原始文件是400 MB，那么随着进程的不断运行，新文件就会增大为400 MB。在原始文件被删除之前，两个文件总共需要占用800 MB的磁盘空间。这比应该需要的空间大400 MB。由于存在这个缺点，因此引来了下一个方法。</font></p><p><b><font color="#0000ff" size="3"> 方法3：一个文件，两个缓存</font></b></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">如果使用这个方法，那么我们假设程序初始化时分配了两个独立的8 KB缓存。程序将文件的第一个8 KB读入一个缓存，再将文件的第二个8 KB 读入另一个缓存。然后进程将两个缓存的内容进行倒序，并将第一个缓存的内容写回文件的结尾处，将第二个缓存的内容写回同一个文件的开始处。每个迭代操作不断进行（以8 KB为单位，从文件的开始和结尾处移动文件块）。如果文件的长度不是16 KB的倍数，并且有两个8 KB的文件块相重叠，那么就需要进行一些特殊的处理。这种特殊处理比上一种方法中的特殊处理更加复杂，不过这难不倒经验丰富的编程员。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">与前面的两种方法相比，这种方法在节省硬盘空间方面有它的优点。由于所有内容都是从同一个文件读取并写入同一个文件，因此不需要增加额外的磁盘空间，至于内存的使用，这种方法也不错，它只需要使用16 KB的内存。当然，这种方法也许是最难实现的方法。与第一种方法一样，如果进程被中断，本方法会导致数据文件被破坏。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">下面让我们来看一看如何使用内存映射文件来完成这个过程。</font></p><p><b><font color="#0000ff" size="3">方法4：一个文件，零缓存</font></b></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">当使用内存映射文件对文件内容进行倒序时，你打开该文件，然后告诉系统将虚拟地址空间的一个区域进行倒序。你告诉系统将文件的第一个字节映射到该保留区域的第一个字节。然后可以访问该虚拟内存的区域，就像它包含了这个文件一样。实际上，如果在文件的结尾处有一个单个0字节，那么只需要调用C运行期函数_ s t r r e v，就可以对文件中的数据进行倒序操作。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">这种方法的最大优点是，系统能够为你管理所有的文件缓存操作。不必分配任何内存，或者将文件数据加载到内存，也不必将数据重新写入该文件，或者释放任何内存块。但是，内存映射文件仍然可能出现因为电源故障之类的进程中断而造成数据被破坏的问题。</font></p><p><a name="03"></a><br /><b><font color="#0000ff" size="3"> 使用内存映射文件</font></b></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">若要使用内存映射文件，必须执行下列操作步骤：</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">1) 创建或打开一个文件内核对象，该对象用于标识磁盘上你想用作内存映射文件的文件。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">2) 创建一个文件映射内核对象，告诉系统该文件的大小和你打算如何访问该文件。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">3) 让系统将文件映射对象的全部或一部分映射到你的进程地址空间中。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">当完成对内存映射文件的使用时，必须执行下面这些步骤将它清除：</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">1) 告诉系统从你的进程的地址空间中撤消文件映射内核对象的映像。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">2) 关闭文件映射内核对象。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">3) 关闭文件内核对象。</font></p><p><strong><font color="#0000ff">步骤1：创建或打开文件内核对象</font></strong></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">若要创建或打开一个文件内核对象，总是要调用C r e a t e F i l e函数：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">HANDLE CreateFile(
   PCSTR pszFileName,
   DWORD dwDesiredAccess,
   DWORD dwShareMode,
   PSECURITY_ATTRIBUTES psa,
   DWORD dwCreationDisposition,
   DWORD dwFlagsAndAttributes,
   HANDLE hTemplateFile);</font></pre></div><p><strong><font color="#0000ff">步骤2：创建一个文件映射内核对象</font></strong></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">调用C r e a t e F i l e函数，就可以将文件映像的物理存储器的位置告诉操作系统。你传递的路径名用于指明支持文件映像的物理存储器在磁盘（或网络或光盘）上的确切位置。这时，必须告诉系统，文件映射对象需要多少物理存储器。若要进行这项操作，可以调用C r e a t e F i l e M a p p i n g函数：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">HANDLE CreateFileMapping(
   HANDLE hFile,
   PSECURITY_ATTRIBUTES psa,
   DWORD fdwProtect,
   DWORD dwMaximumSizeHigh,
   DWORD dwMaximumSizeLow,
   PCTSTR pszName);</font></pre></div><p><strong><font color="#0000ff">步骤3：将文件数据映射到进程的地址空间</font></strong></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">当创建了一个文件映射对象后，仍然必须让系统为文件的数据保留一个地址空间区域，并将文件的数据作为映射到该区域的物理存储器进行提交。可以通过调用M a p Vi e w O f F i l e函数来进行这项操作：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">PVOID MapViewOfFile(
   HANDLE hFileMappingObject,
   DWORD dwDesiredAccess,
   DWORD dwFileOffsetHigh,
   DWORD dwFileOffsetLow,
   SIZE_T dwNumberOfBytesToMap);</font></pre></div><p><strong><font color="#0000ff">步骤4：从进程的地址空间中撤消文件数据的映像</font></strong></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">当不再需要保留映射到你的进程地址空间区域中的文件数据时，可以通过调用下面的函数将它释放：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">BOOL UnmapViewOfFile(PVOID pvBaseAddress);</font></pre></div><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">为了提高速度，系统将文件的数据页面进行高速缓存，并且在对文件的映射视图进行操作时不立即更新文件的磁盘映像。如果需要确保你的更新被写入磁盘，可以强制系统将修改过的数据的一部分或全部重新写入磁盘映像中，方法是调用F l u s h Vi e w O f F i l e函数：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">BOOL FlushViewOfFile(
   PVOID pvAddress,
   SIZE_T dwNumberOfBytesToFlush);</font></pre></div><p><strong><font color="#0000ff">步骤5和步骤6：关闭文件映射对象和文件对象</font></strong></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">不用说，你总是要关闭你打开了的内核对象。如果忘记关闭，在你的进程继续运行时会出现资源泄漏的问题。当然，当你的进程终止运行时，系统会自动关闭你的进程已经打开但是忘记关闭的任何对象。但是如果你的进程暂时没有终止运行，你将会积累许多资源句柄。因此你始终都应该编写清楚而又“正确的”代码，以便关闭你已经打开的任何对象。若要关闭文件映射对象和文件对象，只需要两次调用C l o s e H a n d l e函数，每个句柄调用一次：</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">让我们更加仔细地观察一下这个进程。下面的伪代码显示了一个内存映射文件的例子：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font color="#000000" size="3">HANDLE hFile = CreateFile(...);
HANDLE hFileMapping = CreateFileMapping(hFile, ...);
PVOID pvFile = MapViewOfFile(hFileMapping, ...);

// Use the memory-mapped file.

UnmapViewOfFile(pvFile);
CloseHandle(hFileMapping);
CloseHandle(hFile);</font></pre></div><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">上面的代码显示了对内存映射文件进行操作所用的“预期”方法。但是，它没有显示，当你调用M a p Vi e w O f F i l e时系统对文件对象和文件映射对象的使用计数的递增情况。这个副作用是很大的，因为它意味着我们可以将上面的代码段重新编写成下面的样子：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">HANDLE hFile = CreateFile(...);
HANDLE hFileMapping = CreateFileMapping(hFile, ...);
CloseHandle(hFile);
PVOID pvFile = MapViewOfFile(hFileMapping, ...);
CloseHandle(hFileMapping);

// Use the memory-mapped file.

UnmapViewOfFile(pvFile);</font></pre></div><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">当对内存映射文件进行操作时，通常要打开文件，创建文件映射对象，然后使用文件映射对象将文件的数据视图映射到进程的地址空间。由于系统递增了文件对象和文件映射对象的内部使用计数，因此可以在你的代码开始运行时关闭这些对象，以消除资源泄漏的可能性。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">如果用同一个文件来创建更多的文件映射对象，或者映射同一个文件映射对象的多个视图，那么就不能较早地调用C l o s e H a n d l e函数——以后你可能还需要使用它们的句柄，以便分别对C r e a t e F i l e M a p p i n g和M a p Vi e w O f F i l e函数进行更多的调用。</font></p><p><font color="#0000ff"><strong>使用内存映射文件来处理大文件<br />使用内存映射文件在进程之间共享数据</strong></font></p><p><strong><font color="#0000ff"><font style="LINE-HEIGHT: 25px" size="2">Wi n d o w s总是出色地提供各种机制，使应用程序能够迅速而方便地共享数据和信息。这些机制包括R P C、C O M、O L E、D D E、窗口消息（尤其是W M _ C O P Y D ATA）、剪贴板、邮箱、管道和套接字等。在Wi n d o w s中，在单个计算机上共享数据的最低层机制是内存映射文件。不错，如果互相进行通信的所有进程都在同一台计算机上的话，上面提到的所有机制均使用内存映射文件从事它们的烦琐工作。如果要求达到较高的性能和较小的开销，内存映射文件是举手可得的最佳机制。</font></font></strong></p><p><strong><font color="#0000ff"><font style="LINE-HEIGHT: 25px" size="2">数据共享方法是通过让两个或多个进程映射同一个文件映射对象的视图来实现的，这意味着它们将共享物理存储器的同一个页面。因此，当一个进程将数据写入一个共享文件映射对象的视图时，其他进程可以立即看到它们视图中的数据变更情况。注意，如果多个进程共享单个文件映射对象，那么所有进程必须使用相同的名字来表示该文件映射对象。</font></font></strong></p><p><strong><font color="#0000ff"><font style="LINE-HEIGHT: 25px" size="2">让我们观察一个例子，启动一个应用程序。当一个应用程序启动时，系统调用C r e a t e F i l e函数，打开磁盘上的. e x e文件。然后系统调用C r e a t e F i l e M a p p i n g函数，创建一个文件映射对象。最后，系统代表新创建的进程调用M a p Vi e w O f F i l e E x函数（它带有S E C _ I M A G E标志），这样， . e x e文件就可以映射到进程的地址空间。这里调用的是M a p Vi e w O f F i l e E x，而不是M a p Vi e w O f F i l e，这样，文件的映像将被映射到存放在. e x e文件映像中的基地址中。系统创建该进程的主线程，将该映射视图的可执行代码的第一个字节的地址放入线程的指令指针，然后C P U启动该代码的运行。</font></font></strong></p><p><strong><font color="#0000ff"><font style="LINE-HEIGHT: 25px" size="2">如果用户运行同一个应用程序的第二个实例，系统就认为规定的. e x e文件已经存在一个文件映射对象，因此不会创建新的文件对象或者文件映射对象。相反，系统将第二次映射该文件的一个视图，这次是在新创建的进程的地址空间环境中映射的。系统所做的工作是将相同的文件同时映射到两个地址空间。显然，这是对内存的更有效的使用，因为两个进程将共享包含正在执行的这部分代码的物理存储器的同一个页面。</font></font></strong></p><p><font color="#0000ff"><font style="LINE-HEIGHT: 25px" size="2"><strong>与所有内核对象一样，可以使用3种方法与多个进程共享对象，这3种方法是句柄继承性、句柄命名和句柄复制。<br /></strong></font><strong> 内存映射文件与数据视图的相关性</strong></font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">附录：<br /><br />系统允许你映射一个文件的相同数据的多个视图。例如，你可以将文件开头的10 KB映射到一个视图，然后将同一个文件的头4 KB映射到另一个视图。只要你是映射相同的文件映射对象，系统就会确保映射的视图数据的相关性。例如，如果你的应用程序改变了一个视图中的文件内容，那么所有其他视图均被更新以反映这个变化。这是因为尽管页面多次被映射到进程的虚拟地址空间，但是系统只将数据放在单个R A M页面上。如果多个进程映射单个数据文件的视图，那么数据仍然是相关的，因为在数据文件中，每个R A M页面只有一个实例——正是这个R A M页面被映射到多个进程的地址空间。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">注意Wi n d o w s允许创建若干个由单个数据文件支持的文件映射对象。Wi n d o w s不能保证这些不同的文件映射对象的视图具有相关性。它只能保证单个文件映射对象的多个视图具有相关性。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">然而，当对文件进行操作时，没有理由使另一个应用程序无法调用C r e a t e F i l e函数以打开由另一个进程映射的同一个文件。这个新进程可以使用R e a d F i l e和Wr i t e F i l e函数来读取该文件的数据和将数据写入该文件。当然，每当一个进程调用这些函数时，它必须从内存缓冲区读取文件数据或者将文件数据写入内存缓冲区。该内存缓冲区必须是进程自己创建的一个缓冲区，而不是映射文件使用的内存缓冲区。当两个应用程序打开同一个文件时，问题就可能产生：一个进程可以调用R e a d F i l e函数来读取文件的一个部分，并修改它的数据，然后使用Wr i t e F i l e函数将数据重新写入文件，而第二个进程的文件映射对象却不知道第一个进程执行的这些操作。由于这个原因，当你为将被内存映射的文件调用C r e a t e F i l e函数时，最好将d w S h a r e M o d e参数的值设置为0。这样就可以告诉系统，你想要单独访问这个文件，而其他进程都不能打开它。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">只读文件不存在相关性问题，因此它们可以作为很好的内存映射文件。内存映射文件决不应该用于共享网络上的可写入文件，因为系统无法保证数据视图的相关性。如果某个人的计算机更新了文件的内容，其他内存中含有原始数据的计算机将不知道它的信息已经被修改。</font></p><p><br /></p></font>
		</p>
		<p>
		</p>
<img src ="http://www.cppblog.com/mzty/aggbug/12790.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-21 13:26 <a href="http://www.cppblog.com/mzty/archive/2006/09/21/12790.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程－－虚拟内存</title><link>http://www.cppblog.com/mzty/archive/2006/09/20/12766.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Wed, 20 Sep 2006 10:12:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/20/12766.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12766.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/20/12766.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12766.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12766.html</trackback:ping><description><![CDATA[<font style="LINE-HEIGHT: 25px" face=Arial color=#0000ff size=2>
<p>Wi n d o w s提供了3种进行内存管理的方法，它们是： <br>&#8226;<font style="BACKGROUND-COLOR: #ff1493"> 虚拟内存</font>，最适合用来管理大型对象或结构数组。 </p>
<p>&#8226; <font style="BACKGROUND-COLOR: #ff1493">内存映射文件</font>，最适合用来管理大型数据流（通常来自文件）以及在单个计算机上运行的多个进程之间共享数据。 </p>
<p>&#8226; <font style="BACKGROUND-COLOR: #ff1493">内存堆栈</font>，最适合用来管理大量的小对象。</p>
<p><br><font style="BACKGROUND-COLOR: #ff1493">虚拟内存的状态</font> <br>Wi n d o w s函数G l o b a l M e m o r y S t a t u s可用于检索关于当前内存状态的动态信息： <br>VOID GlobalMemoryStatus(LPMEMORYSTATUS pmst);<br>如果希望应用程序在内存大于4 G B的计算机上运行，或者合计交换文件的大小大于4 G B，那么可以使用新的G l o b a l M e m o r y S t a t u s E x函数： <br>BOOL GlobalMemoryStatusEx(LPMEMORYSTATUSEX pmst);<br><br><font style="BACKGROUND-COLOR: #ff1493">确定地址空间的状态</font><br>Wi n d o w s提供了一个函数，可以用来查询地址空间中内存地址的某些信息（如大小，存储器类型和保护属性等）。<br>这个函数称为Vi r t u a l Q u e r y： <br>DWORD VirtualQuery(<br>&nbsp;&nbsp; LPCVOID pvAddress,<br>&nbsp;&nbsp; PMEMORY_BASIC_INFORMATION pmbi,<br>&nbsp;&nbsp; DWORD dwLength);<br>Wi n d o w s还提供了另一个函数，它使一个进程能够查询另一个进程的内存信息： <br>DWORD VirtualQueryEx(<br>&nbsp;&nbsp; HANDLE hProcess,<br>&nbsp;&nbsp; LPCVOID pvAddress,<br>&nbsp;&nbsp; PMEMORY_BASIC_INFORMATION pmbi,<br>&nbsp;&nbsp; DWORD dwLength);<br>这两个函数基本相同，差别在于使用Vi r t u a l Q u e r y E x时，可以传递你想要查询的地址空间信息的进程的句柄。调试程序和其他实用程序使用这个函数最多，几乎所有的应用程序都只需要调用Vi r t u a l Q u e r y函数。<br>为了获得完整的内存信息，我创建了一个函数，即V M Q u e r y：<br>BOOL VMQuery(<br>&nbsp;&nbsp; HANDLE hProcess,<br>&nbsp;&nbsp; PVOID pvAddress,<br>&nbsp;&nbsp; PVMQUERY pVMQ);<br><strong>系统信息</strong></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>许多操作系统的值是根据主机而定的，比如页面的大小，分配粒度的大小等。这些值决不应该用硬编码的形式放入你的源代码。相反，你始终都应该在进程初始化的时候检索这些值，并在你的源代码中使用检索到的值。G e t S y s t e m I n f o函数将用于检索与主机相关的值：</font> </p>
<p>&#160;</p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2></font></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">VOID&nbsp;GetSystemInfo(LPSYSTEM_INFO&nbsp;psinf);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><br>必须传递S Y S T E M _ I N F O结构的地址给这个函数。这个函数将初始化所有的结构成员然后返回。下面是S Y S T E M _ I N F O数据结构的样子。</p>
</font>
<p>&#160;</p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2></font></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">typedef&nbsp;</span> <span style="COLOR: #0000ff">struct</span> <span style="COLOR: #000000">&nbsp;_SYSTEM_INFO<br><img id=Codehighlighter1_28_500_Open_Image onclick="this.style.display='none'; Codehighlighter1_28_500_Open_Text.style.display='none'; Codehighlighter1_28_500_Closed_Image.style.display='inline'; Codehighlighter1_28_500_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_28_500_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_28_500_Closed_Text.style.display='none'; Codehighlighter1_28_500_Open_Image.style.display='inline'; Codehighlighter1_28_500_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span> <span id=Codehighlighter1_28_500_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"> </span><span id=Codehighlighter1_28_500_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;union<br><img id=Codehighlighter1_42_186_Open_Image onclick="this.style.display='none'; Codehighlighter1_42_186_Open_Text.style.display='none'; Codehighlighter1_42_186_Closed_Image.style.display='inline'; Codehighlighter1_42_186_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_42_186_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_42_186_Closed_Text.style.display='none'; Codehighlighter1_42_186_Open_Image.style.display='inline'; Codehighlighter1_42_186_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span id=Codehighlighter1_42_186_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"> </span><span id=Codehighlighter1_42_186_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwOemId;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">Obsolete,&nbsp;do&nbsp;not&nbsp;use</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">struct</span> <span style="COLOR: #000000">&nbsp;<br><img id=Codehighlighter1_109_180_Open_Image onclick="this.style.display='none'; Codehighlighter1_109_180_Open_Text.style.display='none'; Codehighlighter1_109_180_Closed_Image.style.display='inline'; Codehighlighter1_109_180_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_109_180_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_109_180_Closed_Text.style.display='none'; Codehighlighter1_109_180_Open_Image.style.display='inline'; Codehighlighter1_109_180_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span id=Codehighlighter1_109_180_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"> </span><span id=Codehighlighter1_109_180_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;wProcessorArchitecture;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;wReserved;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwPageSize;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;LPVOID&nbsp;&nbsp;&nbsp;&nbsp;lpMinimumApplicationAddress;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;LPVOID&nbsp;&nbsp;&nbsp;&nbsp;lpMaximumApplicationAddress;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD_PTR&nbsp;dwActiveProcessorMask;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwNumberOfProcessors;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwProcessorType;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwAllocationGranularity;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;WORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wProcessorLevel;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;WORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wProcessorRevision;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span> </span><span style="COLOR: #000000">&nbsp;SYSTEM_INFO,&nbsp;</span> <span style="COLOR: #000000">*</span> <span style="COLOR: #000000">LPSYSTEM_INFO;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><br>当系统引导时，它要确定这些成员的值是什么。对于任何既定的系统来说，这些值总是相同的，因此决不需要为任何既定的进程多次调用该函数。<br></p>
<p align=center>表14-1 与内存有关的成员函数 </p>
<div align=center>
<table style="WIDTH: 578px; HEIGHT: 324px" borderColor=#808000 cellSpacing=1 cellPadding=6 align=center border=2>
    <tbody>
        <tr>
            <td align=middle width="25%">成员名</td>
            <td align=middle width="75%">描述</td>
        </tr>
        <tr>
            <td width="25%">d w P a g e S i z e</td>
            <td width="75%">用于显示C P U的页面大小。在x86 CPU上，这个值是4 0 9 6字节。在Alpha CPU 上，这个值是8 1 9 2字节。在I A - 6 4上，这个值是8 1 9 2字节</td>
        </tr>
        <tr>
            <td width="25%">l p M i n i m u m A p p l i c a t i o n A d d r e s s</td>
            <td width="75%">用于给出每个进程的可用地址空间的最小内存地址。在Windows 98上，这个值是4 194 304，或0 x 0 0 4 0 0 0 0 0，因为每个进程的地址空间中下面的4 M B是不能使用的。在Windows 2000上，这个值是65 536或0 x 0 0 0 1 0 0 0 0，因为每个进程的地址空间中开头的6 4 K B总是空闲的</td>
        </tr>
        <tr>
            <td width="25%">l p M a x i m u m A p p l i c a t i o n A d d r e s s</td>
            <td width="75%">用于给出每个进程的可用地址空间的最大内存地址。在Windows 98 上，这个地址是2 147 483 647或0 x 7 F F F F F F F，因为共享内存映射文件区域和共享操作系统代码包含在上面的2 GB分区中。在Windows 2000上，这个地址是内核方式内存开始的地址，它不足6 4 K B</td>
        </tr>
        <tr>
            <td width="25%">d w A l l o c a t i o n G r a n u l a r i t y</td>
            <td width="75%">显示保留的地址空间区域的分配粒度。截止到撰写本书时，在所有Wi n d o w s平台上，这个值都是65536</td>
        </tr>
    </tbody>
</table>
</div>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>该结构的其他成员与内存管理毫无关系，为了完整起见，下面也对它们进行了介绍（见表1 4 - 2）。</font> </p>
<p>&#160;</p>
<p align=center>表14-2 与内存无关的成员函数 </p>
<div align=center>
<table style="WIDTH: 528px; HEIGHT: 422px" borderColor=#808000 cellSpacing=1 cellPadding=6 align=center border=2>
    <tbody>
        <tr>
            <td align=middle width="25%">成员名</td>
            <td align=middle width="75%">描述</td>
        </tr>
        <tr>
            <td width="25%">d w O e m I d</td>
            <td width="75%">已作废，不引用</td>
        </tr>
        <tr>
            <td width="25%">W R e d e r v e d</td>
            <td width="75%">保留供将来使用，不引用</td>
        </tr>
        <tr>
            <td width="25%">d w N u m b e r O f P r o c e s s o r s</td>
            <td width="75%">用于指明计算机中的C P U数目</td>
        </tr>
        <tr>
            <td width="25%">d w A c t i v e P r o c e s s o r M a s k</td>
            <td width="75%">一个位屏蔽，用于指明哪个C P U是活动的（允许运行线程）</td>
        </tr>
        <tr>
            <td width="25%">d w P r o c e s s o r Ty p e</td>
            <td width="75%">只用于Windows 98，不用于Windows 2000，用于指明处理器的类型，如Intel 386、4 8 6或P e n t i u m</td>
        </tr>
        <tr>
            <td width="25%">w P r o c e s s o r A r c h i t e c t u r e</td>
            <td width="75%">只用于Windows 2000，不用于Windows 98，用于指明处理的结构，如I n t e l、A l p h a、Intel 64位或Alpha 64位</td>
        </tr>
        <tr>
            <td width="25%">w P r o c e s s o r L e v e l</td>
            <td width="75%">只用于Windows 2000，不用于Windows 98，用于进一步细分处理器的结构，如用于设定Intel Pentium Pro或Pentium II</td>
        </tr>
        <tr>
            <td width="25%">w P r o c e s s o r R e v i s i o n</td>
            <td width="75%">只用于Windows 2000 ，不用于Windows 98，用于进一步细分处理器的级别</td>
        </tr>
    </tbody>
</table>
</div>
<br><strong><font face=Arial color=#0000ff>在地址空间中保留一个区域</font> </strong>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>通过调用Vi r t u a l A l l o c函数，可以在进程的地址空间中保留一个区域：</font> </p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>PVOID VirtualAlloc(
PVOID pvAddress,
SIZE_T dwSize,
DWORD fdwAllocationType,
DWORD fdwProtect);</pre>
</div>
<br><font face=Arial size=2>第一个参数p v A d d r e s s包含一个内存地址，用于设定想让系统将地址空间保留在什么地方。在大多数情况下，你为该参数传递M U L L。它告诉Vi r t u a l A l l o c，保存着一个空闲地址区域的记录的系统应该将区域保留在它认为合适的任何地方。系统可以从进程的地址空间的任何位置来保留一个区域，因为不能保证系统可以从地址空间的底部向上或者从上面向底部来分配各个区域。可以使用M E M _ TO P _ D O W N标志来说明该分配方式。<font style="LINE-HEIGHT: 25px" color=#000000 size=2>如果Vi r t u a l A l l o c函数能够满足你的要求，那么它就返回一个值，指明保留区域的基地址。如果传递一个特定的地址作为Vi r t u a l A l l o c的p v A d d r e s s 参数，那么该返回值与传递给Vi r t u a l A l l o c的值相同，并被圆整为（如果需要的话） 6 4 K B边界值。<br></font></font>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>Vi r t u a l A l l o c函数的第二个参数是d w S i z e，用于设定想保留的区域的大小（以字节为计量单位）。由于系统保留的区域始终必须是C P U页面大小的倍数，因此，如果试图保留一个跨越6 2 K B的区域，结果就会在使用4 KB、8 KB或16 KB页面的计算机上产生一个跨越6 4 K B的区域。</font> </p>
<font face=Arial size=2>Vi r t u a l A l l o c函数的第三个参数是f d w A l l o c a t i o n Ty p e，它能够告诉系统你想保留一个区域还是提交物理存储器（这样的区分是必要的，因为Vi r t u a l A l l o c函数也可以用来提交物理存储器）。若要保留一个地址空间区域，必须传递M E M _ R E S E RV E标识符作为F d w A l l o c a t i o n Ty p e参数的值。<br><br><br>最后一个参数是f d w P r o t e c t，用于指明应该赋予该地址空间区域的保护属性。与该区域相关联的保护属性对映射到该区域的已提交内存没有影响。无论赋予区域的保护属性是什么，如果没有提交任何物理存储器，那么访问该范围中的内存地址的任何企图都将导致该线程引发一个访问违规。<br></font><br><strong><font face=Arial color=#0000ff>在保留区域中的提交存储器</font> </strong>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>当保留一个区域后，必须将物理存储器提交给该区域，然后才能访问该区域中包含的内存地址。系统从它的页文件中将已提交的物理存储器分配给一个区域。物理存储器总是按页面边界和页面大小的块来提交的。</font> </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>若要提交物理存储器，必须再次调用Vi r t u a l A l l o c函数。不过这次为f d w A l l o c a t i o n Ty p e参数传递的是M E M _ C O M M I T标志，而不是M E M _ R E S E RV E标志。传递的页面保护属性通常与调用Vi r t u a l A l l o c来保留区域时使用的保护属性相同（大多数情况下是PA G E _ R E A D W R I T E），不过也可以设定一个不同的保护属性。</font> </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>在已保留的区域中，你必须告诉Vi r t u a l A l l o c函数，你想将物理存储器提交到何处，以及要提交多少物理存储器。为了做到这一点，可以在p v A d d r e s s参数中设定你需要的内存地址，并在d w S i z e参数中设定物理存储器的数量（以字节为计量单位）。注意，不必立即将物理存储器提交给整个区域。<br><font size=3><strong><font color=#0000ff>同时进行区域的保留和内存的提交</font></strong><font face="Times New Roman"></font></font></font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>有时你可能想要在保留区域的同时，将物理存储器提交给它。只需要一次调用Vi r t u a l A l l o c函数就能进行这样的操作，如下所示：</font> </p>
<p>&#160;</p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2></font></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">PVOID&nbsp;pvMem&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;VirtualAlloc(NULL,&nbsp;</span> <span style="COLOR: #000000">99</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #000000">*</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #000000">1024</span> <span style="COLOR: #000000">,<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;MEM_RESERVE&nbsp;</span> <span style="COLOR: #000000">|</span> <span style="COLOR: #000000">&nbsp;MEM_COMMIT,&nbsp;PAGE_READWRITE);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><br>这个函数调用请求保留一个99 KB的区域，并且将99 KB的物理存储器提交给它。当系统处理这个函数调用时，它首先要搜索你的进程的地址空间，找出未保留的地址空间中一个地址连续的区域，它必须足够大，能够存放100 KB（在4 KB页面的计算机上）或104 KB（在8 KB页面的计算机上）。</p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>系统之所以要搜索地址空间，原因是已将p v A d d r e s s参数设定为N U L L。如果为p v A d d r e s s设定了内存地址，系统就要查看在该内存地址上是否存在足够大的未保留地址空间。如果系统找不到足够大的未保留地址空间，Vi r t u a l A l l o c将返回N U L L，</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>如果能够保留一个合适的区域，系统就将物理存储器提交给整个区域。无论是该区域还是提交的内存，都将被赋予PA G E _ R E A D W R I T E保护属性。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>最后需要说明的是，Vi r t u a l A l l o c将返回保留区域和提交区域的虚拟地址，然后该虚拟地址被保存在p v M e m变量中。如果系统无法找到足够大的地址空间，或者不能提交该物理存储器，Vi r t u a l A l l o c将返回N U L L。</font> <br><strong><font face=Arial color=#0000ff>回收虚拟内存和释放地址空间区域</font> </strong></p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>若要回收映射到一个区域的物理存储器，或者释放这个地址空间区域，可调用Vi r t u a l F r e e函数：</font> </p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>BOOL VirtualFree(
LPVOID pvAddress,
SIZE_T dwSize,
DWORD fdwFreeType);</pre>
</div>
<p><strong><font face=Arial color=#0000ff>改变保护属性</font> </strong></p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>虽然实践中很少这样做，但是可以改变已经提交的物理存储器的一个或多个页面的保护属性。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>若要改变内存页面的保护属性，可以调用Vi r t u a l P r o t e c t函数：</font> </p>
<p>&#160;</p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2></font></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;VirtualProtect(<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PVOID&nbsp;pvAddress,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;SIZE_T&nbsp;dwSize,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;flNewProtect,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PDWORD&nbsp;pflOldProtect);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><br>当然，保护属性是与内存的整个页面相关联的，而不是赋予内存的各个字节的。因此，如果要使用下面的代码来调用4 KB 页面的计算机上的Vi r t u a l P r o t e c t函数，其结果是把PA G E _ N O A C C E S S保护属性赋予内存的两个页面：</p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>VirtualProtect(pvRgnBase + (3 * 1024), 2 * 1024,
PAGE_NOACCESS, &amp;flOldProtect);</pre>
</div>
<p><strong><font face=Arial color=#0000ff>清除物理存储器的内容<br><br></font></strong><br></p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>为了说明内存的内容已经被清除，我们必须对系统的R A M提出大量的使用需求。若要进行这项操作，可以分3步来进行：</font> </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>1) 调用G l o b a l M e m o r y S t a t u s函数，获取计算机中R A M的总容量。</font> </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>2) 调用Vi r t u a l A l l o c函数，提交该数量的内存。这项操作的运行速度非常快，因为在进程试图访问页面之前，系统实际上并不为该内存分配R A M。</font> </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>3) 调用Z e r o M e m o r y函数，使新提交的页面可以被访问。这将给系统的R A M带来沉重的负担，导致当前正在R A M中的某些页面被写入页文件。</font> </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>如果用户指明该数据将在以后被访问，那么该数据将不被清除，并且在以后访问该数据时将数据转入R A M。但是，如果用户指明以后将不再访问该数据，那么数据将被清除，并且系统不把数据写入页文件，这样就可以提高应用程序的运行性能。</font> </p>
<p><br><br>&nbsp;</p><img src ="http://www.cppblog.com/mzty/aggbug/12766.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-20 18:12 <a href="http://www.cppblog.com/mzty/archive/2006/09/20/12766.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程－－内存结构</title><link>http://www.cppblog.com/mzty/archive/2006/09/20/12764.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Wed, 20 Sep 2006 09:42:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/20/12764.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12764.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/20/12764.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12764.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12764.html</trackback:ping><description><![CDATA[<strong><font face=Arial color=#0000ff>进程的虚拟地址空间</font> </strong>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>每个进程都被赋予它自己的虚拟地址空间。对于3 2位进程来说，这个地址空间是4 G B，因为3 2位指针可以拥有从0 x 0 0 0 0 0 0 0 0至0 x F F F F F F F F之间的任何一个值。这使得一个指针能够拥有4 294 967 296个值中的一个值，它覆盖了一个进程的4 G B虚拟空间的范围。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>由于每个进程可以接收它自己的私有的地址空间，因此当进程中的一个线程正在运行时，该线程可以访问只属于它的进程的内存。属于所有其他进程的内存则隐藏着，并且不能被正在运行的线程访问。注意在Windows 2000中，属于操作系统本身的内存也是隐藏的，正在运行的线程无法访问。这意味着线程常常不能访问操作系统的数据。<br></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>每个进程的虚拟地址空间都要划分成各个分区。地址空间的分区是根据操作系统的基本实现方法来进行的。不同的Wi n d o w s内核，其分区也略有不同。表1 3 - 1显示了每种平台是如何对进程的地址空间进行分区的。</font> </p>
<p>&#160;</p>
<p align=center>表13-1 进程的地址空间如何分区 </p>
<div align=center>
<table style="WIDTH: 508px; HEIGHT: 636px" borderColor=#808000 cellSpacing=1 cellPadding=6 align=center border=2>
    <tbody>
        <tr>
            <td align=middle width="20%">分区</td>
            <td align=middle width="20%">32位Windows 2000(x86和Alpha处理器)</td>
            <td align=middle width="20%">32位Windows 2000(x86w/3GB用户方式)</td>
            <td align=middle width="20%">64位Windows 2000(Alpha和IA-64处理器)</td>
            <td align=middle width="20%">Windows 98</td>
        </tr>
        <tr>
            <td width="20%">N U L L指针分配的分区</td>
            <td width="20%">0 x 0 0 0 0 0 0 0 0 0 x 0 0 0 0 F F F F</td>
            <td width="20%">0 x 0 0 0 0 0 0 0 0 0 x 0 0 0 0 F F F F</td>
            <td width="20%">0x00000000 00000000 0x00000000 0000FFFF</td>
            <td width="20%">0 x 0 0 0 0 0 0 0 0 0 x 0 0 0 0 0 F F F</td>
        </tr>
        <tr>
            <td width="20%">DOS/16位Windows应用程序兼容分区</td>
            <td width="20%">无</td>
            <td width="20%">无</td>
            <td width="20%">无</td>
            <td width="20%">0 x 0 0 0 0 0 1 0 0 0 0 x 0 0 3 F F F F F</td>
        </tr>
        <tr>
            <td width="20%">用户方式</td>
            <td width="20%">0 x 0 0 0 1 0 0 0 0 0 x 7 F F E F F F F</td>
            <td width="20%">0 x 0 0 0 1 0 0 0 0 0 x B F F E F F F F F</td>
            <td width="20%">0x00000000 00010000 0x000003FF FFFEFFFF</td>
            <td width="20%">0 x 0 0 4 0 0 0 0 0 0 x 7 F F F F F F F</td>
        </tr>
        <tr>
            <td width="20%">64-KB</td>
            <td width="20%">0 x 7 F F F 0 0 0 0</td>
            <td width="20%">0 x B F F F 0 0 0 0</td>
            <td width="20%">0 x 0 0 0 0 0 3 F F F F F F 0 0 0 0</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">禁止进入</td>
            <td width="20%">0 x 7 F F F F F F F</td>
            <td width="20%">0 x B F F F F F F F</td>
            <td width="20%">0 x 0 0 0 0 0 3 F F F F F F F F F F</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">共享内存映射</td>
            <td width="20%">无</td>
            <td width="20%">无</td>
            <td width="20%">无</td>
            <td width="20%">0 x 8 0 0 0 0 0 0 0</td>
        </tr>
        <tr>
            <td width="20%">文件(MMF)内核方式</td>
            <td width="20%">0 x 8 0 0 0 0 0 0 0 0 0 x F F F F F F F F</td>
            <td width="20%">0 x C 0 0 0 0 0 0 0 0 x F F F F F F F F</td>
            <td width="20%">0x00000400 00000000 0xFFFFFFFFF FFFFFFF</td>
            <td width="20%">0 x B F F F F F F F 0 x C 0 0 0 0 0 0 0 0 x F F F F F F F F</td>
        </tr>
    </tbody>
</table>
</div>
<br><br><font color=#000000 size=2>NULL指针：就是程序中的NULL哦，</font> <font size=2><font color=#000000><font face=Arial>进程地址空间的这个分区的设置是为了帮助程序员掌握N U L L指针的分配情况。<br>MS-DOS/16位Windows应用程序兼容分区—仅适用于Windows 98：进程地址空间的这个4 M B分区是Windows 98需要的，目的是维护M S - D O S应用程序与1 6位应用程序之间的兼容性。</font> <br>用户方式：</font> </font><font style="LINE-HEIGHT: 25px" face=Arial><font size=2><font color=#000000>这个分区是进程的私有（非共享）地址空间所在的地方。一个进程不能读取、写入、或者以任何方式访问驻留在该分区中的另一个进程的数据。对于所有应用程序来说，该分区是维护进程的大部分数据的地方。由于每个进程可以得到它自己的私有的、非共享分区，以便存放它的数据，因此，应用程序不太可能被其他应用程序所破坏，这使得整个系统更加健壮。系统还可以在这个分区中映射该进程可以访问的所有内存映射文件。当我最初观察3 2位进程的地址空间的时候，我惊奇地发现可以使用的地址空间还不到我的进程的全部地址空间的一半。难道内核方式分区真的需要上面的一半地址空间吗？实际上回答是肯定的。系统需要这个地址空间，供内核代码、设备驱动程序代码、设备I / O高速缓存、非页面内存池的分配和进程页面表等使用。实际上M i c r o s o f t将内核压缩到这个2 G B空间之中。<br><font color=#000000>64KB禁止进入的分区—仅适用于Windows 2000</font><font face="Times New Roman"> ：</font></font> </font><font style="LINE-HEIGHT: 25px" color=#000000 size=2>这个位于用户方式分区上面的64 KB分区是禁止进入的，访问该分区中的内存的任何企图均将导致访问违规。M i c r o s o f t之所以保留该分区，是因为这样做将使得M i c r o s o f t能够更加容易地实现操作系统。当将内存块的地址和它的长度传递给Wi n d o w s函数时，该函数将在执行它的操作之前使内存块生效。<br></font></font><font style="LINE-HEIGHT: 25px" face=Arial><font size=2><font color=#000000>共享的MMF分区—仅适用于Windows 98<font face="Times New Roman"> ：</font></font> </font><font style="LINE-HEIGHT: 25px"><font color=#000000 size=2>这个1 G B分区是系统用来存放所有3 2位进程共享数据的地方。例如，系统的动态链接库K e r n e l 3 2 . d l l、A d v A P I 3 2 . d l l、U s e r 3 2 . d l l和G D I 3 2 . d l l等，全部存放在这个地址空间分区中，因此，所有3 2位进程都能很容易同时访问它们。<br>内核方式分区—适用于Windows 2000和Windows 98 ：</font> <font style="LINE-HEIGHT: 25px" color=#000000 size=2>这个分区是存放操作系统代码的地方。用于线程调度、内存管理、文件系统支持、网络支持和所有设备驱动程序的代码全部在这个分区加载。驻留在这个分区中的一切均可被所有进程共享。在Windows 2000中，这些组件是完全受到保护的。<br><strong><font color=#0000ff>地址空间中的区域</font></strong>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>当进程被创建并被赋予它的地址空间时，该可用地址空间的主体是空闲的，即未分配的。若要使用该地址空间的各个部分，必须通过调用Vi r t u a l A l l o c函数（第1 5章介绍）来分配它里边的各个区域。对一个地址空间的区域进行分配的操作称为保留( r e s e r v i n g )。</font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>每当你保留地址空间的一个区域时，系统要确保该区域从一个分配粒度的边界开始。对于不同的C P U平台来说，分配粒度是各不相同的。<br></font><strong><font color=#0000ff>提交地址空间区域中的物理存储器</font></strong></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>若要使用已保留的地址空间区域，必须分配物理存储器，然后将该物理存储器映射到已保留的地址空间区域。这个过程称为提交物理存储器。物理存储器总是以页面的形式来提交的。若要将物理存储器提交给一个已保留的地址空间区域，也要调用Vi r t u a l A l l o c函数。<br><strong><font color=#0000ff>物理存储器与页文件</font></strong></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>在较老的操作系统中，物理存储器被视为计算机拥有的R A M的容量。换句话说，如果计算机拥有1 6 M B的R A M，那么加载和运行的应用程序最多可以使用1 6 M B的R A M。今天的操作系统能够使得磁盘空间看上去就像内存一样。磁盘上的文件通常称为页文件，它包含了可供所有进程使用的虚拟内存。</font></p>
</font><br>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>当然，若要使虚拟内存能够运行，需要得到C P U本身的大量帮助。当一个线程试图访问一个字节的内存时， C P U必须知道这个字节是在R A M中还是在磁盘上。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>从应用程序的角度来看，页文件透明地增加了应用程序能够使用的R A M（即内存）的数量。如果计算机拥有6 4 M B的R A M，同时在硬盘上有一个100 MB的页文件，那么运行的应用程序就认为计算机总共拥有1 6 4 M B的R A M。<br>当然，实际上并不拥有1 6 4 M B的R A M。相反，操作系统与C P U相协调，共同将R A M的各个部分保存到页文件中，当运行的应用程序需要时，再将页文件的各个部分重新加载到R A M。由于页文件增加了应用程序可以使用的R A M的容量，因此页文件的使用是视情况而定的。如果没有页文件，那么系统就认为只有较少的R A M可供应用程序使用。但是，我们鼓励用户使用页文件，这样他们就能够运行更多的应用程序，并且这些应用程序能够对更大的数据集进行操作。最好将物理存储器视为存储在磁盘驱动器（通常是硬盘驱动器）上的页文件中的数据。这样，当一个应用程序通过调用Vi r t u a l A l l o c函数，将物理存储器提交给地址空间的一个区域时，地址空间实际上是从硬盘上的一个文件中进行分配的。系统的页文件的大小是确定有多少物理存储器可供应用程序使用时应该考虑的最重要的因素， R A M的容量则影响非常小。<br><img style="WIDTH: 646px; HEIGHT: 598px" height=598 alt=o_SpxImage.jpg src="http://www.cppblog.com/images/cppblog_com/mzty/2021/o_SpxImage.jpg" width=646 border=0><br><strong><font color=#0000ff>数据对齐的重要性<br></font></strong></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>当C P U访问正确对齐的数据时，它的运行效率最高。当数据大小的数据模数的内存地址是0时，数据是对齐的。例如， W O R D值应该总是从被2除尽的地址开始，而D W O R D值应该总是从被4除尽的地址开始，如此等等。当C P U试图读取的数据值没有正确对齐时， C P U可以执行两种操作之一。即它可以产生一个异常条件，也可以执行多次对齐的内存访问，以便读取完整的未对齐数据值。</font> </p>
</font></font><img src ="http://www.cppblog.com/mzty/aggbug/12764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-20 17:42 <a href="http://www.cppblog.com/mzty/archive/2006/09/20/12764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--纤程</title><link>http://www.cppblog.com/mzty/archive/2006/09/15/12511.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 15 Sep 2006 07:08:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/15/12511.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12511.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/15/12511.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12511.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12511.html</trackback:ping><description><![CDATA[
		<strong>
				<font face="Arial" color="#0000ff">比线程更小的单位,好像用的不多的哦<br /><br /><br />纤程的操作</font>
		</strong>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">首先要注意的一个问题是，实现线程的是Wi n d o w s内核。操作系统清楚地知道线程的情况，并且根据M i c r o s o f t定义的算法对线程进行调度。纤程是以用户方式代码来实现的，内核并不知道纤程，并且它们是根据用户定义的算法来调度的。由于你定义了纤程的调度算法，因此，就内核而言，纤程采用非抢占式调度方式。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">需要了解的下一个问题是，单线程可以包含一个或多个纤程。就内核而言，线程是抢占调度的，是正在执行的代码。然而，线程每次执行一个纤程的代码—你决定究竟执行哪个纤程（随着我们讲解的深入，这些概念将会越来越清楚）。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">当使用纤程时，你必须执行的第一步操作是将现有的线程转换成一个纤程。可以通过调用C o n v e r t T h r e a d To F i b e r函数来执行这项操作：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>PVOID ConvertThreadToFiber(PVOID pvParam);</pre>
		</div>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">该函数为纤程的执行环境分配相应的内存（约为2 0 0字节）。该执行环境由下列元素组成：</font>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">• 一个用户定义的值，它被初始化为传递给C o n v e r t T h r e a d To F i b e r的p v P a r a m参数的值。 </font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">• 结构化异常处理链的头。 </font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">• 纤程内存栈的最高和最低地址（当将线程转换成纤程时，这也是线程的内存栈）。 </font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">• CPU寄存器，包括堆栈指针、指令指针和其他。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">当对纤程的执行环境进行分配和初始化后，就可以将执行环境的地址与线程关联起来。该线程被转换成一个纤程，而纤程则在该线程上运行。C o n v e r t T h r e a d To F i b e r函数实际上返回纤程的执行环境的内存地址。虽然必须在晚些时候使用该地址，但是决不应该自己对该执行环境数据进行读写操作，因为必要时纤程函数会为你对该结构的内容进行操作。现在，如果你的纤程（线程）返回或调用E x i t T h r e a d函数，那么纤程和线程都会终止运行。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">除非打算创建更多的纤程以便在同一个线程上运行，否则没有理由将线程转换成纤程。若要创建另一个纤程，该线程（当前正在运行纤程的线程）可以调用C r e a t e F i b e r函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>PVOID CreateFiber(
   DWORD dwStackSize,
   PFIBER_START_ROUTINE pfnStartAddress,
   PVOID pvParam);</pre>
		</div>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">C r e a t e F i b e r首先设法创建一个新内存栈，它的大小由d w S t a c k S i z e参数来指明。通常传递的参数是0，按照默认设置，它创建一个内存栈，其大小可以扩展为1 M B，不过开始时有两个存储器页面用于该内存栈。如果设定一个非0值，那么就用设定的大小来保存和使用内存栈。</font>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">接着，C r e a t e F i b e r函数分配一个新的纤程执行环境结构，并对它进行初始化。该用户定义的值被设置为传递给C r e a t e F i b e r的p v P a r a m参数的值，新内存栈的最高和最低地址被保存，同时，纤程函数的内存地址（作为p f n S t a r t A d d r e s s参数来传递）也被保存。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">P f n S t a r t A d d r e s s参数用于设定必须实现的纤程例程的地址，它必须采用下面的原型：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>VOID WINAPI FiberFunc(PVOID pvParam);</pre>
		</div>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">当纤程被初次调度时，该函数就开始运行，并且将原先传递给C r e a t e F i b e r的p v P a r a m的值传递给它。可以在这个纤程函数中执行想执行的任何操作。但是该函数的原型规定返回值是V O I D，这并不是因为返回值没有任何意义，而是因为该函数根本不应该返回。如果纤程确实返回了，那么线程和该线程创建的所有纤程将立即被撤消。</font>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">与C o n v e r t T h r e a d To F i b e r函数一样，C r e a t e F i b e r函数也返回纤程运行环境的内存地址。但是，与C o n v e r t T h r e a d To F i b e r不同的是，这个新纤程并不执行，因为当前运行的纤程仍然在执行。在单个线程上，每次只能运行一个纤程。若要使新纤程能够运行，可以调用Switch To Fiber函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>VOID SwitchToFiber(PVOID pvFiberExecutionContext);</pre>
		</div>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">Switch To Fiber 函数只有一个参数，即p v F i b e r E x e c u t i o n C o n t e x t，它是上次调用C o n v e r t T h r e a d To F i b e r或C r e a t e F i b e r函数时返回的纤程的执行环境的内存地址。该内存地址告诉该函数要对哪个纤程进行调度。S w i t c h To F i b e r函数在内部执行下列操作步骤：</font>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">1) 它负责将某些当前的C P U寄存器保存在当前运行的纤程执行环境中，包括指令指针寄存器和堆栈指针寄存器。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">2) 它将上一次保存在即将运行的纤程的执行环境中的寄存器装入C P U寄存器。这些寄存器包括堆栈指针寄存器。这样，当线程继续执行时，就可以使用该纤程的内存栈。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">3) 它将纤程的执行环境与线程关联起来，线程运行特定的纤程。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">4) 它将线程的指令指针设置为已保存的指令指针。线程（纤程）从该纤程上次执行的地方开始继续执行。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">S w i t c h To F i b e r函数是纤程获得C P U时间的唯一途径。由于你的代码必须在相应的时间显式调用S w i t c h To F i b e r函数，因此你对纤程的调度可以实施全面的控制。记住，纤程的调度与线程调度毫不相干。纤程运行所依赖的线程始终都可以由操作系统终止其运行。当线程被调度时，当前选定的纤程开始运行，而其他纤程则不能运行，除非显式调用S w i t c h To F i b e r函数。若要撤消纤程，可以调用D e l e t e F i b e r函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>VOID DeleteFiber(PVOID pvFiberExecutionContext);</pre>
		</div>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">该函数用于删除p v F i b e r E x e c u t i o n C o n t e x t参数指明的纤程，当然这是纤程的执行环境的地址。该函数能够释放纤程栈使用的内存，然后撤消纤程的执行环境。但是，如果传递了当前与线程相关联的纤程地址，那么该函数就在内部调用E x i t T h r e a d函数，该线程及其创建的所有纤程全部被撤消。</font>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">D e l e t e F i b e r函数通常由一个纤程调用，以便删除另一个纤程。已经删除的纤程的内存栈将被撤消，纤程的执行环境被释放。注意，纤程与线程之间的差别在于，线程通常通过调用E x i t T h r e a d函数将自己撤消。实际上，用一个线程调用Te r m i n a t e T h r e a d函数来终止另一个线程的运行，是一种不好的方法。如果你确实调用了Te r m i n a t e T h r e a d函数，系统并不撤消已经终止运行的线程的内存栈。可以利用纤程的这种能力来删除另一个纤程，后面介绍示例应用程序时将说明这是如何实现的。</font>
		</p>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">为了使操作更加方便，还可以使用另外两个纤程函数。一个线程每次可以执行一个纤程，操作系统始终都知道当前哪个纤程与该线程相关联。如果想要获得当前运行的纤程的执行环境的地址，可以调用G e t C u r r e n t F i b e r函数：</font>
		</p>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>PVOID GetCurrentFiber();</pre>
		</div>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">另一个使用非常方便的函数是G e t F i b e r D a t a：</font>
		<p>
		</p>
		<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
				<pre>PVOID GetFiberData();</pre>
		</div>
		<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">前面讲过，每个纤程的执行环境包含一个用户定义的值。这个值使用作为C o n v e r t T h r e a dTo F i b e r或C r e a t e F i b e r的p v P a r a m参数而传递的值进行初始化。该值也可以作为纤程函数的参数来传递。G e t F i b e r D a t a只是查看当前执行的纤程的执行环境，并返回保存的值。</font>
		<p>
				<font style="LINE-HEIGHT: 25px" face="Arial" color="#000000" size="2">无论G e t C u r r e n t F i b e r还是G e t F i b e r D a t a，运行速度都很快，并且通常是作为内蕴函数(infrinsic funcfion)来实现的，这意味着编译器能够为这些函数生成内联代码。</font>
		</p>
<img src ="http://www.cppblog.com/mzty/aggbug/12511.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-15 15:08 <a href="http://www.cppblog.com/mzty/archive/2006/09/15/12511.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--线程池</title><link>http://www.cppblog.com/mzty/archive/2006/09/15/12510.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 15 Sep 2006 07:06:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/15/12510.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12510.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/15/12510.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12510.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12510.html</trackback:ping><description><![CDATA[先空着,大家有什么详细的关于这个的,欢迎留言跟大家共享.<img src ="http://www.cppblog.com/mzty/aggbug/12510.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-15 15:06 <a href="http://www.cppblog.com/mzty/archive/2006/09/15/12510.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--线程的同步</title><link>http://www.cppblog.com/mzty/archive/2006/09/14/12456.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 14 Sep 2006 07:08:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/14/12456.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12456.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/14/12456.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12456.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12456.html</trackback:ping><description><![CDATA[<font color=#3973de>线程的同步<br></font><font color=#000000>由于同一进程的所有线程共享进程的虚拟地址空间，并且线程的中断是汇编语言级的，所以可能会发生两个线程同时访问同一个对象（包括全局变量、共享资源、<font face="Times New Roman" size=3>API</font><font size=3>函数和</font><font face="Times New Roman" size=3>MFC</font><font size=3>对象等）的情况，这有可能导致程序错误。属于不同进程的线程在同时访问同一内存区域或共享资源时，也会存在同样的问题。<font size=3>因此，在多线程应用程序中，常常需要采取一些措施来同步线程的执行。<br>需要同步的情况包括以下几种：
<blockquote>
<blockquote>
<p align=justify>在多个线程同时访问同一对象时，可能产生错误。例如，如果当一个线程正在读取一个至关重要的共享缓冲区时，另一个线程向该缓冲区写入数据，那么程序的运行结果就可能出错。程序应该尽量避免多个线程同时访问同一个缓冲区或系统资源。</p>
<p align=justify>在</p>
</blockquote></blockquote></font><font face="Times New Roman" size=3>Windows 95</font><font size=3>环境下编写多线程应用程序还需要考虑重入问题。</font><font face="Times New Roman" size=3>Windows NT</font><font size=3>是真正的</font><font face="Times New Roman" size=3>32</font><font size=3>位操作系统，它解决了系统重入问题。而</font><font face="Times New Roman" size=3>Windows 95</font><font size=3>由于继承了</font><font face="Times New Roman" size=3>Windows 3.x</font><font size=3>的部分</font><font face="Times New Roman" size=3>16</font><font size=3>位代码，没能够解决重入问题。这意味着在</font><font face="Times New Roman" size=3>Windows 95</font><font size=3>中两个线程不能同时执行某个系统功能，否则有可能造成程序错误，甚至会造成系统崩溃。应用程序应该尽量避免发生两个以上的线程同时调用同一个</font><font face="Times New Roman" size=3>Windows API</font><font size=3>函数的情况。
<p align=justify>由于大小和性能方面的原因，</p>
</font><font face="Times New Roman" size=3>MFC</font><font size=3>对象在对象级不是线程安全的，只有在类级才是。也就是说，两个线程可以安全地使用两个不同的</font><font face="Times New Roman" size=3>CString</font><font size=3>对象，但同时使用同一个</font><font face="Times New Roman" size=3>CString</font><font size=3>对象就可能产生问题。如果必须使用同一个对象，那么应该采取适当的同步措施。
<p align=justify>多个线程之间需要协调运行。例如，如果第二个线程需要等待第一个线程完成到某一步时才能运行，那么该线程应该暂时挂起以减少对</p>
</font><font face="Times New Roman" size=3>CPU</font><font size=3>的占用时间，提高程序的执行效率。当第一个线程完成了相应的步骤后，应该发出某种信号来激活第二个线程。<br><br></font></font></font><font color=#3973de>关键节和互锁变量访问<br></font>
<p align=justify><font size=3>关键节</font> <font face="Times New Roman" size=3>(Critical Seciton)</font> <font size=3>与</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>的功能类似，但它只能由同一进程中的线程使用。关键节可以防止共享资源被同时访问。<br></font><font face="Times New Roman" size=3></font></p>
<p align=justify>进程负责为关键节分配内存空间，关键节实际上是一个<font face="Times New Roman" size=3>CRITICAL_SECTION</font><font size=3>型的变量，它一次只能被一个线程拥有。在线程使用关键节之前，必须调用</font><font face="Times New Roman" size=3>InitializeCriticalSection</font><font size=3>函数将其初始化。如果线程中有一段关键的代码不希望被别的线程中断，那么可以调用</font><font face="Times New Roman" size=3>EnterCriticalSection</font><font size=3>函数来申请关键节的所有权，在运行完关键代码后再用</font><font face="Times New Roman" size=3>LeaveCriticalSection</font><font size=3>函数来释放所有权。如果在调用</font><font face="Times New Roman" size=3>EnterCriticalSection</font><font size=3>时关键节对象已被另一个线程拥有，那么该函数将无限期等待所有权。<br><br>利用互锁变量可以建立简单有效的同步机制。使用函数<font face="Times New Roman" size=3>InterlockedIncrement</font><font size=3>和</font><font face="Times New Roman" size=3>InterlockedDecrement</font><font size=3>可以增加或减少多个线程共享的一个</font><font face="Times New Roman" size=3>32</font><font size=3>位变量的值，并且可以检查结果是否为</font><font face="Times New Roman" size=3>0</font><font size=3>。线程不必担心会被其它线程中断而导致错误。如果变量位于共享内存中，那么不同进程中的线程也可以使用这种机制。<br><br></font></font></p>
<br><strong><font face=Arial color=#0000ff>原子访问</font> </strong><br><br><font face=Arial size=2>所谓原子访问，是指线程在访问资源时能够确保所有其他线程都不在同一时间内访问相同的资源。互锁的函数家族:<br></font>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>
<span style="COLOR: #000000">LONG&nbsp;InterlockedExchangeAdd(<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PLONG&nbsp;plAddend,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;LONG&nbsp;Increment);</span>
</div>
</pre>
<p align=justify><font face=Arial size=2>这是个最简单的函数了。只需调用这个函数，传递一个长变量地址，并指明将这个值递增多少即可。但是这个函数能够保证值的递增以原子操作方式来完成。</font> <br><br><br></p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>LONG InterlockedExchange(PLONG plTarget,
LONG lValue);
PVOID InterlockedExchangePointer(PVOID* ppvTarget,
PVOID pvValue);</pre>
</div>
<p align=left><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>I n t e r l o c k e d E x c h a n g e和I n t e r l o c k e d E x c h a n g e P o i n t e r能够以原子操作方式用第二个参数中传递的值来取代第一个参数中传递的当前值。</font> <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ------------------------------以上为用户方式同步,以下为内核方式同步---------------------------------<br><br><strong><font face=Arial color=#0000ff>等待函数</font></strong></p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>等待函数可使线程自愿进入等待状态，直到一个特定的内核对象变为已通知状态为止。<br></font></p>
<pre>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>
<span style="COLOR: #000000">DWORD&nbsp;WaitForSingleObject(HANDLE&nbsp;hObject,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwMilliseconds);</span>
</div>
</pre>
<p><br><font face=Arial size=2>函数Wa i t F o r M u l t i p l e O b j e c t s与Wa i t F o r S i n g l e O b j e c t函数很相似，区别在于它允许调用线程同时查看若干个内核对象的已通知状态：</font> </p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>DWORD WaitForMultipleObjects(DWORD dwCount,
CONST HANDLE* phObjects,
BOOL fWaitAll,
DWORD dwMilliseconds);</pre>
</div>
<p><br><br><font color=#3973de>同步对象<br><br></font></p>
<p align=justify><font size=3>同步对象用来协调多线程的执行，它可以被多个线程共享。线程的等待函数用同步对象的句柄作为参数，同步对象应该是所有要使用的线程都能访问到的。同步对象的状态要么是有信号的，要么是无信号的。同步对象主要有三种：事件、</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>和信号灯。</font> <font face="Times New Roman" size=3></font></p>
<p align=justify><font size=3>事件对象</font> <font face="Times New Roman" size=3>(Event)</font> <font size=3>是最简单的同步对象，它包括有信号和无信号两种状态。在线程访问某一资源之前，也许需要等待某一事件的发生，这时用事件对象最合适。例如，只有在通信端口缓冲区收到数据后，监视线程才被激活。</font> <font face="Times New Roman" size=3></font></p>
<p align=justify><font size=3>事件对象是用</font> <font face="Times New Roman" size=3>CreateEvent</font> <font size=3>函数建立的。该函数可以指定事件对象的种类和事件的初始状态。如果是手工重置事件，那么它总是保持有信号状态，直到用</font> <font face="Times New Roman" size=3>ResetEvent</font> <font size=3>函数重置成无信号的事件。如果是自动重置事件，那么它的状态在单个等待线程释放后会自动变为无信号的。用</font> <font face="Times New Roman" size=3>SetEvent</font> <font size=3>可以把事件对象设置成有信号状态。在建立事件时，可以为对象起个名字，这样其它进程中的线程可以用</font> <font face="Times New Roman" size=3>OpenEvent</font> <font size=3>函数打开指定名字的事件对象句柄。</font> <font face="Times New Roman" size=3></font></p>
<p align=justify>mutex<font size=3>对象的状态在它不被任何线程拥有时是有信号的，而当它被拥有时则是无信号的。</font><font face="Times New Roman" size=3>mutex</font><font size=3>对象很适合用来协调多个线程对共享资源的互斥访问</font><font face="Times New Roman" size=3>(mutually exclusive)</font><font size=3>。</font><font face="Times New Roman" size=3></font></p>
<p align=justify><font size=3>线程用</font> <font face="Times New Roman" size=3>CreateMutex</font> <font size=3>函数来建立</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>对象，在建立</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>时，可以为对象起个名字，这样其它进程中的线程可以用</font> <font face="Times New Roman" size=3>OpenMutex</font> <font size=3>函数打开指定名字的</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>对象句柄。在完成对共享资源的访问后，线程可以调用</font> <font face="Times New Roman" size=3>ReleaseMutex</font> <font size=3>来释放</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>，以便让别的线程能访问共享资源。如果线程终止而不释放</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>，则认为该</font> <font face="Times New Roman" size=3>mutex</font> <font size=3>被废弃。</font> <font face="Times New Roman" size=3></font></p>
<p align=justify><font size=3>信号灯对象维护一个从</font> <font face="Times New Roman" size=3>0</font> <font size=3>开始的计数，在计数值大于</font> <font face="Times New Roman" size=3>0</font> <font size=3>时对象是有信号的，而在计数值为</font> <font face="Times New Roman" size=3>0</font> <font size=3>时则是无信号的。信号灯对象可用来限制对共享资源进行访问的线程数量。线程用</font> <font face="Times New Roman" size=3>CreateSemaphore</font> <font size=3>函数来建立信号灯对象，在调用该函数时，可以指定对象的初始计数和最大计数。在建立信号灯时也可以为对象起个名字，别的进程中的线程可以用</font> <font face="Times New Roman" size=3>OpenSemaphore</font> <font size=3>函数打开指定名字的信号灯句柄。</font> <font face="Times New Roman" size=3></font></p>
<p align=justify><font size=3>一般把信号灯的初始计数设置成最大值。每次当信号灯有信号使等待函数返回时，信号灯计数就会减</font> <font face="Times New Roman" size=3>1</font> <font size=3>，而调用</font> <font face="Times New Roman" size=3>ReleaseSemaphore</font> <font size=3>可以增加信号灯的计数。计数值越小就表明访问共享资源的程序越多。</font> <font face="Times New Roman" size=3></font></p>
<p align=justify>可用于同步的对象 </p>
<p align=justify></p>
<table cellSpacing=1 cellPadding=1 width=579 border=1>
    <tbody>
        <tr>
            <td width="22%"><font size=3><strong>
            <p align=justify>对象</p>
            </strong></font></td>
            <td width="78%"><font size=3><strong>
            <p align=justify>描述</p>
            </strong></font></td>
        </tr>
        <tr>
            <td width="22%"><font size=3>
            <p align=justify>变化通知</p>
            </font></td>
            <td width="78%"><font size=3>
            <p align=justify>由</p>
            </font><font face="Times New Roman" size=3>FindFirstChangeNotification</font> <font size=3>函数建立，当在指定目录中发生指定类型的变化时对象变成有信号的。</font> </td>
        </tr>
        <tr>
            <td width="22%"><font size=3>
            <p align=justify>控制台输入</p>
            </font></td>
            <td width="78%"><font size=3>
            <p align=justify>在控制台建立是被创建。它是用</p>
            </font><font face="Times New Roman" size=3>CONIN$</font> <font size=3>调用</font> <font face="Times New Roman" size=3>CreateFile</font> <font size=3>函数返回的句柄，或是</font> <font face="Times New Roman" size=3>GetStdHandle</font> <font size=3>函数的返回句柄。如果控制台输入缓冲区中有数据，那么对象是有信号的，如果缓冲区为空，则对象是无信号的。</font> </td>
        </tr>
        <tr>
            <td width="22%"><font size=3>
            <p align=justify>进程</p>
            </font></td>
            <td width="78%"><font size=3>
            <p align=justify>当调用</p>
            </font><font face="Times New Roman" size=3>CreateProcess</font> <font size=3>建立进程时被创建。进程在运行时对象是无信号的，当进程终止时对象是有信号的。</font> </td>
        </tr>
        <tr>
            <td width="22%"><font size=3>
            <p align=justify>线程</p>
            </font></td>
            <td width="78%"><font size=3>
            <p align=justify>当调用</p>
            </font><font face="Times New Roman" size=3>Createprocess</font> <font size=3>、</font> <font face="Times New Roman" size=3>CreateThread</font> <font size=3>或</font> <font face="Times New Roman" size=3>CreateRemoteThread</font> <font size=3>函数创建新线程时被创建。在线程运行是对象是无信号的，在线程终止时则是有信号的。</font> </td>
        </tr>
    </tbody>
</table>
另外，有时可以用文件或通信设备作为同步对象使用。<font face="Times New Roman" size=3></font><br><br><strong><font face=Arial color=#0000ff>事件内核对象<br><br>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>让我们观察一个简单的例子，以便说明如何使用事件内核对象对线程进行同步。下面就是这个代码：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>// Create a global handle to a manual-reset, nonsignaled event.
HANDLE g_hEvent;
int WINAPI WinMain(...)
{
//Create the manual-reset, nonsignaled event.
g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//Spawn 3 new threads.
HANDLE hThread[3];
DWORD dwThreadID;
hThread[0] = _beginthreadex(NULL, 0, WordCount, NULL, 0, &amp;dwThreadID);
hThread[1] = _beginthreadex(NULL, 0, SpellCheck, NULL, 0, &amp;dwThreadID);
hThread[2] = _beginthreadex(NULL, 0, GrammarCheck, NULL, 0, &amp;dwThreadID);
OpenFileAndReadContentsIntoMemory(...);
//Allow all 3 threads to access the memory.
SetEvent(g_hEvent);
...
}
DWORD WINAPI WordCount(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
return(0);
}
DWORD WINAPI SpellCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
return(0);
}
DWORD WINAPI GrammarCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
return(0);
}</pre>
</div>
<font style="LINE-HEIGHT: 25px" color=#000000 size=2>当这个进程启动时，它创建一个人工重置的未通知状态的事件，并且将句柄保存在一个全局变量中。这使得该进程中的其他线程能够非常容易地访问同一个事件对象。现在3个线程已经产生。这些线程要等待文件的内容读入内存，然后每个线程都要访问它的数据。一个线程进行单词计数，另一个线程运行拼写检查器，第三个线程运行语法检查器。这3个线程函数的代码的开始部分都相同，每个函数都调用Wa i t F o r S i n g l e O b j e c t，这将使线程暂停运行，直到文件的内容由主线程读入内存为止。</font>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>一旦主线程将数据准备好，它就调用S e t E v e n t，给事件发出通知信号。这时，系统就使所有这3个辅助线程进入可调度状态，它们都获得了C P U时间，并且可以访问内存块。注意，这3个线程都以只读方式访问内存。这就是所有3个线程能够同时运行的唯一原因。还要注意，如何计算机上配有多个C P U，那么所有3个线程都能够真正地同时运行，从而可以在很短的时间内完成大量的操作。</font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>如果你使用自动重置的事件而不是人工重置的事件，那么应用程序的行为特性就有很大的差别。当主线程调用S e t E v e n t之后，系统只允许一个辅助线程变成可调度状态。同样，也无法保证系统将使哪个线程变为可调度状态。其余两个辅助线程将继续等待。</font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>已经变为可调度状态的线程拥有对内存块的独占访问权。让我们重新编写线程的函数，使得每个函数在返回前调用S e t E v e n t函数（就像Wi n M a i n函数所做的那样）。这些线程函数现在变成下面的形式：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>DWORD WINAPI WordCount(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
SetEvent(g_hEvent);
return(0);
}
DWORD WINAPI SpellCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
SetEvent(g_hEvent);
return(0);
}
DWORD WINAPI GrammarCheck(PVOID pvParam)
{
//Wait until the file's data is in memory.
WaitForSingleObject(g_hEvent, INFINITE);
//Access the memory block.
...
SetEvent(g_hEvent);
return(0);
}</pre>
</div>
<font style="LINE-HEIGHT: 25px" color=#000000 size=2>当线程完成它对数据的专门传递时，它就调用S e t E v e n t函数，该函数允许系统使得两个正在等待的线程中的一个成为可调度线程。同样，我们不知道系统将选择哪个线程作为可调度线程，但是该线程将进行它自己的对内存块的专门传递。当该线程完成操作时，它也将调用S e t E v e n t函数，使第三个即最后一个线程进行它自己的对内存块的传递。注意，当使用自动重置事件时，如果每个辅助线程均以读/写方式访问内存块，那么就不会产生任何问题，这些线程将不再被要求将数据视为只读数据。</font></font></strong><br><br><strong><font face=Arial color=#0000ff>等待定时器内核对象</font></strong>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象。它们通常用来在某个时间执行某个操作。</font></p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>若要创建等待定时器，只需要调用C r e a t e Wa i t a b l e Ti m e r函数：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>HANDLE CreateWaitableTimer(
PSECURITY_ATTRIBUTES psa,
BOOL fManualReset,
PCTSTR pszName);</pre>
</div>
<font face=Arial size=2>进程可以获得它自己的与进程相关的现有等待定时器的句柄，方法是调用O p e n Wa i t a b l e Ti m e r函数：</font>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>HANDLE OpenWaitableTimer(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);</pre>
</div>
<font face=Arial size=2>当发出人工重置的定时器信号通知时，等待该定时器的所有线程均变为可调度线程。当发出自动重置的定时器信号通知时，只有一个等待的线程变为可调度线程。</font>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>等待定时器对象总是在未通知状态中创建。必须调用S e t Wa i t a b l e Ti m e r函数来告诉定时器你想在何时让它成为已通知状态：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>BOOL SetWaitableTimer(
HANDLE hTimer,
const LARGE_INTEGER *pDueTime,
LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine,
PVOID pvArgToCompletionRoutine,
BOOL fResume);</pre>
</div>
<font face=Arial size=2>定时器函数外，最后还有一个C a n c e l Wa i t a b l e Ti m e r函数：</font>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>BOOL CancelWaitableTimer(HANDLE hTimer);</pre>
</div>
<font style="LINE-HEIGHT: 25px" color=#000000><font face=Arial size=2>这个简单的函数用于取出定时器的句柄并将它撤消，这样，除非接着调用S e t Wa i t a b l e Ti m e r函数以便重新设置定时器，否则定时器决不会进行报时。<br><br><strong><font color=#0000ff>信标内核对象</font></strong></font>
<p><font style="LINE-HEIGHT: 25px" color=#000000><font face=Arial size=2>信标内核对象用于对资源进行计数。它们与所有内核对象一样，包含一个使用数量，但是它们也包含另外两个带符号的3 2位值，一个是最大资源数量，一个是当前资源数量。最大资源数量用于标识信标能够控制的资源的最大数量，而当前资源数量则用于标识当前可以使用的资源的数量。<br></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>信标的使用规则如下：</font></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>&#8226; 如果当前资源的数量大于0，则发出信标信号。</font></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>&#8226; 如果当前资源数量是0，则不发出信标信号。</font></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>&#8226; 系统决不允许当前资源的数量为负值。</font></font></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000><font face=Arial size=2>&#8226; 当前资源数量决不能大于最大资源数量。<br></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>下面的函数用于创建信标内核对象：</font></font></font></p>
<p><font face=Arial size=2></font></p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font face=Arial size=2>HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTE psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);</font></pre>
</div>
</font><font face=Arial size=2>通过调用O p e n S e m a p h o r e函数，另一个进程可以获得它自己的进程与现有信标相关的句柄：</font>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>HANDLE OpenSemaphore(
DWORD fdwAccess,
BOOL bInheritHandle,
PCTSTR pszName);</pre>
</div>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>通过调用R e l e a s e S e m a p h o r e函数，线程就能够对信标的当前资源数量进行递增：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>BOOL ReleaseSemaphore(
HANDLE hsem,
LONG lReleaseCount,
PLONG plPreviousCount);</pre>
</div>
<strong><font face=Arial color=#0000ff>互斥对象内核对象</font></strong>
<p><font style="LINE-HEIGHT: 25px" color=#000000><font face=Arial size=2>互斥对象（m u t e x）内核对象能够确保线程拥有对单个资源的互斥访问权。<br>互斥对象有许多用途，属于最常用的内核对象之一。通常来说，它们用于保护由多个线程访问的内存块。如果多个线程要同时访问内存块，内存块中的数据就可能遭到破坏。互斥对象能够保证访问内存块的任何线程拥有对该内存块的独占访问权，这样就能够保证数据的完整性。 </font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>互斥对象的使用规则如下：</font></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>&#8226; 如果线程I D是0（这是个无效I D），互斥对象不被任何线程所拥有，并且发出该互斥对象的通知信号。</font></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>&#8226; 如果I D是个非0数字，那么一个线程就拥有互斥对象，并且不发出该互斥对象的通知信号。</font></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>&#8226; 与所有其他内核对象不同， 互斥对象在操作系统中拥有特殊的代码，允许它们违反正常的规则（后面将要介绍这个异常情况）。</font></font></font></p>
<p><font size=2><font face=Arial><font style="LINE-HEIGHT: 25px" color=#000000>若要使用互斥对象，必须有一个进程首先调用C r e a t e M u t e x，以便创建互斥对象：</font></font></font></p>
<p><font face=Arial size=2></font></p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font face=Arial size=2>HANDLE CreateMutex(
PSECURITY_ATTRIBUTES psa,
BOOL fInitialOwner,
PCTSTR pszName);</font></pre>
</div>
<p><font face=Arial size=2>通过调用O p e n M u t e x，另一个进程可以获得它自己进程与现有互斥对象相关的句柄：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>HANDLE OpenMutex(
DWORD fdwAccess,
BOOL bInheritHandle,
PCTSTR pszName);</pre>
</div>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>一旦线程成功地等待到一个互斥对象，该线程就知道它已经拥有对受保护资源的独占访问权。试图访问该资源的任何其他线程（通过等待相同的互斥对象）均被置于等待状态中。当目前拥有对资源的访问权的线程不再需要它的访问权时，它必须调用R e l e a s e M u t e x函数来释放该互斥对象：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>BOOL ReleaseMutex(HANDLE hMutex);</pre>
</div>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>该函数将对象的递归计数器递减1。<br><br><font size=3><strong><font color=#0000ff>互斥对象与关键代码段的比较</font></strong><font face="Times New Roman"></font></font></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>就等待线程的调度而言，互斥对象与关键代码段之间有着相同的特性。但是它们在其他属性方面却各不相同。表9 - 1对它们进行了各方面的比较。</font></p>
<p>&#160;</p>
<p align=center>表9-1 互斥对象与关键代码段的比较 </p>
<div align=center>
<table style="WIDTH: 522px; HEIGHT: 527px" borderColor=#808000 cellSpacing=1 cellPadding=6 align=center border=2>
    <tbody>
        <tr>
            <td align=middle width="20%">特性</td>
            <td align=middle width="40%">互斥对象</td>
            <td align=middle width="40%">关键代码段</td>
        </tr>
        <tr>
            <td width="20%">运行速度</td>
            <td width="40%">慢</td>
            <td width="40%">快</td>
        </tr>
        <tr>
            <td width="20%">是否能够跨进程边界来使用</td>
            <td width="40%">是</td>
            <td width="40%">否</td>
        </tr>
        <tr>
            <td width="20%">声明</td>
            <td width="40%">HANDLE hmtx；</td>
            <td width="40%">CRITICAL_SECTION cs；</td>
        </tr>
        <tr>
            <td width="20%">初始化</td>
            <td width="40%">h m t x = C r e a t e M u t e x（N U L L，FA L S E，N U L L）；</td>
            <td width="40%">I n i t i a l i z e C r i t i c a l S e c t i o n ( &amp; e s )；</td>
        </tr>
        <tr>
            <td width="20%">清除</td>
            <td width="40%">C l o s e H a n d l e（h m t x）；</td>
            <td width="40%">D e l e t e C r i t i c a l S e c t i o n（&amp; c s）；</td>
        </tr>
        <tr>
            <td width="20%">无限等待</td>
            <td width="40%">Wa i t F o r S i n g l e O b j e c t（h m t x , I N F I N I T E）； </td>
            <td width="40%">E n t e r C r i t i c a l S e c t i o n（&amp; c s）；</td>
        </tr>
        <tr>
            <td width="20%">0等待</td>
            <td width="40%">Wa i t F o r S i n g l e O b j e c t Tr y（h m t x , 0）； </td>
            <td width="40%">E n t e r C r i t i c a l S e c t i o n（&amp; c s）；</td>
        </tr>
        <tr>
            <td width="20%">任意等待</td>
            <td width="40%">Wa i t F o r S i n g l e O b j e c t（h m t x , d w M i l l i s e c o n d s）；</td>
            <td width="40%">不能</td>
        </tr>
        <tr>
            <td width="20%">释放</td>
            <td width="40%">R e l e a s e M u t e x（h m t x）； </td>
            <td width="40%">L e a v e C r i t i c a l S e c t i o n（&amp; c s）；</td>
        </tr>
        <tr>
            <td width="20%">是否能够等待其他内核对象</td>
            <td width="40%">是（使用Wa i t F o r M u l t i p l e O b j e c t s或类似的函数）</td>
            <td width="40%">否</td>
        </tr>
    </tbody>
</table>
</div>
<div align=left><br><strong><font face=Arial color=#0000ff>线程同步对象速查表<br><br><font face="Times New Roman" color=#000000>内核对象与线程同步之间的相互关系 </font></font></strong></div>
<div align=center>
<table style="WIDTH: 492px; HEIGHT: 684px" borderColor=#808000 cellSpacing=1 cellPadding=6 align=center border=2>
    <tbody>
        <tr>
            <td align=middle width="20%">对象</td>
            <td align=middle width="30%">何时处于未通知状态</td>
            <td align=middle width="30%">何时处于已通知状态</td>
            <td align=middle width="20%">成功等待的副作用</td>
        </tr>
        <tr>
            <td width="20%">进程</td>
            <td width="30%">当进程仍然活动时</td>
            <td width="30%">当进程终止运行时（E x i t P r o c e s s，Te r m i n a t e P r o c e s s）</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">线程</td>
            <td width="30%">当线程仍然活动时</td>
            <td width="30%">当线程终止运行时（E x i t T h r e a d，Te r m i n a t e T h r e a d）</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">作业</td>
            <td width="30%">当作业的时间尚未结束时</td>
            <td width="30%">当作业的时间已经结束时</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">文件</td>
            <td width="30%">当I / O请求正在处理时</td>
            <td width="30%">当I / O请求处理完毕时</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">控制台输入</td>
            <td width="30%">不存在任何输入</td>
            <td width="30%">当存在输入时</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">文件修改通知</td>
            <td width="30%">没有任何文件被修改</td>
            <td width="30%">当文件系统发现修改时</td>
            <td width="20%">重置通知</td>
        </tr>
        <tr>
            <td width="20%">自动重置事件</td>
            <td width="30%">R e s e t E v e n t , P u l s e - E v e n t或等待成功</td>
            <td width="30%">当调用S e t E v e n t / P u l s e E v e n t时</td>
            <td width="20%">重置事件</td>
        </tr>
        <tr>
            <td width="20%">人工重置事件</td>
            <td width="30%">R e s e t E v e n t或P u l s e E v e n t</td>
            <td width="30%">当调用S e t E v e n t / P u l s e E v e n t时</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">自动重置等待定时器</td>
            <td width="30%">C a n c e l Wa i t a b l e Ti m e r或等待成功</td>
            <td width="30%">当时间到时（S e t Wa i t a b l e Ti m e r）</td>
            <td width="20%">重置定时器</td>
        </tr>
        <tr>
            <td width="20%">人工重置等待定时器</td>
            <td width="30%">C a n c e l Wa i t a b l e Ti m e r</td>
            <td width="30%">当时间到时（S e t Wa i t a b l e Ti m e r）</td>
            <td width="20%">无</td>
        </tr>
        <tr>
            <td width="20%">信标</td>
            <td width="30%">等待成功</td>
            <td width="30%">当数量&gt; 0时（R e l e a s e S e m a p h o r e）</td>
            <td width="20%">数量递减1</td>
        </tr>
        <tr>
            <td width="20%">互斥对象</td>
            <td width="30%">等待成功</td>
            <td width="30%">当未被线程拥有时（R e l e a s e互斥对象）</td>
            <td width="20%">将所有权赋予线程</td>
        </tr>
        <tr>
            <td width="20%">关键代码段（用户方式）</td>
            <td width="30%">等待成功（（Tr y）E n t e r C r i t i c a l S e c t i o n）</td>
            <td width="30%">当未被线程拥有时（L e a v e C r i t i c a l S e c t i o n）</td>
            <td width="20%">将所有权赋予线程</td>
        </tr>
    </tbody>
</table>
</div>
<div align=left><br><br><strong><font face=Arial color=#0000ff>其他的线程同步函数<br><br>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>1 异步设备I / O使得线程能够启动一个读操作或写操作，但是不必等待读操作或写操作完成。例如，如果线程需要将一个大文件装入内存，那么该线程可以告诉系统将文件装入内存。然后，当系统加载该文件时，该线程可以忙于执行其他任务，如创建窗口、对内部数据结构进行初始化等等。当初始化操作完成时，该线程可以终止自己的运行，等待系统通知它文件已经读取。<br></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>2 线程也可以调用Wa i t F o r I n p u t I d l e来终止自己的运行：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>DWORD WaitForInputIdle(
HANDLE hProcess,
DWORD dwMilliseconds);</pre>
</div>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>该函数将一直处于等待状态，直到h P r o c e s s标识的进程在创建应用程序的第一个窗口的线程中已经没有尚未处理的输入为止。这个函数可以用于父进程。父进程产生子进程，以便执行某些操作。<br>3 <font style="LINE-HEIGHT: 25px" color=#000000 size=2>线程可以调用M s g Wa i t F o r M u l t i p l e O b j e c t s或M s g Wa i t F o r M u l t i p l e O b j e c t s E x函数，让线程等待它自己的消息：</font></font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>DWORD MsgWaitForMultipleObjects(
DWORD dwCount,
PHANDLE phObjects,
BOOL fWaitAll,
DWORD dwMilliseconds,
DWORD dwWakeMask);
DWORD MsgWaitForMultipleObjectsEx(
DWORD dwCount,
PHANDLE phObjects,
DWORD dwMilliseconds,
DWORD dwWakeMask,
DWORD dwFlags);</pre>
</div>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>这些函数与Wa i t F o r M u l t i p l e O b j e c t s函数十分相似。差别在于它们允许线程在内核对象变成已通知状态或窗口消息需要调度到调用线程创建的窗口中时被调度。<br><br></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>4 Wi n d o w s将非常出色的调试支持特性内置于操作系统之中。当调试程序启动运行时，它将自己附加给一个被调试程序。该调试程序只需闲置着，等待操作系统将与被调试程序相关的调试事件通知它。调试程序通过调用Wa i t F o r D e b u g E v e n t函数来等待这些事件的发生：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>BOOL WaitForDebugEvent(
PDEBUG_EVENT pde,
DWORD dwMilliseconds);</pre>
</div>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>当调试程序调用该函数时，调试程序的线程终止运行，系统将调试事件已经发生的情况通知调试程序，方法是允许调用的Wa i t F o r D e b u g E v e n t函数返回。<br><br>5 <font style="LINE-HEIGHT: 25px" color=#000000 size=2>S i n g l e O b j e c t A n d Wa i t函数用于在单个原子方式的操作中发出关于内核对象的通知并等待另一个内核对象：</font></font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre>DWORD SingleObjectAndWait(
HANDLE hObjectToSignal,
HANDLE hObjectToWaitOn,
DWORD  dwMilliseconds,
BOOL   fAlertable);</pre>
</div>
</font></strong></div><img src ="http://www.cppblog.com/mzty/aggbug/12456.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-14 15:08 <a href="http://www.cppblog.com/mzty/archive/2006/09/14/12456.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--线程高级</title><link>http://www.cppblog.com/mzty/archive/2006/09/14/12437.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 14 Sep 2006 02:13:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/14/12437.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12437.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/14/12437.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12437.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12437.html</trackback:ping><description><![CDATA[
		<font face="Arial" color="#0000ff">
				<strong>暂停和恢复线程的运行<br /><br /></strong>
				<font color="#000000" size="2">在线程内核对象的内部有一个值，用于指明线程的暂停计数。当调用C r e a t e P r o c e s s或C r e a t e T h r e a d函数时，就创建了线程的内核对象，并且它的暂停计数被初始化为1。当线程的暂停计数是0的时候，除非线程正在等待其他某种事情的发生，否则该线程就处于可调度状态。<br /><br />恢复线程,可以用将调用R e s u m e T h r e a d<br />并将C r e a t e T h r e a d函数时返回的线程句柄传递给它（或者是将传递给C r e a t e P r o c e s s的p p i P r o c I n f o参数指向的线程句柄传递给它）：<font face="Times New Roman" size="3"></font><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">DWORD ResumeThread(HANDLE hThread);</font></pre></div>当创建线程时，除了使用C R E AT E _ S U S P E N D E D外，也可以调用S u s p e n dT h r e a d函数来暂停线程的运行： 
<p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">DWORD SuspendThread(HANDLE hThread);</font></pre></div><font color="#0000ff"><strong>暂停和恢复进程的运行<br /><br /></strong></font><font color="#000000">对于Wi n d o w s来说，不存在暂停或恢复进程的概念，因为进程从来不会被安排获得C P U时间。Wi n d o w s确实允许一个进程暂停另一个进程中的所有线程的运行，但是从事暂停操作的进程必须是个调试程序。特别是，进程必须调用Wa i t F o r D e b u g E v e n t和C o n t i n u e D e b u g E v e n t之类的函数。<br /><pre><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">VOID SuspendProcess(DWORD dwProcessID, BOOL fSuspend)<br /><img id="Codehighlighter1_54_1026_Open_Image" onclick="this.style.display='none'; Codehighlighter1_54_1026_Open_Text.style.display='none'; Codehighlighter1_54_1026_Closed_Image.style.display='inline'; Codehighlighter1_54_1026_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_54_1026_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_54_1026_Closed_Text.style.display='none'; Codehighlighter1_54_1026_Open_Image.style.display='inline'; Codehighlighter1_54_1026_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_54_1026_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_54_1026_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Get the list of threads in the system.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">   HANDLE hSnapshot </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> CreateToolhelp32Snapshot(<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      TH32CS_SNAPTHREAD, dwProcessID);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(hSnapshot </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> INVALID_HANDLE_VALUE) <br /><img id="Codehighlighter1_233_1024_Open_Image" onclick="this.style.display='none'; Codehighlighter1_233_1024_Open_Text.style.display='none'; Codehighlighter1_233_1024_Closed_Image.style.display='inline'; Codehighlighter1_233_1024_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_233_1024_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_233_1024_Closed_Text.style.display='none'; Codehighlighter1_233_1024_Open_Image.style.display='inline'; Codehighlighter1_233_1024_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />   </span><span id="Codehighlighter1_233_1024_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_233_1024_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Walk the list of threads.</span><span style="COLOR: #008000"><br /><img id="Codehighlighter1_294_307_Open_Image" onclick="this.style.display='none'; Codehighlighter1_294_307_Open_Text.style.display='none'; Codehighlighter1_294_307_Closed_Image.style.display='inline'; Codehighlighter1_294_307_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_294_307_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_294_307_Closed_Text.style.display='none'; Codehighlighter1_294_307_Open_Image.style.display='inline'; Codehighlighter1_294_307_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" /></span><span style="COLOR: #000000">      THREADENTRY32 te </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span id="Codehighlighter1_294_307_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_294_307_Open_Text"><span style="COLOR: #000000">{ </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(te) }</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      BOOL fOk </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Thread32First(hSnapshot, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">te);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(; fOk; fOk </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Thread32Next(hSnapshot, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">te)) <br /><img id="Codehighlighter1_419_989_Open_Image" onclick="this.style.display='none'; Codehighlighter1_419_989_Open_Text.style.display='none'; Codehighlighter1_419_989_Closed_Image.style.display='inline'; Codehighlighter1_419_989_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_419_989_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_419_989_Closed_Text.style.display='none'; Codehighlighter1_419_989_Open_Image.style.display='inline'; Codehighlighter1_419_989_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />      </span><span id="Codehighlighter1_419_989_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_419_989_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />         </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Is this thread in the desired process?</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">         </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(te.th32OwnerProcessID </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> dwProcessID) <br /><img id="Codehighlighter1_531_981_Open_Image" onclick="this.style.display='none'; Codehighlighter1_531_981_Open_Text.style.display='none'; Codehighlighter1_531_981_Closed_Image.style.display='inline'; Codehighlighter1_531_981_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_531_981_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_531_981_Closed_Text.style.display='none'; Codehighlighter1_531_981_Open_Image.style.display='inline'; Codehighlighter1_531_981_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />         </span><span id="Codehighlighter1_531_981_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_531_981_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Attempt to convert the thread ID into a handle.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">            HANDLE hThread </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> OpenThread(THREAD_SUSPEND_RESUME,<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />               FALSE, te.th32ThreadID);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(hThread </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> NULL) <br /><img id="Codehighlighter1_744_936_Open_Image" onclick="this.style.display='none'; Codehighlighter1_744_936_Open_Text.style.display='none'; Codehighlighter1_744_936_Closed_Image.style.display='inline'; Codehighlighter1_744_936_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_744_936_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_744_936_Closed_Text.style.display='none'; Codehighlighter1_744_936_Open_Image.style.display='inline'; Codehighlighter1_744_936_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />            </span><span id="Codehighlighter1_744_936_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_744_936_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />               </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Suspend or resume the thread.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">               </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(fSuspend)<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />                  SuspendThread(hThread);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />               </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />                  ResumeThread(hThread);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />            }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            CloseHandle(hThread);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />         }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />      }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      CloseHandle(hSnapshot);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />   }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div></pre>以上是作者实现的,但是有的时候会出错.<br /><br /><strong><font color="#0000ff"> 睡眠方式</font></strong><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">线程也能告诉系统，它不想在某个时间段内被调度。这是通过调用S l e e p函数来实现的：</font></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">VOID Sleep(DWORD dwMilliseconds);</font></pre></div>关于S l e e p函数，有下面几个重要问题值得注意： 
<p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 调用S l e e p，可使线程自愿放弃它剩余的时间片。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 系统将在大约的指定毫秒数内使线程不可调度。不错，如果告诉系统，想睡眠1 0 0 m s，那么可以睡眠大约这么长时间，但是也可能睡眠数秒钟或者数分钟。记住， Wi n d o w s不是个实时操作系统。虽然线程可能在规定的时间被唤醒，但是它能否做到，取决于系统中还有什么操作正在进行。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 可以调用S l e e p，并且为d w M i l l i s e c o n d s参数传递I N F I N I T E。这将告诉系统永远不要调度该线程。这不是一件值得去做的事情。最好是让线程退出，并还原它的堆栈和内核对象。</font></p><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">• 可以将0传递给S l e e p。这将告诉系统，调用线程将释放剩余的时间片，并迫使系统调度另一个线程。但是，系统可以对刚刚调用S l e e p的线程重新调度。如果不存在多个拥有相同优先级的可调度线程，就会出现这种情况。</font></p><strong><font color="#0000ff">转换到另一个线程</font></strong><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">系统提供了一个称为S w i t c h To T h r e a d的函数，使得另一个可调度线程（如果存在能够运行）：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">BOOL SwitchToThread();</font></pre></div><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">当调用这个函数的时候，系统要查看是否存在一个迫切需要C P U时间的线程。如果没有线程迫切需要C P U时间，S w i t c h To T h r e a d就会立即返回。如果存在一个迫切需要C P U时间的线程，S w i t c h To T h r e a d就对该线程进行调度（该线程的优先级可能低于调用S w i t c h To T h r e a d的线程）。<br /></font></p><p><strong><font color="#0000ff">线程的运行时间</font></strong></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Get the current time (start time).</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">DWORD dwStartTime </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> GetTickCount();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Perform complex algorithm here.<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Subtract start time from current time to get duration.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">DWORD dwElapsedTime </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> GetTickCount() </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"> dwStartTime;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><p>这个代码做了一个简单的假设：即它不会被中断。但是，在抢占式操作系统中，永远无法知道线程何时被赋予C P U时间。</p></font><br /><br />幸运的是，Wi n d o w s提供了一个称为G e t T h r e a d Ti m e s的函数，它能返回这些信息： 
<p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">BOOL GetThreadTimes(HANDLE hThread,
   PFILETIME pftCreationTime, PFILETIME pftExitTime,
   PFILETIME pftKernelTime, PFILETIME pftUserTime);</font></pre></div><p>使用实例<br /></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">__int64 FileTimeToQuadWord(PFILETIME pft) <br /><img id="Codehighlighter1_43_126_Open_Image" onclick="this.style.display='none'; Codehighlighter1_43_126_Open_Text.style.display='none'; Codehighlighter1_43_126_Closed_Image.style.display='inline'; Codehighlighter1_43_126_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_43_126_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_43_126_Closed_Text.style.display='none'; Codehighlighter1_43_126_Open_Image.style.display='inline'; Codehighlighter1_43_126_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_43_126_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_43_126_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> (Int64ShllMod32(<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      pft</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">dwHighDateTime, </span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">|</span><span style="COLOR: #000000"> pft</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">dwLowDateTime);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> PerformLongOperation() <br /><img id="Codehighlighter1_158_1263_Open_Image" onclick="this.style.display='none'; Codehighlighter1_158_1263_Open_Text.style.display='none'; Codehighlighter1_158_1263_Closed_Image.style.display='inline'; Codehighlighter1_158_1263_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_158_1263_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_158_1263_Closed_Text.style.display='none'; Codehighlighter1_158_1263_Open_Image.style.display='inline'; Codehighlighter1_158_1263_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_158_1263_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_158_1263_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   FILETIME ftKernelTimeStart, ftKernelTimeEnd;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   FILETIME ftUserTimeStart,   ftUserTimeEnd;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   FILETIME ftDummy;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   __int64 qwKernelTimeElapsed, qwUserTimeElapsed,<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      qwTotalTimeElapsed;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Get starting times.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">   GetThreadTimes(GetCurrentThread(), </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftDummy,<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftDummy, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftKernelTimeStart, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftUserTimeStart);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Perform complex algorithm here.<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Get ending times.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">   GetThreadTimes(GetCurrentThread(), </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftDummy,<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftDummy, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftKernelTimeEnd, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftUserTimeEnd);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Get the elapsed kernel and user times by <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">converting the start and end times <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">from FILETIMEs to quad words, and then <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">subtract the start times from the end times.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   qwKernelTimeElapsed </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      FileTimeToQuadWord(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftKernelTimeEnd) </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      FileTimeToQuadWord(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftKernelTimeStart);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   qwUserTimeElapsed </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      FileTimeToQuadWord(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftUserTimeEnd) </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      FileTimeToQuadWord(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ftUserTimeStart);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Get total time duration by adding the kernel<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">and user times.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   qwTotalTimeElapsed </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> qwKernelTimeElapsed </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      qwUserTimeElapsed;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">The total elapsed time is in <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">qwTotalTimeElapsed.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" /></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><p>注意，G e t P r o c e s s Ti m e s是个类似G e t T h r e a d Ti m e s的函数，适用于进程中的所有线程： </p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">BOOL GetProcessTimes(HANDLE hProcess,
   PFILETIME pftCreationTime, PFILETIME pftExitTime,
   PFILETIME pftKernelTime, PFILETIME pftUserTime);</font></pre></div><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">对于高分辨率的配置文件来说， G e t T h r e a d Ti m e s并不完美。Wi n d o w s确实提供了一些高分辨率性能函数：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font style="BACKGROUND-COLOR: #ff1493" size="3">BOOL QueryPerformanceFrequency(
   LARGE_INTEGER* pliFrequency);

BOOL QueryPerformanceCounter(
   LARGE_INTEGER* pliCount);</font></pre></div><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">虽然这些函数认为，正在执行的线程并没有得到抢占的机会，但是高分辨率的配置文件是为短期存在的代码块设置的。为了使这些函数运行起来更加容易一些，我创建了下面这个C + +类：</font><br /></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> CStopwatch <br /><img id="Codehighlighter1_18_607_Open_Image" onclick="this.style.display='none'; Codehighlighter1_18_607_Open_Text.style.display='none'; Codehighlighter1_18_607_Closed_Image.style.display='inline'; Codehighlighter1_18_607_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_18_607_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_18_607_Closed_Text.style.display='none'; Codehighlighter1_18_607_Open_Image.style.display='inline'; Codehighlighter1_18_607_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_18_607_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_18_607_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   CStopwatch() <br /><img id="Codehighlighter1_48_117_Open_Image" onclick="this.style.display='none'; Codehighlighter1_48_117_Open_Text.style.display='none'; Codehighlighter1_48_117_Closed_Image.style.display='inline'; Codehighlighter1_48_117_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_48_117_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_48_117_Closed_Text.style.display='none'; Codehighlighter1_48_117_Open_Image.style.display='inline'; Codehighlighter1_48_117_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />   </span><span id="Codehighlighter1_48_117_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_48_117_Open_Text"><span style="COLOR: #000000">{ <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      QueryPerformanceFrequency(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">m_liPerfFreq);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      Start();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />   }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Start() <br /><img id="Codehighlighter1_140_193_Open_Image" onclick="this.style.display='none'; Codehighlighter1_140_193_Open_Text.style.display='none'; Codehighlighter1_140_193_Closed_Image.style.display='inline'; Codehighlighter1_140_193_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_140_193_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_140_193_Closed_Text.style.display='none'; Codehighlighter1_140_193_Open_Image.style.display='inline'; Codehighlighter1_140_193_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />   </span><span id="Codehighlighter1_140_193_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_140_193_Open_Text"><span style="COLOR: #000000">{ <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      QueryPerformanceCounter(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">m_liPerfStart);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />   }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   __int64 Now() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> <br /><img id="Codehighlighter1_223_482_Open_Image" onclick="this.style.display='none'; Codehighlighter1_223_482_Open_Text.style.display='none'; Codehighlighter1_223_482_Closed_Image.style.display='inline'; Codehighlighter1_223_482_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_223_482_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_223_482_Closed_Text.style.display='none'; Codehighlighter1_223_482_Open_Image.style.display='inline'; Codehighlighter1_223_482_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />   </span><span id="Codehighlighter1_223_482_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_223_482_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Returns # of milliseconds since<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Start was called</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      LARGE_INTEGER liPerfNow;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      QueryPerformanceCounter(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">liPerfNow);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> (((liPerfNow.QuadPart </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"> <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />         m_liPerfStart.QuadPart) </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />         m_liPerfFreq.QuadPart);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />   }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Counts per second</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">   LARGE_INTEGER m_liPerfFreq;   <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Starting count</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">   LARGE_INTEGER m_liPerfStart;  <br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><p>使用这个类如下:(这样的封装类很多的,我的blog有介绍)<br /></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Create a stopwatch timer<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">(which defaults to the current time).</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">CStopwatch stopwatch;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Execute the code I want to profile here.<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Get how much time has elapsed up to now.</span><span style="COLOR: #008000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">  __int64 qwElapsedTime </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> stopwatch.Now();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">qwElapsedTime indicates how long <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">the profiled code executed in milliseconds.<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div><p><font color="#0000ff"><strong>运用结构环境(跟cpu的类型有关系)<br /><br /></strong></font></p></font>
				<font color="#000000">环境结构使得系统能够记住线程的状态，这样，当下次线程拥有可以运行的C P U时，它就能够找到它上次中断运行的地方。<br /><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">Wi n d o w s实际上允许查看线程内核对象的内部情况，以便抓取它当前的一组C P U寄存器。若要进行这项操作，只需要调用G e t T h r e a d C o n t e x t函数：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">BOOL GetThreadContext(HANDLE hThread,
   PCONTEXT pContext);</font></pre></div><p>Wi n d o w s使你能够修改C O N T E X T结构中的成员，然后通过调用S e t T h r e a d C o n t e x t将新寄存器值放回线程的内核对象中： </p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><font size="3">BOOL SetThreadContext(HANDLE hThread,
   CONST CONTEXT *pContext);</font></pre></div><p><font color="#0000ff"><strong>线程的优先级<br /><br /></strong><font color="#000000"><font size="2">若要设置和获得线程的相对优先级，必须调用下面的这些函数：</font></font></font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><strong>BOOL SetThreadPriority(HANDLE hThread,
   int nPriority);</strong></pre></div><p><font style="LINE-HEIGHT: 25px" color="#000000" size="2">下面是检索线程的相对优先级的补充函数：</font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre>int GetThreadPriority(HANDLE hThread);</pre></div><p><br /><br /><strong>程序的优先级(进程的优先级)<br /><br /></strong><font color="#000000"><font size="2">下面是如何使一个进程将它自己的优先级类设置为空闲的例子：</font></font></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><strong>BOOL SetPriorityClass(GetCurrentProcess(),
   IDLE_PRIORITY_CLASS);</strong></pre></div><p><strong><font style="LINE-HEIGHT: 25px" color="#000000" size="2">下面是用来检索进程的优先级类的补充函数：</font></strong></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><strong>DWORD GetPriorityClass(HANDLE hProcess);</strong></pre></div><p><br /><br /><strong>动态提高线程的优先级等级<br /><br /></strong></p><p><strong><font style="LINE-HEIGHT: 25px" color="#000000" size="2">有些编程人员抱怨说，系统动态提高线程优先级等级的功能对他们的线程性能会产生一种不良的影响，为此M i c r o s o f t增加了下面两个函数，这样就能够使系统的动态提高线程优先级等级的功能不起作用：</font></strong></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><strong>BOOL SetProcessPriorityBoost(HANDLE hProcess,
   BOOL DisablePriorityBoost);

BOOL SetThreadPriorityBoost(HANDLE hThread,
   BOOL DisablePriorityBoost);</strong></pre></div><p><strong><font size="2">这两个函数具有许多相似的共性，可以用来确定是激活还是停用优先级提高功能：</font></strong></p><p></p><div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><pre><strong>BOOL GetProcessPriorityBoost(HANDLE hProcess,
   PBOOL pDisablePriorityBoost);

BOOL GetThreadPriorityBoost(HANDLE hThread,
   PBOOL pDisablePriorityBoost);</strong></pre></div><p><br /><strong>为前台进程调整调度程序(windows设置提供可以自定义优先执行application或后台的server)</strong></p></font>
				<br />
				<font size="2">Windows 2000实际上允许用户对这种调整进行相应的配置。在System Properties（系统属性）对话框的A d v a n c e d选项卡上，用户可以单击Performance Options(性能选项)按钮</font>
		</font>
<img src ="http://www.cppblog.com/mzty/aggbug/12437.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-14 10:13 <a href="http://www.cppblog.com/mzty/archive/2006/09/14/12437.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--线程</title><link>http://www.cppblog.com/mzty/archive/2006/09/13/12414.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Wed, 13 Sep 2006 07:34:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/13/12414.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12414.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/13/12414.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12414.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12414.html</trackback:ping><description><![CDATA[<font face=Arial size=2>进程是由两个部分构成的，一个是进程内核对象，另一个是地址空间。同样，线程也是由两个部分组成的：</font>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>&#8226; 一个是线程的内核对象，操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。</font> </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>&#8226; 另一个是线程堆栈，它用于维护线程在执行代码时需要的所有函数参数和局部变量<br><br>进程从来不执行任何东西，它只是线程的容器。线程总是在某个进程环境中创建的，而且它的整个寿命期都在该进程中。如果在单进程环境中，你有两个或多个线程正在运行，那么这两个线程将共享单个地址空间。这些线程能够执行相同的代码，对相同的数据进行操作。这些线程还能共享内核对象句柄，因为句柄表依赖于每个进程而不是每个线程存在。<br>线程用于描述进程中的运行路径。每当进程被初始化时，系统就要创建一个主线程。该线程与C / C + +运行期库的启动代码一道开始运行，启动代码则调用进入点函数（ m a i n、w m a i n、Wi n M a i n或w Wi n M a i n），并且继续运行直到进入点函数返回并且C / C + +运行期库的启动代码调用E x i t P r o c e s s为止。对于许多应用程序来说，这个主线程是应用程序需要的唯一线程。不过，进程能够创建更多的线程来帮助执行它们的操作。<br><br>多线程有很多的好处,能更好地利用cpu,及其他的计算机资源,能够使应用程序界面和后台操作同时进行,提供更加友好的用户接口.但是如果用的不合适的化,会带来不必要的麻烦,例如Windows Explorer为每个文件夹窗口创建了一个独立的线程。它使你能够将文件从一个文件夹拷贝到另一个文件夹，并且仍然可以查看你的系统上的其他文件夹。<br><strong><font color=#0000ff size=3>CreateThread函数</font></strong><br></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>每个线程必须拥有一个进入点函数，线程从这个进入点开始运行。前面已经介绍了主线程的进入点函数：即m a i n、w m a i n、Wi n M a i n或w Wi n M a i n。如果想要在你的进程中创建一个辅助线程，它必定也是个进入点函数，类似下面的样子：
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font size=3>DWORD WINAPI ThreadFunc(PVOID pvParam)
{
DWORD dwResult = 0;
...
return(dwResult);
}</font></pre>
</div>
<p>&#160;</p>
</font>&nbsp;<br>线程函数必须返回一个值，它将成为该线程的退出代码。这与C / C + +运行期库关于让主线程的退出代码作为进程的退出代码的原则是相似的。
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 线程函数（实际上是你的所有函数）应该尽可能使用函数参数和局部变量。当使用静态变量和全局变量时，多个线程可以同时访问这些变量，这可能破坏变量的内容。然而，参数和局部变量是在线程堆栈中创建的，因此它们不太可能被另一个线程破坏。<br></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2><br>前面已经讲述了调用C r e a t e P r o c e s s函数时如何创建进程的主线程。如果想要创建一个或多个辅助函数，只需要让一个已经在运行的线程来调用C r e a t e T h r e a d：</font> </p>
<p>&#160;</p>
<p>&#160;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;CreateThread(<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PSECURITY_ATTRIBUTES&nbsp;psa,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;cbStack,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PTHREAD_START_ROUTINE&nbsp;pfnStartAddr,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PVOID&nbsp;pvParam,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;fdwCreate,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PDWORD&nbsp;pdwThreadID);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><br>当C r e a t e T h r e a d被调用时，系统创建一个线程内核对象。</p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>系统从进程的地址空间中分配内存，供线程的堆栈使用。新线程运行的进程环境与创建线程的环境相同。因此，新线程可以访问进程的内核对象的所有句柄、进程中的所有内存和在这个相同的进程中的所有其他线程的堆栈。这使得单个进程中的多个线程确实能够非常容易地互相通信。</font> </p>
<p><strong><font color=#0000ff>终止线程的运行</font> </strong></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>若要终止线程的运行，可以使用下面的方法：</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 线程函数返回（最好使用这种方法）。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 通过调用E x i t T h r e a d函数，线程将自行撤消（最好不要使用这种方法）。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 同一个进程或另一个进程中的线程调用Te r m i n a t e T h r e a d函数（应该避免使用这种方法）。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 包含线程的进程终止运行（应该避免使用这种方法）。</font> </p>
<p><strong><font color=#0000ff>线程函数返回</font> </strong></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>始终都应该将线程设计成这样的形式，即当想要线程终止运行时，它们就能够返回。这是确保所有线程资源被正确地清除的唯一办法。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>如果线程能够返回，就可以确保下列事项的实现：</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 在线程函数中创建的所有C + +对象均将通过它们的撤消函数正确地撤消。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 操作系统将正确地释放线程堆栈使用的内存。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 系统将线程的退出代码（在线程的内核对象中维护）设置为线程函数的返回值。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 系统将递减线程内核对象的使用计数。</font> </p>
<p><strong><font color=#0000ff>ExitThread函数</font> </strong></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>可以让线程调用E x i t T h r e a d函数，以便强制线程终止运行：</font> <br>VOID ExitThread(DWORD dwExitCode);</p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>该函数将终止线程的运行，并导致操作系统清除该线程使用的所有操作系统资源。但是，C + +资源（如C + +类对象）将不被撤消。<br><strong><font color=#0000ff>TerminateThread函数</font></strong></font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>调用Te r m i n a t e T h r e a d函数也能够终止线程的运行：</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2></font></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;TerminateThread(<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwExitCode);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><br>与E x i t T h r e a d不同，E x i t T h r e a d总是撤消调用的线程，而Te r m i n a t e T h r e a d能够撤消任何线程。<br>注意Te r m i n a t e T h r e a d函数是异步运行的函数，也就是说，它告诉系统你想要线程终止运行，但是，当函数返回时，不能保证线程被撤消。如果需要确切地知道该线程已经终止运行，必须调用Wa i t F o r S i n g l e O b j e c t (第9章介绍)或者类似的函数，传递线程的句柄。此外，当线程终止运行时， D L L通常接收通知。如果使用Terminate Thread 强迫线程终止，D L L就不接收通知，这能阻止适当的清除<br><font color=#0000ff><strong>在进程终止运行时撤消线程<br></strong></font><font color=#000000>E x i t P r o c e s s和Te r m i n a t e P r o c e s s函数也可以用来终止线程的运行。差别在于这些线程将会使终止运行的进程中的所有线程全部终止运行。另外，由于整个进程已经被关闭，进程使用的所有资源肯定已被清除。这当然包括所有线程的堆栈。这两个函数会导致进程中的剩余线程被强制撤消，就像从每个剩余的线程调用Te r m i n a t e T h r e a d一样。显然，这意味着正确的应用程序清除没有发生，即C + +对象撤消函数没有被调用，数据没有转至磁盘等等。<br><strong><font color=#0000ff>线程终止运行时发生的操作</font></strong></font></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>当线程终止运行时，会发生下列操作：</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 线程拥有的所有用户对象均被释放。在Wi n d o w s中，大多数对象是由包含创建这些对象的线程的进程拥有的。但是一个线程拥有两个用户对象，即窗口和挂钩。当线程终止运行时，系统会自动撤消任何窗口，并且卸载线程创建的或安装的任何挂钩。其他对象只有在拥有线程的进程终止运行时才被撤消。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 线程的退出代码从S T I L L _ A C T I V E改为传递给E x i t T h r e a d或Te r m i n a t e T h r e a d的代码。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 线程内核对象的状态变为已通知。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 如果线程是进程中最后一个活动线程，系统也将进程视为已经终止运行。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; 线程内核对象的使用计数递减1。</font> </p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>当一个线程终止运行时，在与它相关联的线程内核对象的所有未结束的引用关闭之前，该内核对象不会自动被释放。</font> </p>
<p>由于线程常常要改变它的（或它的进程的）环境，因此Wi n d o w s提供了一些函数，使线程能够很容易引用它的进程内核对象，或者引用它自己的线程内核对象： <br></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2></font></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">&nbsp;HANDLE&nbsp;GetCurrentProcess();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>HANDLE&nbsp;GetCurrentThread();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><br>(还有对应的函数可以得到进程和线程的id)<br>上面这两个函数都能返回调用线程的进程的伪句柄或线程内核对象的伪句柄。这些函数并不在创建进程的句柄表中创建新句柄。还有，调用这些函数对进程或线程内核对象的使用计数没有任何影响。如果调用C l o s e H a n d l e，将伪句柄作为参数来传递，那么C l o s e H a n d l e就会忽略该函数的调用并返回FA L S E。<br>有时可能需要获得线程的实句柄而不是它的伪句柄。所谓&#8220;实句柄&#8221;，我是指用来明确标识一个独一无二的线程的句柄。<font style="BACKGROUND-COLOR: #ff1493">线程的伪句柄是当前线程的句柄，也就是说，它是调用函数的线程的句柄。<br></font>伪句柄变成实句柄。D u p l i c a t e H a n d l e函数能够执行这一转换： <br><br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;DuplicateHandle(<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hSourceProcess,&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hSource,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hTargetProcess,&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;PHANDLE&nbsp;phTarget,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;fdwAccess,&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;BOOL&nbsp;bInheritHandle,&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;DWORD&nbsp;fdwOptions);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div>
<p><font size=2>通常可以使用这个函数，用与另一个进程相关的内核对象来创建一个与进程相关的新句柄。</font><br></p>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>还要指出，D u p l i c a t e H a n d l e可以用来将进程的伪句柄转换成进程的实句柄，如下面的代码所示：</font> <br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hProcess;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>DuplicateHandle(<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;GetCurrentProcess(),&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Handle&nbsp;of&nbsp;process&nbsp;that&nbsp;the&nbsp;process&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;pseudo-handle&nbsp;is&nbsp;relative&nbsp;to</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;GetCurrentProcess(),&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Process's&nbsp;pseudo-handle</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;GetCurrentProcess(),&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Handle&nbsp;of&nbsp;process&nbsp;that&nbsp;the&nbsp;new,&nbsp;real,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;process&nbsp;handle&nbsp;is&nbsp;relative&nbsp;to</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #000000">&amp;</span> <span style="COLOR: #000000">hProcess,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Will&nbsp;receive&nbsp;the&nbsp;new,&nbsp;real&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;handle&nbsp;identifying&nbsp;the&nbsp;process</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #000000">0</span> <span style="COLOR: #000000">,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Ignored&nbsp;because&nbsp;of&nbsp;DUPLICATE_SAME_ACCESS</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;FALSE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;New&nbsp;thread&nbsp;handle&nbsp;is&nbsp;not&nbsp;inheritable</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;DUPLICATE_SAME_ACCESS);&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;New&nbsp;process&nbsp;handle&nbsp;has&nbsp;same&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;access&nbsp;as&nbsp;pseudo-handle<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span> </div><img src ="http://www.cppblog.com/mzty/aggbug/12414.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-13 15:34 <a href="http://www.cppblog.com/mzty/archive/2006/09/13/12414.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--作业</title><link>http://www.cppblog.com/mzty/archive/2006/09/13/12399.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Wed, 13 Sep 2006 01:15:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/13/12399.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12399.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/13/12399.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12399.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12399.html</trackback:ping><description><![CDATA[<p>作业: 作业可以看作是一组进程的容器,把这些进程当作一个整体,对这个整体整个加入更多的限制.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因为Wi n d o w s并不维护进程之间的父/子关系。即使父进程已经终止运行，子进程仍然会继续运行。Microsoft Windoss 2000提供了一个新的作业内核对象，使你能够将进程组合在一起，并且创建一个&#8220;沙框&#8221;，以便限制进程能够进行的操作。最好将作业对象视为一个进程的容器。但是，创建包含单个进程的作业是有用的，因为这样一来，就可以对该进程加上通常情况下不能加的限制。</p>
<p><br>创建一个新作业内核对象：<br>HANDLE CreateJobObject( PSECURITY_ATTRIBUTES psa, PCTSTR pszName);</p>
<p>与所有的内核对象一样，它的第一个参数将安全信息与新作业对象关联起来，并且告诉系统，是否想要使返回的句柄成为可继承的句柄。最后一个参数用于给作业对象命名，使它可以供另一个进程通过下面所示的O p e n J o b O b j e c t函数进行访问。</p>
<p>HANDLE OpenJobObject( DWORD dwDesiredAccess, <br>&nbsp;&nbsp; BOOL bInheritHandle, PCTSTR pszName);<br>与平常一样，如果知道你将不再需要访问代码中的作业对象，那么就必须通过调用C l o s e H a n d l e来关闭它的句柄。</p>
<p>应该知道，关闭作业对象并不会迫使作业中的所有进程终止运行。该作业对象实际上做上了删除标记，只有当作业中的所有进程全部终止运行之后，该作业对象才被自动撤消。<br>注意，关闭作业的句柄后，尽管该作业仍然存在，但是该作业将无法被所有进程访问。</p>
<p><br>将一个进程放入一个作业，以限制该进程进行某些操作的能力。 Windows 98 Windows 98不支持作业的操作。<br>void StartRestrictedProcess() <br>{<br>&nbsp;&nbsp; //Create a job kernel object.<br>&nbsp;&nbsp; HANDLE hjob = CreateJobObject(NULL, NULL);</p>
<p>&nbsp;&nbsp; //Place some restrictions on processes in the job.<br>&nbsp;&nbsp; //First,set some basic restrictions.<br>&nbsp;&nbsp; JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = { 0 };</p>
<p>&nbsp;&nbsp; //The process always runs in the idle priority class.<br>&nbsp;&nbsp; jobli.PriorityClass = IDLE_PRIORITY_CLASS;</p>
<p>&nbsp;&nbsp; //The job cannot use more than 1 second of CPU time.<br>&nbsp;&nbsp; jobli.PerJobUserTimeLimit.QuadPart = 10000000;&nbsp; <br>&nbsp;&nbsp; //1 sec in 100-ns intervals</p>
<p>&nbsp;&nbsp; //These are the only 2 restrictions I want placed on the job (process).<br>&nbsp;&nbsp; jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS | <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOB_OBJECT_LIMIT_JOB_TIME;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp; SetInformationJobObject(hjob, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobObjectBasicLimitInformation, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;jobli, sizeof(jobli));</p>
<p>&nbsp;&nbsp; //Second, set some UI restrictions.<br>&nbsp;&nbsp; JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;<br>&nbsp;&nbsp; jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp; //A fancy zero</p>
<p>&nbsp;&nbsp; //The process can't log off the system.<br>&nbsp;&nbsp; jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;</p>
<p>&nbsp;&nbsp; //The process can't access USER objects <br>&nbsp;&nbsp; //(such as other windows) in the system.<br>&nbsp;&nbsp; jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;</p>
<p>&nbsp;&nbsp; SetInformationJobObject(hjob,JobObjectBasicUIRestrictions, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;jobuir, sizeof(jobuir));</p>
<p>&nbsp;&nbsp; //Spawn the process that is to be in the job.<br>&nbsp;&nbsp; //Note: You must first spawn the process and then place the process in<br>&nbsp;&nbsp; //the job. This means that the process's thread must be initially<br>&nbsp;&nbsp; //suspended so that it can't execute any code outside <br>&nbsp;&nbsp; //of the job's restrictions.</p>
<p>&nbsp;&nbsp; STARTUPINFO si = { sizeof(si) };<br>&nbsp;&nbsp; PROCESS_INFORMATION pi;<br>&nbsp;&nbsp; CreateProcess(NULL, "CMD", NULL, NULL, FALSE, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CREATE_SUSPENDED, NULL, NULL, &amp;si, &#960;);<br>&nbsp;&nbsp; //Place the process in the job.<br>&nbsp;&nbsp; //Note:if this process spawns any children,the children are <br>&nbsp;&nbsp; //automatically part of the same job.<br>&nbsp;&nbsp; AssignProcessToJobObject(hjob,pi.hProcess);</p>
<p>&nbsp;&nbsp; //Now we can allow the child process's thread to execute code.<br>&nbsp;&nbsp; ResumeThread(pi.hThread);<br>&nbsp;&nbsp; CloseHandle(pi.hThread);</p>
<p>&nbsp;&nbsp; //Wait for the process to terminate or for all the job's <br>&nbsp;&nbsp; //allotted CPU time to be used.<br>&nbsp;&nbsp; HANDLE h[2];<br>&nbsp;&nbsp; h[0] = pi.hProcess;<br>&nbsp;&nbsp; h[1] = hjob;<br>&nbsp;&nbsp; DWORD dw = WaitForMultipleObjects(2,h,FALSE,INFINITE);<br>&nbsp;&nbsp; switch( dw-WAIT_OBJECT_0 ) <br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp; case 0:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //The process has terminated<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp; case 1:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //All of the job's allotted CPU time was used<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; //Clean up properly.<br>&nbsp;&nbsp;&nbsp; CloseHandle(pi.hProcess);<br>&nbsp;&nbsp;&nbsp; CloseHandle(hjob);<br>}</p>
<p><br>对作业进程的限制 <br>进程创建后，通常需要设置一个沙框（设置一些限制），以便限制作业中的进程能够进行的操作。可以给一个作业加上若干不同类型的限制：</p>
<p>&#8226; 基本限制和扩展基本限制，用于防止作业中的进程垄断系统的资源。</p>
<p>&#8226; 基本的U I限制，用于防止作业中的进程改变用户界面。</p>
<p>&#8226; 安全性限制，用于防止作业中的进程访问保密资源（文件、注册表子关键字等）。</p>
<p>通过调用下面的代码，可以给作业加上各种限制：</p>
<p>&nbsp;</p>
<p>BOOL SetInformationJobObject(<br>HANDLE hJob,<br>JOBOBJECTINFOCLASS JobObjectInformationClass,<br>PVOID pJobObjectInformation,<br>DWORD cbJobObjectInformationLength);<br>第一个参数用于标识要限制的作业。第二个参数是个枚举类型，用于指明要使用的限制类型。第三个参数是包含限制设置值的数据结构的地址，第四个参数用于指明该结构的大小（用于确定版本）。</p>
<p>可以做的限制有:(具体参数的意思参看windows核心编程)<br>JOB_OBJECT_BASIC_LIMIT_INFORMATION结构类似下面的样子： (基本限制)</p>
<p>typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION{&nbsp;&nbsp;&nbsp; LARGE_INTEGER&nbsp; PerProcessUserTimeLimit;&nbsp;&nbsp;&nbsp; LARGE_INTEGER&nbsp; PerJobUserTimeLimit;&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LimitFlags;&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MinimumWorkingSetSize;&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MaximumWorkingSetSize;&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ActiveProcessLimit;&nbsp;&nbsp;&nbsp; DWORD_PTR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Affinity;&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PriorityClass;&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SchedulingClass;} JOBOBJECT_BASIC_LIMIT_INFORMATION,&nbsp; *PJOBOBJECT_BASIC_LIMIT_INFORMATION;</p>
<p>J O B O B J E C T _ E X T E N D E D _ L I M I T _ I N F O R M AT I O N结构对作业设置： (扩展限制)<br>typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION<br>{<br>&nbsp;&nbsp;&nbsp; JOBOBJECT_BASIC_LIMIT_INFORMATION&nbsp;&nbsp; BasicLimitInformation;<br>&nbsp;&nbsp;&nbsp; IO_COUNTERS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oInfo;<br>&nbsp;&nbsp;&nbsp; SIZE_T&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ProcessMemoryLimit;<br>&nbsp;&nbsp;&nbsp; SIZE_T&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobMemoryLimit;<br>&nbsp;&nbsp;&nbsp; SIZE_T&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PeakProcessMemoryUsed;<br>&nbsp;&nbsp;&nbsp; SIZE_T&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PeakJobMemoryUsed;<br>} JOBOBJECT_EXTENDED_LIMIT_INFORMATION,&nbsp; *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;</p>
<p>J O B O B J E C T _ B A S I C _ U I _ R E S T R I C T I O NS结构的样子： (其他限制)<br>typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS<br>{<br>&nbsp;&nbsp;&nbsp; DWORD UIRestrictionsClass;<br>} JOBOBJECT_BASIC_UI_RESTRICTIONS, *PJOBOBJECT_BASIC_UI_RESTRICTIONS;<br>J O B O B J E C T _ S E C U R I T Y _ L I M I T _ I N F O R M AT I O N的结构类似下面的形式： (安全限制)<br>typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION<br>{<br>&nbsp;&nbsp;&nbsp; DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SecurityLimitFlags;<br>&nbsp;&nbsp;&nbsp; HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobToken;<br>&nbsp;&nbsp;&nbsp; PTOKEN_GROUPS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SidsToDisable;<br>&nbsp;&nbsp;&nbsp; PTOKEN_PRIVILEGES&nbsp; PrivilegesToDelete;<br>&nbsp;&nbsp;&nbsp; PTOKEN_GROUPS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RestrictedSids;<br>} JOBOBJECT_SECURITY_LIMIT_INFORMATION, *PJOBOBJECT_SECURITY_LIMIT_INFORMATION;</p>
<p>当然，一旦给作业设置了限制条件，就可以查询这些限制。通过调用下面的代码，就可以进行这一操作：</p>
<p>&nbsp;</p>
<p>BOOL QueryInformationJobObject(<br>HANDLE hJob,<br>JOBOBJECTINFOCLASS JobObjectInformationClass,<br>PVOID pvJobObjectInformation,<br>DWORD cbJobObjectInformationLength,<br>PDWORD pdwReturnLength);<br>你为该函数传递作业的句柄（就像你对SetInformationJobObject操作时那样），这些句柄包括用于指明你想要的限制信息的枚举类型，函数要进行初始化的数据结构的地址，以及包含该结构的数据块的长度。最后一个参数是pdwReturnLength，用于指向该函数填写的DWORD，它告诉你有多少字节放入了缓存。如果你愿意的话，可以（并且通常）为该参数传递N U L L。</p>
<p>将进程放入作业：</p>
<p>BOOL AssignProcessToJobObject(<br>&nbsp;&nbsp; HANDLE hJob,<br>&nbsp;&nbsp; HANDLE hProcess); <br>该函数告诉系统，将该进程（由hProcess标识）视为现有作业（由h J o b标识）的一部分。<br>注意，该函数只允许将尚未被赋予任何作业的进程赋予一个作业。一旦进程成为一个作业的组成部分，<br>它就不能转到另一个作业，并且不能是无作业的进程。另外，当作为作业的一部分的进程生成另一个进程的时候，<br>新进程将自动成为父作业的组成部分。注意:调用此函数后要调用ResumeThread();这样，<br>进程的线程就可以在作业的限制下执行代码。终止作业中所有进程的运行<br>若要撤消作业中的进程，只需要调用下面的代码：</p>
<p><br>BOOL TerminateJobObject(<br>HANDLE hJob,<br>UINT uExitCode);<br>这类似为作业中的每个进程调用TerminateProcess函数，将它们的所有退出代码设置为uExitCode。</p>
<p>查询作业统计信息<br>Q u e r y I n f o r m a t i o n J o b O b j e c t函数来获取对作业的当前限制信息。也可以使用它来获取关于作业的统计信息。通过传入不同的参数,可以查询到不同的作业统计信息.<br>例如，若要获取基本的统计信息，可以调用Q u e r y I n f o r m a t i o n J o b O b j e c t，为第二个参数传递J o b O b j e c t B a s i c A c c o u n t i n g I n f o r m a t i o n ,并传递J O B O B J E C T _ B A S I C _ A C C O U N T I N G _ I N F O R M AT I O N结构的地址： </p>
<p>typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION{&nbsp;&nbsp; LARGE_INTEGER TotalUserTime;&nbsp;&nbsp; LARGE_INTEGER TotalKernelTime;&nbsp;&nbsp; LARGE_INTEGER ThisPeriodTotalUserTime;&nbsp;&nbsp; LARGE_INTEGER ThisPeriodTotalKernelTime;&nbsp;&nbsp; DWORD TotalPageFaultCount;&nbsp;&nbsp; DWORD TotalProcesses;&nbsp;&nbsp; DWORD ActiveProcesses;&nbsp;&nbsp; DWORD TotalTerminatedProcesses;} JOBOBJECT_BASIC_ACCOUNTING_INFORMATION, *PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION;</p>
<p>&nbsp;</p>
<p><br>除了查询这些基本统计信息外，可以进行一次函数调用，以同时查询基本统计信息和I/O统计信息。为此，必须为第二个参数传递J o b O b j e c t B a s i c A n d I o A c c o u n t i n g I n f o r m a t i o n ,并传递J O B O B J E C T _ B A S I C _ A N D _ I O _ A C C O U N T I N G _ I N F O R M AT I O N结构的地址：</p>
<p>typedef struct JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION<br>{<br>&nbsp;&nbsp; JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;<br>&nbsp;&nbsp; IO_COUNTERS IoInfo;<br>} JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION;</p>
<p>如你所见，这个结构只返回一个J O B O B J E C T _ B A S I C _ A C C O U N T I N G _ I N F O R M AT I O N结构和I O _ C O U N T E R S结构：</p>
<p>&nbsp;</p>
<p>typedef struct _IO_COUNTERS<br>{<br>&nbsp;&nbsp; ULONGLONG ReadOperationCount;<br>&nbsp;&nbsp; ULONGLONG WriteOperationCount;<br>&nbsp;&nbsp; ULONGLONG OtherOperationCount;<br>&nbsp;&nbsp; ULONGLONG ReadTransferCount;<br>&nbsp;&nbsp; ULONGLONG WriteTransferCount;<br>&nbsp;&nbsp; ULONGLONG OtherTransferCount;<br>} IO_COUNTERS;</p>
<p>另外，可以使用下面这个新的G e t P r o c e s s I o C o u n t e r s函数，以便获取不是这些作业中的进程的这些信息： </p>
<p><br>BOOL GetProcessIoCounters(<br>&nbsp;&nbsp; HANDLE hProcess,<br>&nbsp;&nbsp; PIO_COUNTERS pIoCounters);<br>也可以随时调用Q u e r y I n f o r m a t i o n J o b O b j e c t函数，以便获取当前在作业中运行的进程的一组进程I D。若要进行这项操作，首先必须确定你想在作业中看到多少进程，然后必须分配足够的内存块，来放置这些进程I D的数组，并指定J O B O B J E C T _ B A S I C _ P R O C E S S _ I D _ L I S T结构的大小： </p>
<p><br>typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST<br>{<br>DWORD NumberOfAssignedProcesses;<br>DWORD NumberOfProcessIdsInList;<br>DWORD ProcessIdList[1];<br>} JOBOBJECT_BASIC_PROCESS_ID_LIST,&nbsp; *PJOBOBJECT_BASIC_PROCESS_ID_LIST;<br>因此，若要获得当前作业中的一组进程I D，必须执行类似下面的代码：</p>
<p>void EnumProcessIdsInJob(HANDLE hjob)<br>{<br>&nbsp;&nbsp;&nbsp; //I assume that there will never be more<br>&nbsp;&nbsp;&nbsp; //than 10 processes in this job.<br>&nbsp;&nbsp;&nbsp; #define MAX_PROCESS_IDS&nbsp;&nbsp;&nbsp;&nbsp; 10</p>
<p>&nbsp;&nbsp;&nbsp; //Calculate the number of bytes needed for <br>&nbsp;&nbsp;&nbsp; //structure&nbsp; &amp; process IDs.<br>&nbsp;&nbsp;&nbsp; DWORD Cb = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (MAX_PROCESS_IDS - 1) * sizeof(DWORD);</p>
<p>&nbsp;&nbsp;&nbsp; //Allocate the block of memory.<br>&nbsp;&nbsp;&nbsp; PJOBOBJECT_BASIC_PROCESS_ID_LIST pjobpil = _alloca(cb);</p>
<p>&nbsp;&nbsp;&nbsp; //Tell the function the maximum number of processes <br>&nbsp;&nbsp;&nbsp; //that we allocated space for.<br>&nbsp;&nbsp;&nbsp; pjobpil-&gt;NumberOfAssignedProcesses = MAX_PROCESS_IDS;</p>
<p>&nbsp;&nbsp;&nbsp; //Request the current set of process IDs.<br>&nbsp;&nbsp;&nbsp; QueryInformationJobObject(hjob, JobObjectBasicProcessIdList,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pjobpil, cb, &amp;cb);</p>
<p>&nbsp;&nbsp;&nbsp; //Enumerate the process IDs.<br>&nbsp;&nbsp;&nbsp; for(int x=0; x &lt; pjobpil -&gt; NumberOfProcessIdsInList; x++)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Use pjobpil-&gt;ProcessIdList[x]<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; //Since _alloca was used to allocate the memory,<br>&nbsp;&nbsp;&nbsp; //we don't need to free it here.<br>}</p>
<p>&nbsp;</p>
<p>作业通知信息</p>
<p>如果关心的是分配的所有C P U时间是否已经到期，那么可以非常容易地得到这个通知信息。当作业中的进程尚未用完分配的C P U时间时，作业对象就得不到通知。一旦分配的所有C P U时间已经用完， Wi n d o w s就强制撤消作业中的所有进程，并将情况通知作业对象。通过调用Wa i t F o r S i n g l e O b j e c t (或类似的函数)，可以很容易跟踪这个事件。有时，可以在晚些时候调用S e t I n f o r m a t i o n J o b O b j e c t函数，使作业对象恢复未通知状态，并为作业赋予更多的C P U时间。</p>
<p>当开始对作业进行操作时，我觉得当作业中没有任何进程运行时，应该将这个事件通知作业对象。毕竟当进程和线程停止运行时，进程和线程对象就会得到通知。因此，当作业停止运行时它也应该得到通知。这样，就能够很容易确定作业何时结束运行。但是， M i c r o s o f t选择在分配的C P U时间到期时才向作业发出通知，因为这显示了一个错误条件。由于许多作业启动时有一个父进程始终处于工作状态，直到它的所有子进程运行结束，因此只需要在父进程的句柄上等待，就可以了解整个作业何时运行结束。S t a r t R e s t r i c t e d P r o c e s s函数用于显示分配给作业的C P U时间何时到期，或者作业中的进程何时终止运行。</p>
<p>前面介绍了如何获得某些简单的通知信息，但是尚未说明如何获得更高级的通知信息，如进程创建/终止运行等。如果想要得到这些通知信息，必须将更多的基础结构放入应用程序。特别是，必须创建一个I / O完成端口内核对象，并将作业对象或多个作业对象与完成端口关联起来。然后，必须让一个或多个线程在完成端口上等待作业通知的到来，这样它们才能得到处理。</p>
<p>一旦创建了I / O完成端口，通过调用S e t I n f o r m a t i o n J o b O b j e c t函数，就可以将作业与该端口关联起来，如下面的代码所示：</p>
<p><br>&nbsp;</p>
<p>JOBOBJECT_ASSOCIATE_COMPLETION_PORT joacp;<br>//Any value to uniquely identify this job<br>joacp.CompletionKey = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>//Handle of completion port that receives notifications<br>joacp.CompletionPort = hIOCP;&nbsp; <br>SetInformationJobObject(hJob, <br>&nbsp;&nbsp; jobObjectAssociateCompletionPortInformation,<br>&nbsp;&nbsp; &amp;joacp, sizeof(jaocp));</p>
<p>当上面的代码运行时，系统将监视该作业的运行，当事件发生时，它将事件送往I / O完成端口（顺便说一下，可以调用Q u e r y I n f o r m a t i o m J o b O b j e c t函数来检索完成关键字和完成端口句柄。但是，这样做的机会很少）。线程通过调用G e t Q u e u e d C o m p l e t i o n S t a t u s函数来监控I / O完成端口：</p>
<p><br>BOOL GetQueuedCompletionStatus(<br>&nbsp;&nbsp; HANDLE hIOCP,<br>&nbsp;&nbsp; PDWORD pNumBytesTransferred,<br>&nbsp;&nbsp; PULONG_PTR pCompletionKey,<br>&nbsp;&nbsp; POVERLAPPED *pOverlapped,<br>&nbsp;&nbsp; DWORD dwMilliseconds);</p>
<p>当该函数返回一个作业事件通知时，* p C o m p l e t i o n K e y包含了调用S e t I n f o r m a t i o n J o b O b j e c t时设置的完成关键字值，用于将作业与完成端口关联起来。它使你能够知道哪个作业存在一个事件。* p N u m B y t e s Tr a n s f e r r e d中的值用于指明发生了哪个事件。</p>
<p><br>&nbsp;</p><img src ="http://www.cppblog.com/mzty/aggbug/12399.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-13 09:15 <a href="http://www.cppblog.com/mzty/archive/2006/09/13/12399.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--进程</title><link>http://www.cppblog.com/mzty/archive/2006/09/12/12366.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 12 Sep 2006 06:38:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/12/12366.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12366.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/12/12366.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12366.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12366.html</trackback:ping><description><![CDATA[<p>进程通常被定义为一个正在运行的程序的实例，它由两个部分组成： </p>
<p>&#8226; 一个是操作系统用来管理进程的内核对象。内核对象也是系统用来存放关于进程的统计信息的地方。 <br>&#8226; 另一个是地址空间，它包含所有可执行模块或 D L L 模块的代码和数据。它还包含动态内存分配的空间。如线程堆栈和堆分配空间。&nbsp;&nbsp; </p>
<p>进程是不活泼的。若要使进程完成某项操作，它必须拥有一个在它的环境中运行的线程，该线程负责执行包含在进程的地址空间中的代码。<br>当创建一个进程时，系统会自动创建它的第一个线程，称为主线程。然后，该线程可以创建其他的线程，而这些线程又能创建更多的线程。</p>
<p>进程的实例句柄&nbsp;&nbsp; </p>
<p>加载到进程地址空间的每个可执行文件或 D L L 文件均被赋予一个独一无二的实例句柄。可执行文件的实例作为 ( w ) Wi n M a i n 的第一个参数 h i n s t E x e 来传递。对于加载资源的函数调用来说，通常都需要该句柄的值。例如，若要从可执行文件的映象来加载图标资源，需要调用下面这个函数： </p>
<p>HICON LoadIcon( HINSTANCE hinst, PCTSTR pszIcon); </p>
<p>L o a d I c o n 的第一个参数用于指明哪个文件（可执行文件或 D L L 文件）包含你想加载的资源。 </p>
<p>注意 : 实际情况说明， H M O D U L E 与 H I N S TA N C E 是完全相同的对象。如果函数的文档指明需要一个 H M O D U L E ，那么可以传递一个 H I N S TA N C E ，反过来，如果需要一个 H I N S TA N C E ，也可以传递一个 H M O D U L E 。之所以存在两个数据类型，原因是在 1 6 位 Wi n d o w s 中， H M O D U L E 和 H I N S TA N C E 用于标识不同的东西。 </p>
<p>G e t M o d u l e H a n d l e 函数返回可执行文件或 D L L 文件加载到进程的地址空间时所用的句柄 / 基地址： </p>
<p>HMODULE GetModuleHandle( PCTSTR pszModule); </p>
<p>当调用该函数时，你传递一个以 0 结尾的字符串，用于设定加载到调用进程的地址空间的可执行文件或 D L L 文件的名字。如果系统找到了指定的可 执行文件或 D L L 文件名， G e t M o d u l e H a n d l e 便返回该可执行文件或 D L L 文件映象加载到的基地址。如果系统没有找到该文件，则 返回 N U L L 。也可以调用 G e t M o d u l e H a n d l e ，为 p s z M o d u l e 参数传递 N U L L ， G e t M o d u l e H a n d l e 返回调 用的可执行文件的基地址。&nbsp;&nbsp; </p>
<p>进程的命令行 </p>
<p>当一个新进程创建时，它要传递一个命令行。该命令行几乎永远不会是空的，至少用于创建新进程的可执行文件的名字是命令行上的第一个标记。当 C 运行期的启动代码开始运行的时候，它要检索进程的命令行，跳过可执行文件的名字，并将指向命令行其余部分的指针传递给 Wi n M a i n 的 p s z C m d L i n e 参数。 </p>
<p>进程的环境变量 </p>
<p>每个进程都有一个与它相关的环境块。环境块是进程的地址空间中分配的一个内存块。每个环境块都包含一组字符串，其形式如下： </p>
<p>VarName1=VarValue1\0 </p>
<p>VarName2=VarValue2\0 </p>
<p>VarName3=VarValue3\0 </p>
<p>... </p>
<p>VarNameX=VarValueX\0 </p>
<p>\0 </p>
<p>每个字符串的第一部分是环境变量的名字，后跟一个等号，等号后面是要赋予变量的值。 </p>
<p>DWORD GetEnvironmentVariable( </p>
<p>&nbsp;&nbsp; PCTSTR pszName, </p>
<p>&nbsp;&nbsp; PTSTR pszValue, </p>
<p>&nbsp;&nbsp; DWORD cchValue); </p>
<p>当调用 G e t E n v i r o n m e n t Va r i a b l e 时， p s z N a m e 指向需要的变量名， p s z Va l u e 指向用于存放变量值的缓存， c c h Va l u e 用于指明缓存的大小（用字符数来表示）。该函数可以返回拷贝到缓存的字符数，如果在环境中找不到该变量名，也可以返回 0 。 </p>
<p>BOOL SetEnvironmentVariable( </p>
<p>&nbsp;&nbsp; PCTSTR pszName, </p>
<p>&nbsp;&nbsp; PCTSTR pszValue); </p>
<p>该函数用于将 p s z N a m e 参数标识的变量设置为 p s z Va l u e 参数标识的值。如果带有指定名字的变量已经存在， S e t E n v i r o n m e n t Va r i a b l e 就修改该值。如果指定的变量不存在，便添加该变量，如果 p s z Va l u e 是 N U L L ，便从环境块中删除该变量。 </p>
<p>进程的亲缘性 </p>
<p>一般来说，进程中的线程可以在主计算机中的任何一个 C P U 上执行。但是一个进程的线程可能被强制在可用 C P U 的子集上运行。这称为进程的亲缘性， </p>
<p>进程的错误模式 </p>
<p>进程可以告诉系统如何处理每一种错误。方法是调用 S e t E r r o r M o d e 函数： </p>
<p>UINT SetErrorMode(UINT fuErrorMode); </p>
<p>f u E r r o r M o d e 参数是表 4 - 3 的任何标志按位用 O R 连接在一起的组合。 </p>
<p>表4-3 fuError Mode 参数的标志 </p>
<p>标志 <br>&nbsp;说明 <br>&nbsp;<br>SEM_FAILCRITICALERRORS <br>&nbsp;系统不显示关键错误句柄消息框，并将错误返回给调用进程 <br>&nbsp;<br>SEM_NOGOFAULTERRORBOX <br>&nbsp;系统不显示一般保护故障消息框。本标志只应该由采用异常情况处理程序来处理一般保护（G P）故障的调试应用程序来设定 <br>&nbsp;<br>SEM_NOOPENFILEERRORBOX <br>&nbsp;当系统找不到文件时，它不显示消息框 <br>&nbsp;<br>SEM_NOALIGNMENTFAULTEXCEPT <br>&nbsp;系统自动排除内存没有对齐的故障，并使应用程序看不到这些故障。本标志对x 8 6处理器不起作用 <br>&nbsp;</p>
<p>进程的当前驱动器和目录 </p>
<p>通过调用下面两个函数，线程能够获得和设置它的进程的当前驱动器和目录：<br>&nbsp;&nbsp;<br>DWORD GetCurrentDirectory(<br>&nbsp;&nbsp; DWORD cchCurDir,<br>&nbsp;&nbsp; PTSTR pszCurDir);<br>BOOL SetCurrentDirectory(PCTSTR pszCurDir);<br>CreateProcess 函数 </p>
<p>可以用 C r e a t e P r o c e s s 函数创建一个进程： </p>
<p>BOOL CreateProcess( </p>
<p>&nbsp;&nbsp; PCTSTR pszApplicationName, </p>
<p>&nbsp;&nbsp; PTSTR pszCommandLine, </p>
<p>&nbsp;&nbsp; PSECURITY_ATTRIBUTES psaProcess, </p>
<p>&nbsp;&nbsp; PSECURITY_ATTRIBUTES psaThread, </p>
<p>&nbsp;&nbsp; BOOL bInheritHandles, </p>
<p>&nbsp;&nbsp; DWORD fdwCreate, </p>
<p>&nbsp;&nbsp; PVOID pvEnvironment, </p>
<p>&nbsp;&nbsp; PCTSTR pszCurDir, </p>
<p>&nbsp;&nbsp; PSTARTUPINFO psiStartInfo, </p>
<p>&nbsp;&nbsp; PPROCESS_INFORMATION ppiProcInfo); </p>
<p>当一个线程调用 CreateProcess 时，系统就会创建一个进程内核对象，其初始使用计数是 1 。 </p>
<p>当第一个参数为 NULL 时 , C r e a t e P r o c e s s 也按下面的顺序搜索该可执行文件： </p>
<p>1) 包含调用进程的 . e x e 文件的目录。 </p>
<p>2) 调用进程的当前目录。 </p>
<p>3) Wi n d o w s 的系统目录。 </p>
<p>4) Wi n d o w s 目录。 </p>
<p>5) PAT H 环境变量中列出的目录。 </p>
<p>当然，如果文件名包含全路径，系统将使用全路径来查看可执行文件，并且不再搜索这些目录。如果系统找到了可执行文件，那么它就创建一个新进程，并将可执行文件的代码和数据映射到新进程的地址空间中。然后系统将调用 C / C + + 运行期启动例程。正如前面我们讲过的那样， C / C + + 运行期启动例程要查看进程的命令行，并将地址作为 ( w ) Wi n M a i n 的 p s z C m d L i n e 参数传递给可执行文件的名字后面的第一个参数。 </p>
<p>终止进程的运行 </p>
<p>若要终止进程的运行，可以使用下面四种方法：&nbsp;&nbsp; </p>
<p>&#8226; 主线程的进入点函数返回（最好使用这个方法）。&nbsp;&nbsp; </p>
<p>&#8226; 进程中的一个线程调用 E x i t P r o c e s s 函数（应该避免使用这种方法）。&nbsp;&nbsp; </p>
<p>&#8226; 另一个进程中的线程调用 Te r m i n a t e P r o c e s s 函数（应该避免使用这种方法）。&nbsp;&nbsp; </p>
<p>&#8226; 进程中的所有线程自行终止运行（这种情况几乎从未发生）。&nbsp;&nbsp; </p>
<p>主线程的进入点函数返回 </p>
<p>始终都应该这样来设计应用程序，即只有当主线程的进入点函数返回时，它的进程才终止运行。这是保证所有线程资源能够得到正确清除的唯一办法。让主线程的进入点函数返回，可以确保下列操作的实现： </p>
<p>&#8226; 该线程创建的任何 C + + 对象将能使用它们的析构函数正确地撤消。&nbsp;&nbsp; </p>
<p>&#8226; 操作系统将能正确地释放该线程的堆栈使用的内存。&nbsp;&nbsp; </p>
<p>&#8226; 系统将进程的退出代码（在进程的内核对象中维护）设置为进入点函数的返回值。&nbsp;&nbsp; </p>
<p>&#8226; 系统将进程内核对象的返回值递减 1 。 </p>
<p>ExitProcess 函数 </p>
<p>当进程中的一个线程调用 E x i t P r o c e s s 函数时，进程便终止运行：<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>VOID ExitProcess(UINT fuExitCode);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>当主线程的进入点函数（ WinMain 、 wWinMain 、 main 或 wmain ）返回时，它将返回给 C / C + + 运行期启动代码，它能正确地清除该进程使用的所有的 C 运行期资源。当 C 运行期资源被释放之后， C 运行期启动代码就显式调用 E x i t P r o c e s s ，并将进入点函数返回的值传递给它。这解释了为什么只需要主线程的进入点函数返回，就能够终止整个进程的运行。请注意，进程中运行的任何其他线程都随着进程而一道终止运行。 </p>
<p>注意，调用 E x i t P r o c e s s 或 E x i t T h r e a d 可使进程或线程在函数中就终止运行。就操作系统而言，这很好，进程或线程的所有操作系统资源都将被全部清除。但是， C / C + + 应用程序应该避免调用这些函数，因为 C / C + + 运行期也许无法正确地清除。 </p>
<p>TerminateProcess 函数 </p>
<p>调用 Te r m i n a t e P r o c e s s 函数也能够终止进程的运行： </p>
<p>BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode); </p>
<p>该函数与 E x i t P r o c e s s 有一个很大的差别，那就是任何线程都可以调用 Te r m i n a t e P r o c e s s 来终止另一个进程或它自己的进程的运行。 h P r o c e s s 参数用于标识要终止运行的进程的句柄。 </p>
<p>只有当无法用另一种方法来迫使进程退出时，才应该使用 Te r m i n a t e P r o c e s s 。终止运行的进程绝对得不到关于它将终止运行的任何通知，因为应用程序无法正确地清除，并且不能避免自己被撤消（除非通过正常的安全机制）。 </p>
<p>进程终止运行时出现的情况 </p>
<p>当进程终止运行时，下列操作将启动运行：&nbsp;&nbsp; </p>
<p>1) 进程中剩余的所有线程全部终止运行。&nbsp;&nbsp; </p>
<p>2) 进程指定的所有用户对象和 G D I 对象均被释放，所有内核对象均被关闭（如果没有其他 进程打开它们的句柄，那么这些内核对象将被撤消。但是，如果其他进程打开了它们的句柄， 内核对象将不会撤消）。&nbsp;&nbsp; </p>
<p>3) 进程的退出代码将从 S T I L L _ A C T I V E 改为传递给 E x i t P r o c e s s 或 Te r m i n a t e P r o c e s s 的代码。&nbsp;&nbsp; </p>
<p>4) 进程内核对象的状态变成收到通知的状态（关于传送通知的详细说明，参见第 9 章）。系 统中的其他线程可以挂起，直到进程终止运行。&nbsp;&nbsp; </p>
<p>5) 进程内核对象的使用计数递减 1 。 </p>
<p>注意，进程的内核对象的寿命至少可以达到进程本身那么长，但是进程内核对象的寿命可能大大超过它的进程寿命。当进程终止运行时，系统能够自动确定它的内核对象的使用计数。如果使用计数降为 0 ，那么没有其他进程拥有该对象打开的句柄，当进程被撤消时，对象也被撤消。 </p>
<p>子进程 </p>
<p>子进程 , 能够处理比线程更复杂的东西 , 也能够保持相对的独立 , 但是就会有进程间的数据共享 , Wi n d o w s 提供了若干种方法，以便在不同的进程中间传送数据，比如动态数据交换（ D D E ）、 O L E 、管道和邮箱等。共享数据最方便的方法之一是，使用内存映射文件 . 大多数情况下，应用程序将另一个进程作为独立的进程来启动。这意味着进程创建和开始运行后，父进程并不需要与新进程进行通信，也不需要在完成它的工作后父进程才能继续运行。这就是 E x p l o r e r 的运行方式。当 E x p l o r e r 为用户创建一个新进程后，它并不关心该进程是否继续运行，也不在乎用户是否终止它的运行。 </p>
<p>若要放弃与子进程的所有联系， E x p l o r e r 必须通过调用 C l o s e H a n d l e 来关闭它与新进程及它的主线程之间的句柄。下面的代码示例显示了如何创建新进程以及如何让它以独立方式来运行： </p>
<p><br>PROCESS_INFORMATION pi;<br>//Spawn the child process.<br>BOOL fSuccess = CreateProcess(..., &#960;);<br>if(fSuccess)<br>{<br>&nbsp;&nbsp; //Allow the system to destroy the process &amp; thread kernel<br>&nbsp;&nbsp; //objects as soon as the child process terminates.<br>&nbsp;&nbsp; CloseHandle(pi.hThread);<br>&nbsp;&nbsp; CloseHandle(pi.hProcess);<br>}<br></p><img src ="http://www.cppblog.com/mzty/aggbug/12366.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-12 14:38 <a href="http://www.cppblog.com/mzty/archive/2006/09/12/12366.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--windows程序的执行</title><link>http://www.cppblog.com/mzty/archive/2006/09/12/12331.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 12 Sep 2006 03:57:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/12/12331.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12331.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/12/12331.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12331.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12331.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<b>
						<span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial">Windows</span>
				</b>
				<b>
						<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">应用程序的执行</span>
				</b>
				<b>
						<span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial">
								<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>
								<o:p>
								</o:p>
						</span>
				</b>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<b>
						<span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial">
								<o:p> </o:p>
						</span>
				</b>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">Windows</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">支持两种类型的应用程序。一种是基于图形用户界面（</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">GUI</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">）的应用程序，另一种是基于控制台用户界面（</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">CUI</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">）的应用程序。</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">(</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">两者间可以相互转化</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">,</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">没有明确的界限</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">,</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">就是说可以让</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">CUI</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">程序中可以有</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">Dialog</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">界面等</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">,</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">而</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">GUI</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">界面中也可以有</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">console</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">来输出信息</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p style="LINE-HEIGHT: 18.75pt">
				<font face="宋体">
						<span style="FONT-SIZE: 10pt">对于一个应用程序<span lang="EN-US">:</span></span>
						<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 新宋体">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p style="LINE-HEIGHT: 18.75pt">
				<font face="宋体">
						<span style="FONT-SIZE: 10.5pt; BACKGROUND: red; COLOR: black; mso-bidi-font-family: 'Times New Roman'; mso-highlight: red">一</span>
						<span style="FONT-SIZE: 10.5pt; COLOR: black; mso-bidi-font-family: 'Times New Roman'">操作系统实际上先调用的是<span lang="EN-US">C / C + +</span>运行期启动函数。该函数负责对<span lang="EN-US">C / C + +</span>运行期库进行初始化，这样，就可以调用<span lang="EN-US">m a l l o c </span>和<span lang="EN-US">f r e e </span>之类的函数。它还能够确保已经声明的任何全局对象和静态<span lang="EN-US">C + +</span>对象能够在代码执行以前正确地创建。链接程序负责在它连接可执行文件时选择相应的<span lang="EN-US">C / C + +</span>运行期启动函数。如果设定了<span lang="EN-US">/ S U B S Y S T E M : W I N D O W S </span>链接程序开关，那 么该链接程序期望找到一个<span lang="EN-US">Wi n M a i n </span>或<span lang="EN-US">w Wi n m a i n</span>函数。如果这两个函数都不存在，链接程序便返回一个<span lang="EN-US">“</span>未转换的外部符号<span lang="EN-US">”</span>的错误消 息。否则，它可以分别选择<span lang="EN-US">Wi n M a i n C RT S t a r t u p </span>函数或<span lang="EN-US">w Wi n M a i n C RT S t a r t u p </span>函数。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p style="MARGIN: 0cm 0cm 0pt; mso-line-height-alt: 9.0pt">
				<font face="宋体">
						<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">启动函数的功能归纳如下：</span>
						<span lang="EN-US">
						</span>
				</font>
		</p>
		<p style="MARGIN: 0cm 0cm 0pt; mso-line-height-alt: 9.0pt">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">• </span>
				<font face="宋体">
						<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">检索指向新进程的完整命令行的指针。</span>
				</font>
		</p>
		<p style="MARGIN: 0cm 0cm 0pt; mso-line-height-alt: 9.0pt">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">• </span>
				<font face="宋体">
						<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">检索指向新进程的环境变量的指针。</span>
						<span lang="EN-US">
						</span>
				</font>
		</p>
		<p style="MARGIN: 0cm 0cm 0pt 10pt; TEXT-INDENT: -10pt; mso-line-height-alt: 9.0pt; mso-char-indent-count: -1.0">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">• </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">对</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">C / C + +</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">运行期的全局变量进行初始化。如果包含了</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">S t d L i b . h </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">文件，代码就能访问这些变量。表</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">4 - 1 </span>
				<font face="宋体">
						<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">列出了这些变量。</span>
						<span lang="EN-US">
						</span>
				</font>
		</p>
		<p style="MARGIN: 0cm 0cm 0pt 10pt; TEXT-INDENT: -10pt; mso-line-height-alt: 9.0pt; mso-char-indent-count: -1.0">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">• </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">对</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">C </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">运行期内存单元分配函数（</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">m a l l o c </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">和</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">c a l l o c </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">）和其他低层输入</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">/</span>
				<font face="宋体">
						<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">输出例程使用的内存栈进行初始化。</span>
						<span lang="EN-US">
						</span>
				</font>
		</p>
		<p style="MARGIN: 0cm 0cm 0pt; mso-line-height-alt: 9.0pt">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">• </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">为所有全局和静态</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">C + +</span>
				<font face="宋体">
						<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">类对象调用构造函数。</span>
						<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p style="LINE-HEIGHT: 18.75pt">
				<span style="FONT-SIZE: 10pt; BACKGROUND: red; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-highlight: red">
						<font face="宋体">二</font>
				</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">
				</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">当所有这些初始化操作完成后，</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">C / C + +</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">启动函数就调用应用程序的进入点函数。如果编写了一个</font>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">w Wi n M a i n </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
						<font face="宋体">函数，它将以下面的形式被调用</font>
				</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial">
				</span>
				<font face="宋体">
						<span style="FONT-SIZE: 10pt; COLOR: black; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US">
						</span>
				</font>
		</p>
		<pre style="BACKGROUND: #d7d7d7; LINE-HEIGHT: 18.75pt">GetStartupInfo(&amp;StartupInfo);
int nMainRetVal = wWinMain(GetMjduleHandle(NULL),
   NULL, pszCommandLineUnicode,
   (StartupInfo.dwFlags &amp; STARTF_USESHOWWINDOW) ? 
   StartupInfo.wShowWindow:SW_SHOWDEFAULT);</pre>
		<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
				<font style="BACKGROUND-COLOR: #ff1493">
						<pre> </pre>
						<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 18.75pt">
								<br />三</p>
				</font>
		</span>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; mso-line-height-alt: 0pt">
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">当进入点函数返回时，启动函数便调用</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">C </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">运行期的</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">e x i t </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">函数，将返回值（</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">n M a i n R e t Va l </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">）传递给它。</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">E x i t </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">函数负责下面的操作：</span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-line-height-alt: 0pt; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">• </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">调用由</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">_onexit</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">函数的调用而注册的任何函数。</span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-line-height-alt: 0pt; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">• </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">为所有全局的和静态的</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">C++</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">类对象调用析构函数。</span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-line-height-alt: 0pt; mso-pagination: widow-orphan" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">• </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">调用操作系统的</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">ExitProcess</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">函数，将</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">nMainRetVal</span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">传递给它。这使得该操作系统能够撤消进程并设置它的</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Arial; mso-font-kerning: 0pt">e x i t </span>
				<span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-font-kerning: 0pt">代码。</span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 18.75pt; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; LINE-HEIGHT: 18.75pt; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">附录</span>
				<span lang="EN-US">:</span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">
				</span>
				<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">各种应用程序的进入点及对应的启动函数<span lang="EN-US"><o:p></o:p></span></span>
		</p>
		<p style="LINE-HEIGHT: 18.75pt">
				<span lang="EN-US">
						<o:p>
								<font face="宋体"> </font>
						</o:p>
				</span>
		</p>
		<div align="center">
				<table class="MsoNormalTable" style="BORDER-RIGHT: olive 1.5pt outset; BORDER-TOP: olive 1.5pt outset; BORDER-LEFT: olive 1.5pt outset; WIDTH: 463px; BORDER-BOTTOM: olive 1.5pt outset; HEIGHT: 175px; mso-cellspacing: .7pt; mso-padding-alt: 4.5pt 4.5pt 4.5pt 4.5pt" cellspacing="1" cellpadding="0" width="463" border="1">
						<tbody>
								<tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes">
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 41.72%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="41%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">应用程序类型<span lang="EN-US"><o:p></o:p></span></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 23.84%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="23%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">进入点<span lang="EN-US"><o:p></o:p></span></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 33.78%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="33%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">嵌入可执行文件的启动函数<span lang="EN-US"><o:p></o:p></span></span>
												</p>
										</td>
								</tr>
								<tr style="mso-yfti-irow: 1">
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 41.72%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="41%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">需要<span lang="EN-US">ANSI</span>字符和字符串的<span lang="EN-US">GUI</span>应用程序<span lang="EN-US"><o:p></o:p></span></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 23.84%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="23%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">WinMain<o:p></o:p></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 33.78%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="33%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">WinMainCRTStartup<o:p></o:p></span>
												</p>
										</td>
								</tr>
								<tr style="mso-yfti-irow: 2">
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 41.72%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="41%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">需要<span lang="EN-US">Unicode</span>字符和字符串的<span lang="EN-US">GUI</span>应用程序<span lang="EN-US"><o:p></o:p></span></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 23.84%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="23%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">wWinMainw<o:p></o:p></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 33.78%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="33%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">WinMainCRTStartup<o:p></o:p></span>
												</p>
										</td>
								</tr>
								<tr style="mso-yfti-irow: 3">
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 41.72%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="41%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">需要<span lang="EN-US">ANSI</span>字符和字符串的<span lang="EN-US">CUI</span>应用程序<span lang="EN-US"><o:p></o:p></span></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 23.84%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="23%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">main<o:p></o:p></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 33.78%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="33%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">mainCRTStartup<o:p></o:p></span>
												</p>
										</td>
								</tr>
								<tr style="mso-yfti-irow: 4; mso-yfti-lastrow: yes">
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 41.72%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="41%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">需要<span lang="EN-US">Unicode</span>字符和字符串的<span lang="EN-US">CUI</span>应用程序<span lang="EN-US"><o:p></o:p></span></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 23.84%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="23%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">wmain<o:p></o:p></span>
												</p>
										</td>
										<td style="BORDER-RIGHT: olive 1pt inset; PADDING-RIGHT: 4.5pt; BORDER-TOP: olive 1pt inset; PADDING-LEFT: 4.5pt; PADDING-BOTTOM: 4.5pt; BORDER-LEFT: olive 1pt inset; WIDTH: 33.78%; PADDING-TOP: 4.5pt; BORDER-BOTTOM: olive 1pt inset; BACKGROUND-COLOR: transparent; mso-border-alt: inset olive .75pt" width="33%">
												<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align="center">
														<span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">wmainCRTStartup<o:p></o:p></span>
												</p>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
		<p style="LINE-HEIGHT: 18.75pt">
				<span lang="EN-US">
						<o:p>
								<font face="宋体"> </font>
						</o:p>
				</span>
		</p>
		<p style="LINE-HEIGHT: 18.75pt">
				<span lang="EN-US" style="FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'">
						<o:p>
								<font face="宋体"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
<img src ="http://www.cppblog.com/mzty/aggbug/12331.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-12 11:57 <a href="http://www.cppblog.com/mzty/archive/2006/09/12/12331.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--内核对象</title><link>http://www.cppblog.com/mzty/archive/2006/09/12/12327.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 12 Sep 2006 01:32:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/12/12327.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12327.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/12/12327.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12327.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12327.html</trackback:ping><description><![CDATA[
		<font style="BACKGROUND-COLOR: #ff1493">简单地说:</font>
		<br />
		<br />内核对象是系统的一种资源。系统对象一旦产生，任何应用程序都可以开启并且使用该对象。系统给内核对象一个计数值作为管理只用，内核对象包括：<br />　event,mutex,semaphore,file,file-mapping,preocess,thread. 
<p>这些内核对象每次产生都会返回一个handle,作为标示，每使用一次，对应的计数值加1,调用CloseHandle可以结束内核对象的使用。<br /><br /><font style="BACKGROUND-COLOR: #ff1493">具体:</font></p><br /><p>1.  内核对象:<br />    1).符号对象<br />    2).事件对象<br />    3).文件对象<br />    4).文件影象对象<br />    5).I/O完成对象<br />    6).作业对象<br />    7).信箱对象<br />    8).互斥对象<br />    9).管道对象<br />    10).进程对象<br />    11).信标对象<br />    12).线程对象<br />    13).待计时器对象<br />     等</p><p>2.内核对象只能由内核所拥有,而不是由进程拥有.(就是说进程没有了,内核还可以被其他进程使用)<br /><br />3.内核对象的数据结构有计数器,进程调用时,计数器增1,调用结束,计数器减1,内核对象计数器为零时,销毁此内核对象.(系统来管理内核对象)<br /><br />4.内核安全性,进程使用什么权限调用内核对象,由SECURITY_ATTRIBUTES结构的数据结构来指定.几乎所有的调用内核对象的函数都含有SECURITY_ATTRIBUTES结构的指针参数.(可以由这个参数来判断是不是内核对象哦)<br />typedef struct _SECURITY_ATTRIBUTES { <br />  DWORD  nLength;   //结构体长度<br />  LPVOID lpSecurityDescriptor;  //安全性设置<br />  BOOL   bInheritHandle;  //可继承性<br />} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES; <br /><br />5.进程的内核对象的句柄表,<font style="BACKGROUND-COLOR: #ff1493">进程调用内核对象时,就会创建内核对象的句柄表,就是内核对象在进程中的索引,索引值就是调用内核对象函数返回的句柄.</font>关闭所有的内核对象,使用CloseHandle();<br /><br />6.跨越进程边界共享内核对象<br />MICROSOFT把句柄设计成进程句柄，不设计成系统句柄是为了实现句柄的健壮性和安全性。<br />1)<font style="BACKGROUND-COLOR: #ff1493">内核对象句柄的继承性。(为了实现内核的多个进程的共享)<br /></font>    作用：为了子进程实现对父进程创建的内核对象的访问。 <br />    步骤：首先，父进程创建内核对象时，初始化SECURITY_ATTRIBUTES结构的对象，让SECURITY_ATTRIBUTES结构体的成员变量bInheritHandle设置为TRUE。<br />       然后，子进程创建后，生成自己的句柄表，句柄表遍历父进程的句柄表，找到有继承性的句柄，并复制一份到子进程的句柄表中，子进程的内核对象和父进程的内核对象使用相同的内存块指针，内核对象计数器在子进程中创建内核对象后增一，父进程调用CloseHandle()来关闭内核对象，确不影响子进程使用该内核对象。<br />2)改变句柄的标志<br />BOOL SetHandleInformation(<br />  HANDLE hObject,  // handle to object<br />  DWORD dwMask,    // flags to change<br />  DWORD dwFlags    // new values for flags<br />);</p><p>打开内核的可继承性标志<br />SetHandleInformation(hobj,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);<br />关闭内核的可继承性标志<br />SetHandleInformation(hobj,HANDLE_FLAG_INHERIT,0);<br />若想让内核对象不被关闭，设置HANDLE_FLAG_PROTECT_FROM_CLOSE。</p><p>获得句柄标志的函数<br />BOOL GetHandleInformation(<br />  HANDLE hObject,    // handle to object<br />  LPDWORD lpdwFlags  // handle properties<br />);</p><p>3)命名对象<br />作用：<font style="BACKGROUND-COLOR: #ff1493">让进程中的内核对象可以共享，让别的进程可以通过命名空间，跨进程来访问这个进程的内核对象。<br /></font>创建对象和访问对象使用函数<br />创建对象Create*:如果命名的内核对象已经存在并具备安全访问权限，则参数被忽略，进程的句柄表复制一份内核对象的指针和标志到进程的句柄表，如果不存在，则马上创建内核对象。<br />例子：<br />HANDLE CreateMutex(<br />  LPSECURITY_ATTRIBUTES lpMutexAttributes,  // SD<br />  BOOL bInitialOwner,                       // initial owner<br />  LPCTSTR lpName                            // 对象名字<br />);</p><p>打开对象Open*：如果命名的内核对象已经存在并具备安全访问权限，进程的句柄表复制一份内核对象的指针和标志到进程的句柄表，如果不存在，则返回NULL，使用GetLassError()，得到返回值2。</p><p>4)终端服务的名字空间<br />每个客户程序会话都有自己的服务名字空间，一个会话无法访问另一个会话的对象，尽管他们具备相同的对象名字。<br />服务程序的名字空间对象总放在全局名字空间中。</p><p>5)复制对象句柄<br />DuplicateHandle函数来对另一个进程对象的句柄进行复制到调用此函数的进程句柄表中，实现进程间共享内核对象。<br />BOOL DuplicateHandle(<br />  HANDLE hSourceProcessHandle,  // handle to source process<br />  HANDLE hSourceHandle,         // handle to duplicate<br />  HANDLE hTargetProcessHandle,  // handle to target process<br />  LPHANDLE lpTargetHandle,      // duplicate handle<br />  DWORD dwDesiredAccess,        // requested access<br />  BOOL bInheritHandle,          // handle inheritance option<br />  DWORD dwOptions               // optional actions<br />);<br /></p><img src ="http://www.cppblog.com/mzty/aggbug/12327.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-12 09:32 <a href="http://www.cppblog.com/mzty/archive/2006/09/12/12327.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--字符集</title><link>http://www.cppblog.com/mzty/archive/2006/09/11/12268.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Mon, 11 Sep 2006 08:57:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/11/12268.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12268.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/11/12268.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12268.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12268.html</trackback:ping><description><![CDATA[<font style="BACKGROUND-COLOR: #ff1493">&nbsp;字符unicode与windows<br><br></font>&nbsp;<br><font face=Arial size=2>1 软件的本地化要解决的真正问题，实际上就是如何来处理不同的字符集。以前我们习惯与用单字节字符集来编程.<br>2 单字符集:将文本串作为一系列单字节字符来进行编码，并在结尾处放上一个零。(每个字符用一个字节来表示)<br>3 双字节字符集（D B C S ):在双字节字符集中，字符串中的每个字符可以包含一个字节或包含两个字节。<br>4 unicode字符集:U n i c o d e 提供了一种简单而又一致的表示字符串的方法。U n i c o d e 字符串中的所有字符都是1 6 位的（两个字节）。<br>5 当M i c r o s o f t 公司将C O M 从1 6 位Wi n d o w s 转换成Wi n 3 2 时，公司作出了一个决定，即需要字符串的所有C O M 接口方法都只能接受U n i c o d e 字符串。<br>6 c运行期库支持unicode,即使是windows98也支持.<br>7 Windows 2000 的N o t e p a d (记事本)应用程序允许你既能打开U n i c o d e 文件，也能打开A N S I 文件，并且可以创建这些文件。<br>8 I s Te x t U n i c o d e 函数能够帮助进行区分ANSIC字符和unicode：<font face="Times New Roman" size=3><br></font><font style="LINE-HEIGHT: 25px" face=Arial size=3>DWORD IsTextUnicode(CONST PVOID pvBuffer, int cb,PINT pResult);<br></font>
<p><font color=#000000 size=2>第一个参数p v B u ff e r 用于标识要测试的缓存的地址。该数据是个无效指针，因为你不知道你拥有的是A N S I 字符数组还是U n i c o d e&nbsp;<br>字符数组。</font></p>
<p><font color=#000000 size=2>第二个参数c b 用于设定p v B u ff e r 指向的字节数。同样，由于你不知道缓存中放的是什么，因此c b 是个字节数，而不是字符数。请注意，不必设定缓存的整个长度。当然，I s Te x t U n i c o d e能够测试的字节越多，得到的结果越准确。</font></p>
<p><font color=#000000 size=2>第三个参数p R e s u l t 是个整数的地址，必须在调用I s Te x t U n i c o d e 之前对它进行初始化。对该整数进行初始化后，就可以指明你要I s Te x t U n i c o d e 执行哪些测试。也可以为该参数传递N U L L ，在这种情况下，I s Te x t U n i c o d e 将执行它能够进行的所有测试（详细说明请参见Platform SDK 文档）。</font><br></p>
<p align=left>9&nbsp;对D B C S 字符串进行操作的帮助函数 </p>
<center>
<table style="WIDTH: 644px; HEIGHT: 172px" borderColor=#808000 cellSpacing=1 cellPadding=6 border=2>
    <tbody>
        <tr>
            <td align=middle width="60%">函数</td>
            <td align=middle width="40%">描述</td>
        </tr>
        <tr>
            <td width="60%">PTSTR CharNext(PCTSTR pszCurrentChar);</td>
            <td width="40%">返回字符串中的下一个字符的地址</td>
        </tr>
        <tr>
            <td width="60%">PTSTR CharPrev (PCTSTR pszStart,PCTSTR p s z C u r r e n t C h a r);</td>
            <td width="40%">返回字符串中的上一个字符的地址</td>
        </tr>
        <tr>
            <td width="60%">BOOL IsDBCSLeadByteTRUE(BYTE bTestChar);</td>
            <td width="40%">如果该字节是DBCS 字符的第一个字节，则返回</td>
        </tr>
    </tbody>
</table>
</center>
<center><br></center>
<div align=left><br>10 &#8220;M i c r o s o f t 公司对U n i c o d e 支持的情况&#8221;： </div>
<p align=left><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; Windows 2000 既支持U n i c o d e ，也支持A N S I ，因此可以为任意一种开发应用程序。</font></p>
<p align=left><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; Windows 98 只支持A N S I ，只能为A N S I 开发应用程序。</font></p>
<p align=left><font style="LINE-HEIGHT: 25px" color=#000000 size=2>&#8226; Windows CE 只支持U n i c o d e ，只能为U n i c o d e 开发应用程序。</font></p>
<p align=left><font color=#000000 size=2>11 Wi n d o w s 头文件定义de Uincode 数据类型</font></p>
<center>
<table borderColor=#808000 cellSpacing=1 cellPadding=6 border=2>
    <tbody>
        <tr>
            <td align=middle width="41%">数据类型</td>
            <td align=middle width="59%">说明</td>
        </tr>
        <tr>
            <td align=middle width="41%">W C H A R</td>
            <td width="59%">U n i c o d e 字符</td>
        </tr>
        <tr>
            <td align=middle width="41%">P W S T R</td>
            <td width="59%">指向U n i c o d e 字符串的指针</td>
        </tr>
        <tr>
            <td align=middle width="41%">P C W S T R</td>
            <td width="59%">指向一个恒定的U n i c o d e 字符串的指针</td>
        </tr>
    </tbody>
</table>
</center>
<div align=left>使用实例如下:<br>
<pre>#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif //!UNICODE</pre>
<strong><font color=#0000ff>在Unicode与ANSI之间转换字符串</font></strong>
<p><font style="LINE-HEIGHT: 25px" color=#000000 size=2>Wi n d o w s 函数M u l t i B y t e To Wi d e C h a r 用于将多字节字符串转换成宽字符串。下面显示了M u l t i B y t e To Wi d e C h a r 函数。</font></p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font size=3>int MultiByteToWideChar(
UINT CodePage,          //code page
DWORD dwFlags,          //character-type options
LPCSTR lpMultiByteStr,  //address of string to map
int cchMultiByte,       //number of bytes in string
LPWSTR lpWideCharStr,   //address of wide-character buffer
int cchWideChar         //size of buffer
);</font></pre>
</div>
<font color=#000000 size=2>u C o d e P a g e 参数用于标识一个与多字节字符串相关的代码页号。d w F l a g s 参数用于设定另一个控件，它可以用重音符号之类的区分标记来影响字符。这些标志通常并不使用，在d w F l a g s参数中传递0 。p M u l t i B y t e S t r 参数用于设定要转换的字符串，c c h M u l t i B y t e 参数用于指明该字符串的长度（按字节计算）。如果为c c h M u l t i B y t e 参数传递- 1 ，那么该函数用于确定源字符串的长度。</font>
<p><font color=#000000 size=2>转换后产生的U n i c o d e 版本字符串将被写入内存中的缓存，其地址由p Wi d e C h a r S t r 参数指定。必须在c c h Wi d e C h a r 参数中设定该缓存的最大值（以字符为计量单位）。如果调用M u l t i B y t e To Wi d e C h a r ，给c c h Wi d e C h a r 参数传递0 ，那么该参数将不执行字符串的转换，而是返回为使转换取得成功所需要的缓存的值。一般来说，可以通过下列步骤将多字节字符串转换成U n i c o d e 等价字符串：</font></p>
<p><font color=#000000 size=2>1) 调用M u l t i B y t e To Wi d e C h a r 函数，为p Wi d e C h a r S t r 参数传递N U L L ，为c c h Wi d e C h a r 参数传递0 。<br>2) 分配足够的内存块，用于存放转换后的U n i c o d e 字符串。该内存块的大小由前面对M u l t B y t e To Wi d e C h a r 的调用返回。<br>3) 再次调用M u l t i B y t e To Wi d e C h a r ，这次将缓存的地址作为p Wi d e C h a r S t r 参数来传递，并传递第一次调用M u l t i B y t e To Wi d e C h a r 时返回的缓存大小，作为c c h Wi d e c h a r 参数。<br>4. 使用转换后的字符串。<br>5) 释放U n i c o d e 字符串占用的内存块。<br>函数Wi d e C h a r To M u l t i B y t e 将宽字符串转换成等价的多字节字符串，如下所示：</font></p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font size=3>int WideCharToMultiByte(
UINT CodePage,         // code page
DWORD dwFlags,         // performance and mapping flags
LPCWSTR lpWideCharStr, // address of wide-character string
int cchWideChar,       // number of characters in string
LPSTR lpMultiByteStr,  // address of buffer for new string
int cchMultiByte,      // size of buffer
LPCSTR lpDefaultChar,  // address of default for unmappable
// characters
LPBOOL lpUsedDefaultChar   // address of flag set when default
// char. used
);</font></pre>
</div>
<font color=#000000 size=2>该函数与M u l t i B i t e To Wi d e C h a r 函数相似。同样，u C o d e P a g e 参数用于标识与新转换的字符串相关的代码页。d w F l a g s 则设定用于转换的其他控件。这些标志能够作用于带有区分符号的字符和系统不能转换的字符。通常不需要为字符串的转换而拥有这种程度的控制手段，你将为d w F l a g s 参数传递0 。</font>
<p><font color=#000000 size=2>p Wi d e C h a r S t r 参数用于设定要转换的字符串的内存地址，c c h Wi d e C h a r 参数用于指明该字符串的长度（用字符数来计量）。如果你为c c h Wi d e C h a r 参数传递- 1 ，那么该函数用于确定源字符串的长度。</font></p>
<p><font color=#000000 size=2>转换产生的多字节版本的字符串被写入由p M u l t i B y t e S t r 参数指明的缓存。必须在c c h M u l t i B y t e参数中设定该缓存的最大值（用字节来计量）。如果传递0 作为Wi d e C h a r To M u l t i B y t e 函数的c c h M u l t i B y t e 参数，那么该函数将返回目标缓存需要的大小值。通常可以使用将多字节字符串转换成宽字节字符串时介绍的一系列类似的事件，将宽字节字符串转换成多字节字符串。</font></p>
<p><font color=#000000 size=2>你会发现，Wi d e C h a r To M u l t i B y t e 函数接受的参数比M u l t i B y t e To Wi d e C h a r 函数要多2 个，即p D e f a u l t C h a r 和p f U s e d D e f a u l t C h a r 。只有当Wi d e C h a r To M u l t i B y t e 函数遇到一个宽字节字符，而该字符在u C o d e P a g e 参数标识的代码页中并没有它的表示法时，Wi d e C h a r To M u l t i B y t e 函数才使用这两个参数。如果宽字节字符不能被转换，该函数便使用p D e f a u l t C h a r 参数指向的字符。如果该参数是N U L L （这是大多数情况下的参数值），那么该函数使用系统的默认字符。该默认字符通常是个问号。这对于文件名来说是危险的，因为问号是个通配符。</font></p>
<p><font color=#000000 size=2>p f U s e d D e f a u l t C h a r 参数指向一个布尔变量，如果宽字符串中至少有一个字符不能转换成等价多字节字符，那么函数就将该变量置为T R U E 。如果所有字符均被成功地转换，那么该函数就将该变量置为FA L S E 。当函数返回以便检查宽字节字符串是否被成功地转换后，可以测试该变量。同样，通常为该测试传递N U L L 。<br></font></p>
<p><font color=#000000 size=2>关于如何使用这些函数的详细说明，请参见Platform SDK 文档。</font></p>
<p><font color=#000000 size=2>如果使用这两个函数，就可以很容易创建这些函数的U n i c o d e 版本和A N S I 版本。例如，你可能有一个动态链接库，它包含一个函数，能够转换字符串中的所有字符。可以像下面这样编写该函数的U n i c o d e 版本：</font></p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font size=3>BOOL StringReverseW(PWSTR pWideCharStr)
{
//Get a pointer to the last character in the string.
PWSTR pEndOfStr=pWideCharStr+wcslen(pWideCharStr)-1;
wchar_t cCharT;
//Repeat until we reach the center character
//in the string.
while (pWideCharStr &lt; pEndOfStr)
{
//Save a character in a temporary variable.
cCharT=*pWideCharStr;
//Put the last character in the first character.
*pWideCharStr =*pEndOfStr;
//Put the temporary character in the last character.
*pEndOfStr=cCharT;
//Move in one character from the left.
pWideCharStr++;
//Move in one character from the right.
pEndOfStr--;
}
//The string is reversed; return success.
return(TRUE);
}</font></pre>
</div>
<p><font color=#000000 size=2>你可以编写该函数的A N S I 版本以便该函数根本不执行转换字符串的实际操作。你也可以编写该函数的A N S I 版本，以便该函数它将A N S I 字符串转换成U n i c o d e 字符串，将U n i c o d e 字符串传递给S t r i n g R e v e r s e W 函数，然后将转换后的字符串重新转换成A N S I 字符串。该函数类似下面的样子：</font></p>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font size=3>BOOL StringReverseA(PSTR pMultiByteStr)
{
PWSTR pWideCharStr;
int nLenOfWideCharStr;
BOOL fOk = FALSE;
//Calculate the number of characters needed to hold
//the wide_character version of string.
nLenOfWideCharStr = MultiRyteToWideChar(CP_ACP, 0,
pMultiByteStr, -1, NULL, 0);
//Allocate memory from the process's default heap to
//accommodate the size of the wide-character string.
//Don't forget that MultiByteToWideChar returns the
//number of characters,not the number of bytes,so
//you must multiply by the size of wide character.
pWideCharStr = HeapAlloc(GetProcessHeap(), 0,
nLenOfWideCharStr * sizeof(WCHAR));
if (pWideCharStr == NULL)
return(fOk);
//Convert the multibyte string to a wide_character string.
MultiByteToWideChar(CP_ACP, 0, pMulti8yteStr, -1,
pWideCharStr, nLenOfWideCharStr);
//Call the wide-character version of this
//function to do the actual work
fOk = StnngReverseW(pWideCharStr);
if (fOk)
{
//Convert the wide-character string back
//to a multibyte string.
WideCharToMultiByte(CP_ACP, 0, pWideCharStr, -1,
pMultiByteStr, strlen(pMultiByteStr), NULL, NULL);
}
//Free the momory containing the wide-character string.
HeapFree(GetProcessHeap(), 0, pWideCharStr);
return(fOk),
}</font></pre>
</div>
<font style="LINE-HEIGHT: 25px" color=#000000 size=2>最后，在用动态链接库分配的头文件中，可以像下面这样建立这两个函数的原型：</font>
<p>&#160;</p>
<div style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7">
<pre><font size=3>BOOL StringReverseW (PWSTR pWideCharStr);
BOOL StringReverseA (PSTR pMultiByteStr);
#ifdef UNICODE
#define StnngReverse StringReverseW
#else
#define StringRevcrsc StringReverseA
#endif // UNICODE</font></pre>
</div>
</div>
</font><img src ="http://www.cppblog.com/mzty/aggbug/12268.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-11 16:57 <a href="http://www.cppblog.com/mzty/archive/2006/09/11/12268.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows核心编程--函数返回错误</title><link>http://www.cppblog.com/mzty/archive/2006/09/11/12266.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Mon, 11 Sep 2006 07:45:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/11/12266.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12266.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/11/12266.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12266.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12266.html</trackback:ping><description><![CDATA[<font style="BACKGROUND-COLOR: #ff1493">1 windows程序错误的处理机制<br></font><br>&nbsp;&nbsp;&nbsp; windows API的返回类型<br>
<table style="WIDTH: 640px; HEIGHT: 440px" borderColor=#808000 cellSpacing=1 cellPadding=6 border=2>
    <tbody>
        <tr>
            <td align=middle width="11%"><font style="LINE-HEIGHT: 25px" face=Arial color=#000080 size=2>数据类型 </font></td>
            <td align=middle width="89%">
            <p align=left><font style="LINE-HEIGHT: 25px" face=Arial color=#000080 size=2>表示失败的值 </font></p>
            </td>
        </tr>
        <tr>
            <td align=middle width="11%"><font style="LINE-HEIGHT: 25px" face=Arial color=#000080 size=2>V O I D </font></td>
            <td align=middle width="89%">
            <p align=left><font color=#000080 size=2><font face=Arial><font style="LINE-HEIGHT: 25px">该函数的运行不可能失败。</font><font style="LINE-HEIGHT: 25px">Wi n d o w s 函数的返回值类型很少是</font><font style="LINE-HEIGHT: 25px">V O I D </font></font></font></p>
            </td>
        </tr>
        <tr>
            <td align=middle width="11%"><font style="LINE-HEIGHT: 25px" face=Arial color=#000080 size=2>B O O L</font></td>
            <td align=middle width="89%">
            <p align=left><font color=#000080 size=2><font face=Arial><font style="LINE-HEIGHT: 25px">如果函数运行失败，那么返回值是</font><font style="LINE-HEIGHT: 25px">0 ，否则返回的是非</font><font style="LINE-HEIGHT: 25px">0 值。最好对返回值进行测试，以确定它是</font><font style="LINE-HEIGHT: 25px">0 还是非</font><font style="LINE-HEIGHT: 25px">0 。不要测试返回值是否为</font><font style="LINE-HEIGHT: 25px">T R U E </font></font></font></p>
            </td>
        </tr>
        <tr>
            <td align=middle width="11%"><font style="LINE-HEIGHT: 25px" face=Arial color=#000080 size=2>H A N D L E</font></td>
            <td align=middle width="89%">
            <p align=left><font color=#000080 size=2><font face=Arial><font style="LINE-HEIGHT: 25px">如果函数运行失败，则返回值通常是</font><font style="LINE-HEIGHT: 25px">N U L L ，否则返回值为</font><font style="LINE-HEIGHT: 25px">H A N D L E ，用于标识你可以操作的一个对象。注意，有些函数会返回一个句柄值</font><font style="LINE-HEIGHT: 25px">I N VALID_ HANDLE_VA L U E ，它被定义为</font><font style="LINE-HEIGHT: 25px">- 1 。函数的</font><font style="LINE-HEIGHT: 25px">Platform SDK 文档将会清楚地说明该函数运行失败时返回的是</font><font style="LINE-HEIGHT: 25px">N U L L 还是</font><font style="LINE-HEIGHT: 25px">I N VA L I D _ H A N D L E _ VA L I D </font></font></font></p>
            </td>
        </tr>
        <tr>
            <td align=middle width="11%"><font face=Arial color=#000080 size=2>P V O I D</font></td>
            <td align=middle width="89%">
            <p align=left><font color=#000080 size=2><font face=Arial><font style="LINE-HEIGHT: 25px">如果函数运行失败，则返回值是</font><font style="LINE-HEIGHT: 25px">N U L L ，否则返回</font><font style="LINE-HEIGHT: 25px">P V O I D ，以标识数据块的内存地址 </font></font></font></p>
            </td>
        </tr>
        <tr>
            <td align=middle width="11%"><font style="LINE-HEIGHT: 25px" face=Arial color=#000080 size=2>L O N G / D W O R D </font></td>
            <td align=middle width="89%">
            <p align=left><font color=#000080 size=2><font face=Arial><font style="LINE-HEIGHT: 25px">这是个难以处理的值。返回数量的函数通常返回</font><font style="LINE-HEIGHT: 25px">L O N G 或</font><font style="LINE-HEIGHT: 25px">D W O R D 。如果由于某种原因，函数无法对想要进行计数的对象进行计数，那么该函数通常返回</font><font style="LINE-HEIGHT: 25px">0 或</font><font style="LINE-HEIGHT: 25px">- 1 （根据函数而定）。如果调用的函数返回了</font><font style="LINE-HEIGHT: 25px">L O N G / D W O R D ，那么请认真阅读</font><font style="LINE-HEIGHT: 25px">Platform SDK文档，以确保能正确检查潜在的错误</font></font></font></p>
            </td>
        </tr>
    </tbody>
</table>
<br><font face=Arial size=2>Wi n E r r o r. h 头文件包含了M i c r o s o f t 公司定义的错误代码的列表,每个错误都有三种表示,例如下面:<br></font><br>// MessageId: ERROR_PATH_NOT_FOUND<br>// MessageText:<br>//&nbsp; The system cannot find the path specified.<br>#define ERROR_PATH_NOT_FOUND&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3L<br><br>当有错误发生时,可以通过下面函数得到错误的id,<br>DWORD GetLastError();<br>也可以通过下面函数由id得到对应的text:<br>DWORD FormatMessage(<br>&nbsp; DWORD dwFlags,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // source and processing options<br>&nbsp; LPCVOID lpSource,&nbsp;&nbsp; // pointer to&nbsp; message source<br>&nbsp; DWORD dwMessageId,&nbsp; // requested message identifier<br>&nbsp; DWORD dwLanguageId, // language identifier for requested message<br>&nbsp; LPTSTR lpBuffer,&nbsp;&nbsp;&nbsp; // pointer to message buffer<br>&nbsp; DWORD nSize,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // maximum size of message buffer<br>&nbsp; va_list *Arguments&nbsp; // pointer to array of message inserts<br>);<br>当调用一个API出现错误时,可以立即通过一下方法查看错误,但是后面的API的调用会覆盖调前面的错误<br>
<p align=center><img style="WIDTH: 554px; HEIGHT: 246px" height=246 alt=o_SpxImage1.jpg src="http://www.cppblog.com/images/cppblog_com/mzty/2021/o_SpxImage1.jpg" width=554 border=0></p>
<p align=center>图1-1 在Visual Studio 6.0 的Wa t c h 窗口中键入&#8220;@ e r r, h r &#8221;，就可以查看当前线程的最后错误代码 </p>
<p><font style="LINE-HEIGHT: 25px" face=Arial color=#000000 size=2>Visual studio 还配有一个小的实用程序，称为Error Lookup 。可以使用Error Lookup将错误代码的号码转换成相应文本描述（见图1 - 2 ）。</font></p>
<p align=center><img height=259 alt=o_SpxImage2.jpg src="http://www.cppblog.com/images/cppblog_com/mzty/2021/o_SpxImage2.jpg" width=435 border=0><br><br></p>
用户也可以定义自己的错误代码,但是要建立正确的32位的id哦,不能与系统的冲突啊.<br>
<p align=center>表1-2 错误代码的域</p>
<center>
<table style="WIDTH: 631px; HEIGHT: 280px" borderColor=#808000 cellSpacing=1 cellPadding=6 border=2>
    <tbody>
        <tr>
            <td align=middle width="16%">位</td>
            <td align=middle width="16%">3 1 ~30</td>
            <td align=middle width="17%">29</td>
            <td align=middle width="17%">28</td>
            <td align=middle width="17%">27~16</td>
            <td align=middle width="17%">15~0</td>
        </tr>
        <tr>
            <td align=middle width="16%">内容</td>
            <td align=middle width="16%">严重性</td>
            <td align=middle width="17%">M i c r o s o f t/客户</td>
            <td align=middle width="17%">保留</td>
            <td align=middle width="17%">设备代码</td>
            <td align=middle width="17%">异常代码</td>
        </tr>
        <tr>
            <td align=middle width="16%">含义</td>
            <td align=middle width="16%">0 =成功</td>
            <td align=middle width="17%">0 =M i c r o s o f t公司定义的代码</td>
            <td align=middle width="17%">必须是0</td>
            <td align=middle width="17%">由M i c r o s o f t公司定义</td>
            <td align=middle width="17%">由Microsoft/客户定义</td>
        </tr>
        <tr>
            <td align=middle width="16%">　</td>
            <td align=middle width="16%">1 =供参考</td>
            <td align=middle width="17%">1 =客户定义的代码</td>
            <td align=middle width="17%">　</td>
            <td align=middle width="17%">　</td>
            <td align=middle width="17%">　</td>
        </tr>
        <tr>
            <td align=middle width="16%">　</td>
            <td align=middle width="16%">2 =警告</td>
            <td align=middle width="17%">　</td>
            <td align=middle width="17%">　</td>
            <td align=middle width="17%">　</td>
            <td align=middle width="17%">　</td>
        </tr>
        <tr>
            <td align=middle width="16%">　</td>
            <td align=middle width="16%">3 =错误</td>
            <td align=middle width="17%">　</td>
            <td align=middle width="17%">　</td>
        </tr>
    </tbody>
</table>
</center>
<div align=left><font face=Arial size=2></font>&nbsp;</div><img src ="http://www.cppblog.com/mzty/aggbug/12266.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-11 15:45 <a href="http://www.cppblog.com/mzty/archive/2006/09/11/12266.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows程序简单框架</title><link>http://www.cppblog.com/mzty/archive/2006/09/08/12166.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Fri, 08 Sep 2006 05:56:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/09/08/12166.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/12166.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/09/08/12166.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/12166.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/12166.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 简单的messagebox实例: (vs2003中通过,建立空的vc工程先)#define WIN32_LEAN_AND_MEAN  //no use mfc#include &lt;windows.h&gt;        // the main windows headers #include &lt;windowsx.h&gt;       // a lot of cool macros//...&nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2006/09/08/12166.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/12166.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-09-08 13:56 <a href="http://www.cppblog.com/mzty/archive/2006/09/08/12166.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用API写Windows程序</title><link>http://www.cppblog.com/mzty/archive/2006/08/21/11521.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Mon, 21 Aug 2006 06:36:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/08/21/11521.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/11521.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/08/21/11521.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/11521.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/11521.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一 先来看个简单实例:#include "windows.h" int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { 　　MessageBox (NULL, TEXT ("你好，欢迎来到VC之路"), TEXT ("欢迎"), 0) ; 　　return 0...&nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2006/08/21/11521.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/11521.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-08-21 14:36 <a href="http://www.cppblog.com/mzty/archive/2006/08/21/11521.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为程序增加简单的声音提示(.net封装API --PlaySound())</title><link>http://www.cppblog.com/mzty/archive/2006/07/06/9490.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Thu, 06 Jul 2006 08:40:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/07/06/9490.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/9490.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/07/06/9490.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/9490.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/9490.html</trackback:ping><description><![CDATA[
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />                <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />            <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">using</span>
				<span style="COLOR: #000000"> System;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">using</span>
				<span style="COLOR: #000000"> System.Runtime.InteropServices;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">namespace</span>
				<span style="COLOR: #000000"> tonysound <br /><img id="Codehighlighter1_84_1074_Open_Image" onclick="this.style.display='none'; Codehighlighter1_84_1074_Open_Text.style.display='none'; Codehighlighter1_84_1074_Closed_Image.style.display='inline'; Codehighlighter1_84_1074_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_84_1074_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_84_1074_Closed_Text.style.display='none'; Codehighlighter1_84_1074_Open_Image.style.display='inline'; Codehighlighter1_84_1074_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_84_1074_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_84_1074_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">class</span>
						<span style="COLOR: #000000"> Sound <br /><img id="Codehighlighter1_108_478_Open_Image" onclick="this.style.display='none'; Codehighlighter1_108_478_Open_Text.style.display='none'; Codehighlighter1_108_478_Closed_Image.style.display='inline'; Codehighlighter1_108_478_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_108_478_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_108_478_Closed_Text.style.display='none'; Codehighlighter1_108_478_Open_Image.style.display='inline'; Codehighlighter1_108_478_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_108_478_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_108_478_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #0000ff">public</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">static</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">void</span>
								<span style="COLOR: #000000"> Play( </span>
								<span style="COLOR: #0000ff">string</span>
								<span style="COLOR: #000000"> strFileName, PlaySoundFlags soundFlags) <br /><img id="Codehighlighter1_187_315_Open_Image" onclick="this.style.display='none'; Codehighlighter1_187_315_Open_Text.style.display='none'; Codehighlighter1_187_315_Closed_Image.style.display='inline'; Codehighlighter1_187_315_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_187_315_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_187_315_Closed_Text.style.display='none'; Codehighlighter1_187_315_Open_Image.style.display='inline'; Codehighlighter1_187_315_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span>
								<span id="Codehighlighter1_187_315_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.cppblog.com/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_187_315_Open_Text">
										<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            PlaySound( strFileName, IntPtr.Zero, soundFlags);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> passes to Playsound the filename and a pointer<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> to the Flag</span>
										<span style="COLOR: #008000">
												<br />
												<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />
										</span>
										<span style="COLOR: #000000">        }</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
										<br />
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        [DllImport(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">winmm.dll</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">)] </span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000">inports the winmm.dll used for sound</span>
								<span style="COLOR: #008000">
										<br />
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">        </span>
								<span style="COLOR: #0000ff">private</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">static</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">extern</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">bool</span>
								<span style="COLOR: #000000"> PlaySound( </span>
								<span style="COLOR: #0000ff">string</span>
								<span style="COLOR: #000000"> szSound, IntPtr hMod, PlaySoundFlags flags );<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    [Flags] </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000">enumeration treated as a bit field or set of flags</span>
						<span style="COLOR: #008000">
								<br />
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #000000">    </span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">enum</span>
						<span style="COLOR: #000000"> PlaySoundFlags: </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> <br /><img id="Codehighlighter1_578_1071_Open_Image" onclick="this.style.display='none'; Codehighlighter1_578_1071_Open_Text.style.display='none'; Codehighlighter1_578_1071_Closed_Image.style.display='inline'; Codehighlighter1_578_1071_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_578_1071_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_578_1071_Closed_Text.style.display='none'; Codehighlighter1_578_1071_Open_Image.style.display='inline'; Codehighlighter1_578_1071_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_578_1071_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_578_1071_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_602_635_Open_Image" onclick="this.style.display='none'; Codehighlighter1_602_635_Open_Text.style.display='none'; Codehighlighter1_602_635_Closed_Image.style.display='inline'; Codehighlighter1_602_635_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_602_635_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_602_635_Closed_Text.style.display='none'; Codehighlighter1_602_635_Open_Image.style.display='inline'; Codehighlighter1_602_635_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_SYNC </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x0000</span>
								<span style="COLOR: #000000">, </span>
								<span id="Codehighlighter1_602_635_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_602_635_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> play synchronously (default) </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img id="Codehighlighter1_659_683_Open_Image" onclick="this.style.display='none'; Codehighlighter1_659_683_Open_Text.style.display='none'; Codehighlighter1_659_683_Closed_Image.style.display='inline'; Codehighlighter1_659_683_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_659_683_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_659_683_Closed_Text.style.display='none'; Codehighlighter1_659_683_Open_Image.style.display='inline'; Codehighlighter1_659_683_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_ASYNC </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x0001</span>
								<span style="COLOR: #000000">, </span>
								<span id="Codehighlighter1_659_683_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_659_683_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> play asynchronously </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img id="Codehighlighter1_711_752_Open_Image" onclick="this.style.display='none'; Codehighlighter1_711_752_Open_Text.style.display='none'; Codehighlighter1_711_752_Closed_Image.style.display='inline'; Codehighlighter1_711_752_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_711_752_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_711_752_Closed_Text.style.display='none'; Codehighlighter1_711_752_Open_Image.style.display='inline'; Codehighlighter1_711_752_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_NODEFAULT </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x0002</span>
								<span style="COLOR: #000000">, </span>
								<span id="Codehighlighter1_711_752_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_711_752_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> silence (!default) if sound notfound </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img id="Codehighlighter1_775_817_Open_Image" onclick="this.style.display='none'; Codehighlighter1_775_817_Open_Text.style.display='none'; Codehighlighter1_775_817_Closed_Image.style.display='inline'; Codehighlighter1_775_817_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_775_817_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_775_817_Closed_Text.style.display='none'; Codehighlighter1_775_817_Open_Image.style.display='inline'; Codehighlighter1_775_817_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_LOOP </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x0008</span>
								<span style="COLOR: #000000">, </span>
								<span id="Codehighlighter1_775_817_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_775_817_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> loop the sound until nextsndPlaySound </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img id="Codehighlighter1_842_884_Open_Image" onclick="this.style.display='none'; Codehighlighter1_842_884_Open_Text.style.display='none'; Codehighlighter1_842_884_Closed_Image.style.display='inline'; Codehighlighter1_842_884_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_842_884_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_842_884_Closed_Text.style.display='none'; Codehighlighter1_842_884_Open_Image.style.display='inline'; Codehighlighter1_842_884_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_NOSTOP </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x0010</span>
								<span style="COLOR: #000000">, </span>
								<span id="Codehighlighter1_842_884_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_842_884_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> don't stop any currently playingsound </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img id="Codehighlighter1_913_950_Open_Image" onclick="this.style.display='none'; Codehighlighter1_913_950_Open_Text.style.display='none'; Codehighlighter1_913_950_Closed_Image.style.display='inline'; Codehighlighter1_913_950_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_913_950_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_913_950_Closed_Text.style.display='none'; Codehighlighter1_913_950_Open_Image.style.display='inline'; Codehighlighter1_913_950_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_NOWAIT </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x00002000</span>
								<span style="COLOR: #000000">, </span>
								<span id="Codehighlighter1_913_950_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_913_950_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> don't wait if the driver is busy </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img id="Codehighlighter1_981_1003_Open_Image" onclick="this.style.display='none'; Codehighlighter1_981_1003_Open_Text.style.display='none'; Codehighlighter1_981_1003_Closed_Image.style.display='inline'; Codehighlighter1_981_1003_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_981_1003_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_981_1003_Closed_Text.style.display='none'; Codehighlighter1_981_1003_Open_Image.style.display='inline'; Codehighlighter1_981_1003_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_FILENAME </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x00020000</span>
								<span style="COLOR: #000000">, </span>
								<span id="Codehighlighter1_981_1003_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_981_1003_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> name is file name </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000">
										<br />
										<img id="Codehighlighter1_1033_1067_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1033_1067_Open_Text.style.display='none'; Codehighlighter1_1033_1067_Closed_Image.style.display='inline'; Codehighlighter1_1033_1067_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
										<img id="Codehighlighter1_1033_1067_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1033_1067_Closed_Text.style.display='none'; Codehighlighter1_1033_1067_Open_Image.style.display='inline'; Codehighlighter1_1033_1067_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        SND_RESOURCE </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0x00040004</span>
								<span style="COLOR: #000000"> </span>
								<span id="Codehighlighter1_1033_1067_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span>
								<span id="Codehighlighter1_1033_1067_Open_Text">
										<span style="COLOR: #008000">/*</span>
										<span style="COLOR: #008000"> name is resource name or atom </span>
										<span style="COLOR: #008000">*/</span>
								</span>
								<span style="COLOR: #000000"> <br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>特点就是简单小巧,只能在windows上用啊.<img src ="http://www.cppblog.com/mzty/aggbug/9490.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-07-06 16:40 <a href="http://www.cppblog.com/mzty/archive/2006/07/06/9490.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows API 技巧集</title><link>http://www.cppblog.com/mzty/archive/2006/01/25/3023.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Wed, 25 Jan 2006 08:19:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/01/25/3023.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/3023.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/01/25/3023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/3023.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/3023.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2006/01/25/3023.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/3023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-01-25 16:19 <a href="http://www.cppblog.com/mzty/archive/2006/01/25/3023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关机对话框</title><link>http://www.cppblog.com/mzty/archive/2006/01/14/2725.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Sat, 14 Jan 2006 02:03:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2006/01/14/2725.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/2725.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2006/01/14/2725.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/2725.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/2725.html</trackback:ping><description><![CDATA[&nbsp; 有一个未公开的API来实现这个功能，是在Shell32.dll中，但没有名字，索引号为60。下面是调用方法：&nbsp;<BR>&nbsp;&nbsp;
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">&nbsp;&nbsp;typedef&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;(CALLBACK&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">SHUTDOWNDLG)&nbsp;(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">);&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;CDlgDlg::OnOK()&nbsp;<BR><IMG id=Codehighlighter1_82_367_Open_Image onclick="this.style.display='none'; Codehighlighter1_82_367_Open_Text.style.display='none'; Codehighlighter1_82_367_Closed_Image.style.display='inline'; Codehighlighter1_82_367_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_82_367_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_82_367_Closed_Text.style.display='none'; Codehighlighter1_82_367_Open_Image.style.display='inline'; Codehighlighter1_82_367_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_82_367_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.cppblog.com/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_82_367_Open_Text><SPAN style="COLOR: #000000">{&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CString&nbsp;s;&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HINSTANCE&nbsp;hInst&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;LoadLibrary(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">shell32</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SHUTDOWNDLG&nbsp;SHShutDownDialog;&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(hInst&nbsp;</SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">)&nbsp;<BR><IMG id=Codehighlighter1_224_360_Open_Image onclick="this.style.display='none'; Codehighlighter1_224_360_Open_Text.style.display='none'; Codehighlighter1_224_360_Closed_Image.style.display='inline'; Codehighlighter1_224_360_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_224_360_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_224_360_Closed_Text.style.display='none'; Codehighlighter1_224_360_Open_Image.style.display='inline'; Codehighlighter1_224_360_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_224_360_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.cppblog.com/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_224_360_Open_Text><SPAN style="COLOR: #000000">{&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SHShutDownDialog&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;(SHUTDOWNDLG)GetProcAddress(hInst,&nbsp;(LPSTR)</SPAN><SPAN style="COLOR: #000000">60</SPAN><SPAN style="COLOR: #000000">);&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">SHShutDownDialog)(</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">);&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeLibrary(hInst);&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000">&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000">&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top></SPAN></DIV><img src ="http://www.cppblog.com/mzty/aggbug/2725.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2006-01-14 10:03 <a href="http://www.cppblog.com/mzty/archive/2006/01/14/2725.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows API函数大全---附：windows运行命令详解</title><link>http://www.cppblog.com/mzty/archive/2005/12/27/2180.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 27 Dec 2005 08:12:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2005/12/27/2180.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/2180.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2005/12/27/2180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/2180.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/2180.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2005/12/27/2180.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/2180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2005-12-27 16:12 <a href="http://www.cppblog.com/mzty/archive/2005/12/27/2180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>