<?xml version="1.0" encoding="UTF-8"?>
<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:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>意识流-沉思录</title>
	<atom:link href="http://www.colsir.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.colsir.com</link>
	<description>在牛B的大道上，一路狂奔</description>
	<lastBuildDate>Fri, 19 Feb 2010 13:14:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>包子</title>
		<link>http://www.colsir.com/2010/01/17/buns/</link>
		<comments>http://www.colsir.com/2010/01/17/buns/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 04:03:19 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[随网心情]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=147</guid>
		<description><![CDATA[	因为家族产业的缘故，我很少吃小吃店里的包子，这一习惯维持了好多年。
	公司早上提供早饭，包子+豆浆。老员工每天都是一个包子+一杯豆浆，刚来的一段时间，我每天早上都拿2个包子，不要自己掏钱的早饭，吃起来具香。差不多一个月过去了，渐渐发觉自己吃不下2个包子了，一个，或者一个半，逐步进入老员工的食量状态。
	腻了，真都点腻了。

]]></description>
			<content:encoded><![CDATA[	<p>因为家族产业的缘故，我很少吃小吃店里的包子，这一习惯维持了好多年。</p>
	<p>公司早上提供早饭，包子+豆浆。老员工每天都是一个包子+一杯豆浆，刚来的一段时间，我每天早上都拿2个包子，不要自己掏钱的早饭，吃起来具香。差不多一个月过去了，渐渐发觉自己吃不下2个包子了，一个，或者一个半，逐步进入老员工的食量状态。</p>
	<p>腻了，真都点腻了。
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2010/01/17/buns/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>后三章</title>
		<link>http://www.colsir.com/2009/12/29/after-the-three-chapters/</link>
		<comments>http://www.colsir.com/2009/12/29/after-the-three-chapters/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 12:31:26 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=143</guid>
		<description><![CDATA[	拖拖拉拉整理完了vc++深入详解的前17章，收获还是不少的。开始写这些文档之前便计划着辞掉那份asp.net的工作，在写这份文档完成之前终于如愿了。从asp.net到win ce，虽然都是vs2005平台，跨度可真不小，从不想整到整不了，一时间很难适应。
	《vc++深入详解》是本很不错的书，很仔细的讲解了vc开发的基本知识，本来计划着一口气把书上的例子程序都整理出来，做个笔记，可是因为换了工作，时间上很难保证。另外，书的后三章介绍的分别是active控件，dll，hook与数据库。虽然都是很有用的知识，但是离应用还远，另外，工作上是wince开发，这些知识暂时还用不到，拖拉了一个多星期，也没能把这份文档做个完结。
	这两天空闲的时候在想，为了做个了解，干脆粗乱这整理些文字发上来。可是翻开书本的时候却没有多少兴致。罢了，在此做个标记，等回到MFC开发平台的时候再学习这些吧。
	为了更快熟悉wince，今天在亚马逊上买了本wince开发的书，不知道每天工作加班到深夜之后，还是否有兴致来整理《win ce 学习笔记》之类的东西。如果时间上容许的话，我肯定乐而为之。好脑筋比不上烂笔头，整理vc++学习笔记过程中思考了一些问题，在面试这份工作的时候提供了不小的帮助。即使抄写比人现成的代码也能给我这只菜鸟带来不小的成就感。

]]></description>
			<content:encoded><![CDATA[	<p>拖拖拉拉整理完了vc++深入详解的前17章，收获还是不少的。开始写这些文档之前便计划着辞掉那份asp.net的工作，在写这份文档完成之前终于如愿了。从asp.net到win ce，虽然都是vs2005平台，跨度可真不小，从不想整到整不了，一时间很难适应。</p>
	<p>《vc++深入详解》是本很不错的书，很仔细的讲解了vc开发的基本知识，本来计划着一口气把书上的例子程序都整理出来，做个笔记，可是因为换了工作，时间上很难保证。另外，书的后三章介绍的分别是active控件，dll，hook与数据库。虽然都是很有用的知识，但是离应用还远，另外，工作上是wince开发，这些知识暂时还用不到，拖拉了一个多星期，也没能把这份文档做个完结。</p>
	<p>这两天空闲的时候在想，为了做个了解，干脆粗乱这整理些文字发上来。可是翻开书本的时候却没有多少兴致。罢了，在此做个标记，等回到MFC开发平台的时候再学习这些吧。</p>
	<p>为了更快熟悉wince，今天在亚马逊上买了本wince开发的书，不知道每天工作加班到深夜之后，还是否有兴致来整理《win ce 学习笔记》之类的东西。如果时间上容许的话，我肯定乐而为之。好脑筋比不上烂笔头，整理vc++学习笔记过程中思考了一些问题，在面试这份工作的时候提供了不小的帮助。即使抄写比人现成的代码也能给我这只菜鸟带来不小的成就感。
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/29/after-the-three-chapters/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(17)进程间通信</title>
		<link>http://www.colsir.com/2009/12/23/vc-in-depth-xiangjie-study-notes-17-inter-process-communication/</link>
		<comments>http://www.colsir.com/2009/12/23/vc-in-depth-xiangjie-study-notes-17-inter-process-communication/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 12:33:44 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=141</guid>
		<description><![CDATA[	当一个进程启动后，操作系统为其分配4GB的私有地址空间，位于同一个进程中的线程共享同一个地址空间。然而由于每个进程所拥有的4GB的地址空间都是私有的，一个进程不能访问另外一个进程的地址空间的数据，因此进程之间的通信相对比较困难。本章将介绍下列4中进程通信的方式：
	
	剪贴板
	匿名通道
	命名通道
	邮槽
	
	17.1剪贴板
	当我们在一个程序中复制一份数据之后，可以将数据粘贴到另外一个应用程序中，这就是2个进程利用剪贴板实现诗词数据传输。剪贴板实际上是系统维护管理的一块内存区域，当在一个进程中复制数据时，这个份数据被放到该内存区域中，当执行粘帖操作时，从该内存区域中取出数据，然后显示出来。
	将数据粘帖上剪切板时，首先要打开剪贴板。
	BOOL OpenClipBoard();
	当打开剪贴板成功，完成操作之后，需要关闭剪贴板CloseClipBoard（），以便其他程序调用。在系统系统中之后一块剪贴板区域，如果当前拥有者不关闭剪贴板，其他进程则无法获取到。手动将编辑框內数据复制到剪贴板的示例：
	void CClipDlg::OnButton1()
	
{
	
       // TODO: Add your control notification handler code here
	
       if(OpenClipboard())
	
       {
	
              CString str;//用来存放将要放到剪贴板上的数据
	
              HANDLE hClip;//保存GlobalAlloc动态分配的内存对象的句柄
	
              char *pBuf;//保存调用GlobalLock函数返回的地址
	
              EmptyClipboard();//清空剪贴板
	
              GetDlgItemText(IDC_EDIT1,str);//获取编辑框的内容，保存到str
	
              hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//动态分配内存，返回对象句柄
	
              pBuf=(char*)GlobalLock(hClip);//对内存对象加锁，返回地址
	
              strcpy(pBuf,str);//将str对象中的数据拷贝到pBuf指向的地址空间
	
              GlobalUnlock(hClip);//解锁
	
              SetClipboardData(CF_TEXT,hClip);//以指定的剪贴板格式项剪贴板上存放数据
	
              CloseClipboard();//关闭剪贴板
	
       }
	
}
	其中GlobalAlloc动态分配一块内存区域的参数有几种默认类型，MSDN中给出了详细的说明。
	调用剪贴板上的数据，显示到一个编辑框上。
	void CClipDlg::OnButton2()
	
{
	
       // TODO: Add your control notification handler code here
	
       if(OpenClipboard())
	
       {
	
              if(IsClipboardFormatAvailable(CF_TEXT))
	
              {
	
                     HANDLE hClip;
	
                     char * pBuf;
	
                     hClip=GetClipboardData(CF_TEXT);
	
                     pBuf=(char*)GlobalLock(hClip);
	
                     GlobalUnlock(hClip);
	
                     SetDlgItemText(IDC_EDIT2,pBuf);
	
              }
	
       }    
	
}
	17.2匿名管道
	匿名管道是一个未命名的、单向管道，通常用来在一个父进程和一个子进程之间传输数据。匿名管道只能实现本地机器上的两个进程间的通信，而不能实现跨网络通信。
	17.3命名管道
	命名管道通过网络来实现进程间的通信，它屏蔽了底层的网络协议细节，在不了解网络协议的情况下也可以利用命名管道来实现进程间的通信。命名管道不仅可以在本机上实现2个进程之间的通信，还可以跨网络实现2个进程的通信。
	17.4邮槽
	邮槽式基于广播通信体系设计出来的，它采用无连接的不可靠的数据传输。邮槽是一种单向的通信机制，创建邮槽的服务器进程读取数据，打开邮槽的客户端进程写入数据。为了使邮槽在各种Windows平台下运行，传输消息的时候，应该将消息的长度限制在424字节以下。
	PS:后三个例子代码写不贴了。

]]></description>
			<content:encoded><![CDATA[	<p>当一个进程启动后，操作系统为其分配4GB的私有地址空间，位于同一个进程中的线程共享同一个地址空间。然而由于每个进程所拥有的4GB的地址空间都是私有的，一个进程不能访问另外一个进程的地址空间的数据，因此进程之间的通信相对比较困难。本章将介绍下列4中进程通信的方式：</p>
	<ul>
	<li>剪贴板</li>
	<li>匿名通道</li>
	<li>命名通道</li>
	<li>邮槽</li>
	</ul>
	<p>17.1剪贴板</p>
	<p>当我们在一个程序中复制一份数据之后，可以将数据粘贴到另外一个应用程序中，这就是2个进程利用剪贴板实现诗词数据传输。剪贴板实际上是系统维护管理的一块内存区域，当在一个进程中复制数据时，这个份数据被放到该内存区域中，当执行粘帖操作时，从该内存区域中取出数据，然后显示出来。</p>
	<p>将数据粘帖上剪切板时，首先要打开剪贴板。</p>
	<p>BOOL OpenClipBoard();</p>
	<p>当打开剪贴板成功，完成操作之后，需要关闭剪贴板CloseClipBoard（），以便其他程序调用。在系统系统中之后一块剪贴板区域，如果当前拥有者不关闭剪贴板，其他进程则无法获取到。手动将编辑框內数据复制到剪贴板的示例：</p>
	<pre class="brush: c++">void CClipDlg::OnButton1()
	
{
	
       // TODO: Add your control notification handler code here
	
       if(OpenClipboard())
	
       {
	
              CString str;//用来存放将要放到剪贴板上的数据
	
              HANDLE hClip;//保存GlobalAlloc动态分配的内存对象的句柄
	
              char *pBuf;//保存调用GlobalLock函数返回的地址
	
              EmptyClipboard();//清空剪贴板
	
              GetDlgItemText(IDC_EDIT1,str);//获取编辑框的内容，保存到str
	
              hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//动态分配内存，返回对象句柄
	
              pBuf=(char*)GlobalLock(hClip);//对内存对象加锁，返回地址
	
              strcpy(pBuf,str);//将str对象中的数据拷贝到pBuf指向的地址空间
	
              GlobalUnlock(hClip);//解锁
	
              SetClipboardData(CF_TEXT,hClip);//以指定的剪贴板格式项剪贴板上存放数据
	
              CloseClipboard();//关闭剪贴板
	
       }
	
}</pre>
	<p>其中GlobalAlloc动态分配一块内存区域的参数有几种默认类型，MSDN中给出了详细的说明。</p>
	<p>调用剪贴板上的数据，显示到一个编辑框上。</p>
	<pre class="brush: c++">void CClipDlg::OnButton2()
	
{
	
       // TODO: Add your control notification handler code here
	
       if(OpenClipboard())
	
       {
	
              if(IsClipboardFormatAvailable(CF_TEXT))
	
              {
	
                     HANDLE hClip;
	
                     char * pBuf;
	
                     hClip=GetClipboardData(CF_TEXT);
	
                     pBuf=(char*)GlobalLock(hClip);
	
                     GlobalUnlock(hClip);
	
                     SetDlgItemText(IDC_EDIT2,pBuf);
	
              }
	
       }    
	
}</pre>
	<p>17.2匿名管道</p>
	<p>匿名管道是一个未命名的、单向管道，通常用来在一个父进程和一个子进程之间传输数据。匿名管道只能实现本地机器上的两个进程间的通信，而不能实现跨网络通信。</p>
	<p>17.3命名管道</p>
	<p>命名管道通过网络来实现进程间的通信，它屏蔽了底层的网络协议细节，在不了解网络协议的情况下也可以利用命名管道来实现进程间的通信。命名管道不仅可以在本机上实现2个进程之间的通信，还可以跨网络实现2个进程的通信。</p>
	<p>17.4邮槽</p>
	<p>邮槽式基于广播通信体系设计出来的，它采用无连接的不可靠的数据传输。邮槽是一种单向的通信机制，创建邮槽的服务器进程读取数据，打开邮槽的客户端进程写入数据。为了使邮槽在各种Windows平台下运行，传输消息的时候，应该将消息的长度限制在424字节以下。</p>
	<p>PS:后三个例子代码写不贴了。
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/23/vc-in-depth-xiangjie-study-notes-17-inter-process-communication/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(16)线程同步</title>
		<link>http://www.colsir.com/2009/12/22/vc-in-depth-xiangjie-study-notes-16-1-thread-synchronization/</link>
		<comments>http://www.colsir.com/2009/12/22/vc-in-depth-xiangjie-study-notes-16-1-thread-synchronization/#comments</comments>
		<pubDate>Tue, 22 Dec 2009 13:14:18 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=138</guid>
		<description><![CDATA[	上一章介绍了线程同步，以及利用互斥对象实现线程同步的方法。本章继续介绍另2种线程同步的方法：事件对象和关键代码段，另外，介绍了利用异步套接字编写网络应用程序的实现。
	16.1事件对象
	和互斥对象一样，时间对象也属于内核对象。事件对象分为人工重置的事件对象和自动重置的事件对象。人工重置的事件对象得到通知时，等待该事件对象的所有线程都变为可调度线程。自动重置的事件对象得到通知时，等待该事件对象的线程中只有一个变为可调度线程。
	HANDLE CreateEvent(
	
  LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
	
  BOOL bManualReset,                       // reset type
	
  BOOL bInitialState,                      // initial state
	
  LPCTSTR lpName                           // object name
	
);
	根据事件对象的声明可以了解它的一些参数属性。创建一个事件对象之后，可以通过SetEvent函数和ResetEvent函数来设置事件对象的有无信号状态。通常在单CPU平台下，为了实现线程的通过，常使用自动重置的事件对象，而非人工重置的事件对象。
	16.2关键代码段
	关键代码段：也称为临界区，工作在用户态，它是指一个小段代码，在代码能够执行前，它必须独占对某些资源的访问权。通常把多线程中访问同一种资源的那部分代码称为关键代码段。利用关键代码段实现线程同步的示例代码如下：
	#include &#60;windows.h&#62;
	
#include &#60;iostream.h&#62;
	
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
	
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
	
int ticket=100;
	
CRITICAL_SECTION g_cs;
	
void main()
	
{
	
       HANDLE hThread1;
	
       HANDLE hThread2;
	
       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
	
       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
	
       CloseHandle(hThread1);
	
       CloseHandle(hThread2);
	
       InitializeCriticalSection(&#38;g_cs);//初始化
	
       Sleep(4000);
	
       DeleteCriticalSection(&#38;g_cs);
	
}
	
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
	
{
	
       while(TRUE)
	
       {
	
              EnterCriticalSection(&#38;g_cs);//进入关键代码段
	
              Sleep(1);
	
              if(ticket&#62;0)
	
              {
	
                     Sleep(1);
	
                     cout&#60;&#60;\"thread1 sell [...]]]></description>
			<content:encoded><![CDATA[	<p>上一章介绍了线程同步，以及利用互斥对象实现线程同步的方法。本章继续介绍另2种线程同步的方法：事件对象和关键代码段，另外，介绍了利用异步套接字编写网络应用程序的实现。</p>
	<p><strong>16.1</strong><strong>事件对象</strong></p>
	<p>和互斥对象一样，时间对象也属于内核对象。事件对象分为人工重置的事件对象和自动重置的事件对象。人工重置的事件对象得到通知时，等待该事件对象的所有线程都变为可调度线程。自动重置的事件对象得到通知时，等待该事件对象的线程中只有一个变为可调度线程。</p>
	<pre class="brush: c++">HANDLE CreateEvent(
	
  LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
	
  BOOL bManualReset,                       // reset type
	
  BOOL bInitialState,                      // initial state
	
  LPCTSTR lpName                           // object name
	
);</pre>
	<p>根据事件对象的声明可以了解它的一些参数属性。创建一个事件对象之后，可以通过SetEvent函数和ResetEvent函数来设置事件对象的有无信号状态。通常在单CPU平台下，为了实现线程的通过，常使用自动重置的事件对象，而非人工重置的事件对象。</p>
	<p><strong>16.2</strong><strong>关键代码段</strong></p>
	<p>关键代码段：也称为临界区，工作在用户态，它是指一个小段代码，在代码能够执行前，它必须独占对某些资源的访问权。通常把多线程中访问同一种资源的那部分代码称为关键代码段。利用关键代码段实现线程同步的示例代码如下：</p>
	<pre class="brush: c++">#include &lt;windows.h&gt;
	
#include &lt;iostream.h&gt;
	
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
	
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
	
int ticket=100;
	
CRITICAL_SECTION g_cs;
	
void main()
	
{
	
       HANDLE hThread1;
	
       HANDLE hThread2;
	
       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
	
       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
	
       CloseHandle(hThread1);
	
       CloseHandle(hThread2);
	
       InitializeCriticalSection(&amp;g_cs);//初始化
	
       Sleep(4000);
	
       DeleteCriticalSection(&amp;g_cs);
	
}
	
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
	
{
	
       while(TRUE)
	
       {
	
              EnterCriticalSection(&amp;g_cs);//进入关键代码段
	
              Sleep(1);
	
              if(ticket&gt;0)
	
              {
	
                     Sleep(1);
	
                     cout&lt;&lt;\"thread1 sell the ticket:\"&lt;&lt;ticket--&lt;&lt;endl;
	
                     LeaveCriticalSection(&amp;g_cs);//离开
	
              }
	
              else
	
              {
	
                     LeaveCriticalSection(&amp;g_cs);//离开
	
                     break;
	
              }
	
       }
	
       return 0;
	
}
	
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
	
{
	
       while(TRUE)
	
       {
	
              EnterCriticalSection(&amp;g_cs);//进入关键代码段
	
              Sleep(1);
	
              if(ticket&gt;0)
	
              {
	
                     Sleep(1);
	
                     cout&lt;&lt;\"thread2 sell the ticket:\"&lt;&lt;ticket--&lt;&lt;endl;
	
                     LeaveCriticalSection(&amp;g_cs);//离开
	
              }
	
              else
	
              {
	
                     LeaveCriticalSection(&amp;g_cs);//离开
	
                     break;
	
              }
	
       }
	
       return 0;
	
}</pre>
	<p><strong>16.3</strong><strong>互斥对象，事件对象和关键代码段的比较</strong></p>
	<ul>
	<li>互斥对象和事件对象属于内核对象，速度较慢，但是使用这样的内核对象，可以在多个进程中的各个线程间进行同步；</li>
	<li>关键代码段工作在用户态，速度快。但是使用关键代码段时容易产生死锁，因为在等待进入关键代码段时候无法设定超时值。</li>
	</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/22/vc-in-depth-xiangjie-study-notes-16-1-thread-synchronization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(15)多线程</title>
		<link>http://www.colsir.com/2009/12/20/vc-in-depth-xiangjie-study-notes-15-multi-threaded/</link>
		<comments>http://www.colsir.com/2009/12/20/vc-in-depth-xiangjie-study-notes-15-multi-threaded/#comments</comments>
		<pubDate>Sun, 20 Dec 2009 06:33:59 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=135</guid>
		<description><![CDATA[	本章主要介绍多线程程序的编写，并利用多线程技术创建一个网络聊天室。
	15.1基本概念 
	程序是计算机指令的集合，它以文件形式存储在磁盘上。
	进程被定义为一个正在运行的程序的实例，是一个程序在其自身的地址空间中的一次执行活动。
	进程的组成：操作系统用来管理进程的内核对象和地址空间。进程不执行任何东西，它只是程序的实例，线程的容器或执行环境。创建一个进程之后，操作系统会自动为这个进程创建一个主线程（执行main或者winmain函数的线程）。
	线程是进程中的一个实体，是被系统独立调度和分派的基本单位。
	线程的组成：线程的内核对象（操作系统用来存放线程统计信息）和线程栈（维护线程在执行代码时候所需要的所有的函数和局部变量）。一个线程之后一个内核对象和一个栈。
	15.2线程创建函数
	可使用系统提供的API函数CreateThread来创建一个线程。
	该函数的原形如下：
	HANDLE CreateThread(
	
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
	
  DWORD dwStackSize,                        // initial stack size
	
  LPTHREAD_START_ROUTINE lpStartAddress,    // thread function
	
  LPVOID lpParameter,                       // thread argument
	
  DWORD dwCreationFlags,                    // creation option
	
  LPDWORD lpThreadId                        // thread identifier
	
);
	根据CreateThread函数的参数说明，可以基本了解创建一个线程的规则。
	15.3简单的多线程示例
	#include &#60;windows.h&#62;
	
#include &#60;iostream.h&#62;
	
DWORD WINAPI Function1(LPVOID lpParamete);//申明过程函数
	
void main()
	
{
	
       HANDLE hThreadl;
	
       hThreadl=CreateThread(NULL,0,Function1,NULL,0,NULL);
	
       CloseHandle(hThreadl);
	
       cout&#60;&#60;\"main thread is running\"&#60;&#60;endl;
	
       Sleep(10);//主线程执行完毕后，休眠10毫秒，启动子线程
	
}
	
DWORD WINAPI Function1(LPVOID lpParamete)
	
{
	
       cout&#60;&#60;\"thread1 is running\"&#60;&#60;endl;
	
       return [...]]]></description>
			<content:encoded><![CDATA[	<p>本章主要介绍多线程程序的编写，并利用多线程技术创建一个网络聊天室。</p>
	<p><strong>15.1</strong><strong>基本概念</strong> <strong></strong></p>
	<p><strong>程序</strong>是计算机指令的集合，它以文件形式存储在磁盘上。</p>
	<p><strong>进程</strong>被定义为一个正在运行的程序的实例，是一个程序在其自身的地址空间中的一次执行活动。</p>
	<p>进程的组成：操作系统用来管理进程的内核对象和地址空间。进程不执行任何东西，它只是程序的实例，线程的容器或执行环境。创建一个进程之后，操作系统会自动为这个进程创建一个主线程（执行main或者winmain函数的线程）。</p>
	<p><strong>线程</strong>是进程中的一个实体，是被系统独立调度和分派的基本单位。</p>
	<p>线程的组成：线程的内核对象（操作系统用来存放线程统计信息）和线程栈（维护线程在执行代码时候所需要的所有的函数和局部变量）。一个线程之后一个内核对象和一个栈。</p>
	<p><strong>15.2</strong><strong>线程创建函数</strong><strong></strong></p>
	<p>可使用系统提供的API函数CreateThread来创建一个线程。</p>
	<p>该函数的原形如下：</p>
	<pre class="brush: c++">HANDLE CreateThread(
	
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
	
  DWORD dwStackSize,                        // initial stack size
	
  LPTHREAD_START_ROUTINE lpStartAddress,    // thread function
	
  LPVOID lpParameter,                       // thread argument
	
  DWORD dwCreationFlags,                    // creation option
	
  LPDWORD lpThreadId                        // thread identifier
	
);</pre>
	<p>根据CreateThread函数的参数说明，可以基本了解创建一个线程的规则。</p>
	<p><strong>15.3</strong><strong>简单的多线程示例</strong></p>
	<pre class="brush: c++">#include &lt;windows.h&gt;
	
#include &lt;iostream.h&gt;
	
DWORD WINAPI Function1(LPVOID lpParamete);//申明过程函数
	
void main()
	
{
	
       HANDLE hThreadl;
	
       hThreadl=CreateThread(NULL,0,Function1,NULL,0,NULL);
	
       CloseHandle(hThreadl);
	
       cout&lt;&lt;\"main thread is running\"&lt;&lt;endl;
	
       Sleep(10);//主线程执行完毕后，休眠10毫秒，启动子线程
	
}
	
DWORD WINAPI Function1(LPVOID lpParamete)
	
{
	
       cout&lt;&lt;\"thread1 is running\"&lt;&lt;endl;
	
       return 0;
	
}</pre>
	<p>在创建一个线程的时候需要指定过程函数，因此需要在main函数之前申明Function1，也可以将Function1函数的实现放到main函数之前，这样就不需要声明了。</p>
	<p><strong>15.4</strong><strong>线程同步</strong></p>
	<p>操作系统为每一个运行线程安排一定的CPU时间—时间片。在一个多线程的程序中，系统通过一种循环的方式为线程提供时间片，线程在自己的时间片內运行。这就可以会出现一种情况：当多个线性同时对一个全局的对象进行访问时，一个线程已经进入了循环体，这时候时间片结束，该线程进入睡眠状态，系统转向执行另外一个线程。而当另外一个线程执行的时候对全局变量做了修改。当返回到第一个线程的时候，接着从上次时间片结束的地方执行，这时候会出现一些异常。</p>
	<pre class="brush: c++">DWORD WINAPI Function1(LPVOID lpParamete)
	
{
	
       while(true) {
	
              if(count&gt;0) {
	
                     //当线程执行到此的时候，时间片到了，线程1Sleep，开始执行线程2，当线性2完毕之后再回到线程1，接着从此处执行。这时候有可能线程count的值已经为非正常值，如：0。
	
                     cout&lt;&lt;\"thread1 sell the ticket:\"&lt;&lt;count--&lt;&lt;endl;
	
              }
	
              else
	
                     break;
	
       }
	
       return 0;
	
}
	
DWORD WINAPI Function2(LPVOID lpParamete)
	
{
	
       while(true) {
	
              if(count&gt;0)
	
              {cout&lt;&lt;\"thread2 sell the ticket:\"&lt;&lt;count--&lt;&lt;endl; }
	
              else
	
                     break;
	
       }
	
       return 0;
	
}</pre>
	<p><strong>15.4.1</strong><strong>互斥对象实现线程同步</strong></p>
	<p>互斥对象mutex属于内核对象，它能够确保线程对当资源的互斥访问权。创建互斥对象的CreateMutex函数的声明如下：</p>
	<pre class="brush: c++">HANDLE CreateMutex(
	
  LPSECURITY_ATTRIBUTES lpMutexAttributes,  // 互斥对象安全性，默认NULL
	
  BOOL bInitialOwner,                       // 指定互斥对象的拥有者，默认FALSE
	
  LPCTSTR lpName                            // 指定互斥对象的名称，默认NULL
	
);</pre>
	<p><span id="more-135"></span><br />
一个线程需要申请才能获取对一个互斥对象的所有权，等使用结束之后，需要释放对该对象的所有权。申请和释放的函数申明如下：</p>
	<pre class="brush: c++">DWORD WaitForSingleObject(
	
  HANDLE hHandle,        // 互斥对象句柄
	
  DWORD dwMilliseconds   //等待时间，默认INFINITE
	
);
	
BOOL ReleaseMutex(
	
  HANDLE hMutex   //互斥对象句柄
	
);</pre>
	<p>使用互斥对象的原则是谁拥有谁释放。使用互斥对象实现的火车售票程序的代码如下：</p>
	<pre class="brush: c++">#include &lt;windows.h&gt;
	
#include &lt;iostream.h&gt;
	
DWORD WINAPI Function1(LPVOID lpParamete);
	
DWORD WINAPI Function2(LPVOID lpParamete);
	
int count=100;
	
HANDLE hMutex;
	
void main()
	
{
	
       hMutex=CreateMutex(NULL,TRUE,NULL);//此处第二个参数设置为真相当于把互斥对象授权给主线程，因此需要在主线程中释放
	
       HANDLE hThreadl;
	
       hThreadl=CreateThread(NULL,0,Function1,NULL,0,NULL);
	
       CloseHandle(hThreadl);
	
       HANDLE hThread2;
	
       hThread2=CreateThread(NULL,0,Function2,NULL,0,NULL);
	
       CloseHandle(hThread2);
	
       ReleaseMutex(hMutex);//释放，谁拥有谁释放
	
       Sleep(4000);
	
      
	
}
	
DWORD WINAPI Function1(LPVOID lpParamete)
	
{
	
       while(true)
	
       {
	
              WaitForSingleObject(hMutex,INFINITE);
	
              if(count&gt;0)
	
              {
	
                     //Sleep(1);
	
                     cout&lt;&lt;\"thread1 sell the ticket:\"&lt;&lt;count--&lt;&lt;endl;
	
              }
	
              else
	
                     break;
	
              ReleaseMutex(hMutex);
	
       }
	
       return 0;
	
}
	
DWORD WINAPI Function2(LPVOID lpParamete)
	
{
	
       while(true)
	
       {
	
              WaitForSingleObject(hMutex,INFINITE);
	
              if(count&gt;0)
	
              {
	
                     //Sleep(1);
	
                     cout&lt;&lt;\"thread2 sell the ticket:\"&lt;&lt;count--&lt;&lt;endl;
	
              }
	
              else
	
                     break;
	
              ReleaseMutex(hMutex);
	
       }
	
       return 0;
	
}</pre>
	<p><strong>15.5</strong><strong>网络聊天室的实现</strong></p>
	<p>代码就不贴上来了。
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/20/vc-in-depth-xiangjie-study-notes-15-multi-threaded/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(14)网络编程</title>
		<link>http://www.colsir.com/2009/12/18/vc-in-depth-xiangjie-study-notes-14-network-programming/</link>
		<comments>http://www.colsir.com/2009/12/18/vc-in-depth-xiangjie-study-notes-14-network-programming/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 07:46:09 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=129</guid>
		<description><![CDATA[	网络程序的实现可以有多种方式，Windows Socket就是其中的一种比较简单的实现方式。Socket是连接应用程序和网络驱动程序的桥梁，Socket在应用程序中创建，通过绑定操作和应用程序建立连接关系。
	14.1计算机网络的基本知识
	计算机网络是相互连接的独立自主的计算机的集合，最初建立的目的是实现资源的共享。其中比较重要的概念是协议，其目的是为了进行网络中的数据交换而建立的规则、标准或约定。不同的层有不同的协议。
	14.1.1ISO/OSI七层参考模型
	OSI（Open System Interconnection）参考模型将网络的不同功能分成了七层。由高到底的分层及其功能分别如下：
	
	应用层：为用户的网络应用程序提供网络通信服务；
	表示层：处理被传输数据的表示问题，即信息的语法和语义；
	会话层：在两个相互通信的应用程序之间建立连接，组织和协调之间的通信；
	传输层：为源短主机和目的端主机提供可靠的传输服务，隔离网络的上下层协议，使得网络和上下层协议无关；
	网络层：提供IP寻址和路由，负责找到最佳的数据传输路线；
	数据链路层：提供介质访问，加强物理层的传输功能；
	物理层：提供二进制传输，确定在通信信道上如何传输比特流。
	
	七层参考模型知识一个功能上的划分，不是物理上的划分，各层之间是严格的单向依赖，通信实体的对等层之间不容许出现直接通信，下次向上层提供服务，上层使用下层提供的服务。
	14.1.2数据封装
	一台计算机向另外一台计算机发送数据，必须将该数据打包，打包的过程被称为数据封装。由应用层向下，逐步为数据进行封装，在头部或尾部或同时添加本层的头部或尾部。当数据包到达目标计算机时，再从物理层开始，逐步去除头部或尾部，完成拆分。
	14.1.3TCP/IP模型
	OSI的七层参考模型比较复杂，通常采用TCP/IP模型，该模型有四个层次与OSI七层模型的对应关系为：
	
	应用层：对应应用层+表示层+会话层；
	传输层：对应传输层；
	网络层：对应网络层；
	网络接口层：对应数据链路层+物理层。
	
	14.1.4端口
	为了标识通信实体中进行通信的进程，TCP/IP提供了协议端口的概念。端口是一种抽象的软解结构，应用程序通过系统调用和某端口建立连接后，传输层传给该端口的数据都会被相应得应用程序接收，相依进程发送给传输层的数据也通过该端口输出。（端口存在与传输层?）
	端口的范围是0~65355，1024以下的端口号通常都被系统应用程序占用。如http的80，ftp的21.
	14.1.9套接字Socket的引入
	Socket最早出现在UNIX系统中，后来被引入Windows。Windows Socket只支持一个通信区域：网际域，这个域被使用网际协议簇通信的进程使用。
	14.2Windows Socket的实现
	套接字分为三种类型，其中主要使用的由2种：
	流式套接字SOCK_STREAM：提供面向连接，可靠的传输服务，数据无差错，无重复发送，按发送顺序接收，流式套接字是基于TCP协议实现的；
	数据报式套接字SOCK_DGRAM：提供无连接服务，数据包独立发送，基于UDP协议；
	14.2.1基于TCP的socket编程
	基于TCP的socket编程的服务器端的流程如下：
	
	创建套接字socket；
	将套接字绑定到一个本地的端口上bind；
	将套接字设置为监听模式，准备接收客户端请求listen；
	等待客户端请求，当请求到达后，接受连接要求，返回一个新的对应于此连接的套接字accept；
	用返回套接字和客户端进行通信send/recv；
	返回，等待另一个请求；
	关闭套接字。
	
	示例代码如下：
	#include &#60;Winsock2.h&#62;
#include &#60;stdio.h&#62;
void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD( 2, 2 );
	err = WSAStartup( wVersionRequested, &#38;wsaData );
	if ( err != 0 ) {
		return;
	}
	if ( LOBYTE( wsaData.wVersion ) != 2 &#124;&#124;
        HIBYTE( wsaData.wVersion ) != 2 ) {
		WSACleanup( );
		return;
	}
	//create socket
	SOCKET socksrv=socket(AF_INET,SOCK_STREAM,0);
	SOCKADDR_IN addsrcv;
	addsrcv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
	addsrcv.sin_family=AF_INET;
	addsrcv.sin_port=htons(6000);
	
	//bind
	bind(socksrv,(SOCKADDR*)&#38;addsrcv,sizeof(SOCKADDR));
	//listen
	listen(socksrv,5);
	
	SOCKADDR_IN addrClient;
	int len=sizeof(SOCKADDR);
	
	while(1)
	{
		//wait [...]]]></description>
			<content:encoded><![CDATA[	<p>网络程序的实现可以有多种方式，Windows Socket就是其中的一种比较简单的实现方式。Socket是连接应用程序和网络驱动程序的桥梁，Socket在应用程序中创建，通过绑定操作和应用程序建立连接关系。</p>
	<p><strong>14.1</strong><strong>计算机网络的基本知识</strong></p>
	<p>计算机网络是相互连接的独立自主的计算机的集合，最初建立的目的是实现资源的共享。其中比较重要的概念是协议，其目的是为了进行网络中的数据交换而建立的规则、标准或约定。不同的层有不同的协议。</p>
	<p><strong>14.1.1</strong><strong>ISO/OSI</strong><strong>七层参考模型</strong><strong></strong></p>
	<p>OSI（Open System Interconnection）参考模型将网络的不同功能分成了七层。由高到底的分层及其功能分别如下：</p>
	<ol>
	<li>应用层：为用户的网络应用程序提供网络通信服务；</li>
	<li>表示层：处理被传输数据的表示问题，即信息的语法和语义；</li>
	<li>会话层：在两个相互通信的应用程序之间建立连接，组织和协调之间的通信；</li>
	<li>传输层：为源短主机和目的端主机提供可靠的传输服务，隔离网络的上下层协议，使得网络和上下层协议无关；</li>
	<li>网络层：提供IP寻址和路由，负责找到最佳的数据传输路线；</li>
	<li>数据链路层：提供介质访问，加强物理层的传输功能；</li>
	<li>物理层：提供二进制传输，确定在通信信道上如何传输比特流。</li>
	</ol>
	<p>七层参考模型知识一个功能上的划分，不是物理上的划分，各层之间是严格的单向依赖，通信实体的对等层之间不容许出现直接通信，下次向上层提供服务，上层使用下层提供的服务。</p>
	<p><strong>14.1.2</strong><strong>数据封装</strong><strong></strong></p>
	<p>一台计算机向另外一台计算机发送数据，必须将该数据打包，打包的过程被称为数据封装。由应用层向下，逐步为数据进行封装，在头部或尾部或同时添加本层的头部或尾部。当数据包到达目标计算机时，再从物理层开始，逐步去除头部或尾部，完成拆分。</p>
	<p><strong>14.1.3</strong><strong>TCP/IP</strong><strong>模型</strong><strong></strong></p>
	<p>OSI的七层参考模型比较复杂，通常采用TCP/IP模型，该模型有四个层次与OSI七层模型的对应关系为：</p>
	<ol>
	<li>应用层：对应应用层+表示层+会话层；</li>
	<li>传输层：对应传输层；</li>
	<li>网络层：对应网络层；</li>
	<li>网络接口层：对应数据链路层+物理层。</li>
	</ol>
	<p><strong>14.1.4</strong><strong>端口</strong><strong></strong></p>
	<p>为了标识通信实体中进行通信的进程，TCP/IP提供了协议端口的概念。端口是一种抽象的软解结构，应用程序通过系统调用和某端口建立连接后，传输层传给该端口的数据都会被相应得应用程序接收，相依进程发送给传输层的数据也通过该端口输出。（端口存在与传输层?）</p>
	<p>端口的范围是0~65355，1024以下的端口号通常都被系统应用程序占用。如http的80，ftp的21.</p>
	<p><strong>14.1.9</strong><strong>套接字</strong><strong>Socket</strong><strong>的引入</strong><strong></strong></p>
	<p>Socket最早出现在UNIX系统中，后来被引入Windows。Windows Socket只支持一个通信区域：网际域，这个域被使用网际协议簇通信的进程使用。</p>
	<p><strong>14.2Windows Socket</strong><strong>的实现</strong><strong></strong></p>
	<p>套接字分为三种类型，其中主要使用的由2种：</p>
	<p>流式套接字SOCK_STREAM：提供面向连接，可靠的传输服务，数据无差错，无重复发送，按发送顺序接收，流式套接字是基于TCP协议实现的；</p>
	<p>数据报式套接字SOCK_DGRAM：提供无连接服务，数据包独立发送，基于UDP协议；</p>
	<p><strong>14.2.1</strong><strong>基于</strong><strong>TCP</strong><strong>的</strong><strong>socket</strong><strong>编程</strong><strong></strong></p>
	<p>基于TCP的socket编程的服务器端的流程如下：</p>
	<ol>
	<li>创建套接字socket；</li>
	<li>将套接字绑定到一个本地的端口上bind；</li>
	<li>将套接字设置为监听模式，准备接收客户端请求listen；</li>
	<li>等待客户端请求，当请求到达后，接受连接要求，返回一个新的对应于此连接的套接字accept；</li>
	<li>用返回套接字和客户端进行通信send/recv；</li>
	<li>返回，等待另一个请求；</li>
	<li>关闭套接字。</li>
	</ol>
	<p>示例代码如下：</p>
	<pre class="brush: c++">#include &lt;Winsock2.h&gt;
#include &lt;stdio.h&gt;
void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD( 2, 2 );
	err = WSAStartup( wVersionRequested, &amp;wsaData );
	if ( err != 0 ) {
		return;
	}
	if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
		WSACleanup( );
		return;
	}
	//create socket
	SOCKET socksrv=socket(AF_INET,SOCK_STREAM,0);
	SOCKADDR_IN addsrcv;
	addsrcv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
	addsrcv.sin_family=AF_INET;
	addsrcv.sin_port=htons(6000);
	
	//bind
	bind(socksrv,(SOCKADDR*)&amp;addsrcv,sizeof(SOCKADDR));
	//listen
	listen(socksrv,5);
	
	SOCKADDR_IN addrClient;
	int len=sizeof(SOCKADDR);
	
	while(1)
	{
		//wait for client
		SOCKET sockConn=accept(socksrv,(SOCKADDR*)&amp;addrClient,&amp;len);
		char buf[100];
		sprintf(buf,\"welcome %s to www.colsir.com\",inet_ntoa(addrClient.sin_addr));
		//send
		send(sockConn,buf,strlen(buf)+1,0);
		char recvbuf[100];
		recv(sockConn,recvbuf,100,0);
		printf(\"%s\n\",recvbuf);
		closesocket(sockConn);
	}
}</pre>
	<p>基于TCP的socket编程的客户端端的流程如下：</p>
	<ol>
	<li>创建套接字 socket；</li>
	<li>向服务器发送请求connect；</li>
	<li>和服务器端进行通信send/recv;</li>
	<li>关闭套接字。</li>
	</ol>
	<p>示例代码如下：</p>
	<pre class="brush: c++">#include &lt;Winsock2.h&gt;
#include &lt;stdio.h&gt;
void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD( 2, 2 );
	err = WSAStartup( wVersionRequested, &amp;wsaData );
	if ( err != 0 ) {
		return;
	}
	if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
		WSACleanup( );
		return;
	}
	//create socket
	SOCKET sockclient=socket(AF_INET,SOCK_STREAM,0);
	SOCKADDR_IN addsrcv;
	addsrcv.sin_addr.S_un.S_addr=inet_addr(\"127.0.0.1\");
	addsrcv.sin_family=AF_INET;
	addsrcv.sin_port=htons(6000);
	
	//connect
	connect(sockclient,(SOCKADDR*)&amp;addsrcv,sizeof(SOCKADDR));
	
	//recv
	char recvbuf[100];
	recv(sockclient,recvbuf,100,0);
	printf(\"%s\n\",recvbuf);
	//send
	send(sockclient,\"send message\",strlen(\"send message\")+1,0);
	closesocket(sockclient);
	WSACleanup();
}</pre>
	<p><strong>14.2.2</strong><strong>基于</strong><strong>UDP</strong><strong>的</strong><strong>socket</strong><strong>编程</strong><strong></strong></p>
	<p>基于UDP的socket编程的服务器端的流程如下：</p>
	<ol>
	<li>创建套接字socket；</li>
	<li>将套接字绑定到一个本地地址和端口上bind；</li>
	<li>等待接收数据，接收完毕之后可以选择返回，等待再一次接收recvfrom；</li>
	<li>关闭套接字。</li>
	</ol>
	<p>示例代码如下：</p>
	<pre class="brush: c++">#include &lt;Winsock2.h&gt;
#include &lt;stdio.h&gt;
void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD( 2, 2 );
	err = WSAStartup( wVersionRequested, &amp;wsaData );
	if ( err != 0 ) {
		return;
	}
	if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
		WSACleanup( );
		return;
	}
	//create socket
	SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM/*UDP*/,0);
	SOCKADDR_IN addsrcv;
	addsrcv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
	addsrcv.sin_family=AF_INET;
	addsrcv.sin_port=htons(6000);
	
	//bind
	bind(sockSrv,(SOCKADDR*)&amp;addsrcv,sizeof(SOCKADDR));
	
	//recv
	while(1)
	{
		SOCKADDR_IN addServer;
		int len=sizeof(SOCKADDR);
		char recvbuf[100];
		recvfrom(sockSrv,recvbuf,100,0,(SOCKADDR*)&amp;addServer,&amp;len);
		printf(\"%s\n\",recvbuf);
	}
	
	closesocket(sockSrv);
	WSACleanup();
}</pre>
	<p>基于UDP的socket编程的客户端端的流程如下：</p>
	<ol>
	<li>创建套接字 socket；</li>
	<li>向服务器发送数据sendto;</li>
	<li>关闭套接字。</li>
	</ol>
	<p>示例代码如下：</p>
	<pre class="brush: c++">#include &lt;Winsock2.h&gt;
#include &lt;stdio.h&gt;
void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD( 2, 2 );
	err = WSAStartup( wVersionRequested, &amp;wsaData );
	if ( err != 0 ) {
		return;
	}
	if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
		WSACleanup( );
		return;
	}
	//create socket
	SOCKET sockclient=socket(AF_INET,SOCK_DGRAM,0);
	SOCKADDR_IN addsrcv;
	addsrcv.sin_addr.S_un.S_addr=inet_addr(\"127.0.0.1\");
	addsrcv.sin_family=AF_INET;
	addsrcv.sin_port=htons(6000);
	
	sendto(sockclient,\"hello\",strlen(\"hello\")+1,0,(SOCKADDR*)&amp;addsrcv,sizeof(SOCKADDR));
	
	closesocket(sockclient);
	WSACleanup();
}</pre>
	<p><strong>14.3</strong><strong>小结</strong><strong></strong></p>
	<p>看完了书本上的介绍，把代码照着书本抄了一遍，对于socket编程有了一个初步的认识。真正完成能实用的应用程序要有很远的路。过程中遇到的问题做个简单的小结：</p>
	<ol>
	<li>因为本程序使用了winsock库中的函数，按照动态链接库的使用规则，需要为程序链接相应的lib文件：ws2_32.lib;</li>
	<li>在创建TCP和UDP套接字的时候需要注意类型的区别，二者分别对应：SOCKET sockSrv=socket(AF_INET,SOCK_STREAM/*TCP*/,0);和SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM/*UDP*/,0);</li>
	<li>换行符为”\n”，经常不小心就给写成了”/n”</li>
	</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/18/vc-in-depth-xiangjie-study-notes-14-network-programming/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(13)文档与串行化</title>
		<link>http://www.colsir.com/2009/12/17/vc-in-depth-xiang-jie-study-notes-13-documents-and-serialization/</link>
		<comments>http://www.colsir.com/2009/12/17/vc-in-depth-xiang-jie-study-notes-13-documents-and-serialization/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 12:54:34 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=127</guid>
		<description><![CDATA[	本章首先介绍了一种新的读写文件方式，使用MFC提供的CArchive类来实现。可以利用CArchive类将对象数据保存到永久设备上。这样即使应用程序关闭，再次启动后仍然可以从磁盘上读取对象数据，然后在内存中重构相应的对象。让数据持久性的过程成为串行化或序列化。
	CArchive对象不仅可以处理基本类型的数据，还可以处理CObject类的派生对象。CArchive类重载了提取(&#62;&#62;)和插入(&#60;&#60;)操作符。通过这些重载的函数，可以利用CArchive对象完成对文件的读写操作。
	CArchive构造函数的声明如下：
	
CArchive( CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL );

	pFile：指向文件对象的指针，该文件对象是持久数据的来源或目的地；
	nMode：文件对象的标示符（load，store）读取还是存储；
	CArchive类写入数据的实例：
	
void CFileView::OnFileWrite()
{
       CFile file(\"7.txt\",CFile::modeCreate&#124;CFile::modeWrite);
       CArchive ar(&#38;file,CArchive::store);
       int i=1;
       char ch='1';
       float f=1.3f;
       CString str=\"www.colsir.com\";
       ar&#60;&#60;i&#60;&#60;ch&#60;&#60;f&#60;&#60;str;
}

	完成写入操作之后，用记事本打开7.txt，发现基本上都是乱码。这是因为CArchive对象是一种二进制流。
	CArchive类读取数据的实例：
	
void CFileView::OnFileRead()
{
       CFile file(\"7.txt\",CFile::modeRead);
       CArchive ar(&#38;file,CArchive::load);
       int i;
       char ch;
       float f;
       CString str;
       CString strResult;
       ar&#62;&#62;i&#62;&#62;ch&#62;&#62;f&#62;&#62;str;
       strResult.Format(\"%d,%c,%f,%s\",i,ch,f,str);
       MessageBox(strResult);
}

	对象读取的顺序必须和保存的顺序一致，有些搞不懂，那CArchive类还有什么优势？暂时理解不了。
	MFC新建，保存文件时的格式过滤
	在字符串表中一个ID为IDR_MAINFRAME的行，用来实现一些初始值的设置。该项的值的优先级低于OnNewDocument函数中的设置。通过查看OnNewDocument函数的申明，可以看到OnNewDocument函数是一个虚函数。
	文档串行化
	Serialize？看了半天没看懂什么意思。这两天心情有点浮躁，先平静下再补充。

]]></description>
			<content:encoded><![CDATA[	<p>本章首先介绍了一种新的读写文件方式，使用MFC提供的CArchive类来实现。可以利用CArchive类将对象数据保存到永久设备上。这样即使应用程序关闭，再次启动后仍然可以从磁盘上读取对象数据，然后在内存中重构相应的对象。让数据持久性的过程成为串行化或序列化。</p>
	<p>CArchive对象不仅可以处理基本类型的数据，还可以处理CObject类的派生对象。CArchive类重载了提取(&gt;&gt;)和插入(&lt;&lt;)操作符。通过这些重载的函数，可以利用CArchive对象完成对文件的读写操作。</p>
	<p>CArchive构造函数的声明如下：</p>
	<pre class="brush: c++">
CArchive( CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL );
</pre>
	<p>pFile：指向文件对象的指针，该文件对象是持久数据的来源或目的地；</p>
	<p>nMode：文件对象的标示符（load，store）读取还是存储；</p>
	<p>CArchive类写入数据的实例：</p>
	<pre class="brush: c++">
void CFileView::OnFileWrite()
{
       CFile file(\"7.txt\",CFile::modeCreate|CFile::modeWrite);
       CArchive ar(&amp;file,CArchive::store);
       int i=1;
       char ch='1';
       float f=1.3f;
       CString str=\"www.colsir.com\";
       ar&lt;&lt;i&lt;&lt;ch&lt;&lt;f&lt;&lt;str;
}
</pre>
	<p>完成写入操作之后，用记事本打开7.txt，发现基本上都是乱码。这是因为CArchive对象是一种二进制流。</p>
	<p>CArchive类读取数据的实例：</p>
	<pre class="brush: c++">
void CFileView::OnFileRead()
{
       CFile file(\"7.txt\",CFile::modeRead);
       CArchive ar(&amp;file,CArchive::load);
       int i;
       char ch;
       float f;
       CString str;
       CString strResult;
       ar&gt;&gt;i&gt;&gt;ch&gt;&gt;f&gt;&gt;str;
       strResult.Format(\"%d,%c,%f,%s\",i,ch,f,str);
       MessageBox(strResult);
}
</pre>
	<p>对象读取的顺序必须和保存的顺序一致，有些搞不懂，那CArchive类还有什么优势？暂时理解不了。</p>
	<p><strong>MFC</strong><strong>新建，保存文件时的格式过滤</strong><strong></strong></p>
	<p>在字符串表中一个ID为IDR_MAINFRAME的行，用来实现一些初始值的设置。该项的值的优先级低于OnNewDocument函数中的设置。通过查看OnNewDocument函数的申明，可以看到OnNewDocument函数是一个虚函数。</p>
	<p><strong>文档串行化</strong><strong></strong></p>
	<p>Serialize？看了半天没看懂什么意思。这两天心情有点浮躁，先平静下再补充。
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/17/vc-in-depth-xiang-jie-study-notes-13-documents-and-serialization/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(12)文件和注册表操作</title>
		<link>http://www.colsir.com/2009/12/16/vc-in-depth-xiang-jie-study-notes-12-file-and-registry-operations/</link>
		<comments>http://www.colsir.com/2009/12/16/vc-in-depth-xiang-jie-study-notes-12-file-and-registry-operations/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 13:54:18 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=124</guid>
		<description><![CDATA[	很多与文件操作相关的函数其参数类型都是const char*，本章首先介绍指向常量的指针const char*和指针常量char *const这两种类型的区别。
	12.1char const * 和char * const
	char const * p;
const char * p;
char * const p;
	这三个有什么不同？const char * p;和char const * p;在实现上都是一样的，定义一个指向常量的指针，由于指针指向的是一个常量，常量的值不能改变，但是可以改变指针的指向。char * const p;这是一个指针常量，也就是指针的指向不能改变，但是可以改变指针指向的值。区别指针常量和常量指针的关键看const 和* 的位置。
	12.2C语言对文件操作的支持
	C语言中，对文件的操作是利用FILE结构体实现的。
	12.2.1文件的打开
	MSDN中有一个fopen函数：
	FILE *fopen( const char *filename, const char *mode );
	其中的第一个参数是要打开的文件名称，第二个参数是打开的模式。MSDN中对打开文件的模式进行了如下的定义：
	
	
	
	r
	为读取而打开，如果文件不存在或者不能找到，函数调用失败
	
	
	w
	为写入文件而打开一个空文件，如果文件已经存在，怎清空内容
	
	
	a
	为写入打开一个文件，如果文件存在，则在尾部添加新数据，在写入之前，不会清除文件中已经有的EOF标记，如果文件不存在，新建一个文件
	
	
	r+
	打开文档用户写入操作和读取操作，文件必须存在
	
	
	w+
	为写入操作和读取操作打开一个空的文件，如果给定的文件已经存在，则清空内容
	
	
	a+
	打开文件用于读取和添加操作，在写入之前移除文件已有的EOF标记，写入之后再恢复EOF标记，如果指定文件不存在，那么先创建这个文件
	
	

	打开一个文件的实例代码如下：
	FILE *pFile=fopen(&#8220;1.txt&#8221;,&#8221;w&#8221;);//该操作返回一个FILE类型的指针
	12.2.2文件的写入
	size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
	文件写入有四个参数，分别表示：要写入的数据，以字节为单位的项的大小，写入项的最大数目，指向FILE类型的指针，该参数可以由fopen函数获取到，也就是fopen函数的返回值。写入文件的实例代码如下：
	fwrite(\"new buffer\",1,strlen(\"new buffer\"),pFile);
	由于C语言对文件操作采用缓存文件系统，从内存从磁盘写入的文件首先会被放到内存缓冲区中，只有当内存缓冲区满了或者当写入操作的文件关闭之后，才把要写入的数据存的磁盘文件上。如果要在执行写操作之后立即将数据存放到磁盘文件上，可以先调用fflush函数刷新缓冲区或者调用fclose函数将打开的文件关闭。
	12.2.3文件指针的定位
	int fseek( FILE *stream, long [...]]]></description>
			<content:encoded><![CDATA[	<p>很多与文件操作相关的函数其参数类型都是const char*，本章首先介绍指向常量的指针const char*和指针常量char *const这两种类型的区别。</p>
	<p><strong>12.1char const * </strong><strong>和char * const</strong></p>
	<pre class="brush: c++">char const * p;
const char * p;
char * const p;</pre>
	<p>这三个有什么不同？const char * p;和char const * p;在实现上都是一样的，定义一个指向常量的指针，由于指针指向的是一个常量，常量的值不能改变，但是可以改变指针的指向。char * const p;这是一个指针常量，也就是指针的指向不能改变，但是可以改变指针指向的值。区别指针常量和常量指针的关键看const 和* 的位置。</p>
	<p>12.2C语言对文件操作的支持</p>
	<p>C语言中，对文件的操作是利用FILE结构体实现的。</p>
	<p><strong>12.2.1</strong><strong>文件的打开</strong></p>
	<p>MSDN中有一个fopen函数：</p>
	<pre class="brush: c++">FILE *fopen( const char *filename, const char *mode );</pre>
	<p>其中的第一个参数是要打开的文件名称，第二个参数是打开的模式。MSDN中对打开文件的模式进行了如下的定义：</p>
	<table border="1" cellspacing="0" cellpadding="0">
	<tbody>
	<tr>
	<td width="67" valign="top">r</td>
	<td width="501" valign="top">为读取而打开，如果文件不存在或者不能找到，函数调用失败</td>
	</tr>
	<tr>
	<td width="67" valign="top">w</td>
	<td width="501" valign="top">为写入文件而打开一个空文件，如果文件已经存在，怎清空内容</td>
	</tr>
	<tr>
	<td width="67" valign="top">a</td>
	<td width="501" valign="top">为写入打开一个文件，如果文件存在，则在尾部添加新数据，在写入之前，不会清除文件中已经有的EOF标记，如果文件不存在，新建一个文件</td>
	</tr>
	<tr>
	<td width="67" valign="top">r+</td>
	<td width="501" valign="top">打开文档用户写入操作和读取操作，文件必须存在</td>
	</tr>
	<tr>
	<td width="67" valign="top">w+</td>
	<td width="501" valign="top">为写入操作和读取操作打开一个空的文件，如果给定的文件已经存在，则清空内容</td>
	</tr>
	<tr>
	<td width="67" valign="top">a+</td>
	<td width="501" valign="top">打开文件用于读取和添加操作，在写入之前移除文件已有的EOF标记，写入之后再恢复EOF标记，如果指定文件不存在，那么先创建这个文件</td>
	</tr>
	</tbody>
</table>
	<p>打开一个文件的实例代码如下：</p>
	<p>FILE *pFile=fopen(&#8220;1.txt&#8221;,&#8221;w&#8221;);//该操作返回一个FILE类型的指针</p>
	<p><strong>12.2.2</strong><strong>文件的写入</strong></p>
	<pre class="brush: c++">size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );</pre>
	<p>文件写入有四个参数，分别表示：要写入的数据，以字节为单位的项的大小，写入项的最大数目，指向FILE类型的指针，该参数可以由fopen函数获取到，也就是fopen函数的返回值。写入文件的实例代码如下：</p>
	<pre class="brush: c++">fwrite(\"new buffer\",1,strlen(\"new buffer\"),pFile);</pre>
	<p>由于C语言对文件操作采用缓存文件系统，从内存从磁盘写入的文件首先会被放到内存缓冲区中，只有当内存缓冲区满了或者当写入操作的文件关闭之后，才把要写入的数据存的磁盘文件上。如果要在执行写操作之后立即将数据存放到磁盘文件上，可以先调用fflush函数刷新缓冲区或者调用fclose函数将打开的文件关闭。</p>
	<p><strong>12.2.3</strong><strong>文件指针的定位</strong></p>
	<pre class="brush: c++">int fseek( FILE *stream, long offset, int origin );</pre>
	<p>该函数的第三个参数有三种默认的值，SEEK_CUR，SEEK_END，SEEK_SET，实际上是三个宏定义值，在STDIO.h文件中可以看到它们的值分别是1，2，0。分别表示定位到文件的当前位置，结束位置和开始位置。</p>
	<pre class="brush: c++">fseek(pFile,0,SEEK_SET);
fwrite(\"haha\",1,strlen(\"haha\"),pFile);</pre>
	<p>将指针定位到已经打开的文件的其实位置，并写入新的数据。完成此操作时候会发现文件中起始位置的四个字符已经被替换掉了。<em>尝试了下改变文件的打开模式，但是都不能实现</em><em>a+b</em><em>的效果。</em></p>
	<p><strong>12.2.3</strong><strong>文件的读取</strong></p>
	<pre class="brush: c++">size_t fread( void *buffer, size_t size, size_t count, FILE *stream );</pre>
	<p>由于C语言中字符串是以”\0”符号结束的。在显示字符串的时候，系统会寻找”\0”字符，因此在写入数据的时候需要在结尾添加一个”\0”，在读取数据的时候，可以动态创建一个数据长度+1的字符数组，然后将最后一个元素设置为”\0”。</p>
	<p>写入文件时：</p>
	<pre class="brush: c++">void CFileView::OnFileRead()
{
       // TODO: Add your command handler code here
       FILE *pFile=fopen(\"1.txt\",\"w\");
       //fwrite(\"new buffer\",1,strlen(\"new buffer\"),pFile);
       char buf[22]=\"www.colsir.com\";
       buf[21]='\0';
       fwrite(buf,1,22,pFile);
       fclose(pFile);
}</pre>
	<p>读取文件时：</p>
	<pre class="brush: c++">void CFileView::OnFileWrite()
{
       // TODO: Add your command handler code here
       FILE *pFile=fopen(\"1.txt\",\"r\");
       char *pbuf;
       fseek(pFile,0,SEEK_END); //为了获取数据的长度，将指针指向文件的末尾
       int len=ftell(pFile);
       pbuf =new char[len+1];
       //rewind(pFile); //下同fseek(pFile,0,SEEK_SET);
       fseek(pFile,0,SEEK_SET); //读取数据前，需要将指针再指回起始位置
       fread(pbuf,1,len,pFile);
       pbuf [len]='\0';
       fclose(pFile);
       MessageBox(pbuf);
}</pre>
	<p><strong>12.2.3</strong><strong>二进制文件和文本文件</strong></p>
	<p>字太多，有点啰嗦，不写了，慢慢体会。</p>
	<p><strong>12.3C</strong><strong>++</strong><strong>对文件操作的支持</strong></p>
	<pre class="brush: c++">void CFileView::OnFileWrite()//写入
{
       ofstream ofs(\"3.txt\");
       ofs.write(\"www.colsir.com\",strlen(\"www.colsir.com\"));
       ofs.close();
}
void CFileView::OnFileRead() //读取
{
       // TODO: Add your command handler code here
       ifstream ifs(\"3.txt\");
       char buf[100];
       memset(buf,0,100);
       ifs.read(buf,100);
       ifs.close();
       MessageBox(buf);
}</pre>
	<p><strong>12.4Win32 API</strong><strong>对文件操作的支持</strong></p>
	<pre class="brush: c++">void CFileView::OnFileWrite()//写入
{
       HANDLE hFile;
       hFile=CreateFile(\"4.txt\",GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
       DWORD dwWrites;
       WriteFile(hFile,\"www.colsir.com\",strlen(\"www.colsir.com\"),&amp;dwWrites,NULL);
       CloseHandle(hFile);
}
void CFileView::OnFileRead()//读取
{
       // TODO: Add your command handler code here
       HANDLE hFile;
       hFile=CreateFile(\"4.txt\",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
       char buf[100];
       DWORD dwWrites;
       ReadFile(hFile,buf,100,&amp;dwWrites,NULL);
       buf[dwWrites]=0;
       CloseHandle(hFile);
       MessageBox(buf);
}</pre>
	<p><strong>12.5MFC</strong><strong>对文件操作的支持</strong></p>
	<p>MFC中提供的支持文件操作的基类是：CFile，该类提供了没有缓存的二进制格式的磁盘文件输入输出功能，通过其派生类能够间接的支持文本文件和内存文件。</p>
	<p>利用MFC的CFile类实现文件写入操作：</p>
	<pre class="brush: c++">void CFileView::OnFileWrite()
{
       CFile file(\"5.txt\",CFile::modeCreate|CFile::modeWrite);
       file.Write(\"www.colsir.com\",strlen(\"www.colsir.com\"));
       file.Close();
}</pre>
	<p>利用MFC的CFile类实现文件读取操作：</p>
	<pre class="brush: c++">void CFileView::OnFileRead()
{
       CFile file(\"5.txt\",CFile::modeRead);
       char *pBuf;
       DWORD dwFileLen;
       dwFileLen=file.GetLength();
       pBuf=new char[dwFileLen+1];
       pBuf[dwFileLen]=0;
       file.Read(pBuf,dwFileLen);
       file.Close();
       MessageBox(pBuf);
}</pre>
	<p><strong>12.5</strong><strong>注册表操作</strong></p>
	<p>注册表存储在二进制文件中，Win32 API提供了大量的函数以便应用程序访问注册表。</p>
	<p>1、  创建键：RegCreateKey</p>
	<p>2、  打开键：RegOpenKey</p>
	<p>3、  写入注册表：RegSetValue(默认REG_SZ类型)，RegSetValueEx（其他类型）</p>
	<p>4、  由注册表中读数据：RegQueryValue(默认REG_SZ类型)，RegQueryValue Ex（其他类型）</p>
	<pre class="brush: c++">void CFileView::OnRegWrite()
{
       HKEY hKey;
       RegCreateKey(HKEY_LOCAL_MACHINE,\"SoftWare\\www.colsir.com\\admin\",&amp;hKey);
       RegSetValue(hKey,NULL,REG_SZ,\"pan\",strlen(\"pan\"));
       RegCloseKey(hKey);
}
void CFileView::OnRegRead()
{
       LONG lValue;
       RegQueryValue(HKEY_LOCAL_MACHINE,\"SoftWare\\www.colsir.com\\admin\",NULL,&amp;lValue);
       char *pBuf=new char[lValue];
       RegQueryValue(HKEY_LOCAL_MACHINE,\"SoftWare\\www.colsir.com\\admin\",pBuf,&amp;lValue);
       MessageBox(pBuf);
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/16/vc-in-depth-xiang-jie-study-notes-12-file-and-registry-operations/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(11)绘图的保存与重绘</title>
		<link>http://www.colsir.com/2009/12/16/vc-in-depth-xiang-jie-study-notes-11-preservation-and-redraw-the-drawing/</link>
		<comments>http://www.colsir.com/2009/12/16/vc-in-depth-xiang-jie-study-notes-11-preservation-and-redraw-the-drawing/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 13:46:45 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=122</guid>
		<description><![CDATA[	看了书本上的内容，太多啰嗦，没耐心看，先放过，等兴趣来了再整理吧。

]]></description>
			<content:encoded><![CDATA[	<p>看了书本上的内容，太多啰嗦，没耐心看，先放过，等兴趣来了再整理吧。
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/16/vc-in-depth-xiang-jie-study-notes-11-preservation-and-redraw-the-drawing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>《VC++深入详解–学习笔记》(10)绘图控制</title>
		<link>http://www.colsir.com/2009/12/15/vc-in-depth-xiangjie-study-notes-10-drawing-control/</link>
		<comments>http://www.colsir.com/2009/12/15/vc-in-depth-xiangjie-study-notes-10-drawing-control/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 00:52:05 +0000</pubDate>
		<dc:creator>panmaoru</dc:creator>
				<category><![CDATA[VC++ 学习笔记]]></category>

		<guid isPermaLink="false">http://www.colsir.com/?p=119</guid>
		<description><![CDATA[	在软件的运行过程中，用户可以根据软件提供的设置对话框，颜色对话框和字体对话框等用户接口来对软件进行制定。本章主要介绍对图形绘制的制定，此外，也介绍了如何获取对话框的返回值。
	10.1获取一个对话框的返回值
	创建一个Setting对话框，在View类中添加Commad消息响应函数。然后再Setting对话框类中添加一个public变量m_nWidth。
在View中添加一个变量m_nWidth1，然后就可以设置和获取对话框的变量值了。
	
//#include \"SettingDlg.h\"
void CGraphicView::OnSetting()
{
	// TODO: Add your command handler code here
	CSettingDlg dlg;
	dlg.m_nWidth=m_nWidth1;
	if(IDOK==dlg.DoModal())
	{
		m_nWidth1=dlg.m_nWidth;
	}
}
	10.2获取颜色对话框的值
	MFC为我们提供了一个颜色对话框类CColorDialog，可以在View类中直接创建该类对象。为了设置和获取颜色对话框的RGB默认值，需要在View类中建一个COLORREF类型变量。
	
void CGraphicView::OnColor()
{
	// TODO: Add your command handler code here
	CColorDialog dlg;
	dlg.m_cc.rgbResult=m_ccr;// m_cc为一个COLORREF变量
	dlg.m_cc.Flags&#124;=CC_RGBINIT;
	if(IDOK==dlg.DoModal())
	{
		m_ccr=dlg.m_cc.rgbResult;
	}
}
	10.3获取字体对话框的值
	MFC同样为我们提供了一个字体对话框类CFontDialog，可以在View类中直接创建该类对象。为了获取字体对话框的值，需要在View类中建一个CFont类型变量。
	
void CGraphicView::OnFont()
{
	// TODO: Add your command handler code here
	CFontDialog dlg;
	if(IDOK==dlg.DoModal())
	{
		// m_font为一个CFont变量
		if(m_font.m_hObject)// 判断m_font是否已经和某个字体资源相关联了
			m_font.DeleteObject();//如果已经关联，删除关联资源
		m_font.CreateFontIndirect(dlg.m_cf.lpLogFont);
		m_strFontName=dlg.m_cf.lpLogFont->lfFaceName;
	}
}
	10.4绘图
	设置绘图的一些参数之后，便可以开始实现绘图。将设置的一些参数选择到画笔，并完成相应的图像绘制。
	
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
   CClientDC dc(this);
   CPen pen(m_nLineStyle,m_nWidth,m_ccr);
   dc.SelectObject(&#038;pen);
   CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//透明画刷
   dc.SelectObject(pBrush);
  [...]]]></description>
			<content:encoded><![CDATA[	<p>在软件的运行过程中，用户可以根据软件提供的设置对话框，颜色对话框和字体对话框等用户接口来对软件进行制定。本章主要介绍对图形绘制的制定，此外，也介绍了如何获取对话框的返回值。</p>
	<p><strong>10.1获取一个对话框的返回值</strong></p>
	<p>创建一个Setting对话框，在View类中添加Commad消息响应函数。然后再Setting对话框类中添加一个public变量m_nWidth。<br />
在View中添加一个变量m_nWidth1，然后就可以设置和获取对话框的变量值了。</p>
	<pre class="brush: c++">
//#include \"SettingDlg.h\"
void CGraphicView::OnSetting()
{
	// TODO: Add your command handler code here
	CSettingDlg dlg;
	dlg.m_nWidth=m_nWidth1;
	if(IDOK==dlg.DoModal())
	{
		m_nWidth1=dlg.m_nWidth;
	}
}</pre>
	<p><strong>10.2获取颜色对话框的值</strong></p>
	<p>MFC为我们提供了一个颜色对话框类CColorDialog，可以在View类中直接创建该类对象。为了设置和获取颜色对话框的RGB默认值，需要在View类中建一个COLORREF类型变量。</p>
	<pre class="brush: c++">
void CGraphicView::OnColor()
{
	// TODO: Add your command handler code here
	CColorDialog dlg;
	dlg.m_cc.rgbResult=m_ccr;// m_cc为一个COLORREF变量
	dlg.m_cc.Flags|=CC_RGBINIT;
	if(IDOK==dlg.DoModal())
	{
		m_ccr=dlg.m_cc.rgbResult;
	}
}</pre>
	<p><strong>10.3获取字体对话框的值</strong></p>
	<p>MFC同样为我们提供了一个字体对话框类CFontDialog，可以在View类中直接创建该类对象。为了获取字体对话框的值，需要在View类中建一个CFont类型变量。</p>
	<pre class="brush: c++">
void CGraphicView::OnFont()
{
	// TODO: Add your command handler code here
	CFontDialog dlg;
	if(IDOK==dlg.DoModal())
	{
		// m_font为一个CFont变量
		if(m_font.m_hObject)// 判断m_font是否已经和某个字体资源相关联了
			m_font.DeleteObject();//如果已经关联，删除关联资源
		m_font.CreateFontIndirect(dlg.m_cf.lpLogFont);
		m_strFontName=dlg.m_cf.lpLogFont->lfFaceName;
	}
}</pre>
	<p><strong>10.4绘图</strong></p>
	<p>设置绘图的一些参数之后，便可以开始实现绘图。将设置的一些参数选择到画笔，并完成相应的图像绘制。</p>
	<pre class="brush: c++">
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
   CClientDC dc(this);
   CPen pen(m_nLineStyle,m_nWidth,m_ccr);
   dc.SelectObject(&#038;pen);
   CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//透明画刷
   dc.SelectObject(pBrush);
   //画点
   dc.SetPixel(point,m_ccr);
   //画线
   dc.MoveTo(m_pOrigin);
   dc.LineTo(point);
   //画矩形
   dc.Rectangle(CRect(m_pOrigin,point));
    //画椭圆
   dc.Ellipse(CRect(m_pOrigin,point));
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.colsir.com/2009/12/15/vc-in-depth-xiangjie-study-notes-10-drawing-control/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
