<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/xsl/rss.xsl" type="text/xsl" media="screen"?>
<rss version="2.0" 
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:ppp="http://blog.sohu.com/rss/module/ppp/"
	>

	<channel>
		<title>LoogSon的博客</title>
		<link>http://ccnuliu.blog.sohu.com/</link>
		<description><![CDATA[LoogSon的博客]]></description>
		<pubDate>Sun, 6 Jan 2008 16:33:29 +0800</pubDate>
		<generator>搜狐博客</generator>
		<ppp:ebi>4197588792</ppp:ebi>
		<image>
			<title>http://blog.sohu.com</title>
			<url>http://js.pp.sohu.com/ppp/blog/images/common/logo_150_60.gif</url>
			<link>http://blog.sohu.com/</link>
			<width>100</width>
			<height>43</height>
			<description>搜狐博客</description>
		</image>
		<item>
			<title>那些逝去的青春</title>
			<link>http://ccnuliu.blog.sohu.com/75795823.html</link>
			<comments>http://ccnuliu.blog.sohu.com/75795823.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Sun, 6 Jan 2008 16:33:29 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/75795823.html</guid>
			<description><![CDATA[<p>写这篇文章的时候，我就想到了连载。</p>
<p>我一直很害怕忘记，害怕冷漠，更害怕不理睬。</p>
<p>但是，突然，却不知道从哪里说起。索性就想起一点写一点吧。慢慢挖掘，总是会把最美丽的事情都显现出来。</p>
<p>【 音乐厅 】 <br />晚上，下着小雨，特别是入夏的小雨，嘻嘻琳琳的，给人一种清新， <br />今夜的小雨似乎给晚上的演出增加诗意！ <br />第一次踏进音乐学院音乐厅，而且是享受钢琴和美声的熏陶~，似乎这就是第一次。 <br />要是搁平常，敲着锣打着鼓我才懒得去呢。人们常说，活着就有品味，有诗意。 <br />西方古代绅士喜欢用跳跳舞，听听古典高雅的音乐来以示自己的风雅。我却不以为然。 <br />他们去的很早，我晚去的。</p>
<p>远远的就看见音乐学院那座红房子，到达音乐学院门口的时候，有人接待，我顺手就拿了一份节目单。 <br />匆匆的走进演播厅，一眼就看到了他们，两个人坐在最后面。 <br />&quot;认识我吗，早就听说你大名啊，久仰久仰！&quot;一下子似乎就给我个下马威。 <br />&quot;哪里，哪里？&quot;赶紧回答到，算是寒暄吧.互通姓名之后，闲聊了几句。她莫不作声，只是在那里笑。一会，有人宣布演出开始。 晚上的表演------是三个即将毕业的女生，作为向恩师作最后告别的演出-----离别！ <br />我这才环视了一下四周，刚才似乎魂魄不属于我自己，这才附到我身体上。 <br />不小的演播厅尽然坐满了人。 <br />很优美的旋律，很精致的回音。心得熏陶，美的享受。 <br />尽管此行的目的不是为此，但是还是感受到了这种古典艺术的魅力！ <br />演出之间，学生哭了，老师也哭了........观众在那里看,似乎在笑。 <br />突然想到，大部分的人生其实我们都是在扮演这种角色，你在桥上看风景,看风景的人在楼上看你. <br />美好的时间总是过得如此之快，还没等我反应过来就有人宣布演出结束了。 <br />&ldquo;啊，结束了？&rdquo; <br />&ldquo;是啊，走啦！&rdquo; <br />出来的时候依然下着不要打伞的小雨，刚才的琴声已不在脑海中游荡， <br />现实就是这么残酷，似乎容不得任何梦想，非要把他摔得粉碎才肯罢休。 <br />&ldquo;很精彩啊，一种享受。你们认为表演者中谁最出色&rdquo; <br />&ldquo;那个长很高的人不错啊，人长得漂亮，歌唱的也好&rdquo; <br />&ldquo;呵呵，是吗？&rdquo;&nbsp;<br />....... <br />笑声在回荡在这夜空中回荡，刹的也就没了。<br />生活加上修饰就成了艺术！<img style="DISPLAY: none; POSITION: relative" src="http://imgcache.qq.com/qzone_v4/b.gif" /></p>
<p>每个人都是一个故事，都希望讲故事。生活中的小片段，整理修饰一下，就是一部完整的小说。</p>
<p>连载中...... </p>]]></description>
		</item>
		    
		
		<item>
			<title>计算机类部分期刊杂志投稿信息</title>
			<link>http://ccnuliu.blog.sohu.com/70593894.html</link>
			<comments>http://ccnuliu.blog.sohu.com/70593894.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Fri, 16 Nov 2007 08:26:14 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/70593894.html</guid>
			<description><![CDATA[<p align="left"><strong><span style="FONT-SIZE: 10pt; COLOR: red; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体; mso-bidi-font-size: 12.0pt"></span></strong><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">http://blog.csdn.net/image_graphics/archive/2007/06/09/1645845.aspx</span></p>]]></description>
		</item>
		    
		
		<item>
			<title>struct的巨大作用</title>
			<link>http://ccnuliu.blog.sohu.com/69004202.html</link>
			<comments>http://ccnuliu.blog.sohu.com/69004202.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Wed, 31 Oct 2007 18:03:20 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/69004202.html</guid>
			<description><![CDATA[<div align="left"><a>1. struct的巨大作用</a><br />　　在网络协议、通信控制、嵌入式系统的C/C++编程中，我们经常要传送的不是简单的字节流（char型数组），而是多种数据组合起来的一个整体，其表现形式是一个结构体。<br /></div>
<p align="left"><br />　　经验不足的开发人员往往将所有需要传送的内容依顺序保存在char型数组中，通过指针偏移的方法传送网络报文等信息。这样做编程复杂，易出错，而且一旦控制方式及通信协议有所变化，程序就要进行非常细致的修改。</p>
<div align="left"><br /></div>
<p align="left">　　一个有经验的开发者则灵活运用结构体，举一个例子，假设网络或控制协议中需要传送三种报文，其格式分别为packetA、packetB、packetC：</p>
<div align="left"><br /></div>
<p align="left">struct structA<br />{<br />int a;<br />char b;<br />};</p>
<div align="left"><br /></div>
<p align="left">struct structB<br />{<br />char a;<br />short b;<br />};</p>
<div align="left"><br /></div>
<p align="left">struct structC<br />{<br />int a;<br />char b;<br />float c;<br />}<br />　　优秀的程序设计者这样设计传送的报文：</p>
<div align="left"><br /></div>
<p align="left">struct CommuPacket<br />{<br />int iPacketType;　　//报文类型标志<br />union　　　　　　//每次传送的是三种报文中的一种，使用union<br />{<br />&nbsp; struct structA packetA;<br />&nbsp; struct structB packetB;<br />&nbsp; struct structC packetC;<br />}<br />};<br />　　在进行报文传送时，直接传送struct CommuPacket一个整体。</p>
<div align="left"><br /></div>
<p align="left">　　假设发送函数的原形如下：</p>
<div align="left"><br /></div>
<p align="left">// pSendData：发送字节流的首地址，iLen：要发送的长度<br />Send(char * pSendData, unsigned int&nbsp; iLen);<br />发送方可以直接进行如下调用发送struct CommuPacket的一个实例sendCommuPacket：<br />Send( (char *)&amp;sendCommuPacket , sizeof(CommuPacket) );<br />假设接收函数的原形如下：<br />// pRecvData：发送字节流的首地址，iLen：要接收的长度<br />//返回值：实际接收到的字节数<br />unsigned int Recv(char * pRecvData, unsigned int&nbsp; iLen)；<br />　　接收方可以直接进行如下调用将接收到的数据保存在struct CommuPacket的一个实例<br />recvCommuPacket中：</p>
<div align="left"><br /></div>
<p align="left">Recv( (char *)&amp;recvCommuPacket , sizeof(CommuPacket) );<br />　　接着判断报文类型进行相应处理：</p>
<div align="left"><br /></div>
<p align="left">switch(recvCommuPacket. iPacketType)<br />{<br />&nbsp;&nbsp;&nbsp; case PACKET_A:<br />&nbsp;&nbsp;&nbsp; &hellip;&nbsp;&nbsp;&nbsp; //A类报文处理<br />&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; case PACKET_B:<br />&nbsp;&nbsp;&nbsp; &hellip;　&nbsp; //B类报文处理<br />&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; case PACKET_C:<br />&nbsp;&nbsp;&nbsp; &hellip;&nbsp;&nbsp; //C类报文处理<br />&nbsp;&nbsp;&nbsp; break;<br />}<br />　　以上程序中最值得注意的是</p>
<div align="left"><br /></div>
<p align="left">Send( (char *)&amp;sendCommuPacket , sizeof(CommuPacket) );<br />Recv( (char *)&amp;recvCommuPacket , sizeof(CommuPacket) );<br />　　中的强制类型转换：(char *)&amp;sendCommuPacket、(char *)&amp;recvCommuPacket，先取地址，再转化为char型指针，这样就可以直接利用处理字节流的函数。</p>
<div align="left"><br /></div>
<p align="left">　　利用这种强制类型转化，我们还可以方便程序的编写，例如要对sendCommuPacket所处内存初始化为0，可以这样调用标准库函数memset()：</p>
<div align="left"><br /></div>
<p align="left">memset((char *)&amp;sendCommuPacket,0, sizeof(CommuPacket));</p>
<div align="left"><br /></div>
<p align="left">2. struct的成员对齐<br />　　Intel、微软等公司曾经出过一道类似的面试题：</p>
<div align="left"><br /></div>
<p align="left">1. ＃i nclude &lt;iostream.h&gt;</p>
<div align="left"><br /></div>
<p align="left">2. #pragma pack(8)<br />3. struct example1<br />4. {<br />5. short a;<br />6. long b;<br />7. };</p>
<div align="left"><br /></div>
<p align="left">8. struct example2<br />9. {<br />10. char c;<br />11. example1 struct1;<br />12. short e;&nbsp;&nbsp;&nbsp;<br />13. };<br />14. #pragma pack()</p>
<div align="left"><br /></div>
<p align="left">15. int main(int argc, char* argv[])<br />16. {<br />17. example2 struct2;</p>
<div align="left"><br /></div>
<p align="left">18. cout &lt;&lt; sizeof(example1) &lt;&lt; endl;<br />19. cout &lt;&lt; sizeof(example2) &lt;&lt; endl;<br />20. cout &lt;&lt; (unsigned int)(&amp;struct2.struct1) - (unsigned int)(&amp;struct2)<br />&lt;&lt; endl;</p>
<div align="left"><br /></div>
<p align="left">21. return 0;<br />22. }<br />　　问程序的输入结果是什么？</p>
<div align="left"><br /></div>
<p align="left">　　答案是：</p>
<div align="left"><br /></div>
<p align="left">8<br />16<br />4</p>
<div align="left"><br /></div>
<p align="left">　　不明白？还是不明白？下面一一道来：</p>
<div align="left"><br /></div>
<p align="left">2.1 自然对界</p>
<div align="left"><br /></div>
<p align="left">　　struct是一种复合数据类型，其构成元素既可以是基本数据类型（如int、long、float等）的变量，也可以是一些复合数据类型（如array、struct、union等）的数据单元。对于结构体，编译器会自动进行成员变量的对齐，以提高运算效率。缺省情况下，编译器为结构体的每个成员按其自然对界（natural alignment）条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储，第一个成员的地址和整个结构的地址相同。</p>
<div align="left"><br /></div>
<p align="left">　　自然对界(natural alignment)即默认对齐方式，是指按结构体的成员中size最大的成员对齐。</p>
<div align="left"><br /></div>
<p align="left">　　例如：</p>
<div align="left"><br /></div>
<p align="left">struct naturalalign<br />{<br />char a;<br />short b;<br />char c;<br />};<br />　　在上述结构体中，size最大的是short，其长度为2字节，因而结构体中的char成员a、c都以2为单位对齐，sizeof(naturalalign)的结果等于6；</p>
<div align="left"><br /></div>
<p align="left">　　如果改为：</p>
<div align="left"><br /></div>
<p align="left">struct naturalalign<br />{<br />char a;<br />int b;<br />char c;<br />};<br />　　其结果显然为12。</p>
<div align="left"><br /></div>
<p align="left">2.2指定对界</p>
<div align="left"><br /></div>
<p align="left">　　一般地，可以通过下面的方法来改变缺省的对界条件：</p>
<div align="left"><br /></div>
<p align="left">　　&middot; 使用伪指令#pragma pack (n)，编译器将按照n个字节对齐；<br />　　&middot; 使用伪指令#pragma pack ()，取消自定义字节对齐方式。</p>
<div align="left"><br /></div>
<p align="left">　　注意：如果#pragma pack (n)中指定的n大于结构体中最大成员的size，则其不起作用，结构体仍然按照size最大的成员进行对界。</p>
<div align="left"><br /></div>
<p align="left">　　例如：</p>
<div align="left"><br /></div>
<p align="left">#pragma pack (n)<br />struct naturalalign<br />{<br />char a;<br />int b;<br />char c;<br />};<br />#pragma pack ()<br />　　当n为4、8、16时，其对齐方式均一样，sizeof(naturalalign)的结果都等于12。而当n为2时，其发挥了作用，使得sizeof(naturalalign)的结果为8。</p>
<div align="left"><br /></div>
<p align="left">　　在VC++ 6.0编译器中，我们可以指定其对界方式，其操作方式为依次选择projetct &gt;setting &gt; C/C++菜单，在struct member alignment中指定你要的对界方式。</p>
<p align="left"><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" alt="" src="http://blog.21ic.com/uploadfile-/2006823104549222.gif" border="0" /></p>
<div align="left"><strong>&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; 图1：</strong><em>在VC++ 6.0中指定对界方式</em><br /></div>
<p align="left">　　另外，通过__attribute((aligned (n)))也可以让所作用的结构体成员对齐在n字节边界上，但是它较少被使用，因而不作详细讲解。</p>
<div align="left"><br /></div>
<p align="left">2.3 面试题的解答</p>
<div align="left"><br /></div>
<p align="left">　　至此，我们可以对Intel、微软的面试题进行全面的解答。</p>
<div align="left"><br /></div>
<p align="left">　　程序中第2行#pragma pack (8)虽然指定了对界为8，但是由于struct example1中的成员最大size为4（long变量size为4），故struct example1仍然按4字节对界，struct example1的size为8，即第18行的输出结果；</p>
<div align="left"><br /></div>
<p align="left">　　struct example2中包含了struct example1，其本身包含的简单数据成员的最大size为2（short变量e），但是因为其包含了struct example1，而struct example1中的最大成员size为4，struct example2也应以4对界，#pragma pack (8)中指定的对界对struct example2也不起作用，故19行的输出结果为16；</p>
<div align="left"><br /></div>
<p align="left">　　由于struct example2中的成员以4为单位对界，故其char变量c后应补充3个空，其后才是成员struct1的内存空间，20行的输出结果为4。</p>
<div align="left"><br /></div>
<p align="left"><br />3. C和C++间struct的深层区别<br />　　在C++语言中struct具有了&ldquo;类&rdquo;　的功能，其与关键字class的区别在于struct中成员变量和函数的默认访问权限为public，而class的为private。</p>
<div align="left"><br /></div>
<p align="left">　　例如，定义struct类和class类：</p>
<div align="left"><br /></div>
<p align="left">struct structA<br />{<br />char a;<br />&hellip;<br />}<br />class classB<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char a;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &hellip;<br />}<br />　　则：</p>
<div align="left"><br /></div>
<p align="left">struct A a;<br />a.a = 'a';&nbsp;&nbsp;&nbsp; //访问public成员，合法<br />classB b;<br />b.a = 'a';&nbsp;&nbsp;&nbsp; //访问private成员，不合法<br />　　许多文献写到这里就认为已经给出了C++中struct和class的全部区别，实则不然，另外一点需要注意的是：</p>
<div align="left"><br /></div>
<p align="left">　　C++中的struct保持了对C中struct的全面兼容（这符合C++的初衷&mdash;&mdash;&ldquo;a better c&rdquo;），因而，下面的操作是合法的：</p>
<div align="left"><br /></div>
<p align="left">//定义struct<br />struct structA<br />{<br />char a;<br />char b;<br />int c;<br />};<br />structA a = {'a' , 'a' ,1};&nbsp;&nbsp;&nbsp; //&nbsp; 定义时直接赋初值<br />　　即struct可以在定义的时候直接以{ }对其成员变量赋初值，而class则不能，在经典书目《thinking C++ 2nd edition》中作者对此点进行了强调。</p>
<div align="left"><br /></div>
<p align="left">4. struct编程注意事项<br />　　看看下面的程序：</p>
<div align="left"><br /></div>
<p align="left">1. ＃i nclude &lt;iostream.h&gt;</p>
<div align="left"><br /></div>
<p align="left">2. struct structA<br />3. {<br />4. int iMember;<br />5. char *cMember;<br />6. };</p>
<div align="left"><br /></div>
<p align="left">7. int main(int argc, char* argv[])<br />8. {<br />9. structA instant1,instant2;<br />10.char c = 'a';<br />&nbsp;&nbsp;&nbsp;<br />11. instant1.iMember = 1;<br />12. instant1.cMember = &amp;c;</p>
<div align="left"><br /></div>
<p align="left">13.instant2 = instant1;</p>
<div align="left"><br /></div>
<p align="left">14.cout &lt;&lt; *(instant1.cMember) &lt;&lt; endl;</p>
<div align="left"><br /></div>
<p align="left">15.*(instant2.cMember) = 'b';</p>
<div align="left"><br /></div>
<p align="left">16. cout &lt;&lt; *(instant1.cMember) &lt;&lt; endl;</p>
<div align="left"><br /></div>
<p align="left">17. return 0;<br />}<br />　　14行的输出结果是：a<br />　　16行的输出结果是：b</p>
<div align="left"><br /></div>
<p align="left">　　Why?我们在15行对instant2的修改改变了instant1中成员的值！</p>
<div align="left"><br /></div>
<p align="left">　　原因在于13行的instant2 = instant1赋值语句采用的是变量逐个拷贝，这使得instant1和instant2中的cMember指向了同一片内存，因而对instant2的修改也是对instant1的修改。</p>
<div align="left"><br /></div>
<p align="left">　　在C语言中，当结构体中存在指针型成员时，一定要注意在采用赋值语句时是否将2个实例中的指针型成员指向了同一片内存。</p>
<div align="left"><br /></div>
<p align="left">　　在C++语言中，当结构体中存在指针型成员时，我们需要重写struct的拷贝构造函数并进行&ldquo;=&rdquo;操作符重载。</p>]]></description>
		</item>
		    
		
		<item>
			<title>如何判断一个单向链表是否存在环路</title>
			<link>http://ccnuliu.blog.sohu.com/68989682.html</link>
			<comments>http://ccnuliu.blog.sohu.com/68989682.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Wed, 31 Oct 2007 15:41:07 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/68989682.html</guid>
			<description><![CDATA[<div>
<p><code><span style="COLOR: #000000">1.如何判断一个单向链表是否存在环路</span></code></p>
<p><code><span style="COLOR: #000000">struct node {</span></code></p>
<p><code><span style="COLOR: #000000">int data;</span></code></p>
<p><code><span style="COLOR: #000000">struct node * next;</span></code></p>
<p><code><span style="COLOR: #000000">};<br />&nbsp;</span></code></p></div>
<p>
<table style="BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" bgcolor="#f1f1f1" border="1">
<tbody>
<tr>
<td>
<p><code><span style="COLOR: #000000"><span style="COLOR: #0000ff">bool</span> check<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000ff">const</span> node<span style="COLOR: #0000cc">*</span> head<span style="COLOR: #0000cc">)</span><br /><span style="COLOR: #0000cc">{</span><br /><span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span>head<span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span><span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000ff">false</span><span style="COLOR: #0000cc">;</span><br />node <span style="COLOR: #0000cc">*</span>low<span style="COLOR: #0000cc">=</span>head<span style="COLOR: #0000cc">,</span> <span style="COLOR: #0000cc">*</span>fast<span style="COLOR: #0000cc">=</span>head<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>next<span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span>fast!=NULL <span style="COLOR: #0000cc">&amp;</span><span style="COLOR: #0000cc">&amp;</span> fast<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>next!=NULL<span style="COLOR: #0000cc">)</span><br /><span style="COLOR: #0000cc">{</span><br />low<span style="COLOR: #0000cc">=</span>low<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>next<span style="COLOR: #0000cc">;</span><br />fast<span style="COLOR: #0000cc">=</span>fast<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>next<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>next<span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span>low<span style="COLOR: #0000cc">=</span><span style="COLOR: #0000cc">=</span>fast<span style="COLOR: #0000cc">)</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000ff">true</span><span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000cc">}</span><br /><span style="COLOR: #0000ff">return</span> <span style="COLOR: #0000ff">false</span><span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000cc">}</span><br /><br /></span></code></p></td></tr></tbody></table></p>
<p>&nbsp;</p>
<p>为什么用1,2应该可以这么解释：设当两指针进入环后，走的快的离走的慢的m&gt;0步，而环中节点数为n,显然(n&gt;m)，再设两指针每次走的步数为a,b(不妨a&gt;b) <br />如果当再走k次可以重合，必然满足k*(a-b)&nbsp;=&nbsp;n*l&nbsp;+&nbsp;m&nbsp;(l&gt;=0)两边mod&nbsp;n&nbsp;右边为m,即1...n-1都有可能,则必须(a-b)与n要互质(当然a-b&nbsp;=&nbsp;1也满足)，只有互质，才能确保经过有限次k后， <br />k*(a-b)&nbsp;mod&nbsp;n&nbsp;可以遍历1，...，n-1.又考虑到链表移动跨度不易过大，因此a,b要尽量选小，2，1是最佳选择。 </p>
<p>2.如何找到这个环的开始节点</p>
<p>&nbsp;</p>
<p>
<table style="BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" bgcolor="#f1f1f1" border="1">
<tbody>
<tr>
<td>
<p><code><span style="COLOR: #000000">node <span style="COLOR: #0000cc">*</span> findnode<span style="COLOR: #0000cc">(</span><span style="COLOR: #0000ff">const</span> node <span style="COLOR: #0000cc">*</span> head<span style="COLOR: #0000cc">)</span><br /><span style="COLOR: #0000cc">{</span><br /><span style="COLOR: #0000ff">if</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">!</span>check<span style="COLOR: #0000cc">(</span>head<span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">)</span> ruturn <span style="COLOR: #ff0000">NULL</span><span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000ff">else</span><br /><span style="COLOR: #0000ff">do</span><span style="COLOR: #0000cc">{</span><br />lasthead <span style="COLOR: #0000cc">=</span> head<span style="COLOR: #0000cc">;</span><br />head <span style="COLOR: #0000cc">=</span> head<span style="COLOR: #0000cc">-</span><span style="COLOR: #0000cc">&gt;</span>next<span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000cc">}</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #0000cc">(</span><span style="COLOR: #0000cc">!</span>check<span style="COLOR: #0000cc">(</span>head<span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">)</span><span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000ff">return</span> lasthead<span style="COLOR: #0000cc">;</span><br /><span style="COLOR: #0000cc">}</span><br /></span></code></p></td></tr></tbody></table></p>]]></description>
		</item>
		    
		
		<item>
			<title>匈牙利命名法</title>
			<link>http://ccnuliu.blog.sohu.com/64916009.html</link>
			<comments>http://ccnuliu.blog.sohu.com/64916009.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Sun, 23 Sep 2007 19:32:02 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/64916009.html</guid>
			<description><![CDATA[<p><strong>匈牙利命名法</strong><br /><font size="2"></font></p>
<p>匈牙利命名法是一种编程时的命名规范。基本原则是：变量名＝属性＋类型＋对象描述，其中每一对象的名称都要求有明确含义，可以取对象名字全称或名字的一部分。命名要基于容易记忆容易理解的原则。保证名字的连贯性是非常重要的。　　 </p>
<p>举例来说，表单的名称为form，那么在匈牙利命名法中可以简写为frm，则当表单变量名称为Switchboard时，变量全称应该为frmSwitchboard。这样可以很容易从变量名看出Switchboard是一个表单，同样，如果此变量类型为标签，那么就应命名成lblSwitchboard。可以看出，匈牙利命名法非常便于记忆，而且使变量名非常清晰易懂，这样，增强了代码的可读性，方便各程序员之间相互交流代码。　　 </p>
<p>这种命名技术是由一位能干的Microsoft程序员查尔斯&middot;西蒙尼(Charles Simonyi) 提出的，他出生在匈牙利。在 Microsoft 公司中和他一起工作的人被教会使用这种约定。这对他们来说一切都很正常。但对那些 Simonyi 领导的项目组之外的人来说却感到很奇特，他们认为这是死板的表达方式，甚至说带有这样奇怪的外观是因为它是用匈牙利文写的。从此这种命名方式就被叫做匈牙利命名法。 <br /><br />据说这种命名法是一位叫 Charles Simonyi 的匈牙利程序员发明的，后来他在微软呆了几年，于是 <br />这种命名法就通过微软的各种产品和文档资料向世界传播开了。现在，大部分程序员不管自己使用 <br />什么软件进行开发，或多或少都使用了这种命名法。这种命名法的出发点是把量名变按：属性+类型 <br />+对象 描述的顺序组合起来，以使程序员作变量时对变量的类型和其它属性有直观的了解，下面 <br />是HN变量命名规范，其中也有一些是我个人的偏向： <br /><br />属性部分 <br />全局变量 <br />g_ <br />常量 <br />c_ <br />c++类成员变量 <br />m_ <br />静态变量 <br />s_ <br /><br />类型部分 <br />指针 <br />p <br />函数 <br />fn <br />无效 <br />v <br />句柄 <br />h <br />长整型 <br />l <br />布尔 <br />b <br />浮点型（有时也指文件） <br />f <br />双字 <br />dw <br />字符串 <br />sz <br />短整型 <br />n <br />双精度浮点 <br />d <br />计数 <br />c（通常用cnt） <br />字符 <br />ch（通常用c） <br />整型 <br />i（通常用n） <br />字节 <br />by <br />字 <br />w <br />实型 <br />r <br />无符号 <br />u <br /><br />描述部分 <br />最大 <br />Max <br />最小 <br />Min <br />初始化 <br />Init <br />临时变量 <br />T（或Temp） <br />源对象 <br />Src <br />目的对象 <br />Dest <br /><br /><br /><br />这里顺便写几个例子： <br />hwnd ： h 是类型描述，表示句柄， wnd 是变量对象描述，表示窗口，所以 hwnd 表示窗口句柄； <br />pfnEatApple ： pfn 是类型描述，表示指向函数的指针， EatApple 是变量对象描述，所以它表示 <br />指向 EatApple 函数的函数指针变量。 <br />g_cch ： g_ 是属性描述，表示全局变量，c 和 ch 分别是计数类型和字符类型，一起表示变量类 <br />型，这里忽略了对象描述，所以它表示一个对字符进行计数的全局变量。 <br />上面就是HN命名法的一般规则。 <br /><br /><br />小结:匈牙利命名法 </p>
<p align="center"><font face="宋体" size="7"><strong>匈牙利命名法</strong></font></p>
<p align="center"><br /><font face="宋体"><strong>MFC、句柄、控件及结构的命名规范</strong></font> 
<table style="557px: " border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>Windows类型</strong></font></td>
<td><font face="宋体" size="2"><strong>样本变量</strong></font></td>
<td><font face="宋体" size="2"><strong>MFC类</strong></font></td>
<td><font face="宋体" size="2"><strong>样本变量</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HWND</strong></font></td>
<td><font face="宋体" size="2">hWnd；</font></td>
<td><font face="宋体" size="2"><strong>CWnd*</strong></font></td>
<td><font face="宋体" size="2">pWnd；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HDLG</strong></font></td>
<td><font face="宋体" size="2">hDlg；</font></td>
<td><font face="宋体" size="2"><strong>CDialog*</strong></font></td>
<td><font face="宋体" size="2">pDlg；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HDC</strong></font></td>
<td><font face="宋体" size="2">hDC；</font></td>
<td><font face="宋体" size="2"><strong>CDC*</strong></font></td>
<td><font face="宋体" size="2">pDC；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HGDIOBJ</strong></font></td>
<td><font face="宋体" size="2">hGdiObj；</font></td>
<td><font face="宋体" size="2"><strong>CGdiObject*</strong></font></td>
<td><font face="宋体" size="2">pGdiObj；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HPEN</strong></font></td>
<td><font face="宋体" size="2">hPen；</font></td>
<td><font face="宋体" size="2"><strong>CPen*</strong></font></td>
<td><font face="宋体" size="2">pPen；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HBRUSH</strong></font></td>
<td><font face="宋体" size="2">hBrush；</font></td>
<td><font face="宋体" size="2"><strong>CBrush*</strong></font></td>
<td><font face="宋体" size="2">pBrush；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HFONT </strong></font></td>
<td><font face="宋体" size="2">hFont； </font></td>
<td><font face="宋体" size="2"><strong>CFont*</strong></font></td>
<td><font face="宋体" size="2">pFont；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HBITMAP </strong></font></td>
<td><font face="宋体" size="2">hBitmap；</font></td>
<td><font face="宋体" size="2"><strong>CBitmap*</strong></font></td>
<td><font face="宋体" size="2">pBitmap；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HPALETTE </strong></font></td>
<td><font face="宋体" size="2">hPaltte；</font></td>
<td><font face="宋体" size="2"><strong>CPalette*</strong></font></td>
<td><font face="宋体" size="2">pPalette；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HRGN </strong></font></td>
<td><font face="宋体" size="2">hRgn；</font></td>
<td><font face="宋体" size="2"><strong>CRgn*</strong></font></td>
<td><font face="宋体" size="2">pRgn；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HMENU </strong></font></td>
<td><font face="宋体" size="2">hMenu；</font></td>
<td><font face="宋体" size="2"><strong>CMenu*</strong></font></td>
<td><font face="宋体" size="2">pMenu；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HWND </strong></font></td>
<td><font face="宋体" size="2">hCtl；</font></td>
<td><font face="宋体" size="2"><strong>CState* </strong></font></td>
<td><font face="宋体" size="2">pState；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HWND </strong></font></td>
<td><font face="宋体" size="2">hCtl；</font></td>
<td><font face="宋体" size="2"><strong>CButton*</strong></font></td>
<td><font face="宋体" size="2">pButton；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HWND </strong></font></td>
<td><font face="宋体" size="2">hCtl；</font></td>
<td><font face="宋体" size="2"><strong>CEdit*</strong></font></td>
<td><font face="宋体" size="2">pEdit；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HWND </strong></font></td>
<td><font face="宋体" size="2">hCtl；</font></td>
<td><font face="宋体" size="2"><strong>CListBox*</strong></font></td>
<td><font face="宋体" size="2">pListBox；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HWND </strong></font></td>
<td><font face="宋体" size="2">hCtl；</font></td>
<td><font face="宋体" size="2"><strong>CComboBox*</strong></font></td>
<td><font face="宋体" size="2">pComboBox；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HWND </strong></font></td>
<td><font face="宋体" size="2">hCtl；</font></td>
<td><font face="宋体" size="2"><strong>CScrollBar*</strong></font></td>
<td><font face="宋体" size="2">pScrollBar；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HSZ </strong></font></td>
<td><font face="宋体" size="2">hszStr；</font></td>
<td><font face="宋体" size="2"><strong>CString </strong></font></td>
<td><font face="宋体" size="2">pStr；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>POINT </strong></font></td>
<td><font face="宋体" size="2">pt；</font></td>
<td><font face="宋体" size="2"><strong>CPoint </strong></font></td>
<td><font face="宋体" size="2">pt；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>SIZE </strong></font></td>
<td><font face="宋体" size="2">size；</font></td>
<td><font face="宋体" size="2"><strong>CSize </strong></font></td>
<td><font face="宋体" size="2">size；</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>RECT </strong></font></td>
<td><font face="宋体" size="2">rect；</font></td>
<td><font face="宋体" size="2"><strong>CRect </strong></font></td>
<td><font face="宋体" size="2">rect；</font></td></tr></tbody></table></p>
<p align="center"><strong><font face="宋体">一般前缀命名规范</font></strong> 
<table style="78px: " border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>前缀</strong></font></td>
<td><font face="宋体" size="2"><strong>类型</strong></font></td>
<td><font face="宋体" size="2"><strong>实例</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>C</strong></font></td>
<td><font face="宋体" size="2">类或结构</font></td>
<td><font face="宋体" size="2">CDocument，CPrintInfo</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>m_</strong></font></td>
<td><font face="宋体" size="2">成员变量</font></td>
<td><font face="宋体" size="2">m_pDoc，m_nCustomers</font></td></tr></tbody></table></p>
<p align="center"><strong><font face="宋体">变量命名规范</font></strong><strong> 
<table border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>前缀</strong></font></td>
<td><font face="宋体" size="2"><strong>类型</strong></font></td>
<td><font face="宋体" size="2"><strong>描述</strong></font></td>
<td><font face="宋体" size="2"><strong>实例</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>ch</strong></font></td>
<td><font face="宋体" size="2">char</font></td>
<td><font face="宋体" size="2">8位字符</font></td>
<td><font face="宋体" size="2">chGrade</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>ch </strong></font></td>
<td><font face="宋体" size="2">TCHAR</font></td>
<td><font face="宋体" size="2">如果<strong>_UNICODE</strong>定义，则为16位字符</font></td>
<td><font face="宋体" size="2">chName</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>b</strong></font></td>
<td><font face="宋体" size="2">BOOL</font></td>
<td><font face="宋体" size="2">布尔值</font></td>
<td><font face="宋体" size="2">bEnable</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>n </strong></font></td>
<td><font face="宋体" size="2">int</font></td>
<td><font face="宋体" size="2">整型（其大小依赖于操作系统）</font></td>
<td><font face="宋体" size="2">nLength</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>n </strong></font></td>
<td><font face="宋体" size="2">UINT </font></td>
<td><font face="宋体" size="2">无符号值（其大小依赖于操作系统）</font></td>
<td><font face="宋体" size="2">nHeight</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>w </strong></font></td>
<td><font face="宋体" size="2">WORD </font></td>
<td><font face="宋体" size="2">16位无符号值</font></td>
<td><font face="宋体" size="2">wPos</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>l </strong></font></td>
<td><font face="宋体" size="2">LONG </font></td>
<td><font face="宋体" size="2">32位有符号整型</font></td>
<td><font face="宋体" size="2">lOffset</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>dw </strong></font></td>
<td><font face="宋体" size="2">DWORD </font></td>
<td><font face="宋体" size="2">32位无符号整型 </font></td>
<td><font face="宋体" size="2">dwRange</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>p </strong></font></td>
<td><font face="宋体" size="2">* </font></td>
<td><font face="宋体" size="2">指针</font></td>
<td><font face="宋体" size="2">pDoc</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>lp </strong></font></td>
<td><font face="宋体" size="2">FAR* </font></td>
<td><font face="宋体" size="2">远指针 </font></td>
<td><font face="宋体" size="2">lpszName</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>lpsz </strong></font></td>
<td><font face="宋体" size="2">LPSTR </font></td>
<td><font face="宋体" size="2">32位字符串指针</font></td>
<td><font face="宋体" size="2">lpszName</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>lpsz </strong></font></td>
<td><font face="宋体" size="2">LPCSTR </font></td>
<td><font face="宋体" size="2">32位常量字符串指针</font></td>
<td><font face="宋体" size="2">lpszName</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>lpsz </strong></font></td>
<td><font face="宋体" size="2">LPCTSTR </font></td>
<td><font face="宋体" size="2">如果<strong>_UNICODE</strong>定义，则为32位常量字符串指针</font></td>
<td><font face="宋体" size="2">lpszName</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>h </strong></font></td>
<td><font face="宋体" size="2">handle </font></td>
<td><font face="宋体" size="2">Windows对象句柄</font></td>
<td><font face="宋体" size="2">hWnd</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>lpfn </strong></font></td>
<td><font face="宋体" size="2">callback</font></td>
<td><font face="宋体" size="2">指向<strong>CALLBACK</strong>函数的远指针 </font></td>
<td></td></tr></tbody></table></strong></p>
<p align="center"><font size="2"></font>
<table border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>前缀</strong></font></td>
<td><font face="宋体" size="2"><strong>符号类型</strong></font></td>
<td><font face="宋体" size="2"><strong>实例</strong></font></td>
<td><font face="宋体" size="2"><strong>范围</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDR_ </strong></font></td>
<td><font face="宋体" size="2">不同类型的多个资源共享标识</font></td>
<td><font face="宋体" size="2">IDR_MAIINFRAME</font></td>
<td><font face="宋体" size="2">1～0x6FFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDD_</strong></font></td>
<td><font face="宋体" size="2">对话框资源</font></td>
<td><font face="宋体" size="2">IDD_SPELL_CHECK </font></td>
<td><font face="宋体" size="2">1～0x6FFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HIDD_</strong></font></td>
<td><font face="宋体" size="2">对话框资源的Help上下文</font></td>
<td><font face="宋体" size="2">HIDD_SPELL_CHECK </font></td>
<td><font face="宋体" size="2">0x20001～0x26FF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDB_ </strong></font></td>
<td><font face="宋体" size="2">位图资源</font></td>
<td><font face="宋体" size="2">IDB_COMPANY_LOGO </font></td>
<td><font face="宋体" size="2">1～0x6FFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDC_</strong></font></td>
<td><font face="宋体" size="2">光标资源</font></td>
<td><font face="宋体" size="2">IDC_PENCIL </font></td>
<td><font face="宋体" size="2">1～0x6FFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDI_</strong></font></td>
<td><font face="宋体" size="2">图标资源</font></td>
<td><font face="宋体" size="2">IDI_NOTEPAD </font></td>
<td><font face="宋体" size="2">1～0x6FFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>ID_</strong></font></td>
<td><font face="宋体" size="2">来自菜单项或工具栏的命令</font></td>
<td><font face="宋体" size="2">ID_TOOLS_SPELLING </font></td>
<td><font face="宋体" size="2">0x8000～0xDFFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HID_</strong></font></td>
<td><font face="宋体" size="2">命令Help上下文</font></td>
<td><font face="宋体" size="2">HID_TOOLS_SPELLING </font></td>
<td><font face="宋体" size="2">0x18000～0x1DFFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDP_</strong></font></td>
<td><font face="宋体" size="2">消息框提示</font></td>
<td><font face="宋体" size="2">IDP_INVALID_PARTNO </font></td>
<td><font face="宋体" size="2">8～0xDEEF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>HIDP_</strong></font></td>
<td><font face="宋体" size="2">消息框Help上下文</font></td>
<td><font face="宋体" size="2">HIDP_INVALID_PARTNO </font></td>
<td><font face="宋体" size="2">0x30008～0x3DEFF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDS_</strong></font></td>
<td><font face="宋体" size="2">串资源</font></td>
<td><font face="宋体" size="2">IDS_COPYRIGHT </font></td>
<td><font face="宋体" size="2">1～0x7EEF</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>IDC_</strong></font></td>
<td><font face="宋体" size="2">对话框内的控件</font></td>
<td><font face="宋体" size="2">IDC_RECALC </font></td>
<td><font face="宋体" size="2">8～0xDEEF</font></td></tr></tbody></table></p>
<p align="center"><font face="宋体"><strong>Microsoft MFC宏命名规范</strong></font> 
<table style="203px: " border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>名称</strong></font></td>
<td><font face="宋体" size="2"><strong>类型</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>_AFXDLL</strong></font></td>
<td><font face="宋体" size="2">唯一的动态连接库（Dynamic Link Library，DLL）版本</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>_ALPHA</strong></font></td>
<td><font face="宋体" size="2">仅编译DEC Alpha处理器</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>_DEBUG</strong></font></td>
<td><font face="宋体" size="2">包括诊断的调试版本</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>_MBCS</strong></font></td>
<td><font face="宋体" size="2">编译多字节字符集</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>_UNICODE</strong></font></td>
<td><font face="宋体" size="2">在一个应用程序中打开Unicode</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>AFXAPI </strong></font></td>
<td><font face="宋体" size="2">MFC提供的函数</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>CALLBACK</strong></font></td>
<td><font face="宋体" size="2">通过指针回调的函数 </font></td></tr></tbody></table></p>
<p align="center"><font face="宋体"><strong>库标识符命名法</strong></font> 
<table style="78px: " border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>标识符</strong></font></td>
<td><font face="宋体" size="2"><strong>值和含义</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>u </strong></font></td>
<td><font face="宋体" size="2">ANSI（N）或Unicode（U）</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>d </strong></font></td>
<td><font face="宋体" size="2">调试或发行：D = 调试；忽略标识符为发行。</font></td></tr></tbody></table></p>
<p align="center"><strong><font face="宋体">静态库版本命名规范</font></strong> 
<table style="147px: " border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>库</strong></font></td>
<td><font face="宋体" size="2"><strong>描述</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>NAFXCWD.LIB</strong></font></td>
<td><font face="宋体" size="2">调试版本：MFC静态连接库</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>NAFXCW.LIB</strong></font></td>
<td><font face="宋体" size="2">发行版本：MFC静态连接库</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>UAFXCWD.LIB</strong></font></td>
<td><font face="宋体" size="2">调试版本：具有Unicode支持的MFC静态连接库</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>UAFXCW.LIB</strong></font></td>
<td><font face="宋体" size="2">发行版本：具有Unicode支持的MFC静态连接库</font></td></tr></tbody></table></p>
<p align="center"><font face="宋体"><strong>动态连接库命名规范</strong></font> 
<table style="97px: " border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>名称</strong></font></td>
<td><font face="宋体" size="2"><strong>类型</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>_AFXDLL</strong></font></td>
<td><font face="宋体" size="2">唯一的动态连接库（DLL）版本</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>WINAPI </strong></font></td>
<td><font face="宋体" size="2">Windows所提供的函数</font></td></tr></tbody></table></p>
<p align="center"><font face="宋体"><strong>Windows.h中新的命名规范</strong></font> 
<table border="1">
<tbody>
<tr>
<td><font face="宋体" size="2"><strong>类型</strong></font></td>
<td><font face="宋体" size="2"><strong>定义描述</strong></font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>WINAPI</strong></font></td>
<td><font face="宋体" size="2">使用在API声明中的FAR PASCAL位置，如果正在编写一个具有导出API人口点的DLL，则可以在自己的API中使用该类型</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>CALLBACK</strong></font></td>
<td><font face="宋体" size="2">使用在应用程序回叫例程，如窗口和对话框过程中的FAR PASCAL的位置</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>LPCSTR</strong></font></td>
<td><font face="宋体" size="2">与LPSTR相同，只是LPCSTR用于只读串指针，其定义类似（const char FAR*）</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>UINT</strong></font></td>
<td><font face="宋体" size="2">可移植的无符号整型类型，其大小由主机环境决定（对于Windows NT和Windows 9x为32位）；它是unsigned int的同义词</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>LRESULT</strong></font></td>
<td><font face="宋体" size="2">窗口程序返回值的类型</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>LPARAM</strong></font></td>
<td><font face="宋体" size="2">声明lParam所使用的类型，lParam是窗口程序的第四个参数</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>WPARAM</strong></font></td>
<td><font face="宋体" size="2">声明wParam所使用的类型，wParam是窗口程序的第三个参数</font></td></tr>
<tr>
<td><font face="宋体" size="2"><strong>LPVOID</strong></font></td>
<td><font face="宋体" size="2">一般指针类型，与（void *）相同，可以用来代替LPSTR </font></td></tr></tbody></table></p>]]></description>
		</item>
		    
		
		<item>
			<title>MFC框架各部分指针获取方式</title>
			<link>http://ccnuliu.blog.sohu.com/61351130.html</link>
			<comments>http://ccnuliu.blog.sohu.com/61351130.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Sun, 26 Aug 2007 11:20:19 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/61351130.html</guid>
			<description><![CDATA[<table cellspacing="0" cellpadding="3" border="1">
<tbody>
<tr>
<td style="FONT-SIZE: 10pt">
<p align="center">&nbsp;</p></td>
<td style="FONT-SIZE: 10pt">
<p align="center"><strong>获得CWinApp </strong></p></td>
<td style="FONT-SIZE: 10pt">
<p align="center"><strong>获得CMainFrame </strong></p></td>
<td style="FONT-SIZE: 10pt">
<p align="center"><strong>获得CChildFrame </strong></p></td>
<td style="FONT-SIZE: 10pt">
<p align="center"><strong>获得CDocument </strong></p></td>
<td style="FONT-SIZE: 10pt">
<p align="center"><strong>获得CView</strong> </p></td></tr>
<tr>
<td style="FONT-SIZE: 10pt"><strong>在CWinApp中</strong> </td>
<td style="FONT-SIZE: 10pt">
<p>&nbsp;</p></td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetMainWnd() </p>
<p>m_pMainWnd </p></td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetMainWnd()-&gt;MDIGetActive() </p>
<p>AfxGetMainWnd()-&gt;GetActiveFrame()</p></td>
<td style="FONT-SIZE: 10pt">
<p>SDI:AfxGetMainWnd()-&gt;GetActiveView()-&gt;GetDocument()</p>
<p>MDI:AfxGetMainWnd()-&gt;MDIGetActive()-&gt;GetActiveView()-&gt;GetDocument()</p></td>
<td style="FONT-SIZE: 10pt">SDI:AfxGetMainWnd()-&gt;GetActiveView()&nbsp;&nbsp;<br />MDI:AfxGetMainWnd()-&gt;MDIGetActive()-&gt;GetActiveView()&nbsp;</td></tr>
<tr>
<td style="FONT-SIZE: 10pt"><strong>在CMainFrame中</strong> </td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetApp() </p>
<p>theApp </p></td>
<td style="FONT-SIZE: 10pt"></td>
<td style="FONT-SIZE: 10pt">
<p>MDIGetActive() </p>
<p>GetActiveFrame()</p></td>
<td style="FONT-SIZE: 10pt">SDI:GetActiveView()-&gt;GetDocument()&nbsp;&nbsp;<br />MDI:MDIGetActive()-&gt;GetActiveView()-&gt;GetDocument()&nbsp;&nbsp;</td>
<td style="FONT-SIZE: 10pt">SDI:GetActiveView()&nbsp;&nbsp;<br />MDI:MDIGetActive()-&gt;GetActiveView()&nbsp;</td></tr>
<tr>
<td style="FONT-SIZE: 10pt"><strong>在CChildFrame中</strong> </td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetApp() </p>
<p>theApp </p></td>
<td style="FONT-SIZE: 10pt">GetParentFrame()&nbsp; </td>
<td style="FONT-SIZE: 10pt">
<p>&nbsp;</p></td>
<td style="FONT-SIZE: 10pt">GetActiveView()-&gt;GetDocument()&nbsp;&nbsp;</td>
<td style="FONT-SIZE: 10pt">GetActiveView()</td></tr>
<tr>
<td style="FONT-SIZE: 10pt"><strong>在CDocument中</strong> </td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetApp() </p>
<p>theApp </p></td>
<td style="FONT-SIZE: 10pt">AfxGetMainWnd()&nbsp;&nbsp; </td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetMainWnd()-&gt;MDIGetActive() </p>
<p>AfxGetMainWnd()-&gt;GetActiveFrame()</p></td>
<td style="FONT-SIZE: 10pt"></td>
<td style="FONT-SIZE: 10pt">POSITION&nbsp;&nbsp; pos&nbsp;&nbsp; =&nbsp;&nbsp; GetFirstViewPosition();GetNextView(pos)&nbsp;&nbsp;</td></tr>
<tr>
<td style="FONT-SIZE: 10pt"><strong>在CView中</strong> </td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetApp() </p>
<p>theApp </p></td>
<td style="FONT-SIZE: 10pt">AfxGetMainWnd()&nbsp;&nbsp; </td>
<td style="FONT-SIZE: 10pt">GetParentFrame()&nbsp;&nbsp; </td>
<td style="FONT-SIZE: 10pt">GetDocument()</td>
<td style="FONT-SIZE: 10pt"></td></tr>
<tr>
<td style="FONT-SIZE: 10pt"><strong>在其他类中</strong> </td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetApp() </p></td>
<td style="FONT-SIZE: 10pt">AfxGetMainWnd()&nbsp;&nbsp; </td>
<td style="FONT-SIZE: 10pt">
<p>AfxGetMainWnd()-&gt;MDIGetActive() </p>
<p>AfxGetMainWnd()-&gt;GetActiveFrame()&nbsp;</p></td>
<td style="FONT-SIZE: 10pt">
<p>SDI:AfxGetMainWnd()-&gt;GetActiveView()-&gt;GetDocument()</p>
<p>MDI:AfxGetMainWnd()-&gt;MDIGetActive()-&gt;GetActiveView()-&gt;GetDocument()</p></td>
<td style="FONT-SIZE: 10pt">SDI:AfxGetMainWnd()-&gt;GetActiveView()&nbsp;&nbsp;<br />MDI:AfxGetMainWnd()-&gt;MDIGetActive()-&gt;GetActiveView()&nbsp;</td></tr></tbody></table>]]></description>
		</item>
		    
		
		<item>
			<title>Windows 中不规则窗体的编程实现</title>
			<link>http://ccnuliu.blog.sohu.com/61312945.html</link>
			<comments>http://ccnuliu.blog.sohu.com/61312945.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Sat, 25 Aug 2007 23:15:47 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/61312945.html</guid>
			<description><![CDATA[、序言 <br /><br />　　在绝大多数的Windows应用程序中，其窗体都是使用的正规正矩的矩形窗体,例如我们常用的，&ldquo;记事本&rdquo;，&ldquo;扫雷&rdquo;，等等。矩形窗体，具有编程实现简单，风格简洁的优点，所以在普通文档应用程序和简单小游戏中使用足矣。但在某些娱乐游戏程序中使用就略显呆板些了，这时若用不规则窗体替代原先的矩形窗体，将会使这类程序更添情趣。典型的例子有windows 自代的Media Player,新版本的Media Player有个控制面板的选项，选中这些面板，播放器就以选中的面板形状出现，这时的播放器比以前版本的Media Player的古老矩形界面要生动有趣的多了。 要实现不规则窗体不是太难，知道了基本原理后，你也可以创建各种有趣的不规则窗体。<br /><br />　　<b>二、实现原理</b><br /><br />　　所有的 Windows 窗体都位于一个称为&ldquo;region&rdquo;中，窗体的大小如果超出&ldquo;region&rdquo;的范围，windows 会自动裁剪超出&quot;region&quot;范围那部分的窗体，使其不可见。所以，要创建不规则窗体有两个步骤：第一步就是创建不规则&quot;region&quot;.第二步就是将窗体放到创建的&ldquo;region&rdquo;中。<br /><br />　　其中第二步很简单就调用一条语句即可。在SDK中调用API函数SetWindowRgn，该函数原型如下：<br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>int SetWindowRgn( HWND hWnd, HRGN hRgn, BOOL bRedraw );</td></tr></tbody></table><br />　　其中hWnd为待设置的窗体句柄，hRgn为已经创建的&quot;region&quot;句柄，bRedraw代表是否要重绘窗体。在MFC 中使用窗口类CWnd的成员函数int CWnd::SetWindowRgn（HRGN hRgn, BOOL bRedraw );该函数的参数意义与API中同名函数相同。<br /><br />　　相对与第二步，创建不规则窗体的第一步要复杂许多，并且不规则窗体越复杂，创建其&quot;region&quot;的过程也越复杂。接下去我们将由浅入深地介绍各种创建&rdquo;region&rdquo;的方法。<br /><br />　　在MFC中&quot;region&quot;对象，由CRgn类实现。CRgn的几乎每个成员函数都有同名的SDK API函数对应。<br /><br />　　<b>三、简单&ldquo;region&rdquo;的创建</b><br /><br />　　类CRgn创建一个新的&quot;region&quot;的简单方法有以下几个成员函数： BOOL CRgn::CreateRectRgn( int x1, int y1, int x2, int y2 ); 创建矩形的&ldquo;region&rdquo;。 <br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>BOOL CRgn::CreateEllipticRgn( int x1, int y1, int x2, int y2 ); 创建圆形或椭圆形&ldquo;region&rdquo;。 <br />BOOL CRgn::CreateRoundRectRgn( int x1, int y1, int x2, int y2, int x3, int y3 ); 创建圆角矩形&ldquo;region&rdquo;。 <br />BOOL CRgn::CreatePolygonRgn( LPPOINT lpPoints, int nCount, int nMode ); 创建多边形&ldquo;region&rdquo;。 </td></tr></tbody></table><br />　　这里以创建椭圆窗体为例，介绍椭圆窗体创建的方法。在创建椭圆&ldquo;region&rdquo;的CreateEllipticRgn函数中，x1,y1指椭圆所在矩形的左上角坐标，x2,y2指该矩形的右下角坐标。<br /><br />　　下面的代码加入到MFC对话框程序的OnInitDialog函数中，可将该对话框变成椭圆窗体：<br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>BOOL CTestDlg::OnInitDialog()<br />{<br />CDialog::OnInitDialog();<br />...<br />CRgn rgn;<br />rgn. CreateEllipticRgn(0,0,200,100);<br />SetWindowRgn(rgn,TRUE);<br />}</td></tr></tbody></table><br />
<table align="center" border="0">
<tbody>
<tr>
<td>
<div align="center"><img src="http://www.yesky.com/image20010518/225485.gif" border="1" /><br />图一 椭圆窗体效果图</div></td></tr></tbody></table><br />　　<b>四、作图路径法创建&rdquo;region&rdquo;</b><br /><br />　　使用该方法创建&rdquo;region&rdquo;的过程如下：<br /><br />　　第一步绘制所要创建的窗体形状。<br />　 <br />　　该步骤中使用到CDC类中的一些成员函数如下：BOOL CDC::BeginPath( );<br /><br />　　调用该函数后当前设备环境(DC)开始追踪绘图的过程。<br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>int CDC::SetBkMode( int nBkMode );</td></tr></tbody></table><br />　　设置绘图时的背景模式，此应用中nBkMode必须取值为TRANSPARENT 。即设置绘图时背景不发生变化。<br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>BOOL CDC::EndPath( );</td></tr></tbody></table><br />　　调用该函数后当前设备环境(DC)结束追踪绘图的过程。<br /><br />　　开始绘图前，先调用BeginPath，然后调用SetBkMode。接下去就可调用CDC的其他绘图函数作图，例如Arc,AngleArc,LineTo,MoveTo,RoundRect,,Textout等等。绘图完毕调用EndPath().<br /><br />　　第二步将绘制的结果转成&rdquo;region&rdquo;.<br /><br />　　此步骤中使用SDK API函数<br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>HRGN PathToRegion( HDC hdc );</td></tr></tbody></table><br />　　Hdc为作图DC的句柄， CDC类中的m_hDC成员变量可做此参数传入。示例，将下面代码加入某个按钮单击事件中，可以将当前窗体变为字符串&rdquo;hello&rdquo;的形状<br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>void CTestDlg::OnTest() <br />{<br />　HRGN wndRgn;<br />　CClientDC dc(this);<br />　CFont mFont;<br /><br />　if (dc.m_hDC!=NULL)<br />　{<br />　　VERIFY(mFont.CreateFont(200, 50, 0, 0, FW_HEAVY, TRUE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, <br />CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, &quot;宋体&quot;)); <br /><br />　　//开始记录窗体轮廓路径<br />　　dc.BeginPath(); <br /><br />　　//设置背景为透明模式,这句话是必须有的。<br />　　dc.SetBkMode(TRANSPARENT); <br /><br />　　CFont * pOldFont;<br />　　pOldFont = dc.SelectObject( &amp;mFont );<br />　　dc.TextOut(0, 0, &quot;Hello&quot;);<br /><br />　　//结束记录窗体轮廓路径<br />　　dc.SelectObject( pOldFont );<br />　　dc.EndPath();<br /><br />　　//把所记录的路径转化为窗体轮廓句柄<br />　　wndRgn = ::PathToRegion(dc.m_hDC);<br /><br />　　//赋予窗体指定的轮廓形状 <br />　　this-&gt;SetWindowRgn(wndRgn, TRUE); <br />　}<br />}</td></tr></tbody></table><br />　　CClientDC是CDC的派生类，故此该类具有所有CDC类的成员变量和成员函数。 <br /><br />
<table align="center" border="0">
<tbody>
<tr>
<td>
<div align="center"><img src="http://www.yesky.com/image20010518/225486.gif" border="1" /><br />图二 hello形状的窗体效果图</div></td></tr></tbody></table><br />　　<b>五、根据图像创建&rdquo;region&rdquo;</b><br /><br />　　此法创建不规则窗体比较复杂。首先准备一张含有目标窗体形状的图片，设置透明色即将图片中部不属于窗体形状的部分，标记成同一种颜色，例如蓝色RGB(0,0,255).程序运行后先装入图片。然后逐个扫描图片的每个像素，如这个像素不属于透明色，则在相应位置创建一个只含一个像素的&ldquo;region&rdquo;然后将这些小&rdquo;region &rdquo;合并起来组成一个任意形状的&rdquo;region&rdquo;.这里将使用到CRgn的一个成员函数 ：int CRgn::CombineRgn( CRgn* pRgn1, CRgn* pRgn2, int nCombineMode );<br /><br />　　其中pRgn1,pRgn2为要合并的两个&ldquo;region&rdquo;，nCombineMode为合并的方式，此应用中取RGN_OR，即两&rdquo;region&rdquo;全部合并去处重复部分。代码实现如下：<br /><br />
<table align="center" bgcolor="#dadacf" border="1">
<tbody>
<tr>
<td>void SetupRegion(<br />　CDC *pDC, //窗体的DC指针<br />　CBitmap &amp;cBitmap, //含有窗体形状的位图对象<br />　COLORREF TransColor //透明色<br />)<br />{ <br />　CDC memDC;<br />　//创建与传入DC兼容的临时DC<br />　memDC.CreateCompatibleDC(pDC);<br /><br />　CBitmap *pOldMemBmp=NULL;<br />　//将位图选入临时DC<br />　pOldMemBmp=memDC.SelectObject(&amp;cBitmap);<br /><br />　CRgn wndRgn;<br />　//创建总的窗体区域，初始region为0<br />　wndRgn.CreateRectRgn(0,0,0,0);<br /><br />　BITMAP bit; <br />　cBitmap.GetBitmap (&amp;bit);//取得位图参数，这里要用到位图的长和宽 <br /><br />　int y;<br />　for(y=0;y&lt;=bit.bmHeight ;y++)<br />　{<br />　　CRgn rgnTemp; //保存临时region<br /><br />　　int iX = 0;<br />　　do<br />　　{<br />　　　//跳过透明色找到下一个非透明色的点.<br />　　　while (iX &lt;= bit.bmWidth &amp;&amp; memDC.GetPixel(iX, y) == TransColor)<br />　　　　iX++;<br />　　　　//记住这个起始点<br />　　　　int iLeftX = iX;<br /><br />　　　　//寻找下个透明色的点<br />　　　　while (iX &lt;= bit.bmWidth &amp;&amp; memDC.GetPixel(iX, y) != TransColor)<br />　　　　　++iX;<br /><br />　　　　//创建一个包含起点与重点间高为1像素的临时&ldquo;region&rdquo;<br />　　　　rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1);<br /><br />　　　　//合并到主&quot;region&quot;.<br />　　　　wndRgn.CombineRgn(&amp;wndRgn, &amp;rgnTemp, RGN_OR);<br /><br />　　　//删除临时&quot;region&quot;,否则下次创建时和出错<br />　　　rgnTemp.DeleteObject();<br />　　}while(iX GetWindow();<br />　　pWnd-&gt;SetWindowRgn(wndRgn,TRUE); <br />　　pWnd-&gt;SetForegroundWindow(); <br />　}</td></tr></tbody></table><br />　　上述代码创建的不规则窗体中，在OnEraseBkgnd事件中绘制该位图，就可得到与该位图形状一模一样的窗体。 <br /><br />
<table align="center" border="0">
<tbody>
<tr>
<td>
<div align="center"><img src="http://www.yesky.com/image20010518/225488.gif" border="1" /><br />图三 根据位图和位图中的透明色创建的窗体效果图</div></td></tr></tbody></table><br />　　<b>六、小结</b><br /><br />　　三种创建&ldquo;region&rdquo;的方法，第一种最简单，如果所需的窗体形状是简单的几何图形，这种方法最合适；第二种稍微复杂些，但是创建的窗体形状更多些；第三种方法可以创建任何在图片中画出的窗体形状，但是实现的复杂度也最高]]></description>
		</item>
		    
		
		<item>
			<title>键盘消息</title>
			<link>http://ccnuliu.blog.sohu.com/61281046.html</link>
			<comments>http://ccnuliu.blog.sohu.com/61281046.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Sat, 25 Aug 2007 20:00:33 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/61281046.html</guid>
			<description><![CDATA[Windows系统是建立在事件驱动的机制上的，说穿了就是整个系统都是通过消息的传递来实现的。而钩子是Windows系统中非常重要的系统接口，用它可以截获并处理送给其他应用程序的消息，来完成普通应用程序难以实现的功能。钩子可以监视系统或进程中的各种事件消息，截获发往目标窗口的消息并进行处理。这样，我们就可以在系统中安装自定义的钩子，监视系统中特定事件的发生，完成特定的功能，比如截获键盘、鼠标的输入，屏幕取词，日志监视等等。可见，利用钩子可以实现许多特殊而有用的功能。因此，对于高级编程人员来说，掌握钩子的编程方法是很有必要的。 <br /><br />钩子的类型 <br />　　一． 按事件分类，有如下的几种常用类型 <br />　　（1） 键盘钩子和低级键盘钩子可以监视各种键盘消息。 <br />　　（2） 鼠标钩子和低级鼠标钩子可以监视各种鼠标消息。 <br />　　（3） 外壳钩子可以监视各种Shell事件消息。比如启动和关闭应用程序。 <br />　　（4） 日志钩子可以记录从系统消息队列中取出的各种事件消息。 <br />　　（5） 窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。 <br />　　此外，还有一些特定事件的钩子提供给我们使用，不一一列举。 <br />下面描述常用的Hook类型： <br />1、WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks <br />WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你可以监视发送到窗口过程的消息。系统在消息发送到接收窗口过程之前调用WH_CALLWNDPROC Hook子程，并且在窗口过程处理完消息之后调用WH_CALLWNDPRO <br />CRET Hook子程。WH_CALLWNDPROCRET Hook传递指针到CWPRETSTRUCT结构，再传递到Hook子程。CWPRETSTRUCT结构包含了来自处理消息的窗口过程的返回值，同样也包括了与这个消息关联的消息参数。 <br />2、WH_CBT Hook <br />在以下事件之前，系统都会调用WH_CBT Hook子程，这些事件包括： <br />1. 激活，建立，销毁，最小化，最大化，移动，改变尺寸等窗口事件； <br />2. 完成系统指令； <br />3. 来自系统消息队列中的移动鼠标，键盘事件； <br />4. 设置输入焦点事件； <br />5. 同步系统消息队列事件。 <br />Hook子程的返回值确定系统是否允许或者防止这些操作中的一个。 <br />3、WH_DEBUG Hook <br />在系统调用系统中与其他Hook关联的Hook子程之前，系统会调用WH_DEBUG Hook子程。你可以使用这个Hook来决定是否允许系统调用与其他Hook关联的Hook子程。 <br />4、WH_FOREGROUNDIDLE Hook <br />当应用程序的前台线程处于空闲状态时，可以使用WH_FOREGROUNDIDLE Hook执行低优先级的任务。当应用程序的前台线程大概要变成空闲状态时，系统就会调用WH_FOREGROUNDIDLE Hook子程。 <br />5、WH_GETMESSAGE Hook <br />应用程序使用WH_GETMESSAGE Hook来监视从GetMessage or PeekMessage函数返回的消息。你可以使用WH_GETMESSAGE Hook去监视鼠标和键盘输入，以及其他发送到消息队列中的消息。 <br />6、WH_JOURNALPLAYBACK Hook <br />WH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可以使用这个Hook回放通过使用WH_JOURNALRECORD Hook记录下来的连续的鼠标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装，正常的鼠标和键盘事件就是无效的。WH_JOURNALPLAYBACK Hook是全局Hook，它不能象线程特定Hook一样使用。WH_JOURNALPLAYBACK Hook返回超时值，这个值告诉系统在处理来自回放Hook当前消息之前需要等待多长时间（毫秒）。这就使Hook可以控制实时事件的回放。WH_JOURNALPLAYBACK是system-wide local hooks，它們不會被注射到任何行程位址空間。（估计按键精灵是用这个hook做的） <br />7、WH_JOURNALRECORD Hook <br />WH_JOURNALRECORD Hook用来监视和记录输入事件。典型的，可以使用这个Hook记录连续的鼠标和键盘事件，然后通过使用WH_JOURNALPLAYBACK Hook来回放。WH_JOURNALRECORD Hook是全局Hook，它不能象线程特定Hook一样使用。WH_JOURNALRECORD是system-wide local hooks，它們不會被注射到任何行程位址空間。 <br />8、WH_KEYBOARD Hook <br />在应用程序中，WH_KEYBOARD Hook用来监视WM_KEYDOWN and WM_KEYUP消息，这些消息通过GetMessage or PeekMessage function返回。可以使用这个Hook来监视输入到消息队列中的键盘消息。 <br />9、WH_KEYBOARD_LL Hook <br />WH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。 <br />10、WH_MOUSE Hook <br />WH_MOUSE Hook监视从GetMessage 或者 PeekMessage 函数返回的鼠标消息。使用这个Hook监视输入到消息队列中的鼠标消息。 <br />11、WH_MOUSE_LL Hook <br />WH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息。 <br />12、WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks <br />WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单，滚动条，消息框，对话框消息并且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。WH_MSGFILTER Hook只能监视传递到菜单，滚动条，消息框的消息，以及传递到通过安装了Hook子程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook监视所有应用程序消息。WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间过滤消息，这等价于在主消息循环中过滤消息。通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这个函数，应用程序能够在模式循环期间使用相同的代码去过滤消息，如同在主消息循环里一样。 <br />13、WH_SHELL Hook <br />外壳应用程序可以使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是激活的并且当顶层窗口建立或者销毁时，系统调用WH_SHELL Hook子程。 <br />WH_SHELL 共有５钟情況： <br />1. 只要有个top-level、unowned 窗口被产生、起作用、或是被摧毁； <br />2. 当Taskbar需要重画某个按钮； <br />3. 当系统需要显示关于Taskbar的一个程序的最小化形式； <br />4. 当目前的键盘布局状态改变； <br />5. 当使用者按Ctrl+Esc去执行Task Manager（或相同级别的程序）。 <br />按照惯例，外壳应用程序都不接收WH_SHELL消息。所以，在应用程序能够接收WH_SHELL消息之前，应用程序必须调用SystemParametersInfo function注册它自己。 <br />以上是13种常用的hook类型！ <br />　　二． 按使用范围分类，主要有线程钩子和系统钩子 <br />　　（1） 线程钩子监视指定线程的事件消息。 <br />　　（2） 系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序，所以钩子函数必须放在独立的动态链接库(DLL) <br />中。这是系统钩子和线程钩子很大的不同之处。 <br />　　 几点需要说明的地方： <br />　　（1） 如果对于同一事件（如鼠标消息）既安装了线程钩子又安装了系统钩子，那么系统会自动先调用线程钩子，然后调用系统钩子。 <br />　　（2） 对同一事件消息可安装多个钩子处理过程，这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。而且最近安装的钩子放在链的开始，而最早安装的钩子放在最后，也就是后加入的先获得控制权。 <br />　　（3） 钩子特别是系统钩子会消耗消息处理时间，降低系统性能。只有在必要的时候才安装钩子，在使用完毕后要及时卸载。 <br />编写钩子程序 <br />　　 编写钩子程序的步骤分为三步：定义钩子函数、安装钩子和卸载钩子。 <br />　　1．定义钩子函数 <br />　　钩子函数是一种特殊的回调函数。钩子监视的特定事件发生后，系统会调用钩子函数进行处理。不同事件的钩子函数的形式是各不相同的。下面以鼠标钩子函数举例说明钩子函数的原型： <br />LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam) <br />参数wParam和 lParam包含所钩消息的信息，比如鼠标位置、状态，键盘按键等。nCode包含有关消息本身的信息，比如是否从消息队列中移出。 <br />我们先在钩子函数中实现自定义的功能，然后调用函数 CallNextHookEx.把钩子信息传递给钩子链的下一个钩子函数。CallNextHookEx.的原型如下： <br />LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam ) <br />参数 hhk是钩子句柄。nCode、wParam和lParam 是钩子函数。 <br />当然也可以通过直接返回TRUE来丢弃该消息，就阻止了该消息的传递。 <br />2．安装钩子 <br />　　在程序初始化的时候，调用函数SetWindowsHookEx安装钩子。其函数原型为： <br />HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId ) <br />参数idHook表示钩子类型，它是和钩子函数类型一一对应的。比如，WH_KEYBOARD表示安装的是键盘钩子，WH_MOUSE表示是鼠标钩子等等。 <br />　　Lpfn是钩子函数的地址。 <br />　　HMod是钩子函数所在的实例的句柄。对于线程钩子，该参数为NULL；对于系统钩子，该参数为钩子函数所在的DLL句柄。 <br />　　 dwThreadId 指定钩子所监视的线程的线程号。对于全局钩子，该参数为NULL。 <br />　　SetWindowsHookEx返回所安装的钩子句柄。 <br />　　3．卸载钩子 <br />　　 当不再使用钩子时，必须及时卸载。简单地调用函数 BOOL UnhookWindowsHookEx( HHOOK hhk)即可。 <br />　　 <br />值得注意的是线程钩子和系统钩子的钩子函数的位置有很大的差别。线程钩子一般在当前线程或者当前线程派生的线程内，而系统钩子必须放在独立的动态链接库中，实现起来要麻烦一些。 <br /><br />线程钩子的编程实例： <br />　　按照上面介绍的方法实现一个线程级的鼠标钩子。钩子跟踪当前窗口鼠标移动的位置变化信息。并输出到窗口。 <br />　　(1)在VC＋＋6.0中利用MFC <br />APPWizard（EXE）生成一个不使用文档/视结构的单文档应用mousehook。打开childview.cpp文件，加入全局变量： <br />HHOOK hHook;//鼠标钩子句柄 <br />CPoint point;//鼠标位置信息 <br />CChildView ＊pView; <br />// 鼠标钩子函数用到的输出窗口指针 <br /><br />　　在CChildView::OnPaint()添加如下代码： <br />CPaintDC dc(this); <br />char str[256]; <br />sprintf(str,&ldquo;x=％d,y=％d&quot;,point.x,point.y); <br />//构造字符串 <br />dc.TextOut(0,0,str); //显示字符串 <br /><br />　　(2)childview.cpp文件中定义全局的鼠标钩子函数。 <br />LRESULT CALLBACK MouseProc <br />(int nCode, WPARAM wParam, LPARAM lParam) <br />{//是鼠标移动消息 <br />if(wParam==WM_MOUSEMOVE||wParam <br />==WM_NCMOUSEMOVE) <br />{ <br />point=((MOUSEHOOKSTRUCT ＊)lParam)－&gt;pt; <br />//取鼠标信息 <br />pView－&gt;Invalidate(); //窗口重画 <br />} <br />return CallNextHookEx(hHook,nCode,wParam,lParam); <br />//传递钩子信息 <br />} <br />(3)CChildView类的构造函数中安装钩子。 <br />CChildView::CChildView() <br />{ <br />pView=this;//获得输出窗口指针 <br />hHook=SetWindowsHookEx(WH_MOUSE,MouseProc,0,GetCurrentThreadId()); <br />} <br />(4)CChildView类的析构函数中卸载钩子。 <br />CChildView::～CChildView() <br />{ <br />if(hHook) <br />UnhookWindowsHookEx(hHook); <br />} <br /><br />系统钩子的编程实例： <br />由于系统钩子要用到dll，所以先介绍下win32 dll的特点： <br />Win32 DLL与 Win16 DLL有很大的区别，这主要是由操作系统的设计思想决定的。一方面，在Win16 DLL中程序入口点函数和出口点函数（LibMain和WEP）是分别实现的；而在Win32 DLL中却由同一函数DLLMain来实现。无论何时，当一个进程或线程载入和卸载DLL时，都要调用该函数，它的原型是BOOL WINAPI DllMain <br />(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved);，其中，第一个参数表示DLL的实例句柄；第三个参数系统保留；这里主要介绍一下第二个参数，它有四个可能的值：DLL_PROCESS_ATTACH（进程载入），DLL_THREAD_ATTACH（线程载入），DLL_THREAD_DETACH（线程卸载），DLL_PROCESS_DETACH（进程卸载），在DLLMain函数中可以对传递进来的这个参数的值进行判别，并根据不同的参数值对DLL进行必要的初始化或清理工作。举个例子来说，当有一个进程载入一个DLL时，系统分派给DLL的第二个参数为DLL_PROCESS_ATTACH，这时，你可以根据这个参数初始化特定的数据。另一方面，在Win16环境下，所有应用程序都在同一地址空间；而在Win32环境下，所有应用程序都有自己的私有空间，每个进程的空间都是相互独立的，这减少了应用程序间的相互影响，但同时也增加了编程的难度。大家知道，在Win16环境中，DLL的全局数据对每个载入它的进程来说都是相同的；而在Win32环境中，情况却发生了变化，当进程在载入DLL时，系统自动把DLL地址映射到该进程的私有空间，而且也复制该DLL的全局数据的一份拷贝到该进程空间，也就是说每个进程所拥有的相同的DLL的全局数据其值却并不一定是相同的。因此，在Win32环境下要想在多个进程中共享数据，就必须进行必要的设置。亦即把这些需要共享的数据分离出来，放置在一个独立的数据段里，并把该段的属性设置为共享。 <br />在VC6中有三种形式的MFC DLL（在该DLL中可以使用和继承已有的MFC类)可供选择，即Regular statically linked to MFC DLL（标准静态链接MFC DLL）和Regular using the shared MFC DLL（标准动态链接MFC DLL）以及Extension MFC DLL（扩展MFC DLL）。第一种DLL的特点是，在编译时把使用的MFC代码加入到DLL中，因此，在使用该程序时不需要其他MFC动态链接类库的存在，但占用磁盘空间比较大；第二种DLL的特点是，在运行时，动态链接到MFC类库，因此减少了空间的占用，但是在运行时却依赖于MFC动态链接类库；这两种DLL既可以被MFC程序使用也可以被Win32程序使用。第三种DLL的特点类似于第二种，做为MFC类库的扩展，只能被MFC程序使用。 <br />下面说说在VC6中全局共享数据的实现 <br />　　在主文件中，用#pragma data_seg建立一个新的数据段并定义共享数据，其具体格式为： <br />　　#pragma data_seg （&quot;shareddata&quot;) <br />　　HWND sharedwnd=NULL;//共享数据 <br />　　#pragma data_seg() <br />　　仅定义一个数据段还不能达到共享数据的目的，还要告诉编译器该段的属性，有两种方法可以实现该目的（其效果是相同的），一种方法是在.DEF文件中加入如下语句： <br />SETCTIONS shareddata READ WRITE SHARED <br />　　另一种方法是在项目设置链接选项中加入如下语句： <br />　　/SECTION:shareddata,rws <br />好了，准备知识已经学完了，让我们开始编写个全局的钩子程序吧！ <br /><br /><br /><br />由于全局钩子函数必须包含在动态链接库中，所以本例由两个程序体来实现。 <br />1．建立钩子Mousehook.DLL <br />　　(1)选择MFC AppWizard(DLL)创建项目Mousehook； <br />　　(2)选择MFC Extension DLL（共享MFC拷贝）类型； <br />　　(3)由于VC5没有现成的钩子类，所以要在项目目录中创建Mousehook.h文件，在其中建立钩子类： <br />　　class AFX_EXT_CLASS Cmousehook:public CObject <br />　　{ <br />　　public: <br />　　Cmousehook(); <br />　　//钩子类的构造函数 <br />　　~Cmousehook(); <br />　　//钩子类的析构函数 <br />　　BOOL starthook(HWND hWnd); <br />　　//安装钩子函数 <br />　　BOOL stophook(); <br />　　卸载钩子函数 <br />　　}; <br />　　(4)在Mousehook.app文件的顶部加入#include&quot;Mousehook.h&quot;语句； <br />　　(5)加入全局共享数据变量： <br />　　#pragma data_seg(&quot;mydata&quot;) <br />　　HWND glhPrevTarWnd=NULL; <br />　　//上次鼠标所指的窗口句柄 <br />　　HWND glhDisplayWnd=NULL; <br />　　//显示目标窗口标题编辑框的句柄 <br />　　HHOOK glhHook=NULL; <br />　　//安装的鼠标钩子句柄 <br />　　HINSTANCE glhInstance=NULL; <br />　　//DLL实例句柄 <br />　　#pragma data_seg() <br />　　(6)在DEF文件中定义段属性： <br />　　SECTIONS <br />　　mydata READ WRITE SHARED <br />　　(7)在主文件Mousehook.cpp的DllMain函数中加入保存DLL实例句柄的语句： <br />　　DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) <br />　　{ <br />　　//如果使用lpReserved参数则删除下面这行 <br />　　UNREFERENCED_PARAMETER(lpReserved); <br />　　if (dwReason == DLL_PROCESS_ATTACH) <br />　　{ <br />　　 TRACE0(&quot;MOUSEHOOK.DLL Initializing!\n&quot;); <br />　　 //扩展DLL仅初始化一次 <br />　　 if (!AfxInitExtensionModule(MousehookDLL, hInstance)) <br />　　 return 0; <br />　　 new CDynLinkLibrary(MousehookDLL); <br />　　 //把DLL加入动态MFC类库中 <br />　　 glhInstance=hInstance; <br />　　 //插入保存DLL实例句柄 <br />　　} <br />　　else if (dwReason == DLL_PROCESS_DETACH) <br />　　{ <br />　　 TRACE0(&quot;MOUSEHOOK.DLL Terminating!\n&quot;); <br />　　 //终止这个链接库前调用它 <br />　　 AfxTermExtensionModule(MousehookDLL); <br />　　} <br />　　return 1; <br />　　} <br />　　(8)类Cmousehook的成员函数的具体实现： <br />　　Cmousehook::Cmousehook() <br />　　//类构造函数 <br />　　{ <br />　　} <br />　　Cmousehook::~Cmousehook() <br />　　//类析构函数 <br />　　{ <br />　　stophook(); <br />　　} <br />　　BOOL Cmousehook::starthook(HWND hWnd) <br />　　//安装钩子并设定接收显示窗口句柄 <br />　　{ <br />　　BOOL bResult=FALSE; <br />　　glhHook=SetWindowsHookEx(WH_MOUSE,MouseProc,glhInstance,0); <br />　　if(glhHook!=NULL) <br />　　 bResult=TRUE; <br />　　glhDisplayWnd=hWnd; <br />　　//设置显示目标窗口标题编辑框的句柄 <br />　　return bResult; <br />　　} <br />　　BOOL Cmousehook::stophook() <br />　　//卸载钩子 <br />　　{ <br />　　BOOL bResult=FALSE; <br />　　if(glhHook) <br />　　{ <br />　　 bResult= UnhookWindowsHookEx(glhHook); <br />　　 if(bResult) <br />　　 { <br />　　 glhPrevTarWnd=NULL; <br />　　 glhDisplayWnd=NULL;//清变量 <br />　　 glhHook=NULL; <br />　　 } <br />　　} <br />　　return bResult; <br />　　} <br />　　(9)钩子函数的实现： <br />　　LRESULT WINAPI MouseProc(int nCode,WPARAM wparam,LPARAM lparam) <br />　　{ <br />　　LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *) lparam; <br />　　 if (nCode&gt;=0) <br />　　 { <br />　　HWND glhTargetWnd=pMouseHook-&gt;hwnd; <br />　　//取目标窗口句柄 <br />　　 HWND ParentWnd=glhTargetWnd; <br />　　 while (ParentWnd !=NULL) <br />　　 { <br />　　 glhTargetWnd=ParentWnd; <br />　　 ParentWnd=GetParent(glhTargetWnd); <br />　　 //取应用程序主窗口句柄 <br />　　 } <br />　　 if(glhTargetWnd!=glhPrevTarWnd) <br />　　 { <br />　　 char szCaption[100]; <br />　　 GetWindowText(glhTargetWnd,szCaption,100); <br />　　 //取目标窗口标题 <br />　　 if(IsWindow(glhDisplayWnd)) <br />　　 SendMessage(glhDisplayWnd,WM_SETTEXT,0,(LPARAM)(LPCTSTR)szCaption); <br />　　 glhPrevTarWnd=glhTargetWnd; <br />　　 //保存目标窗口 <br />　　 } <br />　　 } <br />　　 return CallNextHookEx(glhHook,nCode,wparam,lparam); <br />　　 //继续传递消息 <br />　　} <br />　　(10)编译项目生成mousehook.dll。 <br />　　2．创建钩子可执行程序 <br />　　(1)用MFC的AppWizard(EXE)创建项目Mouse； <br />　　(2)选择&ldquo;基于对话应用&rdquo;并按下&ldquo;完成&rdquo;键； <br />　　(3)编辑对话框，删除其中原有的两个按钮，加入静态文本框和编辑框，用鼠标右键点击静态文本框，在弹出的菜单中选择&ldquo;属性&rdquo;，设置其标题为&ldquo;鼠标所在的窗口标题&rdquo;； <br /><br />　　(4)在Mouse.h中加入对Mousehook.h的包含语句#Include&quot;..\Mousehook\Mousehook.h&quot;； <br />　　(5)在CMouseDlg.h的CMouseDlg类定义中添加私有数据成员： <br />　　CMouseHook m_hook;//加入钩子类作为数据成员 <br />　　(6)修改CmouseDlg::OnInitDialog()函数： <br />　　BOOL CMouseDlg::OnInitDialog() <br />　　{ <br />　　CDialog::OnInitDialog(); <br />　　ASSERT((IDM_ABOUTBOX &amp; 0xFFF0) == IDM_ABOUTBOX); <br />　　ASSERT(IDM_ABOUTBOX &lt;0xF000); <br />　　CMenu* pSysMenu = GetSystemMenu(FALSE); <br />　　if (pSysMenu != NULL) <br />　　{ <br />　　 CString strAboutMenu; <br />　　 strAboutMenu.LoadString(IDS_ABOUTBOX); <br />　　 if (!strAboutMenu.IsEmpty()) <br />　　 { <br />　　 pSysMenu-&gt;AppendMenu(MF_SEPARATOR); <br />　　 pSysMenu-&gt;AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); <br />　　 } <br />　　} <br />　　SetIcon(m_hIcon, TRUE);//Set big icon <br />　　SetIcon(m_hIcon, FALSE);//Set small icon <br />　　//TODO: Add extra initialization here <br />　　CWnd * pwnd=GetDlgItem(IDC_EDIT1); <br />　　//取得编辑框的类指针 <br />　　m_hook.starthook(pwnd-&gt;GetSafeHwnd()); <br />　　//取得编辑框的窗口句柄并安装钩子 <br />　　return TRUE; <br />　　//return TRUE unless you set the focus to a control <br />　　} <br />　　(7)链接DLL库，即把..\Mousehook\debug\Mousehook.lib加入到项目设置链接标签中； <br />　　(8)编译项目生成可执行文件； <br />　　(9)把Mousehook.DLL拷贝到..\mouse\debug目录中； <br />　　(10)先运行几个可执行程序，然后运行Mouse.exe程序，把鼠标在不同窗口中移动，在Mouse.exe程序窗口中的编辑框内将显示出鼠标所在的应用程序主窗口的标题。 <br /><br />好了，终于写完了，累ing，这是钩子函数的入门知识，包括了线程钩子和全局钩子，希望高手们加以指点斧正！谢谢大家！ <br />[附：我有个疑问，希望高手们帮忙解决下，在编写线程钩子时，我用的是这个函数来安装钩子hHook=SetWindowsHookEx(WH_MOUSE,MouseProc,0,GetCurrentThreadId());第4个参数是GetCurrentThreadId() <br />是指此钩子函数监测的是自己的那个程序，那么如果我想监测其他一个特定程序的话，此参数该如何定义出来呢？比如想只监测mir3程序，该如何定义第4个参数呢？谢谢！]]></description>
		</item>
		    
		
		<item>
			<title>避免图形闪烁的方法</title>
			<link>http://ccnuliu.blog.sohu.com/61103070.html</link>
			<comments>http://ccnuliu.blog.sohu.com/61103070.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Fri, 24 Aug 2007 15:45:51 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/61103070.html</guid>
			<description><![CDATA[以下内容借鉴了网络资料。避免图形闪烁的方法还有其它，但双缓冲是比较好的一种。该技术用于数字图像处理软件中，效果还勉强过得去，算是帮了本人的大忙。 
<p><font size="2">显示图形时如何避免闪烁，如何提高显示效率是问得比较多的问题。其解决办法是利用双缓冲技术（不过好像效果仍然不太理想）。<br /><br />1、显示的图形为什么会闪烁？</font></p>
<p><font size="2">绘图过程大多放在OnDraw()或者OnPaint()函数中。在进行屏幕显示时OnDraw()由OnPaint()调用。当窗口需要重绘时（由于任何原因），系统总是先用背景色将显示区清除，然后才调用OnPaint()；而背景色往往与绘图内容反差很大，这样在短时间内背景色与显示图形的交替出现，使得显示窗口看起来在闪烁。解决办法是利用双缓冲技术。</font></p>
<p><font size="2">2. 如何实现双缓冲</font></p>
<p><font size="2">在OnDraw(<a name="baidusnap0"></a><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">CDC</strong> *pDC)中：<br /><br /><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">CDC</strong> MemDC; ///首先定义一个显示设备对象<br />CBitmap MemBitmap;///定义一个位图对象<br /><br />///随后建立与屏幕显示兼容的内存显示设备<br />MemDC.CreateCompatibleDC(NULL);<br />///建立一个与屏幕显示兼容的位图（相当于构建<a name="baidusnap1"></a><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">画布</strong>），位图的大小可以用窗口的大小<br />MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);<br /><br />///将位图选入内存显示设备，相当于选择<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">画布</strong><br />CBitmap *pOldBit=MemDC.SelectObject(&amp;MemBitmap);<br /><br />///先用背景色（如白色）将位图清除干净<br />MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));<br /><br />///然后加入绘图代码<br />MemDC.MoveTo(&hellip;&hellip;);<br />MemDC.LineTo(&hellip;&hellip;);<br /><br />///再一次性把内存中的图形显示到屏幕<br />pDC-&gt;BitBlt(0,0,nWidth,nHeight,&amp;MemDC,0,0,SRCCOPY);<br /><br />///最后是绘图完成后的清理工作<br />MemBitmap.DeleteObject();<br />MemDC.DeleteDC();</font></p>
<p><font size="2">尽管效果仍然不尽人意，但已经比直接绘图要好很多了</font></p>]]></description>
		</item>
		    
		
		<item>
			<title>使用CDC的四个派生类</title>
			<link>http://ccnuliu.blog.sohu.com/61102861.html</link>
			<comments>http://ccnuliu.blog.sohu.com/61102861.html#comment</comments>
			<dc:creator>LoogSon的博客</dc:creator>
			<pubDate>Fri, 24 Aug 2007 15:44:27 +0800</pubDate>
			<guid>http://ccnuliu.blog.sohu.com/61102861.html</guid>
			<description><![CDATA[1<span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">．首先介绍一下什么是</span><span style="FONT-SIZE: 12pt; COLOR: black">DC</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">（设备描述表）</span><span style="FONT-SIZE: 12pt; COLOR: black"></span> 
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; COLOR: black">Windows</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">应用程序通过为指定设备（屏幕，打印机等）创建一个设备描述表（</span><span style="FONT-SIZE: 12pt; COLOR: black">Device Context, DC</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">）在</span><span style="FONT-SIZE: 12pt; COLOR: black">DC</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">表示的逻辑意义的&ldquo;画布&rdquo;上进行图形的绘制。</span><span style="FONT-SIZE: 12pt; COLOR: black">DC</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">是一种包含设备信息的数据结构，它包含了物理设备所需的各种状态信息。</span><span style="FONT-SIZE: 12pt; COLOR: black">Win32</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">程序在绘制图形之前需要获取</span><span style="FONT-SIZE: 12pt; COLOR: black">DC</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">的句柄</span><span style="FONT-SIZE: 12pt; COLOR: black">HDC</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">，并在不继续使用时释放掉。</span><span style="FONT-SIZE: 12pt; COLOR: black"></span></font> </p>
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; COLOR: black">2</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">．</span><span style="FONT-SIZE: 12pt; COLOR: black">CDC</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">及其派生类</span><span style="FONT-SIZE: 12pt; COLOR: black"></span><span style="FONT-SIZE: 12pt; COLOR: black"></span></font><font size="2"> CDC及其派生类的继承视图:<br />CObject<br />public |------CDC<br />public |------CClientDC<br />public |------CPaintDC<br />public |------CWindowDC<br />public |------CMetaFileDC <br />(注意: 除CMetaFileDC以外的三个派生类用于图形绘制.)<br /><span style="FONT-SIZE: 12pt; COLOR: black">[</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">以下几段是翻译</span><span style="FONT-SIZE: 12pt; COLOR: black">MSDN</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">中资料</span><span style="FONT-SIZE: 12pt; COLOR: black">]<br /></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">CDC</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">类定义了一个设备描述表相关的类，<span>其</span>对象提供成员函数操作设备描述表进行工作，如显示器，打印机，以及显示器描述表相关的窗口客户区域。<br /></span></font></p>
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">通过<span>CDC</span>的成员函数可进行一切绘图操作。<span>CDC</span>提供成员函数进行设备描述表的基本操作，使用绘图工具，选择类型安全的图形设备结构（<span>GDI</span>），以及色彩，调色板。除此之外还提供成员函数获取和设置绘图属性，映射，控制视口，窗体范围，转换坐标，区域操作，裁减，划线以及绘制简单图形（椭圆，多边形等）。成员函数也提供绘制文本，设置字体，打印机换码，滚动，处理元文件。</span></font> </p>
<p align="left">&nbsp;</p>
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">通过<span>CDC</span>的成员函数可进行一切绘图操作。<span>CDC</span>提供成员函数进行设备描述表的基本操作，使用绘图工具，选择类型安全的图形设备结构（<span>GDI</span>），以及色彩，调色板。除此之外还提供成员函数获取和设置绘图属性，映射，控制视口，窗体范围，转换坐标，区域操作，裁减，划线以及绘制简单图形（椭圆，多边形等）。成员函数也提供绘制文本，设置字体，打印机换码，滚动，处理元文件。<span></span></span></font><font size="2"> 其派生类:<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><br />PaintDC:</span> 封装<span>BeginPaint</span>和<span>EndPaint</span>两个<span>API</span>的调用。<span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><br />CClientDC:</span> 处理显示器描述表的相关的窗体客户区域。<span></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><br />CWindowDC</span>: 处理显示器描述表相关的整个窗体区域，包括了框架和控 件（子窗体）。<span></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><br />CMetaFileDC</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">: 与元文件相关的设备描述表关联。<span></span></span> <br /></font></p>
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">CDC</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">提供两个函数，<span>GetLayout</span>和<span>SetLayout</span>用于反转设备描述表的布局。用于方便阿拉伯，希伯来的书写文化习惯的设计，以及非欧洲表中的字体布局。<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">CDC</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">包含两个设备描述表，<span>m_hDC</span>和<span>m_hAttribDC</span>对应于相同的设备，<span>CDC</span>为<span>m_hDC</span>指定所有的输出<span>GDI</span>调用，大多数的<span>GDI</span>属性调用由<span>m_hAttribDC</span>控制。（如,<span>GetTextColor</span>是属性调用，而<span>SetTextColor</span>是一种输出调用。）<span></span></span></font> </p>
<p align="left">&nbsp;</p>
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">例子：框架使用这两个设备描述表，一个<span>CMetaFileDC</span>对象从物理设备中读取属性输出到元文件。打印机预览在框架中被执行时也是相同的形式。你也可以编写代码使用这两个设备描述表在你的应用程序中进行类似的操作。</span></font> </p>
<p align="left">&nbsp;</p>
<p align="left"><font size="2"><span style="FONT-SIZE: 12pt; COLOR: black">3</span><span style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">．使用方法</span><span style="FONT-SIZE: 12pt; COLOR: black"></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">创建一个<span>UseDC</span>的<span>MFC</span>单文档程序，定制<span>7</span>个按钮用来选择使用的<span>DC</span>，每个按钮由一个成员变量标识控制<span>[</span>互斥<span>]</span>，分别是<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">bool m_bHDCDisplay<span> </span>----<span> </span></span><span style="FONT-FAMILY: 宋体">使用整个屏幕的<span>HDC</span>；<span><br />bool m_bHDC<span> </span>----<span> </span></span>使用当前视图的对应的<span>DC</span>；<span><br />bool m_bCDC<span> </span>----<span> </span></span>使用<span>CDC</span>类<span>[</span>当前视图窗体<span>]</span>；<span><br />bool m_bCClientDC<span> </span>----<span> </span></span>使用<span>CClientDC</span>类<span>[</span>视图客户区域<span>DC]</span>；<span><br />bool m_bCPaintDC<span> </span>----<span> </span></span>使用<span>CPaintDC[</span>视图窗体<span>]</span>；<span><br />bool m_bCWindowDC<span> </span>----<span> </span></span>使用<span>CWindowDC[</span>整个视图窗体<span>]</span>；<span><br />bool m_bCMetaFileDC<span> </span>----<span> </span></span>使用<span>CMetaFileDC</span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">添加<span>7</span>个按钮的响应函数以控制这些<span>bool</span>变量<span>.</span>（这里比较简单我就不提供代码了）<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">视图类构造函数：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">CUseDCView::CUseDCView()</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">{</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">this-&gt;m_bHDCDisplay = false;<br />this-&gt;m_bHDC = false; <br />this-&gt;m_bCDC = false; <br />this-&gt;m_bCClientDC = false; <br />this-&gt;m_bCPaintDC = false;<br />this-&gt;m_bCWindowDC = false; <br />this-&gt;m_bCMetaFileDC = false;<br />m_hMetaFile = NULL;</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">}</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">视图类<span>OnDraw</span>函数<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">void CUseDCView::OnDraw(CDC* pDC)</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">{</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">CUseDCDoc* pDoc = GetDocument();<br />ASSERT_VALID(pDoc);<br /><br />//</span><span style="FONT-FAMILY: 宋体">窗体在<span>OnDraw</span>中会自动传入关联当前视图窗体客户矩形区域的<span>CPaintDC<br />//</span>才能获取相应的设备描述表<span><br /><br />HDC HDCDisplay = NULL;<span> </span>//</span>屏幕<span>DC</span>的句柄 对应<span>m_bHDCDisplay<br />HDC hDC = NULL;<span> </span><span></span>//</span>普通<span>DC</span>的句柄<span><span> </span></span>对应<span>m_bHDC;<br />CDC * pCDC = NULL;<span> </span>//</span>对应<span>m_bCDC<br />CClientDC * pClientDC = NULL;<span> </span>//</span>对应<span>m_bCClientDC<br />CPaintDC * pPaintDC = NULL;<span> </span>//</span>对应<span>m_bCPaintDC<span> </span><br />CWindowDC * pWindowDC = NULL;<span> </span>//</span>对应<span>m_bCWindowDC <br />CMetaFileDC * pMetaFileDC = NULL;<span> </span>//</span>对应<span>m_bMetaFileDC<br /><br />HMETAFILE hMetaFile = NULL;<br /><br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">RECT rect;<span> </span><span></span><span></span>//</span><span style="FONT-FAMILY: 宋体">定义一个设备左上角的矩形区域<span><br />rect.left = 0;<br />rect.top = 0;<br />rect.right = 200;<br />rect.bottom = 30;<br /><br />//</span>注意<span>: HDCDisplay</span>和<span>hDC</span>的<span>::Release()</span>中第一个参数<span>HWND<br />//</span>与<span>GetDC()</span>的第一个参数必须对应。<span><br />if(m_bHDCDisplay)<br />{<br /><span></span>HDCDisplay = ::GetDC(NULL);<span> </span>//</span>获得整个显示器区域的<span>DC<br /><span></span>::DrawText(HDCDisplay, &quot;HDC of Display&quot;, 14, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>::ReleaseDC(NULL, HDCDisplay);<br /><span></span>HDCDisplay = NULL;<br />}<br />if(m_bHDC)<span> </span>//</span>绘制在客户区域<span><br />{<br /><span></span>hDC = ::GetDC(this-&gt;m_hWnd);<span> </span>//</span>本窗体的<span>DC<br /><span></span>::DrawText(hDC, &quot;HDC&quot;, 3, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>::ReleaseDC(this-&gt;m_hWnd, hDC);<br /><span></span>hDC = NULL;<br />}<br />else if(m_bCDC){<br /><span></span>//</span>必须释放由程序框架传入的<span>pDC</span>才能获取当前客户区域设备描述表<span><br /><span></span>pCDC = this-&gt;GetDC();<span> </span>//</span>当前窗体<span>(</span>视图<span>)</span>的设备描述表<span><br /><span></span>pCDC-&gt;DrawText(&quot;Use class CDC&quot;, 13, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>this-&gt;ReleaseDC(pCDC);<br /><span></span>pCDC = NULL;<br />}<br />else if(m_bCClientDC){<br /><span></span>pClientDC = new CClientDC(this);<span> </span>//</span>获取本窗体客户区域的<span>DC<br /><span></span>pClientDC-&gt;DrawText(&quot;Use class CClientDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>delete pClientDC;<br /><span></span>pClientDC = NULL;<br />}<br />else if(m_bCPaintDC)<span> </span>{<span> </span>//</span>测试当前传入的<span>CDC</span>是不是<span>CPaintDC<br /><span></span>pPaintDC = (CPaintDC*)pDC;<br /><span></span>pPaintDC-&gt;DrawText(&quot;Use class CPaintDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br />}<br />else if(m_bCWindowDC){<br /><span></span>pWindowDC = new CWindowDC(this);<span> </span>//</span>获取本窗体框架和客户区域的<span>DC<br /><span></span>//</span>注意：绘制字符串的矩形区域空白部分覆盖了视图子窗体的边缘．<span><br /><span></span>pWindowDC-&gt;DrawText(&quot;Use class CWindowDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>delete pWindowDC;<br /><span></span>pWindowDC = NULL;<br />}<br />else if(m_bCMetaFileDC){<br /><span></span>//</span>传入<span>pDC-&gt;m_hDC</span>使用<span>pDC</span>绘制<span>,</span>图形在视图窗体左上角<span><br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>pMetaFileDC-&gt;m_hDC = pDC-&gt;m_hDC;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>delete pMetaFileDC;<br /><span></span>pDC-&gt;PlayMetaFile(m_hMetaFile);<br />}</span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">}</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">MFC</span><span style="FONT-FAMILY: 宋体">程序中使用<span>CPaintDC</span>在视图窗口中绘制图象时要注意，应该在<span>OnPaint()</span>编写关于<span>CPaintDC</span>相关的代码，而不是在<span>OnDraw()</span>中<span>.</span>但是请注意，如果使用<span>OnPaint()</span>函数响应<span>WM_PAINT</span>事件，<span>OnDraw</span>函数将会被屏蔽；<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">可以使用以下代码测试：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">在<span>CUseDCView.h</span>，<span>CUseDCView</span>的类定义中语句<span>DECLARE_MESSAGE_MAP()</span>之前加上<span>afx_msg void OnPaint()</span>，在<span>CUseDCView.cpp</span>中<span>BEGIN_MESSAGE_MAP (CUseDCView, CView)</span>和<span>END_MESSAGE_MAP()</span>之间加上<span>ON_WM_PAINT()</span>。<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">void CUseDCView::OnPaint() </span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">{<br /><span></span>CPaintDC dc(this); <br /><span></span>RECT rect;<span> </span><br /><span></span>rect.left = 0;<br /><span></span>rect.top = 0;<br /><span></span>rect.right = 200;<br /><span></span>rect.bottom = 30;<br /><span></span>dc.Draw3dRect(&amp;rect, (COLORREF)0xff0000, (COLORREF)0x0000ff);<br />}</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">使用<span>CMetaFileDC</span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">有兴趣可以在以下语句中可以尝试以下几种情况：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">else if(m_bCMetaFileDC){</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">...<br /><span></span>...</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">}</span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>1</span>：（与上面的<span>OnDraw</span>函数中相同）<span><br /><span></span>//</span>传入<span>pDC-&gt;m_hDC</span>使用<span>pDC</span>绘制<span>,</span>图形在视图窗体左上角<span><br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>pMetaFileDC-&gt;m_hDC = pDC-&gt;m_hDC;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<br /><span></span>delete pMetaFileDC;<br /><span></span>pDC-&gt;PlayMetaFile(m_hMetaFile);<span> </span><br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>2</span>：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"><span></span>//</span><span style="FONT-FAMILY: 宋体">传入<span>pDC-&gt;m_hDC</span>使用屏幕<span>DC</span>绘制<span>,</span>图形在视图窗体左上角<span><br /><span></span>HDC hdc;<br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>hdc = ::GetDC(NULL);<br /><span></span>pMetaFileDC-&gt;m_hDC = pDC-&gt;m_hDC;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>delete pMetaFileDC;<br /><span></span>::PlayMetaFile(hdc, m_hMetaFile);<br /><span></span>::ReleaseDC(NULL, hdc);<br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>3</span>：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">//</span><span style="FONT-FAMILY: 宋体">传入屏幕<span>DC,</span>使用屏幕<span>DC</span>绘制<span>,</span>图像在屏幕左上角<span><br /><span></span>HDC hdc;<br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>hdc = ::GetDC(NULL);<br /><span></span>pMetaFileDC-&gt;m_hDC = hdc;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>delete pMetaFileDC;<br /><span></span>::PlayMetaFile(hdc, m_hMetaFile);<br /><span></span>::ReleaseDC(NULL, hdc);<br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>4</span>：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">//</span><span style="FONT-FAMILY: 宋体">传入屏幕<span>DC,</span>使用<span>pDC</span>绘制<span>, </span>图像在屏幕左上角<span><br /><span></span>HDC hdc;<br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>hdc = ::GetDC(NULL);<br /><span></span>pMetaFileDC-&gt;m_hDC = hdc;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>delete pMetaFileDC;<br /><span></span>pDC-&gt;PlayMetaFile(m_hMetaFile);<br /><span></span>::ReleaseDC(NULL, hdc);<br /><br /></span></span><span style="FONT-FAMILY: 宋体"></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>5</span>：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">//</span><span style="FONT-FAMILY: 宋体">传入屏幕<span>DC,</span>使用<span>pDC</span>绘制<span>,</span>但是绘制前释放屏幕<span>DC,<br /><span></span>//</span>没有出错<span>,</span>而且图像绘制在屏幕左上角<span><br /><span></span>HDC hdc;<br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>hdc = ::GetDC(NULL);<br /><span></span>pMetaFileDC-&gt;m_hDC = hdc;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>delete pMetaFileDC;<br /><span></span>::ReleaseDC(NULL, hdc);<span> </span><br /><span></span>pDC-&gt;PlayMetaFile(m_hMetaFile);<br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>6</span>：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"><span></span><span></span>//</span><span style="FONT-FAMILY: 宋体">传入屏幕<span>pDC-&gt;hDC,</span>使用<span>CMetaFileDC</span>绘制，图像在视图窗体左上角<span><br /><span></span>HDC hdc;<br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>hdc = pDC-&gt;m_hDC;<br /><span></span>pMetaFileDC-&gt;m_hDC = hdc;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>pMetaFileDC-&gt;PlayMetaFile(m_hMetaFile);<br /><span></span>delete pMetaFileDC;<br /><span></span>::ReleaseDC(NULL, hdc);<br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>7</span>：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"><span></span>//</span><span style="FONT-FAMILY: 宋体">传入屏幕<span>DC,</span>使用<span>CMetaFileDC</span>绘制，图像在屏幕左上角<span><br /><span></span>HDC hdc;<br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>hdc = ::GetDC(NULL);<br /><span></span>pMetaFileDC-&gt;m_hDC = hdc;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>pMetaFileDC-&gt;PlayMetaFile(m_hMetaFile);<br /><span></span>delete pMetaFileDC;<br /><span></span>::ReleaseDC(NULL, hdc);<br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">情况<span>8</span>：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"><span></span>//</span><span style="FONT-FAMILY: 宋体">传入屏幕<span>DC,</span>使用<span>CMetaFileDC</span>绘制，绘图前释放<span>hdc<br /><span></span>//</span>仍然没有出错<span>,</span>图像在屏幕左上角<span><br /><span></span>HDC hdc;<br /><span></span>pMetaFileDC = new CMetaFileDC();<br /><span></span>hdc = ::GetDC(NULL);<br /><span></span>pMetaFileDC-&gt;m_hDC = hdc;<br /><span></span>pMetaFileDC-&gt;DrawText(&quot;Use class CMetaFileDC&quot;, &amp;rect, DT_LEFT|DT_TOP);<br /><span></span>pMetaFileDC-&gt;Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);<br /><span></span>m_hMetaFile = pMetaFileDC-&gt;Close();<span> </span><br /><span></span>::ReleaseDC(NULL, hdc);<br /><span></span>pMetaFileDC-&gt;PlayMetaFile(m_hMetaFile);<br /><span></span>delete pMetaFileDC;<br /><br /></span></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">由上面代码可见绘图的位置与传入<span>CMetaFileDC::m_hDC</span>的值有关。<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">使用<span>CMetaFileDC</span>需要注意：<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体">使用<span>CMetaFileDC</span>对象调用一系列你想重复的<span>CDC</span>的<span>GDI</span>命令，只能使用<span>CDC</span>类中<span>GDI</span>输出命令。<span>CDC</span>的<span>PlayMetaFile</span>可以使用图元文件句柄来执行图元文件中的命令，图元文件也能使用<span>CopyMetaFile</span>使其存储在磁盘上。当不再需要图元文件时，调用<span>DeleteMetaFile</span>从内存中删除它。<span></span></span></font> </p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"></span></font></p>
<p align="left"><font size="2"><span style="FONT-FAMILY: 宋体"><span></span></span><span style="FONT-FAMILY: 宋体">以上代码都通过测试，有兴趣的朋友欢迎讨论，如果有错误和不足欢迎指出，需要测试源码的朋友可以留下邮箱，我看到后会尽快发给你</span></font></p>]]></description>
		</item>
		    
		
	</channel>
</rss>
