﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-To Be C++</title><link>http://www.cppblog.com/shaker/</link><description>shaker's Blog&lt;br&gt;生当作人杰，死亦为鬼雄，至今思项羽，不肯过江东。</description><language>zh-cn</language><lastBuildDate>Fri, 13 Mar 2026 01:16:41 GMT</lastBuildDate><pubDate>Fri, 13 Mar 2026 01:16:41 GMT</pubDate><ttl>60</ttl><item><title>Neocs</title><link>http://www.cppblog.com/shaker/archive/2014/04/08/206508.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Tue, 08 Apr 2014 15:13:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2014/04/08/206508.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/206508.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2014/04/08/206508.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/206508.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/206508.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: <script src='http://git.oschina.net/shaker/neocs/widget_preview'></script> <br><style> .pro_name a{color: #4183c4;} .osc_git_title{background-color: #d8e5f1;} .osc_git_box{background-color: #fafafa;} .osc_git_box{border-color: #ddd;} .osc_git_info{color: #666;} .osc_git_main a{color: #4183c4;} </style>&nbsp;&nbsp;<a href='http://www.cppblog.com/shaker/archive/2014/04/08/206508.html'>阅读全文</a><img src ="http://www.cppblog.com/shaker/aggbug/206508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2014-04-08 23:13 <a href="http://www.cppblog.com/shaker/archive/2014/04/08/206508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Relocate SVN</title><link>http://www.cppblog.com/shaker/archive/2011/12/28/162978.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Wed, 28 Dec 2011 05:59:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/12/28/162978.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/162978.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/12/28/162978.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/162978.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/162978.html</trackback:ping><description><![CDATA[自己搞点小东西用的到。<br />在工程的根目录里建一个svn目录，然后在svn目录里创建一个版本库，用svn检出一下。<br />这样这个工程就可以被svn管理了。<br />但是如果整个工程被移动过了，那么svn就会出错，于是写了个小程序来重定位，从此可以把工程放在u盘带着到处跑了。<br /><div>
<div>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp; 1</span>&nbsp;#include&nbsp;"stdafx.h"<br />
<span style="color: #008080; ">&nbsp;&nbsp;2</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;&nbsp;3</span>&nbsp;<span style="color: #0000FF; ">using</span>&nbsp;<span style="color: #0000FF; ">namespace</span>&nbsp;std;<br />
<span style="color: #008080; ">&nbsp;&nbsp;4</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;&nbsp;5</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;AlertError(DWORD&nbsp;err)<br />
<span style="color: #008080; ">&nbsp;&nbsp;6</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPVOID&nbsp;lpMsgBuf;<br />
<span style="color: #008080; ">&nbsp;&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPVOID&nbsp;lpDisplayBuf;<br />
<span style="color: #008080; ">&nbsp;&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FormatMessage(<br />
<span style="color: #008080; ">&nbsp;11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FORMAT_MESSAGE_ALLOCATE_BUFFER&nbsp;|&nbsp;<br />
<span style="color: #008080; ">&nbsp;12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FORMAT_MESSAGE_FROM_SYSTEM&nbsp;|<br />
<span style="color: #008080; ">&nbsp;13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FORMAT_MESSAGE_IGNORE_INSERTS,<br />
<span style="color: #008080; ">&nbsp;14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,<br />
<span style="color: #008080; ">&nbsp;15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err,<br />
<span style="color: #008080; ">&nbsp;16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAKELANGID(LANG_NEUTRAL,&nbsp;SUBLANG_DEFAULT),<br />
<span style="color: #008080; ">&nbsp;17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(LPTSTR)&nbsp;&amp;lpMsgBuf,<br />
<span style="color: #008080; ">&nbsp;18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0,&nbsp;NULL&nbsp;);<br />
<span style="color: #008080; ">&nbsp;19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpDisplayBuf&nbsp;=&nbsp;(LPVOID)LocalAlloc(LMEM_ZEROINIT,&nbsp;<br />
<span style="color: #008080; ">&nbsp;21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strlen((<span style="color: #0000FF; ">char</span>*)lpMsgBuf)&nbsp;+&nbsp;40);&nbsp;<br />
<span style="color: #008080; ">&nbsp;22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sprintf((<span style="color: #0000FF; ">char</span>*)lpDisplayBuf,"错误码:&nbsp;%d\n信　息:&nbsp;%s",&nbsp;err,lpMsgBuf);<br />
<span style="color: #008080; ">&nbsp;23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,&nbsp;(LPCTSTR)lpDisplayBuf,&nbsp;"错误",&nbsp;MB_OK|MB_ICONERROR);&nbsp;<br />
<span style="color: #008080; ">&nbsp;24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocalFree(lpMsgBuf);<br />
<span style="color: #008080; ">&nbsp;26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocalFree(lpDisplayBuf);<br />
<span style="color: #008080; ">&nbsp;27</span>&nbsp;}<br />
<span style="color: #008080; ">&nbsp;28</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;29</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;GetCommandOutput(<span style="color: #0000FF; ">char</span>*&nbsp;CmdLine,&nbsp;<span style="color: #0000FF; ">string</span>&amp;&nbsp;strOutput,&nbsp;<span style="color: #0000FF; ">bool</span>&nbsp;IncludeErr=<span style="color: #0000FF; ">false</span>)<br />
<span style="color: #008080; ">&nbsp;30</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strOutput="";<br />
<span style="color: #008080; ">&nbsp;32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SECURITY_ATTRIBUTES&nbsp;&nbsp;sa;<br />
<span style="color: #008080; ">&nbsp;33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hRead,&nbsp;hWrite;<br />
<span style="color: #008080; ">&nbsp;34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(&amp;sa,0,<span style="color: #0000FF; ">sizeof</span>(sa));<br />
<span style="color: #008080; ">&nbsp;35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sa.nLength=<span style="color: #0000FF; ">sizeof</span>(sa);<br />
<span style="color: #008080; ">&nbsp;36</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sa.bInheritHandle=TRUE;<br />
<span style="color: #008080; ">&nbsp;37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sa.lpSecurityDescriptor=NULL;<br />
<span style="color: #008080; ">&nbsp;38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(CreatePipe(&amp;hRead,&amp;hWrite,&amp;sa,0))<br />
<span style="color: #008080; ">&nbsp;39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">&nbsp;40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STARTUPINFO&nbsp;si;<br />
<span style="color: #008080; ">&nbsp;41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(&amp;si,0,<span style="color: #0000FF; ">sizeof</span>(si));<br />
<span style="color: #008080; ">&nbsp;42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.cb=<span style="color: #0000FF; ">sizeof</span>(si);<br />
<span style="color: #008080; ">&nbsp;43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.hStdOutput=hWrite;<br />
<span style="color: #008080; ">&nbsp;44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.hStdInput=GetStdHandle(STD_INPUT_HANDLE);<br />
<span style="color: #008080; ">&nbsp;45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.hStdError=(IncludeErr?hWrite:GetStdHandle(STD_ERROR_HANDLE));<br />
<span style="color: #008080; ">&nbsp;46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;<br />
<span style="color: #008080; ">&nbsp;47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.wShowWindow=SW_HIDE;<br />
<span style="color: #008080; ">&nbsp;48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PROCESS_INFORMATION&nbsp;pi;<br />
<span style="color: #008080; ">&nbsp;50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(CreateProcess(NULL,CmdLine,&amp;sa,&amp;sa,TRUE,CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS,<br />
<span style="color: #008080; ">&nbsp;51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,NULL,&amp;si,&amp;pi))<br />
<span style="color: #008080; ">&nbsp;52</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">&nbsp;53</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;szBuf[512];<br />
<span style="color: #008080; ">&nbsp;54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwReaded;<br />
<span style="color: #008080; ">&nbsp;55</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(WaitForSingleObject(pi.hProcess,INFINITE)!=WAIT_TIMEOUT)<br />
<span style="color: #008080; ">&nbsp;56</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">&nbsp;57</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hWrite);<br />
<span style="color: #008080; ">&nbsp;58</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(ReadFile(hRead,szBuf,511,&amp;dwReaded,NULL))<br />
<span style="color: #008080; ">&nbsp;59</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">&nbsp;60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szBuf[dwReaded]='\0';<br />
<span style="color: #008080; ">&nbsp;61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strOutput+=szBuf;<br />
<span style="color: #008080; ">&nbsp;62</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;63</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;64</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />
<span style="color: #008080; ">&nbsp;65</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">&nbsp;66</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;"WaitForSingleObject错误;"&lt;&lt;endl;<br />
<span style="color: #008080; ">&nbsp;67</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hWrite);<br />
<span style="color: #008080; ">&nbsp;68</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AlertError(GetLastError());<br />
<span style="color: #008080; ">&nbsp;69</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;70</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(pi.hThread);<br />
<span style="color: #008080; ">&nbsp;71</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(pi.hProcess);<br />
<span style="color: #008080; ">&nbsp;72</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;73</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />
<span style="color: #008080; ">&nbsp;74</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">&nbsp;75</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;"建立进程错误;"&lt;&lt;endl;<br />
<span style="color: #008080; ">&nbsp;76</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AlertError(GetLastError());<br />
<span style="color: #008080; ">&nbsp;77</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;78</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hRead);<br />
<span style="color: #008080; ">&nbsp;79</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;80</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />
<span style="color: #008080; ">&nbsp;81</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">&nbsp;82</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;"建立管道错误;"&lt;&lt;endl;<br />
<span style="color: #008080; ">&nbsp;83</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AlertError(GetLastError());<br />
<span style="color: #008080; ">&nbsp;84</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;85</span>&nbsp;}<br />
<span style="color: #008080; ">&nbsp;86</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;87</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;APIENTRY&nbsp;WinMain(HINSTANCE&nbsp;hInstance,<br />
<span style="color: #008080; ">&nbsp;88</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HINSTANCE&nbsp;hPrevInstance,<br />
<span style="color: #008080; ">&nbsp;89</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPSTR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpCmdLine,<br />
<span style="color: #008080; ">&nbsp;90</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCmdShow)<br />
<span style="color: #008080; ">&nbsp;91</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;92</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;szBuf[MAX_PATH+20];<br />
<span style="color: #008080; ">&nbsp;93</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wchar_t&nbsp;wcBuf[MAX_PATH];<br />
<span style="color: #008080; ">&nbsp;94</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i,&nbsp;j;<br />
<span style="color: #008080; ">&nbsp;95</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">string</span>&nbsp;msg;<br />
<span style="color: #008080; ">&nbsp;96</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;97</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetCommandOutput("svn&nbsp;info&nbsp;--xml",msg);<br />
<span style="color: #008080; ">&nbsp;98</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TiXmlDocument&nbsp;*doc&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;TiXmlDocument();<br />
<span style="color: #008080; ">&nbsp;99</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doc-&gt;Parse(msg.c_str());<br />
<span style="color: #008080; ">100</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TiXmlNode&nbsp;*node;<br />
<span style="color: #008080; ">101</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node=doc-&gt;FirstChild("info");<br />
<span style="color: #008080; ">102</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(node==NULL)<br />
<span style="color: #008080; ">103</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">104</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"当前目录没有被SVN","结果",MB_OK|MB_ICONINFORMATION);<br />
<span style="color: #008080; ">105</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">106</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">107</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node=node-&gt;FirstChild("entry");<br />
<span style="color: #008080; ">108</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(node==NULL)<br />
<span style="color: #008080; ">109</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">110</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"当前目录没有被SVN","结果",MB_OK|MB_ICONINFORMATION);<br />
<span style="color: #008080; ">111</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">112</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">113</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node=node-&gt;FirstChild("wc-info");<br />
<span style="color: #008080; ">114</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(node==NULL)<br />
<span style="color: #008080; ">115</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">116</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"当前目录没有被SVN","结果",MB_OK|MB_ICONINFORMATION);<br />
<span style="color: #008080; ">117</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">118</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">119</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node=node-&gt;FirstChild("wcroot-abspath");<br />
<span style="color: #008080; ">120</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(node==NULL)<br />
<span style="color: #008080; ">121</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">122</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"当前目录没有被SVN","结果",MB_OK|MB_ICONINFORMATION);<br />
<span style="color: #008080; ">123</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">124</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">125</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(szBuf,node-&gt;ToElement()-&gt;GetText());<br />
<span style="color: #008080; ">126</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;node;<br />
<span style="color: #008080; ">127</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;doc;<br />
<span style="color: #008080; ">128</span>&nbsp;<br />
<span style="color: #008080; ">129</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j=strlen(szBuf);<br />
<span style="color: #008080; ">130</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i=MultiByteToWideChar(CP_UTF8,0,szBuf,j,wcBuf,MAX_PATH);<br />
<span style="color: #008080; ">131</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wcBuf[i]=static_cast&lt;wchar_t&gt;(0);<br />
<span style="color: #008080; ">132</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(szBuf,"svn&nbsp;relocate&nbsp;file:///");<br />
<span style="color: #008080; ">133</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j=strlen(szBuf);<br />
<span style="color: #008080; ">134</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i=WideCharToMultiByte(CP_ACP,0,wcBuf,i,&amp;szBuf[j],MAX_PATH,NULL,NULL);<br />
<span style="color: #008080; ">135</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szBuf[i+j]=static_cast&lt;<span style="color: #0000FF; ">char</span>&gt;(0);<br />
<span style="color: #008080; ">136</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetCurrentDirectory(&amp;szBuf[j]);<br />
<span style="color: #008080; ">137</span>&nbsp;<br />
<span style="color: #008080; ">138</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i+=j;<br />
<span style="color: #008080; ">139</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>((szBuf[i-1]=='\\')||(szBuf[i-1]=='/'))<br />
<span style="color: #008080; ">140</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat(szBuf,"svn/");<br />
<span style="color: #008080; ">141</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />
<span style="color: #008080; ">142</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat(szBuf,"/svn/");<br />
<span style="color: #008080; ">143</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(i=0,j=strlen(szBuf);i&lt;j;i++)<br />
<span style="color: #008080; ">144</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<span style="color: #008080; ">145</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(szBuf[i]=='\\')<br />
<span style="color: #008080; ">146</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szBuf[i]='/';<br />
<span style="color: #008080; ">147</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">148</span>&nbsp;<br />
<span style="color: #008080; ">149</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetCommandOutput(szBuf,msg,<span style="color: #0000FF; ">true</span>);<br />
<span style="color: #008080; ">150</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,msg.c_str(),"结果",MB_OK);<br />
<span style="color: #008080; ">151</span>&nbsp;<br />
<span style="color: #008080; ">152</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">153</span>&nbsp;}</div>
</div>
</div><img src ="http://www.cppblog.com/shaker/aggbug/162978.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-12-28 13:59 <a href="http://www.cppblog.com/shaker/archive/2011/12/28/162978.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LISTVIEW_LButtonDown</title><link>http://www.cppblog.com/shaker/archive/2011/09/15/155890.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Thu, 15 Sep 2011 13:45:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/09/15/155890.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/155890.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/09/15/155890.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/155890.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/155890.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/shaker/archive/2011/09/15/155890.html'>阅读全文</a><img src ="http://www.cppblog.com/shaker/aggbug/155890.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-09-15 21:45 <a href="http://www.cppblog.com/shaker/archive/2011/09/15/155890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>又是一个APIHOOK</title><link>http://www.cppblog.com/shaker/archive/2011/07/31/152142.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Sun, 31 Jul 2011 07:21:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/07/31/152142.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/152142.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/07/31/152142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/152142.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/152142.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: API Hook&nbsp;&nbsp;<a href='http://www.cppblog.com/shaker/archive/2011/07/31/152142.html'>阅读全文</a><img src ="http://www.cppblog.com/shaker/aggbug/152142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-07-31 15:21 <a href="http://www.cppblog.com/shaker/archive/2011/07/31/152142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt] Windows APC机制</title><link>http://www.cppblog.com/shaker/archive/2011/05/05/145733.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Thu, 05 May 2011 04:09:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/05/05/145733.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/145733.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/05/05/145733.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/145733.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/145733.html</trackback:ping><description><![CDATA[<p>异步过程调用(APCs) 是NT异步处理体系结构中的一个基础部分，理解了它，对于了解NT怎样操作和执行几个核心的系统操作很有帮助。</p>
<p>1) APCs允许用户程序和系统元件在一个进程的地址空间内某个线程的上下文中执行代码。<br>2) I/O管理器使用APCs来完成一个线程发起的异步的I/O操作。例如：当一个设备驱动调用IoCompleteRequest来通知I/O管理器，它已经结束处理一个异步I/O请求时，I/O管理器排队一个apc到发起请求的线程。然后线程在一个较低IRQL级别，来执行APC. APC的作用是从系统空间拷贝I/O操作结果和状态信息到线程虚拟内存空间的一个缓冲中。<br>3) 使用APC可以得到或者设置一个线程的上下文和挂起线程的执行。</p>
<p>上面是网上找来的，下面是MSDN上的说明：</p>
<p><br>An asynchronous procedure call (APC) is a function that executes asynchronously in the context of a particular thread. When an APC is queued to a thread, the system issues a software interrupt. The next time the thread is scheduled, it will run the APC function. An APC generated by the system is called a kernel-mode APC. An APC generated by an application is called a user-mode APC. A thread must be in an alertable state to run a user-mode APC.</p>
<p>Each thread has its own APC queue. An application queues an APC to a thread by calling the QueueUserAPC function. The calling thread specifies the address of an APC function in the call to QueueUserAPC. The queuing of an APC is a request for the thread to call the APC function.</p>
<p>还先看一下那些重要结构：</p>
<p>kd&gt; dt KTHREAD<br>nt!KTHREAD<br>+0x000 Header : _DISPATCHER_HEADER<br>+0x010 MutantListHead : _LIST_ENTRY<br>+0x018 InitialStack : Ptr32 Void<br>+0x01c StackLimit : Ptr32 Void<br>+0x020 KernelStack : Ptr32 Void<br>+0x024 ThreadLock : Uint4B<br>+0x028 ApcState : _KAPC_STATE<br>+0x028 ApcStateFill : [23] UChar<br>+0x03f ApcQueueable : UChar<br>+0x040 NextProcessor : UChar<br>+0x041 DeferredProcessor : UChar<br>+0x042 AdjustReason : UChar<br>+0x043 AdjustIncrement : Char<br>+0x044 ApcQueueLock : Uint4B<br>+0x048 ContextSwitches : Uint4B<br>+0x04c State : UChar<br>+0x04d NpxState : UChar<br>+0x04e WaitIrql : UChar<br>+0x04f WaitMode : Char<br>+0x050 WaitStatus : Int4B<br>+0x054 WaitBlockList : Ptr32 _KWAIT_BLOCK<br>+0x054 GateObject : Ptr32 _KGATE<br>+0x058 Alertable : UChar<br>+0x059 WaitNext : UChar<br>+0x05a WaitReason : UChar<br>+0x05b Priority : Char<br>+0x05c EnableStackSwap : UChar<br>+0x05d SwapBusy : UChar<br>+0x05e Alerted : [2] UChar<br>+0x060 WaitListEntry : _LIST_ENTRY<br>+0x060 SwapListEntry : _SINGLE_LIST_ENTRY<br>+0x068 Queue : Ptr32 _KQUEUE<br>+0x06c WaitTime : Uint4B<br>+0x070 KernelApcDisable : Int2B<br>+0x072 SpecialApcDisable : Int2B<br>+0x070 CombinedApcDisable : Uint4B<br>+0x074 Teb : Ptr32 Void<br>+0x078 Timer : _KTIMER<br>+0x078 TimerFill : [40] UChar<br>+0x0a0 AutoAlignment : Pos 0, 1 Bit<br>+0x0a0 DisableBoost : Pos 1, 1 Bit<br>+0x0a0 ReservedFlags : Pos 2, 30 Bits<br>+0x0a0 ThreadFlags : Int4B<br>+0x0a8 WaitBlock : [4] _KWAIT_BLOCK<br>+0x0a8 WaitBlockFill0 : [23] UChar<br>+0x0bf SystemAffinityActive : UChar<br>+0x0a8 WaitBlockFill1 : [47] UChar<br>+0x0d7 PreviousMode : Char<br>+0x0a8 WaitBlockFill2 : [71] UChar<br>+0x0ef ResourceIndex : UChar<br>+0x0a8 WaitBlockFill3 : [95] UChar<br>+0x107 LargeStack : UChar<br>+0x108 QueueListEntry : _LIST_ENTRY<br>+0x110 TrapFrame : Ptr32 _KTRAP_FRAME<br>+0x114 CallbackStack : Ptr32 Void<br>+0x118 ServiceTable : Ptr32 Void<br>+0x11c ApcStateIndex : UChar<br>+0x11d IdealProcessor : UChar<br>+0x11e Preempted : UChar<br>+0x11f ProcessReadyQueue : UChar<br>+0x120 KernelStackResident : UChar<br>+0x121 BasePriority : Char<br>+0x122 PriorityDecrement : Char<br>+0x123 Saturation : Char<br>+0x124 UserAffinity : Uint4B<br>+0x128 Process : Ptr32 _KPROCESS<br>+0x12c Affinity : Uint4B<br>+0x130 ApcStatePointer : [2] Ptr32 _KAPC_STATE<br>+0x138 SavedApcState : _KAPC_STATE<br>+0x138 SavedApcStateFill : [23] UChar<br>+0x14f FreezeCount : Char<br>+0x150 SuspendCount : Char<br>+0x151 UserIdealProcessor : UChar<br>+0x152 CalloutActive : UChar<br>+0x153 Iopl : UChar<br>+0x154 Win32Thread : Ptr32 Void<br>+0x158 StackBase : Ptr32 Void<br>+0x15c SuspendApc : _KAPC<br>+0x15c SuspendApcFill0 : [1] UChar<br>&#8230;&#8230;&#8230;&#8230;</p>
<p>&#8230;&#8230;&#8230;&#8230;</p>
<p>上面红色部分是APC机制用到的几个字段！！</p>
<p>kd&gt; dt _KAPC_STATE<br>nt!_KAPC_STATE<br>+0x000 ApcListHead : [2] _LIST_ENTRY，每个指针指向_KAPC结构<br>+0x010 Process : Ptr32 _KPROCESS<br>+0x014 KernelApcInProgress : UChar<br>+0x015 KernelApcPending : UChar<br>+0x016 UserApcPending : UChar</p>
<p>显然，这里的 ApcListHead 就是 APC 队列头。不过这是个大小为 2 的数组，说明实际<br>上(每个线程)有两个 APC 队列。这是因为 APC 函数分为用户 APC 和内核 APC 两种，各有<br>各的队列。所谓用户 APC，是指相应的 APC 函数位于用户空间、在用户空间执行；而内核<br>APC，则相应的 APC 函数为内核函数。</p>
<p>SavedApcState也是个_KAPC_STATE结构，当当前程暂时&#8220;挂靠(Attach)&#8221;到另一个进程的地址空间的时侯，ApcState就拷贝到SavedApcState暂时存放！</p>
<p>当然，还要有状态信息说明本线程当前是处于&#8220;原始环境&#8221;还是&#8220;挂靠环境&#8221;，这就是 ApcStateIndex 的作用，代码中为 ApcStateIndex的值定义了一种枚举类型：</p>
<p>typedef enum _KAPC_ENVIRONMENT {<br>OriginalApcEnvironment,<br>AttachedApcEnvironment,<br>CurrentApcEnvironment,<br>InsertApcEnvironment<br>} KAPC_ENVIRONMENT;</p>
<p>实际可用于 ApcStateIndex 的只是 OriginalApcEnvironment和 AttachedApcEnvironment。</p>
<p>KAPC_STATE 指针数组 ApcStatePointer[2]，就用ApcStateIndex 的当前值作为下标，而数组中的指针则根据情况可以分别指向两个APC_STATE 数据结构中的一个。</p>
<p>kd&gt; dt _KAPC ;APC对象<br>nt!_KAPC<br>+0x000 Type : UChar<br>+0x001 SpareByte0 : UChar<br>+0x002 Size : UChar<br>+0x003 SpareByte1 : UChar<br>+0x004 SpareLong0 : Uint4B<br>+0x008 Thread : Ptr32 _KTHREAD<br>+0x00c ApcListEntry : _LIST_ENTRY<br>+0x014 KernelRoutine : Ptr32 void<br>+0x018 RundownRoutine : Ptr32 void<br>+0x01c NormalRoutine : Ptr32 void<br>+0x020 NormalContext : Ptr32 Void<br>+0x024 SystemArgument1 : Ptr32 Void<br>+0x028 SystemArgument2 : Ptr32 Void<br>+0x02c ApcStateIndex : Char<br>+0x02d ApcMode : Char<br>+0x02e Inserted : UChar</p>
<p>KernelRoutine、RundownRoutine、NormalRoutine。其中只有 NormalRoutine才指向(执行)APC 函数的请求者所提供的函数，其余两个都是辅助性的！</p>
<p>NTKERNELAPI<br>VOID<br>KeInitializeApc (<br>__out PRKAPC Apc,<br>__in PRKTHREAD Thread,<br>__in KAPC_ENVIRONMENT Environment,<br>__in PKKERNEL_ROUTINE KernelRoutine,<br>__in_opt PKRUNDOWN_ROUTINE RundownRoutine,<br>__in_opt PKNORMAL_ROUTINE NormalRoutine,<br>__in_opt KPROCESSOR_MODE ProcessorMode,<br>__in_opt PVOID NormalContext<br>);</p>
<p>这个函数主要用来初始化Apc（_KAPC）这个结构的，如果Environment==CurrentApcEnvironment,Apc-&gt;ApcStateIndex就由KTHREAD中的ApcStateIndex决定，但Environment不能大于KTHREAD中的ApcStateIndex！</p>
<p>最后，APC 请求的模式ProcessorMode，但是有个例外，那就是：如果指针NormalRoutine 为 0，那么实际的模式变成了 KernelMode。这是因为在这种情况下没有用户空间APC函数可以执行， 唯一将得到执行的是KernelRoutine！</p>
<p>最后，KeInitializeApc 设置Inserted域为FALSE。然而初始化APC对象，并没有把它存放到相应的APC队列中。</p>
<p><br>NTKERNELAPI<br>BOOLEAN<br>KeInsertQueueApc (<br>__inout PRKAPC Apc,<br>__in_opt PVOID SystemArgument1,<br>__in_opt PVOID SystemArgument2,<br>__in KPRIORITY Increment<br>);</p>
<p>据APC请求的具体情况，有时候要插在队列的前头，一般则挂在队列的尾部。</p>
<p>_KiServiceExit:</p>
<p>cli ; disable interrupts<br>DISPATCH_USER_APC ebp, ReturnCurrentEax</p>
<p>;<br>; Exit from SystemService<br>;</p>
<p>EXIT_ALL NoRestoreSegs, NoRestoreVolatile ;这个宏以后再讲</p>
<p>DISPATCH_USER_APC macro TFrame, ReturnCurrentEax<br>local a, b, c<br>c:<br>.errnz (EFLAGS_V86_MASK AND 0FF00FFFFh)</p>
<p>test byte ptr [TFrame]+TsEflags+2, EFLAGS_V86_MASK/010000h ; is previous mode v86?<br>jnz short b ; if nz, yes, go check for APC<br>test byte ptr [TFrame]+TsSegCs,MODE_MASK ; is previous mode user mode?<br>jz a ; No, previousmode=Kernel, jump out<br>b: mov ebx, PCR[PcPrcbData+PbCurrentThread]; get addr of current thread<br>mov byte ptr [ebx]+ThAlerted, 0 ; clear kernel mode alerted<br>cmp byte ptr [ebx]+ThApcState.AsUserApcPending, 0<br>je a ; if eq, no user APC pending</p>
<p>mov ebx, TFrame<br>ifnb &lt;ReturnCurrentEax&gt;;条件宏汇编，如果ReturnCurrentEax参数不为空，则编译！</p>
<p>;DISPATCH_USER_APC ebp, ReturnCurrentEax，显然这里是编译的！<br>mov [ebx].TsEax, eax ; Store return code in trap frame<br>mov dword ptr [ebx]+TsSegFs, KGDT_R3_TEB OR RPL_MASK<br>mov dword ptr [ebx]+TsSegDs, KGDT_R3_DATA OR RPL_MASK<br>mov dword ptr [ebx]+TsSegEs, KGDT_R3_DATA OR RPL_MASK<br>mov dword ptr [ebx]+TsSegGs, 0<br>endif</p>
<p>;<br>; Save previous IRQL and set new priority level<br>;<br>RaiseIrql APC_LEVEL<br>push eax ; Save OldIrql</p>
<p>sti ; Allow higher priority ints</p>
<p>;<br>; call the APC delivery routine.<br>;<br>; ebx - Trap frame<br>; 0 - Null exception frame<br>; 1 - Previous mode<br>;<br>; call APC deliver routine<br>;</p>
<p>stdCall _KiDeliverApc, &lt;1, 0, ebx&gt; ;1就是UserMode</p>
<p>pop ecx ; (ecx) = OldIrql<br>LowerIrql ecx</p>
<p>ifnb &lt;ReturnCurrentEax&gt; ;同上分析<br>mov eax, [ebx].TsEax ; Restore eax, just in case<br>endif</p>
<p>cli<br>jmp b ; 注意这个循环！！</p>
<p>ALIGN 4<br>a:<br>endm</p>
<p>这段代码主要检查：</p>
<p>即将返回的是否用户空间。<br>是否有用户APC请求正在等待执行</p>
<p>条件符合才用KiDeliverApc真正投递APC。注意代码jmp b，好像在返回用户空间前KiDeliverApc会被循环调用直到没有user APC，其实不是的，KiDeliverApc每处理完一个User APC就把UserApcPending清零，所以User APCs在返回用户空间时还是只能投递一次！KiDeliverApc中用while处理完所有Kernel Mode APCs，但User Mode APC却只处理一个！事实上User APC的投递是很特殊的，以后会讲到，而且每次只能投递一次！</p>
<p><br>前面讲过，KTHREAD 中有两个 KAPC_STATE 数据结构，一个是 ApcState，另一个是SavedApcState，二者都有APC 队列，但是要投递的只是ApcState 中的队列。</p>
<p>KiDeliverApc (<br>IN KPROCESSOR_MODE PreviousMode,//写成DeliverMode不是更好<br>IN PKEXCEPTION_FRAME ExceptionFrame,//这个参数几乎就是0<br>IN PKTRAP_FRAME TrapFrame<br>)</p>
<p>这个函数里面还比较复杂，代码不帖了。</p>
<p>参数PreviousMode表示需要&#8220;投递&#8221;哪一种 APC，可以是UserMode，也可以是KernelMode。不过，KernelMode 确实表示只要求执行内核 APC，而UserMode 却表示在执行内核 APC 之外再执行用户APC。</p>
<p>The Windows operating system uses three kinds of APCs:</p>
<p><br>User APCs run strictly in user mode and only when the current thread is in an alertable wait state. The operating system uses user APCs to implement mechanisms such as overlapped I/O and the QueueUserApc Win32 routine. （run IRQL = PASSIVE_LEVEL）<br>Normal kernel APCs run in kernel mode at IRQL = PASSIVE_LEVEL. A normal kernel APC preempts all user-mode code, including user APCs. Normal kernel APCs are generally used by file systems and file-system filter drivers.<br>Special kernel APCs run in kernel mode at IRQL = APC_LEVEL. A special kernel APC preempts user-mode code and kernel-mode code that executes at IRQL = PASSIVE_LEVEL, including both user APCs and normal kernel APCs. The operating system uses special kernel APCs to handle operations such as I/O request completion.<br>从代码的角度看是这样的：</p>
<p>User APCs<br>_KAPC.ApcMode==UserMode,_KAPC.KernelRoutine!=NULL,_KAPC.NormolRoutine!=NULL</p>
<p>Normal kernel APCs</p>
<p>_KAPC.ApcMode==KernelMode,_KAPC.KernelRoutine!=NULL,_KAPC.NormolRoutine!=NULL</p>
<p>Special kernel APCs</p>
<p>_KAPC.ApcMode==KernelMode,_KAPC.KernelRoutine!=NULL,_KAPC.NormolRoutine==NULL</p>
<p>有一点它们的_KAPC.KernelRoutine肯定不为空。并且，如果NormolRoutine也不为空，那么KernelRoutine都在NormolRoutine被调用前被调用！！</p>
<p>上文中讲到投递User Mode APCs是很特殊的，道理很简单，因为User Mode APC是ring3下的回调函数，显然ring0中的KiDeliverAPC（）不能像Kernel Mode APC那样直接call，必须要先回到ring3环境下。当然不能像普通情况那样返回（否则就回到ring3系统调用的地方了），只有一个办法，那就是修改TrapFrame ，欺骗系统返回&#8220;APC回调函数&#8221;！KiInitializeUserApc就是这么做的！</p>
<p>该函数首先把TrapFrame转化为ContextFrame，然后移动用户态ESP指针，分配大约sizeof（CONTEXT）+sizeof（KAPC_RECORD）个字节:</p>
<p>UserStack-&gt; &#8230;&#8230;</p>
<p>KAPC_RECORD</p>
<p>&#8230;&#8230;</p>
<p>&#8230;&#8230;</p>
<p>CONTEXT</p>
<p>TopOfStack-&gt; &#8230;&#8230;</p>
<p>KAPC_RECORD就是KiInitializeUserApc的最后四个参数</p>
<p>nt!_KAPC_RECORD</p>
<p>+0x000 NormalRoutine : Ptr32 void</p>
<p>+0x004 NormalContext : Ptr32 Void</p>
<p>+0x008 SystemArgument1 : Ptr32 Void</p>
<p>+0x00c SystemArgument2 : Ptr32 Void</p>
<p>CONTEXT结构主要来存放被修改前的TrapFrame，之所以用CONTEXT结构是跟APC函数返回有关！</p>
<p>TrapFrame-&gt;HardwareEsp = UserStack;</p>
<p>TrapFrame-&gt;Eip = (ULONG)KeUserApcDispatcher;</p>
<p>TrapFrame-&gt;ErrCode = 0;</p>
<p>从上面的代码看到确实修改了TrapFrame，并且返回到的是ring3下的KeUserApcDispatcher，刚才说的_KAPC_RECORD其实也是它的参数！真正我们的User APC回调函数是由KeUserApcDispatcher调用的！</p>
<p>.func <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#75;&#105;&#85;&#115;&#101;&#114;&#65;&#112;&#99;&#68;&#105;&#115;&#112;&#97;&#116;&#99;&#104;&#101;&#114;&#64;&#49;&#54;">KiUserApcDispatcher@16</a></p>
<p>.globl <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#95;&#75;&#105;&#85;&#115;&#101;&#114;&#65;&#112;&#99;&#68;&#105;&#115;&#112;&#97;&#116;&#99;&#104;&#101;&#114;&#64;&#49;&#54;">_KiUserApcDispatcher@16</a></p>
<p><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#95;&#75;&#105;&#85;&#115;&#101;&#114;&#65;&#112;&#99;&#68;&#105;&#115;&#112;&#97;&#116;&#99;&#104;&#101;&#114;&#64;&#49;&#54;">_KiUserApcDispatcher@16</a>:</p>
<p>/* Setup SEH stack */</p>
<p>lea eax, [esp+CONTEXT_ALIGNED_SIZE+16]</p>
<p>mov ecx, fs:[TEB_EXCEPTION_LIST]</p>
<p>mov edx, offset _KiUserApcExceptionHandler</p>
<p>mov [eax], ecx</p>
<p>mov [eax+4], edx</p>
<p>/* Enable SEH */</p>
<p>mov fs:[TEB_EXCEPTION_LIST], eax</p>
<p>/* Put the Context in EDI */</p>
<p>pop eax</p>
<p>lea edi, [esp+12]</p>
<p>/* Call the APC Routine */</p>
<p>call eax</p>
<p>/* Restore exception list */</p>
<p>mov ecx, [edi+CONTEXT_ALIGNED_SIZE]</p>
<p>mov fs:[TEB_EXCEPTION_LIST], ecx</p>
<p>/* Switch back to the context */</p>
<p>push 1 ; TestAlert</p>
<p>push edi ;edi-&gt;CONTEXT结构</p>
<p>call <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#95;&#90;&#119;&#67;&#111;&#110;&#116;&#105;&#110;&#117;&#101;&#64;&#56;">_ZwContinue@8</a></p>
<p>;;不会返回到这里的</p>
<p>上面的代码并不难理解，我们的User APC回调函数返回后，立即调用了ZwContinue，这是个ntdll中的导出函数，这个函数又通过系统调用进入kernel中的NtContinue！</p>
<p>NTSTATUS</p>
<p>; NtContinue (</p>
<p>; IN PCONTEXT ContextRecord,</p>
<p>; IN BOOLEAN TestAlert</p>
<p>; )</p>
<p>;</p>
<p>; Routine Description:</p>
<p>;</p>
<p>; This routine is called as a system service to continue execution after</p>
<p>; an exception has occurred. Its function is to transfer information from</p>
<p>; the specified context record into the trap frame that was built when the</p>
<p>; system service was executed, and then exit the system as if an exception</p>
<p>; had occurred.</p>
<p>;</p>
<p>; WARNING - Do not call this routine directly, always call it as</p>
<p>; ZwContinue!!! This is required because it needs the</p>
<p>; trapframe built by KiSystemService.</p>
<p>;</p>
<p>; Arguments:</p>
<p>;</p>
<p>; KTrapFrame (ebp+0: after setup) -&gt; base of KTrapFrame</p>
<p>;</p>
<p>; ContextRecord (ebp+8: after setup) = Supplies a pointer to a context rec.</p>
<p>;</p>
<p>; TestAlert (esp+12: after setup) = Supplies a boolean value that specifies</p>
<p>; whether alert should be tested for the previous processor mode.</p>
<p>;</p>
<p>; Return Value:</p>
<p>;</p>
<p>; Normally there is no return from this routine. However, if the specified</p>
<p>; context record is misaligned or is not accessible, then the appropriate</p>
<p>; status code is returned.</p>
<p>;</p>
<p>;--</p>
<p>NcTrapFrame equ [ebp + 0]</p>
<p>NcContextRecord equ [ebp + 8]</p>
<p>NcTestAlert equ [ebp + 12]</p>
<p>align dword</p>
<p>cPublicProc _NtContinue ,2</p>
<p>push ebp ;ebp-&gt;TrapFrame</p>
<p>;</p>
<p>; Restore old trap frame address since this service exits directly rather</p>
<p>; than returning.</p>
<p>;</p>
<p>mov ebx, PCR[PcPrcbData+PbCurrentThread] ; get current thread address</p>
<p>mov edx, [ebp].TsEdx ; restore old trap frame address</p>
<p>mov [ebx].ThTrapFrame, edx ;</p>
<p>;</p>
<p>; Call KiContinue to load ContextRecord into TrapFrame. On x86 TrapFrame</p>
<p>; is an atomic entity, so we don't need to allocate any other space here.</p>
<p>;</p>
<p>; KiContinue(NcContextRecord, 0, NcTrapFrame)</p>
<p>;</p>
<p>mov ebp,esp</p>
<p>mov eax, NcTrapFrame</p>
<p>mov ecx, NcContextRecord</p>
<p>stdCall _KiContinue, &lt;ecx, 0, eax&gt;</p>
<p>or eax,eax ; return value 0?</p>
<p>jnz short Nc20 ; KiContinue failed, go report error</p>
<p>;</p>
<p>; Check to determine if alert should be tested for the previous processor mode.</p>
<p>;</p>
<p>cmp byte ptr NcTestAlert,0 ; Check test alert flag</p>
<p>je short Nc10 ; if z, don't test alert, go Nc10</p>
<p>mov al,byte ptr [ebx]+ThPreviousMode ; No need to xor eax, eax.</p>
<p>stdCall _KeTestAlertThread, &lt;eax&gt; ; test alert for current thread</p>
<p>;如果User APCs不为空，它会设置UserApcPending,</p>
<p>;跟Alertable无关</p>
<p>Nc10: pop ebp ; (ebp) -&gt; TrapFrame</p>
<p>mov esp,ebp ; (esp) = (ebp) -&gt; trapframe</p>
<p>jmp _KiServiceExit2 ; common exit</p>
<p>Nc20: pop ebp ; (ebp) -&gt; TrapFrame</p>
<p>mov esp,ebp ; (esp) = (ebp) -&gt; trapframe</p>
<p>jmp _KiServiceExit ; common exit</p>
<p>stdENDP _NtContinue</p>
<p>NtContinue把CONTEXT结构转化成TrapFrame（回复原来的陷阱帧），然后就从KiServiceExit2处退出系统调用！</p>
<p>;++</p>
<p>;</p>
<p>; _KiServiceExit2 - same as _KiServiceExit BUT the full trap_frame</p>
<p>; context is restored</p>
<p>;</p>
<p>;--</p>
<p>public _KiServiceExit2</p>
<p>_KiServiceExit2:</p>
<p>cli ; disable interrupts</p>
<p>DISPATCH_USER_APC ebp</p>
<p>;</p>
<p>; Exit from SystemService</p>
<p>;</p>
<p>EXIT_ALL ; RestoreAll</p>
<p>KiServiceExit2跟KiServiceExit差不多，只是宏参数的不同!同样如果还有User APC又会进入上文描述的情形，直到没有User APC，至此才会返回真正发起原始系统调用的地方！</p>
<p><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/better0332/archive/2009/06/29/4306683.aspx">http://blog.csdn.net/better0332/archive/2009/06/29/4306683.aspx</a></p><img src ="http://www.cppblog.com/shaker/aggbug/145733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-05-05 12:09 <a href="http://www.cppblog.com/shaker/archive/2011/05/05/145733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]谈谈对APC的一点理解</title><link>http://www.cppblog.com/shaker/archive/2011/05/05/145731.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Thu, 05 May 2011 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/05/05/145731.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/145731.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/05/05/145731.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/145731.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/145731.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; LETTER-SPACING: normal; BORDER-COLLAPSE: separate; FONT: 16px Arial,Microsoft Yahei,Simsun,sans-serif; WHITE-SPACE: normal; ORPHANS: 2; COLOR: rgb(83,100,130); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="LINE-HEIGHT: 18px; FONT-FAMILY: 'Lucida Grande', 'Trebuchet MS', Verdana, Helvetica, Arial, sans-serif; COLOR: rgb(51,51,51); FONT-SIZE: 13px" class=Apple-style-span>异步过程调用(APCs) 是NT异步处理体系结构中的一个基础部分，理解了它，对于了解NT怎样操作和执行几个核心的系统操作很有帮助。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">1) APCs允许用户程序和系统元件在一个进程的地址空间内某个线程的上下文中执行代码。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">2) I/O管理器使用APCs来完成一个线程发起的异步的I/O操作。例如：当一个设备驱动调用IoCompleteRequest来通知I/O管理器，它已经结束处理一个异步I/O请求时，I/O管理器排队一个apc到发起请求的线程。然后线程在一个较低IRQL级别，来执行APC. APC的作用是从系统空间拷贝I/O操作结果和状态信息到线程虚拟内存空间的一个缓冲中。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">3) 使用APC可以得到或者设置一个线程的上下文和挂起线程的执行。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">尽管APCs在nt体系结构下被广泛使用，但是关于怎样使用它的文档却非常的缺乏。本篇我们详细介绍下nt系统是怎样处理APCs的，并且记录导出的nt函数，方便设备驱动开发者在他们的程序中使用APCs。我也会展示一个非常可靠的NT的APC调度子程序KiDeliverApc的实现，来帮助你更好的掌握APC调度的内幕。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">APC对象<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">在NT中，有两种类型的APCs：用户模式和内核模式。用户APCs运行在用户模式下目标线程当前上下文中，并且需要从目标线程得到许可来运行。特别是，用户模式的APCs需要目标线程处在alertable等待状态才能被成功的调度执行。通过调用下面任意一个函数，都可以让线程进入这种状态。这些函数是：KeWaitForSingleObject, KeWaitForMultipleObjects, KeWaitForMutexObject, KeDelayExecutionThread。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">对于用户模式下，可以调用函数SleepEx, SignalObjectAndWait, WaitForSingleObjectEx, WaitForMultipleObjectsEx,MsgWaitForMultipleObjectsEx 都可以使目标线程处于alertable等待状态，从而让用户模式APCs执行,原因是这些函数最终都是调用了内核中的KeWaitForSingleObject, KeWaitForMultipleObjects, KeWaitForMutexObject, KeDelayExecutionThread等函数。另外通过调用一个未公开的alert-test服务KeTestAlertThread，用户线程可以使用户模式APCs执行。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">当一个用户模式APC被投递到一个线程，调用上面的等待函数，如果返回等待状态STATUS_USER_APC，在返回用户模式时，内核转去控制APC例程，当APC例程完成后，再继续线程的执行.<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">和用户模式APCs比较，内核模式APCs执行在内核模式下。可以被划分为常规的和特殊的两类。当APCs被投递到一个特殊的线程，特殊的内核模式APCs不需要从线程得到许可来运行。然而，常规的内核模式APCs在他们成功执行前，需要有特定的环境。此外，特殊的内核APC被尽可能快地执行，既只要APC_LEVEL级上有可调度的活动。在很多情况下，特殊的内核APC甚至能唤醒阻塞的线程。普通的内核APC仅在所有特殊APC都被执行完，并且目标线程仍在运行，同时该线程中也没有其它内核模式APC正执行时才执行。用户模式APC在所有内核模式APC执行完后才执行，并且仅在目标线程有alertable属性时才执行。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">每一个等待执行的APC都存在于一个线程执行体，由内核管理的队列中。系统中的每一个线程都包含两个APC队列，一个是为用户模式APCs,另一个是为内核模式APCs的。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NT通过一个成为KAPC的内核控制对象来描述一个ＡＰＣ．尽管ＤＤＫ中没有明确的文档化ＡＰＣｓ，但是在NTDDK.H中却非常清楚的定义了ＡＰＣ对象。从下面的KAPC对象的定义看，有些是不需要说明的。像Type和Size。Type表示了这是一个APC内核对象。在nt中，每一个内核对象或者执行体对象都有Type和Size这两个域。由此处理函数可以确定当前处理的对象。Size表示一个字对齐的结构体的大小。也就是指明了对象占的内存空间大小。Spare0看起来有些晦涩难懂，但是它是没用什么任何深远的意义，仅仅是为了内存补齐。其他的域将在下面的篇幅中介绍。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">//-------------------------------------------------------------------------------------------------------<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">几个函数声明和结构定义：<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">typedef struct _KAPC {<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">CSHORT Type;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">CSHORT Size;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">ULONG Spare0;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">struct _KTHREAD *Thread;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">LIST_ENTRY ApcListEntry;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">PKKERNEL_ROUTINE KernelRoutine;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">PKRUNDOWN_ROUTINE RundownRoutine;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">PKNORMAL_ROUTINE NormalRoutine;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">PVOID NormalContext;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">//<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">// N.B. The following two members MUST be together.<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">//<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">PVOID SystemArgument1;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">PVOID SystemArgument2;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">CCHAR ApcStateIndex;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">KPROCESSOR_MODE ApcMode;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">BOOLEAN Inserted;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">} KAPC, *PKAPC, *RESTRICTED_POINTER PRKAPC;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">//------<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">APC环境<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">一个线程在它执行的任意时刻，假设当前的IRQL是在Passive级，它可能需要临时在其他的进程上下文中执行代码，为了完成这个操作，线程调用系统功能函数KeAttachProcess，在从这个调用返回时，线程执行在另一个进程的地址空间。先前所有在线程自己的进程上下文中等待执行的APCs,由于这时其所属进程的地址空间不是当前可用的，因此他们不能被投递执行。然而，新的插入到这个线程的APCs可以执行在这个新的进程空间。甚至当线程最后从新的进程中分离时，新的插入到这个线程的APCs还可以在这个线程所属的进程上下文中执行。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">为了达到控制APC传送的这个程度，NT中每个线程维护了两个APC环境或者说是状态。每一个APC环境包含了用户模式的APC队列和内核模式的APC队列，一个指向当前进程对象的指针和三个控制变量，用于指出：是否有未决的内核模式APCs(KernelApcPending),是否有常规内核模式APC在进行中(KernelApcInProgress)，是否有未决的用户模式的APC(UserApcPending). 这些APC的环境保存在线程对象的ApcStatePointer域中。这个域是由2个元素组成的数组。即：+0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">typedef struct _KAPC_STATE {<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">LIST_ENTRY ApcListHead[MaximumMode];<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">struct _KPROCESS *Process;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">BOOLEAN KernelApcInProgress;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">BOOLEAN KernelApcPending;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">BOOLEAN UserApcPending;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">} KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">lkd&gt; dt _kthread<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">ntdll!_KTHREAD<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x000 Header : _DISPATCHER_HEADER<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x010 MutantListHead : _LIST_ENTRY<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x018 InitialStack : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x01c StackLimit : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x020 Teb : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x024 TlsArray : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x028 KernelStack : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x02c DebugActive : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x02d State : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x02e Alerted : [2] UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x030 Iopl : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x031 NpxState : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x032 Saturation : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x033 Priority : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x034 ApcState : _KAPC_STATE<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x04c ContextSwitches : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x050 IdleSwapBlock : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x051 Spare0 : [3] UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x054 WaitStatus : Int4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x058 WaitIrql : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x059 WaitMode : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x05a WaitNext : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x05b WaitReason : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x05c WaitBlockList : Ptr32 _KWAIT_BLOCK<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x060 WaitListEntry : _LIST_ENTRY<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x060 SwapListEntry : _SINGLE_LIST_ENTRY<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x068 WaitTime : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x06c BasePriority : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x06d DecrementCount : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x06e PriorityDecrement : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x06f Quantum : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x070 WaitBlock : [4] _KWAIT_BLOCK<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0d0 LegoData : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0d4 KernelApcDisable : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0d8 UserAffinity : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0dc SystemAffinityActive : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0dd PowerState : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0de NpxIrql : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0df InitialNode : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0e0 ServiceTable : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0e4 Queue : Ptr32 _KQUEUE<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0e8 ApcQueueLock : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x0f0 Timer : _KTIMER<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x118 QueueListEntry : _LIST_ENTRY<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x120 SoftAffinity : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x124 Affinity : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x128 Preempted : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x129 ProcessReadyQueue : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x12a KernelStackResident : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x12b NextProcessor : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x12c CallbackStack : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x130 Win32Thread : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x134 TrapFrame : Ptr32 _KTRAP_FRAME<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x140 PreviousMode : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x141 EnableStackSwap : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x142 LargeStack : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x143 ResourceIndex : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x144 KernelTime : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x148 UserTime : Uint4B<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x14c SavedApcState : _KAPC_STATE<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x164 Alertable : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x165 ApcStateIndex : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x166 ApcQueueable : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x167 AutoAlignment : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x168 StackBase : Ptr32 Void<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x16c SuspendApc : _KAPC<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x19c SuspendSemaphore : _KSEMAPHORE<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x1b0 ThreadListEntry : _LIST_ENTRY<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x1b8 FreezeCount : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x1b9 SuspendCount : Char<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x1ba IdealProcessor : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x1bb DisableBoost : UChar<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">主APC环境是位于线程对象的ApcState 域，即：<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">+0x034 ApcState : _KAPC_STATE<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">线程中等待在当前进程上下文中执行的APC保存在ApcState的队列中。无论何时，NT的APC派发器(dispatcher)和其他系统元件查询一个线程未决的APCs时, 他们都会检查主APC环境，如果这里有任何未决的APCs,就会马上被投递，或者修改它的控制变量稍后投递。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">第二个APC环境是位于线程对象的SavedApcState域，当线程临时挂接到其他进程时，它是用来备份主APC环境的。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">当一个线程调用KeAttachProcess，在另外的进程上下文中执行后续的代码时，ApcState域的内容就被拷贝到SavedApcState域。然后ApcState域被清空，它的APC队列重新初始化，控制变量设置为0，当前进程域设置为新的进程。这些步骤成功的确保先前在线程所属的进程上下文地址空间中等待的APCs，当线程运行在其它不同的进程上下文时，这些APCs不被传送执行。随后，ApcStatePointer域数组内容被更新来反映新的状态，数组中第一个元素指向SavedApcState域，第二个元素指向ApcState域，表明线程所属进程上下文的APC环境位于SavedApcState域。线程的新的进程上下文的APC环境位于ApcState域。最后，当前进程上下文切换到新的进程上下文。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">对于一个APC对象，决定当前APC环境的是ApcStateIndex域。ApcStateIndex域的值作为ApcStatePointer域数组的索引来得到目标APC环境指针。随后，目标APC环境指针用来在相应的队列中存放apc对象.<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">当线程从新的进程中脱离时(KeDetachProcess), 任何在新的进程地址空间中等待执行的未决的内核APCs被派发执行。随后SavedApcState 域的内容被拷贝回ApcState域。SavedApcState 域的内容被清空，线程的ApcStateIndex域被设为OriginalApcEnvironment，ApcStatePointer域更新，当前进程上下文切换到线程所属进程。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">使用APCs<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">设备驱动程序使用两个主要函数来利用APCs, 第一个是KeInitializeApc，用来初始化APC对象。这个函数接受一个驱动分配的APC对象，一个目标线程对象指针，APC环境索引（指出APC对象存放于哪个APC环境），APC的kernel,rundown和normal例程指针，APC类型（用户模式或者内核模式）和一个上下文参数。 函数声明如下：<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NTKERNELAPI<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">VOID<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">KeInitializeApc (<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PRKAPC Apc,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PKTHREAD Thread,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN KAPC_ENVIRONMENT Environment,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PKKERNEL_ROUTINE KernelRoutine,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PKNORMAL_ROUTINE NormalRoutine OPTIONAL,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN KPROCESSOR_MODE ApcMode,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID NormalContext<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">);<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">typedef enum _KAPC_ENVIRONMENT {<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">OriginalApcEnvironment,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">AttachedApcEnvironment,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">CurrentApcEnvironment<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">} KAPC_ENVIRONMENT;<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">KeInitializeApc 首先设置APC对象的Type和Size域一个适当的值，然后检查参数Environment的值，如果是CurrentApcEnvironment，那么ApcStateIndex域设置为目标线程的ApcStateIndex域。否则，ApcStateIndex域设置为参数Environment的值。随后，函数直接用参数设置APC对象Thread，RundownRoutine，KernelRoutine域的值。为了正确地确定APC的类型，KeInitializeApc 检查参数NormalRoutine的值，如果是NULL，ApcMode域的值设置为KernelMode，NormalContext域设置为NULL。如果NormalRoutine的值不是NULL，这时候它一定指向一个有效的例程，就用相应的参数来设置ApcMode域和NormalContext域。最后，KeInitializeApc 设置Inserted域为FALSE.然而初始化APC对象，并没有把它存放到相应的APC队列中。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">从这个解释看，你可以了解到APCs对象如果缺少有效的NormalRoutine，就会被当作内核模式APCs.尤其是它们会被认为是特殊的内核模式APCs.<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">实际上，I/O管理器就是用这类的APC来完成异步I/O操作。相反地，APC对象定义了有效的NormalRoutine，并且ApcMode域是KernelMode，就会被当作常规的内核模式APCs,否则就会被当作是用户模式APCs. NTDDK.H中KernelRoutine, RundownRoutine, and NormalRoutine 的定义如下：<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">typedef<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">VOID<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">(*PKKERNEL_ROUTINE) (<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN struct _KAPC *Apc,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN OUT PKNORMAL_ROUTINE *NormalRoutine,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN OUT PVOID *NormalContext,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN OUT PVOID *SystemArgument1,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN OUT PVOID *SystemArgument2<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">);<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">typedef<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">VOID<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">(*PKRUNDOWN_ROUTINE) (<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN struct _KAPC *Apc<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">);<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">typedef<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">VOID<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">(*PKNORMAL_ROUTINE) (<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID NormalContext,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID SystemArgument1,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID SystemArgument2<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">);<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">//------------------<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">通常，无论是什么类型，每个APC对象必须要包含一个有效的KernelRoutine 函数指针。当这个APC被NT的APC dispatcher传送执行时，这个例程首先被执行。用户模式的APCs必须包含一个有效的NormalRoutine 函数指针，这个函数必须在用户内存区域。同样的，常规内核模式APCs也必须包含一个有效的NormalRoutine，但是它就像KernelRoutine一样运行在内核模式。作为可选择的，任意类型的APC都可以定义一个有效的RundownRoutine，这个例程必须在内核内存区域，并且仅仅当系统需要释放APC队列的内容时，才被调用。例如线程退出时，在这种情况下，KernelRoutine和NormalRoutine都不执行，只有RundownRoutine执行。没有这个例程的APC对象会被删除。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">记住，投递APCs到一个线程的动作，仅仅是操作系统调用KiDeliverApc完成的。执行APC实际上就是调用APC内的例程。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">一旦APC对象完成初始化后，设备驱动调用KeInsertQueueApc来将APC对象存放到目标线程的相应的APC队列中。这个函数接受一个由KeInitializeApc完成初始化的APC对象指针，两个系统参数和一个优先级增量。跟传递给KeInitializeApc函数的参数context 一样，这两个系统参数只是在APC的例程执行时，简单的传递给APC的例程。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NTKERNELAPI<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">BOOLEAN<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">KeInsertQueueApc (<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PRKAPC Apc,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID SystemArgument1,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID SystemArgument2,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN KPRIORITY Increment<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">);<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">//-----------------<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">在KeInsertQueueApc 将APC对象存放到目标线程相应的APC队列之前，它首先检查目标线程是否是APC queueable。如果不是，函数立即返回FALSE.如果是，函数直接用参数设置SystemArgument1域和SystemArgument2 域，随后，函数调用KiInsertQueueApc来将APC对象存放到相应的APC队列。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">KiInsertQueueApc 仅仅接受一个APC对象和一个优先级增量。这个函数首先得到线程APC队列的spinlock并且持有它，防止其他线程修改当前线程的APC结构。随后，检查APC对象的Inserted 域。如果是TRUE,表明这个APC对象已经存放到APC队列中了，函数立即返回FALSE.如果APC对象的Inserted 域是FALSE.函数通过ApcStateIndex域来确定目标APC环境，然后把APC对象存放到相应的APC队列中，即将APC对象中的ApcListEntry 域链入到APC环境的ApcListHead域中。链入的位置由APC的类型决定。常规的内核模式APC,用户模式APC都是存放到相应的APC队列的末端。相反的，如果队列中已经存放了一些APC对象，特殊的内核模式APC存放到队列中第一个常规内核模式APC对象的前面。如果是内核定义的一个当线程退出时使用的用户APC,它也会被放在相应的队列的前面。然后，线程的主APC环境中的UserApcPending域杯设置为TRUE。这时KiInsertQueueApc 设置APC对象的Inserted 域为TRUE，表明这个APC对象已经存放到APC队列中了。接下来，检查这个APC对象是否被排队到线程的当前进程上下文APC环境中，如果不是，函数立即返回TRUE。如果这是一个内核模式APC，线程主APC环境中的KernelApcPending域设置为TRUE。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">在WIN32 SDK文档中是这样描述APCs的： 当一个APC被成功的存放到它的队列后，发出一个软中断，APC将会在线程被调度运行的下一个时间片执行。然而这不是完全正确的。这样一个软中断，仅仅是当一个内核模式的APC（无论是常规的内核模式APC还是特殊的内核模式APC）针对于调用线程时，才会发出。随后函数返回TRUE。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">1）如果APC不是针对于调用线程，目标线程在Passive权限等级处在等待状态；<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">2）这是一个常规内核模式APC<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">3）这个线程不再临界区<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">4）没有其他的常规内核模式APC仍然在进行中<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">那么这个线程被唤醒，返回状态是STATUS_KERNEL_APC。但是等待状态没有aborted。 如果这是一个用户模式APC，KiInsertQueueApc检查判断目标线程是否是alertable等待状态，并且WaitMode域等于UserMode。如果是，主APC环境的UserApcPending 域设置为TRUE。等待状态返回STATUS_USER_APC，最后，函数释放spinlock，返回TRUE，表示APC对象已经被成功放入队列。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">早期作为APC管理函数的补充，设备驱动开发者可以使用未公开的系统服务NtQueueApcThread来直接将一个用户模式的APC投递到某个线程。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">这个函数内部实际上是调用了KeInitializeApc 和KeInsertQueueApc 来完成这个任务。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NTSYSAPI<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NTSTATUS<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NTAPI<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NtQueueApcThread (<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN HANDLE Thread,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PKNORMAL_ROUTINE NormalRoutine,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID NormalContext,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID SystemArgument1,<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">IN PVOID SystemArgument2<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">);<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NT的APC派发器<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">NT检查是否线程有未决的APCs. 然后APC派发器子程序KiDeliverApc在这个线程上下文执行来开始将未决的APC执行。注意，这个行为中断了线程的正常执行流程，首先将控制权给APC派发器，随后当KiDeliverApc完成后，继续线程的执行。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">例如：当一个线程被调度运行时，最后一步，上下文切换函数 SwapContext 用来检查是否新的线程有未决的内核APCs.如果是，SwapContext要么（1）请求一个APC级别的软中断来开始APC执行，由于新线程运行在低的IRQL（Passive级别。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">或者（2）返回TRUE，表示新的线程有未决的内核APCs。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">究竟是执行(1)还是(2)取决于新线程所处的IRQL级别. 如果它的权限级别高于Passive级,SwapContext 执行(1),如果它是在Passive级,则选择执行(2).<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">SwapContext的返回值仅仅是特定系统函数可用的,这些系统函数调用SwapContext来强制切换线程上下文到另一个线程. 然后,当这些系统函数经过一段时间再继续时,他们通常检查SwapContext 的返回值,如果是TRUE,他们就会调用APC派发器来投递内核APCs到当前的线程. 例如:<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">系统函数KiSwapThread被等待服务用来放弃处理器，直到等待结束。这个函数内部调用SwapContext。当等待结束，继续从调用SwapContext处执行时，就会检查SwapContext的返回值。如果是TRUE，KiSwapThread会降低IRQL级别到APC级，然后调用KiDeliverApc来在当前线程执行内核APCs.<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">对于用户APCs, 内核调用APC派发器仅仅是当线程回到用户模式，并且线程的主APC环境的UserApcPending域为TRUE时。例如：当系统服务派发器KiSystemService完成一个系统服务请求正打算回到用户模式时，它会检查是否有未决的用户APCs。在执行上，KiDeliverApc调用用户APC的KernelRoutine. 随后，KiInitializeUserApc函数被调用，用来设置线程的陷阱帧。所以从内核模式退出时，线程开始在用户模式下执行<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">。KiInitializeUserApc的函数的作用是拷贝当前线程先前的执行状态（当进入内核模式时，这个状态保存在线程内核栈创建的陷阱帧里），从内核栈到线程的用户模式栈，初始化用户模式APC。APC派发器子程序KiUserApcDispatcher在Ntdll.dll内。最后，加载陷阱帧的EIP寄存器和Ntdll.dll中KiUserApcDispatcher的地址。当陷阱帧最后释放时，内核将控制转交给KiUserApcDispatcher，这个函数调用APC的NormalRoutine例程，NormalRoutine函数地址以及参数都在栈中，当例程完成时，它调用NtContinue来让线程利用在栈中先前的上下文继续执行，仿佛什么事情也没有发生过。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">当内核调用KiDeliverApc来执行一个用户模式APC时，线程中的PreviousMode域被设为UserMode. TrapFrame域指向线程的陷阱帧。当内核调用KiDeliverApc来执行内核APCs时，线程中的PreviousMode域被设为KernelMode. TrapFrame域指向NULL。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">注意，无论何时只要KernelRoutine被调用，传递给它的指针是一个局部的APC属性的副本，由于APC对象已经脱离了队列，所以可以安全的在KernelRoutine中释放APC内存。此外，这个例程在它的参数被传递给其他例程之前，有一个最后的机会来修改这些参数。<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">结论：<br style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">APC提供了一个非常有用的机制，允许在特定的线程上下文中异步的执行代码。作为一个设备驱动开发者，你可以依赖APCs在某个特定的线程上下文中执行一个例程，而不需要线程的许可和干涉。对于用户应用程序，用户模式APCs可以用来有效地实现一些回调通知机制。</span></span><img src ="http://www.cppblog.com/shaker/aggbug/145731.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-05-05 11:46 <a href="http://www.cppblog.com/shaker/archive/2011/05/05/145731.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NtProtectVirtualMemory</title><link>http://www.cppblog.com/shaker/archive/2011/03/23/142548.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Wed, 23 Mar 2011 02:01:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/03/23/142548.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/142548.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/03/23/142548.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/142548.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/142548.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080">&nbsp;&nbsp;1</span>&nbsp;<span style="COLOR: #000000">NTSTATUS<br></span><span style="COLOR: #008080">&nbsp;&nbsp;2</span>&nbsp;<span style="COLOR: #000000">NTAPI<br></span><span style="COLOR: #008080">&nbsp;&nbsp;3</span>&nbsp;<span style="COLOR: #000000">NtProtectVirtualMemory(IN&nbsp;HANDLE&nbsp;ProcessHandle,<br></span><span style="COLOR: #008080">&nbsp;&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;OUT&nbsp;PVOID&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeBaseAddress,<br></span><span style="COLOR: #008080">&nbsp;&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;OUT&nbsp;SIZE_T&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeNumberOfBytesToProtect,<br></span><span style="COLOR: #008080">&nbsp;&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;ULONG&nbsp;NewAccessProtection,<br></span><span style="COLOR: #008080">&nbsp;&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUT&nbsp;PULONG&nbsp;UnsafeOldAccessProtection)<br></span><span style="COLOR: #008080">&nbsp;&nbsp;8</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;PEPROCESS&nbsp;Process;<br></span><span style="COLOR: #008080">&nbsp;10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;ULONG&nbsp;OldAccessProtection;<br></span><span style="COLOR: #008080">&nbsp;11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;ULONG&nbsp;Protection;<br></span><span style="COLOR: #008080">&nbsp;12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;PEPROCESS&nbsp;CurrentProcess&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;PsGetCurrentProcess();<br></span><span style="COLOR: #008080">&nbsp;13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;BaseAddress&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br></span><span style="COLOR: #008080">&nbsp;14</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SIZE_T&nbsp;NumberOfBytesToProtect&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;KPROCESSOR_MODE&nbsp;PreviousMode&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;ExGetPreviousMode();<br></span><span style="COLOR: #008080">&nbsp;16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;Status;<br></span><span style="COLOR: #008080">&nbsp;17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;BOOLEAN&nbsp;Attached&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;FALSE;<br></span><span style="COLOR: #008080">&nbsp;18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;KAPC_STATE&nbsp;ApcState;<br></span><span style="COLOR: #008080">&nbsp;19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;PAGED_CODE();<br></span><span style="COLOR: #008080">&nbsp;20</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;21</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;22</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Check&nbsp;for&nbsp;valid&nbsp;protection&nbsp;flags<br></span><span style="COLOR: #008080">&nbsp;23</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;24</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NewAccessProtection&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">(PAGE_GUARD</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">PAGE_NOCACHE);<br></span><span style="COLOR: #008080">&nbsp;25</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_NOACCESS&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;26</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_READONLY&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;27</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_READWRITE&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;28</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_WRITECOPY&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;29</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_EXECUTE&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;30</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_EXECUTE_READ&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;31</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_EXECUTE_READWRITE&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;32</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protection&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PAGE_EXECUTE_WRITECOPY)<br></span><span style="COLOR: #008080">&nbsp;33</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;34</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;35</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Fail<br></span><span style="COLOR: #008080">&nbsp;36</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;37</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;STATUS_INVALID_PAGE_PROTECTION;<br></span><span style="COLOR: #008080">&nbsp;38</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;39</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;40</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;41</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Check&nbsp;if&nbsp;we&nbsp;came&nbsp;from&nbsp;user&nbsp;mode<br></span><span style="COLOR: #008080">&nbsp;42</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;43</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(PreviousMode&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;KernelMode)<br></span><span style="COLOR: #008080">&nbsp;44</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;45</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;46</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Enter&nbsp;SEH&nbsp;for&nbsp;probing<br></span><span style="COLOR: #008080">&nbsp;47</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;48</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_SEH2_TRY<br></span><span style="COLOR: #008080">&nbsp;49</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;50</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;51</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Validate&nbsp;all&nbsp;outputs<br></span><span style="COLOR: #008080">&nbsp;52</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;53</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProbeForWritePointer(UnsafeBaseAddress);<br></span><span style="COLOR: #008080">&nbsp;54</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);<br></span><span style="COLOR: #008080">&nbsp;55</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProbeForWriteUlong(UnsafeOldAccessProtection);<br></span><span style="COLOR: #008080">&nbsp;56</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;57</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;58</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Capture&nbsp;them<br></span><span style="COLOR: #008080">&nbsp;59</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;60</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BaseAddress&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeBaseAddress;<br></span><span style="COLOR: #008080">&nbsp;61</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberOfBytesToProtect&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeNumberOfBytesToProtect;<br></span><span style="COLOR: #008080">&nbsp;62</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;63</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)<br></span><span style="COLOR: #008080">&nbsp;64</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;65</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;66</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Get&nbsp;exception&nbsp;code<br></span><span style="COLOR: #008080">&nbsp;67</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;68</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_SEH2_YIELD(</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;_SEH2_GetExceptionCode());<br></span><span style="COLOR: #008080">&nbsp;69</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;70</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_SEH2_END;<br></span><span style="COLOR: #008080">&nbsp;71</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;72</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;73</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;74</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;75</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Capture&nbsp;directly<br></span><span style="COLOR: #008080">&nbsp;76</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;77</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BaseAddress&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeBaseAddress;<br></span><span style="COLOR: #008080">&nbsp;78</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberOfBytesToProtect&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeNumberOfBytesToProtect;<br></span><span style="COLOR: #008080">&nbsp;79</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;80</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;81</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;82</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Catch&nbsp;illegal&nbsp;base&nbsp;address<br></span><span style="COLOR: #008080">&nbsp;83</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;84</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(BaseAddress&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;MM_HIGHEST_USER_ADDRESS)&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;STATUS_INVALID_PARAMETER_2;<br></span><span style="COLOR: #008080">&nbsp;85</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;86</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;87</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Catch&nbsp;illegal&nbsp;region&nbsp;size<br></span><span style="COLOR: #008080">&nbsp;88</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;89</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;((MmUserProbeAddress&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;(ULONG_PTR)BaseAddress)&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;NumberOfBytesToProtect)<br></span><span style="COLOR: #008080">&nbsp;90</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;91</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;92</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Fail<br></span><span style="COLOR: #008080">&nbsp;93</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;94</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;STATUS_INVALID_PARAMETER_3;<br></span><span style="COLOR: #008080">&nbsp;95</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;96</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;97</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;98</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;0&nbsp;is&nbsp;also&nbsp;illegal<br></span><span style="COLOR: #008080">&nbsp;99</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">100</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">NumberOfBytesToProtect)&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;STATUS_INVALID_PARAMETER_3;<br></span><span style="COLOR: #008080">101</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">102</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">103</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Get&nbsp;a&nbsp;reference&nbsp;to&nbsp;the&nbsp;process<br></span><span style="COLOR: #008080">104</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">105</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Status&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;ObReferenceObjectByHandle(ProcessHandle,<br></span><span style="COLOR: #008080">106</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PROCESS_VM_OPERATION,<br></span><span style="COLOR: #008080">107</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PsProcessType,<br></span><span style="COLOR: #008080">108</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PreviousMode,<br></span><span style="COLOR: #008080">109</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(PVOID</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Process),<br></span><span style="COLOR: #008080">110</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL);<br></span><span style="COLOR: #008080">111</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">NT_SUCCESS(Status))&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;Status;<br></span><span style="COLOR: #008080">112</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">113</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">114</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Check&nbsp;if&nbsp;we&nbsp;should&nbsp;attach<br></span><span style="COLOR: #008080">115</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">116</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(CurrentProcess&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;Process)<br></span><span style="COLOR: #008080">117</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">118</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">119</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Do&nbsp;it<br></span><span style="COLOR: #008080">120</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">121</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeStackAttachProcess(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">Process</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Pcb,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ApcState);<br></span><span style="COLOR: #008080">122</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Attached&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;TRUE;<br></span><span style="COLOR: #008080">123</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">124</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">125</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">126</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Do&nbsp;the&nbsp;actual&nbsp;work<br></span><span style="COLOR: #008080">127</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">128</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Status&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MiProtectVirtualMemory(Process,<br></span><span style="COLOR: #008080">129</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">BaseAddress,<br></span><span style="COLOR: #008080">130</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">NumberOfBytesToProtect,<br></span><span style="COLOR: #008080">131</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NewAccessProtection,<br></span><span style="COLOR: #008080">132</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">OldAccessProtection);<br></span><span style="COLOR: #008080">133</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">134</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">135</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Detach&nbsp;if&nbsp;needed<br></span><span style="COLOR: #008080">136</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">137</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(Attached)&nbsp;KeUnstackDetachProcess(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ApcState);<br></span><span style="COLOR: #008080">138</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">139</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">140</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Release&nbsp;reference<br></span><span style="COLOR: #008080">141</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">142</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;ObDereferenceObject(Process);<br></span><span style="COLOR: #008080">143</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">144</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">145</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Enter&nbsp;SEH&nbsp;to&nbsp;return&nbsp;data<br></span><span style="COLOR: #008080">146</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">147</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;_SEH2_TRY<br></span><span style="COLOR: #008080">148</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">149</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">150</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Return&nbsp;data&nbsp;to&nbsp;user<br></span><span style="COLOR: #008080">151</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">152</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeOldAccessProtection&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;OldAccessProtection;<br></span><span style="COLOR: #008080">153</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeBaseAddress&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;BaseAddress;<br></span><span style="COLOR: #008080">154</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">UnsafeNumberOfBytesToProtect&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NumberOfBytesToProtect;<br></span><span style="COLOR: #008080">155</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">156</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)<br></span><span style="COLOR: #008080">157</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">158</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">159</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;_SEH2_END;<br></span><span style="COLOR: #008080">160</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">161</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">162</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Return&nbsp;status<br></span><span style="COLOR: #008080">163</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">164</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;Status;<br></span><span style="COLOR: #008080">165</span>&nbsp;<span style="COLOR: #000000">}</span></div><img src ="http://www.cppblog.com/shaker/aggbug/142548.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-03-23 10:01 <a href="http://www.cppblog.com/shaker/archive/2011/03/23/142548.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转帖】Windows网络体系结构总结</title><link>http://www.cppblog.com/shaker/archive/2011/02/22/140439.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Tue, 22 Feb 2011 06:48:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/02/22/140439.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/140439.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/02/22/140439.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/140439.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/140439.html</trackback:ping><description><![CDATA[<p><span style="FONT-FAMILY: 宋体; FONT-SIZE: 9pt"><span style="COLOR: #333333">标 题:</span><span style="COLOR: black">&nbsp;Windows网络体系结构总结</span><span style="COLOR: #666666"><br></span><span style="COLOR: #333333">作 者:</span><span style="COLOR: #666666">&nbsp;</span><span style="COLOR: black">jbwang</span><span style="COLOR: #666666"><br></span><span style="COLOR: #333333">时 间:</span><span style="COLOR: #666666">&nbsp;2009-11-23,11:22:25<br></span><span style="COLOR: #333333">链 接:</span><span style="COLOR: #666666">&nbsp;http://bbs.pediy.com/showthread.php?t=101794<br></span><span style="COLOR: #13253c"><br>做了一些东西自己也看了一些书，最近总结了一下，想给大家分享一下，高手可以飞过了。如果有什么问题可以给小弟指正一下，多谢！<img alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/022211_0647_Windows1.gif"><br><br>在介绍Windows网络体系架构之前，我首先介绍一下Windows中的两个重要编程规范——TDI，NDIS.，然后再介绍网络体系的架构。<br>TDI，Transport&nbsp;Driver&nbsp;Interface，传输驱动程序接口。\Windows\System32\Drivers\Tdi.sys<br>在实现网络API驱动程序时，由于牵涉到很多不同协议，会用到不同协议驱动提供的接口，使得开发的工作复杂化。所以Microsoft在网络API驱动程序和协议驱动之间又增加了一层TDI。TDI接口只是一种"将网络请求格式化成IRP，以及申请网络地址和数据通信"的做法规范化。遵从TDI标准的传输协议向他们的客户（如Socket&nbsp;emulator，Netbios&nbsp;emulator等）导出了TDI接口，有利于上下层之间的通信：<br>&nbsp;&nbsp;一方面，对于TDI上层的网络API驱动程序就不需要使用所有协议驱动程序所提供的接口，直接使用TDI提供的统一接口。<br>&nbsp;&nbsp;另一方面，对于下层协议驱动程序（也称为TDI&nbsp;Transport&nbsp;Provider传输器）直接由TDI接口来调用，发出请求。<br>&nbsp; </span></span></p>
<p style="TEXT-ALIGN: center"><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/140439-1.jpg" width=446 height=218><img alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/022211_0647_Windows2.png"><span style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt"> </span></p>
<p><span style="FONT-FAMILY: 宋体"><span style="COLOR: #13253c; FONT-SIZE: 9pt"><br>在Windows&nbsp;VISTA版本之后，TDI就不再使用了，取而代之的是Windows&nbsp;filter&nbsp;platform和Winsock&nbsp;kernel。<br><br>NDIS，Network&nbsp;Driver&nbsp;Interface&nbsp;Specification，网络驱动程序接口规范，在操作系统中的位置<br>\Windows\System32\Drivers\NDIS.sys<br>当一个协议驱动程序想要按照其协议的格式解析网上读写的数据时，而这些数据必须通过网络适配器才能取得，期望协议驱动程序能够理解市场上的每一款网络适配器的细微区别是不可能的。所以在1989年，由Microsoft和3Com联合开发的了NDIS，使得协议驱动程序可以以一种与设备无关的方式来跟网络适配器驱动程序进行通信。遵从NDIS的网络适配器驱动程序称为NDIS&nbsp;minport&nbsp;driver。</span><span style="FONT-SIZE: 12pt"> </span></span></p>
<p style="TEXT-ALIGN: center"><span style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt"><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/140439-2.jpg" width=289 height=277>&nbsp;</span></p>
<p><span style="FONT-FAMILY: 宋体"><span style="COLOR: #13253c; FONT-SIZE: 9pt">&nbsp;<br>NDIS规范实现了与TDI标准类似的功能，都是将复杂的下层调用规范化、标准化，大大提高了Windows操作系统的可扩展性和兼容性。也表现在两个方面：<br>&nbsp;&nbsp;对于下层，让网络适配器制造商很easy的开发自己的设备驱动程序，也就是Ndis&nbsp;miniport&nbsp;driver。这些miniport&nbsp;driver直接利用NDIS提供的接口发送指令，NDIS对这些格式化的指令进行解析，做进一步处理。（这些处理就到了HAL了）<br>&nbsp;&nbsp;对于上层，多个协议驱动程序与下层minport&nbsp;driver之间的通信，也都是通过统一的NDIS接口，NidsAllocatePacket，NdisSend等函数来收发数据。<br><br>废话两句：TDI和NDIS两大接口规范，有力的提升了Windows操作系统对不同设备厂商的支持，降低了设备厂商对设备驱动程序开发的难度；也增加了对于不同网络协议的支持，给用户更强大的网络功能支持。这种设计我们也可以在Windows存储管理中看到，从中我们似乎可以了解到一些，Windows操作系统在商业上取得成功的原因。Linux操作系统中没有这样的驱动层次结构。<br><br>设备制造商开发的Ndis&nbsp;miniport&nbsp;driver直接调用NDIS库中的接口函数，因此不需要考虑重入的问题，就是一个请求尚未结束的时候，新的请求又进来了。NDIS库对请求进行了序列化，但是这种序列化也妨碍了多处理器的扩展性。所以NDIS5中提供了非序列化的操作项。下面，我来介绍一下，Deserialized和Serialized&nbsp;minport&nbsp;driver的区别：<br>Deserialized&nbsp;NDIS&nbsp;miniport&nbsp;driver自己序列化对MinportXxx函数的操作，排队和管理多个并发请求的任务都由驱动程序自己来完成。而Serialized&nbsp;NDIS&nbsp;miniport&nbsp;driver以上的工作都是依赖于NDIS库来完成的。从性能角度看，Deserialized&nbsp;NDIS&nbsp;miniport&nbsp;driver的性能是Serialized&nbsp;NDIS&nbsp;miniport&nbsp;driver性能的2倍多，所以到NDIS6.0之后的所有Miniport&nbsp;driver都是deserialize的。<br><br>&nbsp;<br>以上是我参考MSDN以及自己的一些理解画出来的windows网络架构图，下面我就从上到下来简单介绍一下其中的各个层。</span><span style="FONT-SIZE: 12pt"> </span></span></p>
<p style="TEXT-ALIGN: center"><span style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt"><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/140439-3.jpg" width=554 height=523>&nbsp;</span></p>
<p><span style="FONT-FAMILY: 宋体"><span style="COLOR: #13253c; FONT-SIZE: 9pt"><br>1.&nbsp;&nbsp;网络应用程，Network&nbsp;applicantion，用户态的应用程序调用Windows操作系统提供的网络API，网络API包括：<br>a)&nbsp;&nbsp;Windows套接字（winsock）<br>b)&nbsp;&nbsp;远程过程调用RPC<br>c)&nbsp;&nbsp;Web访问API<br>d)&nbsp;&nbsp;命名管道和邮件槽<br>e)&nbsp;&nbsp;其他网络API<br>这些API既可以在用户模式下实现，也可以同时在用户模式和内核模式下实现。从本质上说这些API是下层提供接口的另一层封装而已。<br>2.&nbsp;&nbsp;TDI&nbsp;Clients，传输驱动程序接口客户，是内核模式的设备驱动程序，用于实现网络API的内核部分。将网络API的请求转换成IRP，通过TDI标准格式化后，发送给下层的协议驱动（也就是TDI传输器）。从sockets&nbsp;emulator的架构图看到，TDI&nbsp;Clients的实现可以有用户态的部分，也有内核态的部分。AFD辅助功能驱动程序通过向协议驱动程序发送TDI&nbsp;IRP来执行网络套接字操作，比如发送和接受消息。AFD没有不是确定使用哪一个协议驱动，而是上层通知其要使用的协议名称，然后AFD去打开相应协议的设备对象。</span><span style="FONT-SIZE: 12pt"> </span></span></p>
<p style="TEXT-ALIGN: center"><span style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt"><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/140439-4.jpg" width=374 height=356>&nbsp;</span></p>
<p><span style="FONT-FAMILY: 宋体; COLOR: #13253c; FONT-SIZE: 9pt">&nbsp;<br>3.&nbsp;&nbsp;TDI&nbsp;Transport&nbsp;Providers、TDI传输器、NDIS协议驱动程序、协议驱动程序，所有这些其实就是指的同一个东西，我在后面就称其为协议驱动程序。这个部分就是我们对某个协议的具体实现部分。做过网络协议开发的朋友一定知道，协议其实就是双发协商好的一套通信的规则。以IP协议为例，实际上就是对网络数据的一种处理方式，根据网络数据包的解析结构，做出相应的处理。Windows的tcpip.sys就实现了多个协议，ip、tcp、udp、arp、icmp、igmp，它为上层的TDI&nbsp;Clients提供了5个设备对象，用于访问使用这些协议，TDI&nbsp;Clients打开这些设备对象，向其发送IRP请求来实现自己的操作。通过DDK的DeviceTree我们可以得到这些设备对象<br>a)&nbsp;&nbsp;\Device\Rawip<br>b)&nbsp;&nbsp;\Device\Tcp<br>c)&nbsp;&nbsp;\Device\Udp<br>d)&nbsp;&nbsp;\Device\IPMULTICAST<br>e)&nbsp;&nbsp;\Device\Ip<br>协议驱动程序处理的数据是通过NDIS库中提供的接口来获取的，不需要发送IRP来取得。在DDK&nbsp;XP中提供了一个协议驱动程序了源程序Ndisuio，DDK&nbsp;XP后的版本提供的是Ndisport。在DriverEntry中我们可以看到，驱动程序一开始就注册了一个NDIS_PROTOCOL_CHARACTERISTICS，这个结构体中是一堆NdisXxxx函数。NDIS规范在这里就开始发挥它的作用了。<br>协议驱动程序的另一个作用就是监听网络数据，自己开发一个网络协议通过Ndis&nbsp;API获得所有的网络数据，但是不能够拦截网络数据，因为其他协议驱动也可以通过Nids&nbsp;API获取数据。一个典型的应用就是Winpcap了，使用NPF.SYS来捕获网络数据，并且做好充分缓冲处理，防止大数据量到来时出现数据包丢失的情况。详情情节winpcap的开源代码。<br>具体的协议驱动开发过程，我就不细述了，大家可以参看Ndisuio和DDK&nbsp;doc，我推荐boywhp的一篇文档《NDIS协议驱动开发》给大家。<br>4.&nbsp;&nbsp;NDIS，Network&nbsp;Driver&nbsp;Interface&nbsp;Specification，网络协议接口标准。从图中我们可以看到包裹在其中的两个驱动程序，一个是NDIS&nbsp;intermediate&nbsp;driver，NDIS中间层驱动程序，另一个是NDIS&nbsp;minport&nbsp;driver，小端口驱动程序。下面简单介绍一下这两个驱动程序：<br>a)&nbsp;&nbsp;Ndis&nbsp;intermediate&nbsp;driver，NDIS中间层驱动程序，对于上层的protocol&nbsp;driver它充当minport&nbsp;driver的作用，对于下层的minport&nbsp;driver它充当一个protocol&nbsp;driver的作用，所以在驱动程序DriverEntry中就注册NDIS_PROTOCOL_CHARACTERISTICS和NDIS_MINIPORT_CHARACTERISTICS，使用protocol&nbsp;characteristics中NDIS&nbsp;API从miniport&nbsp;driver那里取得数据包，再用miniport&nbsp;characteristics的NDIS&nbsp;API向上层的protocol&nbsp;driver发送数据包。Nids&nbsp;intermediate&nbsp;driver最大的优势就是所有miniport&nbsp;driver的数据包都要通过它这里倒手给protocol&nbsp;driver，所以网络防火墙就看上了这块风水宝地。现在很多网络防火墙都使用NDIS&nbsp;intermediate&nbsp;driver做数据包的过滤和拦截工作，过滤的规则设置到MPSendPackets，PTReceive，PTReceiveRacket这三个函数。具体开发过程请大家参考DDK提供的PassThru源代码，www.ndis.com，&nbsp;网上有很多相关的资料。<br>NDIS&nbsp;6.0之后，filter&nbsp;driver就取代了Ndis&nbsp;intermediate&nbsp;driver，WDK中提供源码。<br>b)&nbsp;&nbsp;Ndis&nbsp;miniport&nbsp;driver一般是由设备厂商提供的，在DDK中也提供了miniport&nbsp;driver的一个例子e100bex，支持Intel&nbsp;EtherExpressTM&nbsp;PRO/100+&nbsp;Ethernet&nbsp;PCI&nbsp;adapter&nbsp;和Intel&nbsp;EtherExpressTM&nbsp;PRO/100B&nbsp;PCI&nbsp;adapter两款网络适配器。<br>5.&nbsp;&nbsp;最后介绍一下总线，计算机总线有好几种，USB总线、ISA总线、PCI总线、虚拟总线等，一般都是以PCI总线作为根总线，在Windows系统中其他的总线可以理解为PCI总线上的一个设备。PCI总线作为根总线，其传输速度较高，可以达到133MB/S，显卡和网卡很多都是用PCI插槽。<br>PCI-ISA桥设备，也称为南桥，实现了ISA总线与PCI总线的桥接，&nbsp;南桥还包括终端、IDE、USB、DMA等控制器设备。其中USB-HOST设备实现了USB总线和PCI总线的桥接。HOST/PCI桥称为北桥，是主处理器中心啊到基础PCI局部总线。南桥和北桥组成了主板的芯片组，通过芯片的扩展实现了多种总线与基础PCI局部总线的桥接。<br>总线驱动程序和PNP管理器实现了即插即用的功能，物理设备对象PDO就是由总线驱动程序产生的。</span></p><img src ="http://www.cppblog.com/shaker/aggbug/140439.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-02-22 14:48 <a href="http://www.cppblog.com/shaker/archive/2011/02/22/140439.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows内核情景分析(前五章)</title><link>http://www.cppblog.com/shaker/archive/2011/02/18/140293.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Fri, 18 Feb 2011 14:57:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/02/18/140293.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/140293.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/02/18/140293.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/140293.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/140293.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Linux内核情景分析 作者毛德操的又一巨著<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/shaker/archive/2011/02/18/140293.html'>阅读全文</a><img src ="http://www.cppblog.com/shaker/aggbug/140293.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-02-18 22:57 <a href="http://www.cppblog.com/shaker/archive/2011/02/18/140293.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Delphi对象创建和释放过程</title><link>http://www.cppblog.com/shaker/archive/2011/02/06/139759.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Sun, 06 Feb 2011 03:36:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/02/06/139759.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/139759.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/02/06/139759.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/139759.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/139759.html</trackback:ping><description><![CDATA[<p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">一个类实例的生成需要经过对象内存分配、内存初始化、设置对象执行框架三个步骤。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">编译器首先调用</span><span style="font-family:Consolas">System._ClassCreate</span><span style="font-family:微软雅黑">进行对象内存分配、内存初始化的工作。而</span><span style="font-family:Consolas">System._ClassCreate</span><span style="font-family:微软雅黑">调用</span><span style="font-family:Consolas">TObject</span><span style="font-family:微软雅黑">类的虚方法</span><span style="font-family:Consolas">NewInstance</span><span style="font-family:微软雅黑">建立对象的实例空间，继承类通常不需要重载</span><span style="font-family:Consolas">TObject.NewInstance</span><span style="font-family:微软雅黑">，除非你使用自己的内存管理器，因此缺省是调用</span><span style="font-family:Consolas">TObject.NewInstance</span><span style="font-family:微软雅黑">。</span><span style="font-family:Consolas">TObject.NewInstance</span><span style="font-family:微软雅黑">方法将根据编译器在类信息数据中初始化的对象实例尺寸（</span><span style="font-family:Consolas">TObject.InstanceSize</span><span style="font-family:微软雅黑">），调用系统缺省的</span><span style="font-family:Consolas">MemoryManager.GetMem</span><span style="font-family:微软雅黑">过程为该对象在堆（</span><span style="font-family:Consolas">Heap</span><span style="font-family:微软雅黑">）中分配内存，然后调用</span><span style="font-family:Consolas">TObject.InitInstance</span><span style="font-family:微软雅黑">方法将分配的空间初始化。</span><span style="font-family:Consolas">InitInstance</span><span style="font-family:微软雅黑">方法首先将对象空间的头</span><span style="font-family:Consolas">4</span><span style="font-family:微软雅黑">个字节初始化为指向对象类的</span><span style="font-family:Consolas">VMT</span><span style="font-family:微软雅黑">的指针，然后将其余的空间清零。如果类中还设计了接口，它还要初始化接口表格（</span><span style="font-family:Consolas">Interface Table</span><span style="font-family:微软雅黑">）。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">当对象实例在内存中分配且初始化后，开始设置执行框架。所谓设置执行框架就是执行你在</span><span style="font-family:Consolas">Create</span><span style="font-family:微软雅黑">方法里真正写的代码。设置执行框架的规矩是先设置基类的框架，然后再设置继承类的，通常用</span><span style="font-family:Consolas">Inherited</span><span style="font-family:微软雅黑">关键字来实现。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">上述工作都做完后，编译器还要调用</span><span style="font-family:Consolas">System._AfterConstruction</span><span style="font-family:微软雅黑">让你有最后一次机会进行一些事务的处理工作。</span><span style="font-family:Consolas">System._AfterConstruction</span><span style="font-family:微软雅黑">是调用虚方法</span><span style="font-family:Consolas">AfterConstruction</span><span style="font-family:微软雅黑">实现的。在</span><span style="font-family:Consolas">TObject</span><span style="font-family:微软雅黑">中</span><span style="font-family:Consolas">AfterConstruction</span><span style="font-family:微软雅黑">中只是个</span><span style="font-family:Consolas">Place Holder</span><span style="font-family:微软雅黑">，你很少需要重载这个方法，重载这个方法通常只是为了与</span><span style="font-family:Consolas">C++ Builder</span><span style="font-family:微软雅黑">对象模型兼容。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">最后，编译器返回对象实例数据的地址指针。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">对象释放服务其实就是对象创建服务的逆过程，可以认为对象释放服务就是回收对象在创建过程中分配的资源。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">当编译器遇到</span><span style="font-family:Consolas">destructor</span><span style="font-family:微软雅黑">关键字通常会这样编码：首先调用</span><span style="font-family:Consolas">System._BeforeDestruction</span><span style="font-family:微软雅黑">，而</span><span style="font-family:Consolas">System._BeforeDestruction</span><span style="font-family:微软雅黑">继而调用虚方法</span><span style="font-family:Consolas">BeforeDestruction</span><span style="font-family:微软雅黑">，在</span><span style="font-family:Consolas">TObject</span><span style="font-family:微软雅黑">中</span><span style="font-family:Consolas">BeforeDestruction</span><span style="font-family:微软雅黑">中只是个</span><span style="font-family:Consolas">Place Holder</span><span style="font-family:微软雅黑">，你很少需要重载这个方法，重载这个方法通常只是为了与</span><span style="font-family:Consolas">C++ Builder</span><span style="font-family:微软雅黑">对象模型兼容。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">这之后，编译器调用你在</span><span style="font-family:Consolas">Destroy</span><span style="font-family:微软雅黑">中真正写的代码，如果当前你在撰写的类是继承链上的一员，不要忘记通过</span><span style="font-family:Consolas">inherited</span><span style="font-family:微软雅黑">调用父类的析构函数以释放父类分配的资源，但规矩是，先释放当前类的资源，然后再调用父类的，这和对象创建服务中设置对象执行框架的顺序恰好相反。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">当前类及继承链中所有类中分配的资源全部释放后，最后执行的就是释放掉对象本身及一些特别数据类型占用的内存空间。编译器调用</span><span style="font-family:Consolas">System._ClassDestroy</span><span style="font-family:微软雅黑">来完成这件工作。</span><span style="font-family:Consolas">System._ClassDestroy</span><span style="font-family:微软雅黑">继而调用虚方法</span><span style="font-family:Consolas">FreeInstance</span><span style="font-family:微软雅黑">，继承类通常不需要重载</span><span style="font-family:Consolas">TObject.FreeInstance</span><span style="font-family:微软雅黑">，除非你使用自己的内存管理器，因此缺省是调用</span><span style="font-family:Consolas">TObject.FreeInstance</span><span style="font-family:微软雅黑">。</span><span style="font-family:Consolas">TObject.FreeInstance</span><span style="font-family:微软雅黑">继而调用</span><span style="font-family:Consolas">TObject.CleanupInstance</span><span style="font-family:微软雅黑">完成对于字符串数组、宽字符串数组、</span><span style="font-family:Consolas">Variant</span><span style="font-family:微软雅黑">、未定义类型数组、记录、接口和动态数组这些特别数据类型占用资源的释放</span><span style="font-family:Consolas">[4]</span><span style="font-family:微软雅黑">，最后</span><span style="font-family:Consolas">TObject.FreeInstance</span><span style="font-family:微软雅黑">调用</span><span style="font-family:Consolas">MemoryManager.FreeMem</span><span style="font-family:微软雅黑">释放对象本身占用的内存空间。</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">很有意思的是，对象释放服务与对象创建服务所用方法、函数是一一对应的，是不是有一种很整齐的感觉？</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">对象创建服务</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">对象释放服务</span><span style="font-family:Consolas">
			</span></span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">System._ClassCreate
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">System._ClassDestroy
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">System._AfterConstruction
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">System._BeforeDestruction
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">TObject.AfterConstruction(virtual)
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">TObject.BeforeDestruction(virtual)
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">TObject.NewInstance(virtual)
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">TObject.FreeInstance(virtual)
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">TObject.InitInstance
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">TObject.CleanupInstance
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">MemoryManager.GetMem
</span></p><p><span style="color:black; font-family:Consolas; font-size:10pt">MemoryManager.FreeMem
</span></p><p><span style="color:black; font-size:10pt"><span style="font-family:微软雅黑">还有一点要注意，通常我们不会直接调用</span><span style="font-family:Consolas"> Destroy </span><span style="font-family:微软雅黑">来释放对象，而是调用</span><span style="font-family:Consolas"> TObject.Free</span><span style="font-family:微软雅黑">，它会在释放对象之前检查对象引用是否为</span><span style="font-family:Consolas"> nil</span><span style="font-family:微软雅黑">。</span></span></p><img src ="http://www.cppblog.com/shaker/aggbug/139759.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-02-06 11:36 <a href="http://www.cppblog.com/shaker/archive/2011/02/06/139759.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自己开发Delphi的VCL</title><link>http://www.cppblog.com/shaker/archive/2011/01/12/138379.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Wed, 12 Jan 2011 01:12:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2011/01/12/138379.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/138379.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2011/01/12/138379.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/138379.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/138379.html</trackback:ping><description><![CDATA[<p style="text-align: center"><span style="color:#ff3300; font-size:13pt"><strong><span style="font-family:宋体">自己开发</span><span style="font-family:Consolas">Delphi</span><span style="font-family:宋体">的</span><span style="font-family:Consolas">VCL
</span></strong></span></p><p><span style="color:#656d77"><span style="font-family:Consolas">Delphi</span><span style="font-family:宋体; font-size:10pt">为何成为广大程序员爱好的开发工具，其中一个原因就是它有大量的共享的</span><span style="font-family:Consolas">VCL</span><span style="font-family:宋体; font-size:10pt">库，打打扩展了</span><span style="font-family:Consolas">Delphi</span><span style="font-family:宋体; font-size:10pt">的功能。但是在实际的开发过程中，有时候根据项目的需要要开发自己的</span><span style="font-family:Consolas">VCL</span><span style="font-family:宋体; font-size:10pt">控件，我就有过不少这样的需求，因此自己也开发了多个</span><span style="font-family:Consolas">VCL</span><span style="font-size:10pt"><span style="font-family:宋体">控件，由于水平有限，功能也不是很强大，下面将自己的一些经验介绍一下。</span><span style="font-family:Consolas"> <br/>1</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">选择</span><span style="font-family:Consolas">File | New</span><span style="font-family:宋体">，在对话框中选择</span></span><span style="font-family:Consolas">C<span style="font-size:10pt">omponent</span></span><span style="font-family:宋体">。<span style="font-size:10pt">在</span></span><span style="font-family:Consolas">A<span style="font-size:10pt">ncestor Type</span></span><span style="font-size:10pt"><span style="font-family:宋体">中选择你的控件是从那个类继承下来的，然后在</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">"</span><span style="font-family:Consolas">Class Name</span><span style="font-family:宋体">"输入你的类的名称，在</span></span><span style="font-family:Consolas">P<span style="font-size:10pt">alette </span>P<span style="font-size:10pt">age </span></span><span style="font-family:宋体; font-size:10pt">中选择要把你的控件放到哪一个页面中。输入完毕后点击</span><span style="font-family:Consolas">OK</span><span style="font-size:10pt"><span style="font-family:宋体">，生成</span><span style="font-family:Consolas">pas</span><span style="font-family:宋体">文件。</span><span style="font-family:Consolas"> <br/>2</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">在控件中添加属性：</span><span style="font-family:Consolas"> <br/></span><span style="font-family:宋体">首先，控件的属性要存储在一个类变量中，比如一个类型为</span><span style="font-family:Consolas">string</span><span style="font-family:宋体">的变量，就可以存储在一个可以存储</span><span style="font-family:Consolas">string</span><span style="font-family:宋体">的类变量，比如一个</span><span style="font-family:Consolas">string</span><span style="font-family:宋体">，</span><span style="font-family:Consolas">TStringList</span><span style="font-family:宋体">等。因此首先要在类的</span><span style="font-family:Consolas">private</span><span style="font-family:宋体">区域声明一个私有的类变量，为了防止名字重复，一般在私有的类变量前加一个"</span><span style="font-family:Consolas">F</span><span style="font-family:宋体">"。如</span><span style="font-family:Consolas"> <br/>private<br/>  Fname:String<br/></span><span style="font-family:宋体">我们假设这个属性的名字叫</span><span style="font-family:Consolas"> FieldName</span><span style="font-family:宋体">，那我们就需要在</span><span style="font-family:Consolas">published</span><span style="font-family:宋体">区域加上如下语句：</span><span style="font-family:Consolas"><br/>property FieldName:String read Fname write Fname;<br/></span><span style="font-family:宋体">这样的属性你可以访问，但是不在</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">"</span><span style="font-family:Consolas">Object Inspector</span><span style="font-family:宋体">"中出现，如果想如此，应这样写：</span><span style="font-family:Consolas"><br/>property FieldName:String read Fname write Fname stored true;<br/></span><span style="font-family:宋体">这样的方法只实用于一些基本的数据类型，如</span><span style="font-family:Consolas">integer, double ,String</span><span style="font-family:宋体">等等，对一些类，如</span><span style="font-family:Consolas">Tstringlist</span><span style="font-family:宋体">，就不适合，对这些类应该怎么办呢？首先，还是要声明一个私有的变量存储该属性，以</span><span style="font-family:Consolas"> Tstringlist</span><span style="font-family:宋体">为例子：</span><span style="font-family:Consolas"> <br/>private Fnames:Tstringlist;<br/></span><span style="font-family:宋体">同时要写两个方法来对此类变量进行存取：</span><span style="font-family:Consolas"><br/>protected <br/>  Function getNames:Tstringlist; <br/>  Procedure setNames(value:Tstringlist); <br/></span><span style="font-family:宋体">在</span><span style="font-family:Consolas">getName</span><span style="font-family:宋体">的函数体中，应这样写：</span><span style="font-family:Consolas"><br/>begin <br/>  result:=Fname; <br/>end; <br/></span><span style="font-family:宋体">在</span><span style="font-family:Consolas">setNames</span><span style="font-family:宋体">的方法中，应这样写：</span><span style="font-family:Consolas"> <br/>begin <br/>  Fname.assign(value); <br/>end; <br/></span><span style="font-family:宋体">在</span><span style="font-family:Consolas">published</span><span style="font-family:宋体">中写：</span><span style="font-family:Consolas"> <br/>property Names:Tstringlist read getNames write setNames; <br/></span><span style="font-family:宋体">同样如果想要这个属性在</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">"</span><span style="font-family:Consolas">Object Inspector</span><span style="font-family:宋体">"中出现，要在后面加</span><span style="font-family:Consolas"> stored true. <br/></span><span style="font-family:宋体">当然，你也可以通过其他类型的类对这个属性进行存取，比如通过</span><span style="font-family:Consolas">Tlistbox</span><span style="font-family:宋体">来存取</span><span style="font-family:Consolas">Tstringlist</span><span style="font-family:宋体">，因为类</span><span style="font-family:Consolas">Tlistbox</span><span style="font-family:宋体">也包含有一个</span><span style="font-family:Consolas">Tstringlist</span><span style="font-family:宋体">类。</span><span style="font-family:Consolas"> <br/>3</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">在控件中添加方法</span><span style="font-family:Consolas"> <br/></span><span style="font-family:宋体">添加方法比较简单，在</span><span style="font-family:Consolas">published</span><span style="font-family:宋体">中声明方法，然后写方法体就可以。</span><span style="font-family:Consolas"> <br/>4</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">在控件中添加事件</span><span style="font-family:Consolas"> <br/></span><span style="font-family:宋体">添加事件之前，首先要声明一个事件类，如</span><span style="font-family:Consolas">TnotifyEvent <br/>private  <br/>  MyEvent:TnotifyEvent; <br/></span><span style="font-family:宋体">声明事件</span><span style="font-family:Consolas"> <br/>published <br/>  property OnMyEvent:TnotifyEvent read MyEvent write MyEvent stored true; <br/></span><span style="font-family:宋体">然后在特定的条件下调用这个事件：</span><span style="font-family:Consolas"> <br/>OnMyEvent(owner); <br/>5</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">写数据敏感的控件：</span><span style="font-family:Consolas"> <br/></span><span style="font-family:宋体">数据敏感的控件和普通控件基本相同，只是有一个类</span><span style="font-family:Consolas">Tdatalink</span><span style="font-family:宋体">，</span><span style="font-family:Consolas">Tdatalink</span><span style="font-family:宋体">有一个</span><span style="font-family:Consolas">onDatachange</span><span style="font-family:宋体">事件，你可以声明一个事件，然后将事件指向</span><span style="font-family:Consolas">Tdatalink</span><span style="font-family:宋体">的</span><span style="font-family:Consolas">onDatachange</span><span style="font-family:宋体">事件，然后在事件中写下程序就可以实现数据敏感了。</span><span style="font-family:Consolas"> <br/>  FDataLink.OnDataChange := DataChange; <br/></span><span style="font-family:宋体">然后在</span><span style="font-family:Consolas">Datachange</span><span style="font-family:宋体">中写程序。</span><span style="font-family:Consolas"> <br/>6</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">重载构造器和构析器。在</span><span style="font-family:Consolas">public</span><span style="font-family:宋体">或</span><span style="font-family:Consolas">published</span><span style="font-family:宋体">中写：</span><span style="font-family:Consolas"> <br/></span><span style="font-family:宋体">构造器：</span><span style="font-family:Consolas"> <br/>constructor Create(Aowner:Tcomponent); override; <br/></span><span style="font-family:宋体">构析器：</span><span style="font-family:Consolas"> <br/>destructor Destory; override; <br/></span><span style="font-family:宋体">在构造时对一些类变量进行初始化，有的需要调用类变量的类构造方法进行构造，如</span><span style="font-family:Consolas"> <br/>  Fnames:=Tstirnglist.create; <br/></span><span style="font-family:宋体">在构析时对类变量进行释放</span><span style="font-family:Consolas"> <br/>  Fnames.Free; <br/>7</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">对于一些界面有关的控件，如果有特殊的界面需要，需要重载</span><span style="font-family:Consolas">onpaint</span><span style="font-family:宋体">事件，在重画时对自己的</span><span style="font-family:Consolas">canvas</span><span style="font-family:宋体">进行操作，当然，也可以对别的类的</span><span style="font-family:Consolas">canvas</span><span style="font-family:宋体">进行操作，比如写一个控件，在重画时对它的容器用一个画进行平铺处理。</span><span style="font-family:Consolas"> <br/>8</span><span style="font-family:宋体">、</span><span style="font-family:Consolas">
				</span><span style="font-family:宋体">对于从哪些类继承，根据自己的需要选择，尽可能选择功能接近，已经实现部分功能的类，这样写比较方便。</span><span style="font-family:Consolas"> <br/></span><span style="font-family:宋体">以上是自己的一些心得，还望多多指正。</span></span></span></p><img src ="http://www.cppblog.com/shaker/aggbug/138379.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2011-01-12 09:12 <a href="http://www.cppblog.com/shaker/archive/2011/01/12/138379.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZT]正则表达式30分钟入门教程</title><link>http://www.cppblog.com/shaker/archive/2010/08/31/125461.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Tue, 31 Aug 2010 14:19:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2010/08/31/125461.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/125461.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2010/08/31/125461.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/125461.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/125461.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/shaker/archive/2010/08/31/125461.html'>阅读全文</a><img src ="http://www.cppblog.com/shaker/aggbug/125461.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2010-08-31 22:19 <a href="http://www.cppblog.com/shaker/archive/2010/08/31/125461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Pro OGRE 3D Programming 中文翻译版本0.2.0</title><link>http://www.cppblog.com/shaker/archive/2010/08/18/123851.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Wed, 18 Aug 2010 09:04:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2010/08/18/123851.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/123851.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2010/08/18/123851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/123851.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/123851.html</trackback:ping><description><![CDATA[<object id=reader codeBase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" classid=clsid:d27cdb6e-ae6d-11cf-96b8-444553540000 width=900 align=middle height=800>
<param value="http://wenku.baidu.com/static/flash/apireader.swf?docurl=http://wenku.baidu.com/play&amp;docid=8209ca45b307e87101f6962c&amp;title=Pro OGRE 3D Programming&amp;doctype=pdf&amp;fpn=5&amp;npn=5&amp;readertype=external" name="movie"><embed height="500" align="middle" width="630" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" name="reader" src="http://wenku.baidu.com/static/flash/apireader.swf?docurl=http://wenku.baidu.com/play&amp;docid=8209ca45b307e87101f6962c&amp;title=Pro OGRE 3D Programming&amp;doctype=pdf&amp;fpn=5&amp;npn=5&amp;readertype=external" allowfullscreen="true" wmode="window" allowscriptaccess="always" bgcolor="#FFFFFF" ver="9.0.0"></embed></object><img src ="http://www.cppblog.com/shaker/aggbug/123851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2010-08-18 17:04 <a href="http://www.cppblog.com/shaker/archive/2010/08/18/123851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Boost的状态机库教程 补充</title><link>http://www.cppblog.com/shaker/archive/2010/08/16/123601.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Mon, 16 Aug 2010 06:55:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2010/08/16/123601.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/123601.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2010/08/16/123601.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/123601.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/123601.html</trackback:ping><description><![CDATA[<p>来自:<a href="http://www.cppblog.com/shanoa/archive/2009/05/30/86143.html">http://www.cppblog.com/shanoa/archive/2009/05/30/86143.html</a><br>接触了boost的状态机，发现不是想象中的那么好用，在一些地方还得用上mpl库里的东西，由于对模板元编程不是很熟练，搞了好些天才算弄明白这该死的mpl::list的原理和用法。<br>boost的状态机是属于静态链接的状态机，也就是说，它的图结构是编译期间就确定了的，在运行时不可以动态配置。所以，它的用途是有一定局限性的，但在一般情况下，它不仅很通用，而且在你会用并熟练地情况下，还会很好用，用起来很舒服，逻辑也很合理。下面就是一段代码，当然也是借鉴了别人的东西，自己修改了一下，在MainState中添加了一个Transition做了测试，因为此前我还不知道一个状态如何包含多个Transition，呵呵，原来是用mpl::list来做。至于这个状态机的入门教程，网上随处可见的三部曲：《boost 状态机入门教程》说得很清楚。<br></p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080">&nbsp;&nbsp;1</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;2</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">ctime</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;3</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;4</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">transition.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;5</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;6</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">state_machine.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;7</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">simple_state.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;8</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;&nbsp;9</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sc&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;boost::statechart;<br></span><span style="COLOR: #008080">&nbsp;10</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;11</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;12</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;13</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;EvtStartStop&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtStartStop</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">{};<br></span><span style="COLOR: #008080">&nbsp;14</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;EvtReset&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtReset</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">{};<br></span><span style="COLOR: #008080">&nbsp;15</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;EvtGo&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtGo</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">{};<br></span><span style="COLOR: #008080">&nbsp;16</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;17</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;18</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;MainState;<br></span><span style="COLOR: #008080">&nbsp;19</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;StopState;<br></span><span style="COLOR: #008080">&nbsp;20</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;RunState;<br></span><span style="COLOR: #008080">&nbsp;21</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TwoState;<br></span><span style="COLOR: #008080">&nbsp;22</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;23</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Machine&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::state_machine</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Machine,&nbsp;MainState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;24</span>&nbsp;<span style="COLOR: #000000">{};<br></span><span style="COLOR: #008080">&nbsp;25</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;26</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;27</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;28</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;29</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;30</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;31</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;MainState&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MainState,&nbsp;Machine,&nbsp;StopState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;32</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;33</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;34</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;sc::transition</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtReset,&nbsp;MainState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactReset;<br></span><span style="COLOR: #008080">&nbsp;35</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;sc::transition</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtGo,&nbsp;TwoState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactGo;<br></span><span style="COLOR: #008080">&nbsp;36</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;boost::mpl::list</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">reactReset,&nbsp;reactGo</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactions;<br></span><span style="COLOR: #008080">&nbsp;37</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;38</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;MainState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;39</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">进入MainState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;40</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mTime&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;41</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;42</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;43</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">MainState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;44</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">退出MainState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;45</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;46</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;47</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">double</span><span style="COLOR: #000000">&nbsp;mTime;<br></span><span style="COLOR: #008080">&nbsp;48</span>&nbsp;<span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">&nbsp;49</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;50</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;51</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;该状态属于无用状态，用于测试mpl::list的多transition用法</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;52</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TwoState&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">TwoState,&nbsp;Machine</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;53</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;54</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;55</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;sc::transition</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtGo,&nbsp;MainState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactions;<br></span><span style="COLOR: #008080">&nbsp;56</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;57</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;TwoState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;58</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">进入TwoState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;59</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;60</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;61</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TwoState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;62</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">退出TwoState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;63</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;64</span>&nbsp;<span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">&nbsp;65</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;66</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;67</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;StopState&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">StopState,&nbsp;MainState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;68</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;69</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;70</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;sc::transition</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtStartStop,&nbsp;RunState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactions;<br></span><span style="COLOR: #008080">&nbsp;71</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;StopState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;72</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">进入StopState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;73</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;74</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;75</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">StopState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;76</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">退出StopState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;77</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;78</span>&nbsp;<span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">&nbsp;79</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;80</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;RunState&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">RunState,&nbsp;MainState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;81</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;82</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;83</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;sc::transition</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">EvtStartStop,&nbsp;StopState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactions;<br></span><span style="COLOR: #008080">&nbsp;84</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;RunState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;85</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">进入RunState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;86</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mStartTime&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;87</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;88</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;89</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">RunState(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">&nbsp;90</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">退出RunState</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">std::endl;<br></span><span style="COLOR: #008080">&nbsp;91</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;context</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">MainState</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">().mTime&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;std::difftime(std::time(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">),&nbsp;mStartTime);<br></span><span style="COLOR: #008080">&nbsp;92</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;93</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;94</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;std::time_t&nbsp;mStartTime;<br></span><span style="COLOR: #008080">&nbsp;95</span>&nbsp;<span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">&nbsp;96</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;97</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;98</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br></span><span style="COLOR: #008080">&nbsp;99</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">100</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Machine&nbsp;mc;<br></span><span style="COLOR: #008080">101</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;mc.initiate();<br></span><span style="COLOR: #008080">102</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">103</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;mc.process_event(EvtStartStop());<br></span><span style="COLOR: #008080">104</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;mc.process_event(EvtStartStop());<br></span><span style="COLOR: #008080">105</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;mc.process_event(EvtReset());<br></span><span style="COLOR: #008080">106</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;mc.process_event(EvtGo());<br></span><span style="COLOR: #008080">107</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;mc.process_event(EvtGo());<br></span><span style="COLOR: #008080">108</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">109</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">110</span>&nbsp;<span style="COLOR: #000000">}</span></div><img src ="http://www.cppblog.com/shaker/aggbug/123601.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2010-08-16 14:55 <a href="http://www.cppblog.com/shaker/archive/2010/08/16/123601.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Boost的状态机库教程(3)</title><link>http://www.cppblog.com/shaker/archive/2010/08/16/123599.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Mon, 16 Aug 2010 06:53:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2010/08/16/123599.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/123599.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2010/08/16/123599.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/123599.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/123599.html</trackback:ping><description><![CDATA[<div class=Section0>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><strong><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">1.2 增加动作</span> </span></strong></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><br><strong></strong><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp; 此时我们将只用一种动作：transitions，我们在下面的代码中插入了黑体的部分。</span> </p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080">&nbsp;1</span><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><strong><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">transition.hpp</span><span style="COLOR: #000000">&gt;</span></strong><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Stopped;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Active&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Active,&nbsp;StopWatch,&nbsp;Stopped&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img id=Codehighlighter1_133_192_Open_Image onclick="this.style.display='none'; Codehighlighter1_133_192_Open_Text.style.display='none'; Codehighlighter1_133_192_Closed_Image.style.display='inline'; Codehighlighter1_133_192_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_133_192_Closed_Image onclick="this.style.display='none'; Codehighlighter1_133_192_Closed_Text.style.display='none'; Codehighlighter1_133_192_Open_Image.style.display='inline'; Codehighlighter1_133_192_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_133_192_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_133_192_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;<strong>typedef&nbsp;&nbsp;sc::transition</strong></span><strong><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;EvReset,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span></strong><span style="COLOR: #000000"><strong>&nbsp;reactions;</strong><br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Running&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Running,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img id=Codehighlighter1_250_314_Open_Image onclick="this.style.display='none'; Codehighlighter1_250_314_Open_Text.style.display='none'; Codehighlighter1_250_314_Closed_Image.style.display='inline'; Codehighlighter1_250_314_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_250_314_Closed_Image onclick="this.style.display='none'; Codehighlighter1_250_314_Closed_Text.style.display='none'; Codehighlighter1_250_314_Open_Image.style.display='inline'; Codehighlighter1_250_314_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_250_314_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_250_314_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;<strong>typedef&nbsp;&nbsp;sc::transition</strong></span><strong><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;EvStartStop,&nbsp;Stopped&nbsp;</span><span style="COLOR: #000000">&gt;</span></strong><span style="COLOR: #000000"><strong>&nbsp;reactions;</strong><br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Stopped&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Stopped,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img id=Codehighlighter1_372_436_Open_Image onclick="this.style.display='none'; Codehighlighter1_372_436_Open_Text.style.display='none'; Codehighlighter1_372_436_Closed_Image.style.display='inline'; Codehighlighter1_372_436_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_372_436_Closed_Image onclick="this.style.display='none'; Codehighlighter1_372_436_Closed_Text.style.display='none'; Codehighlighter1_372_436_Open_Image.style.display='inline'; Codehighlighter1_372_436_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_372_436_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_372_436_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;<strong>typedef&nbsp;&nbsp;sc::transition</strong></span><strong><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;EvStartStop,&nbsp;Running&nbsp;</span><span style="COLOR: #000000">&gt;</span></strong><span style="COLOR: #000000"><strong>&nbsp;reactions;</strong><br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">一个状态可以定义任意数量的动作。这就是为什么当多于一个时，<br></span><span style="COLOR: #008080">22</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">我们不得不将它们放到一个mpl::list&lt;&gt;&nbsp;里。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">23</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;main()<br></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img id=Codehighlighter1_514_737_Open_Image onclick="this.style.display='none'; Codehighlighter1_514_737_Open_Text.style.display='none'; Codehighlighter1_514_737_Closed_Image.style.display='inline'; Codehighlighter1_514_737_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_514_737_Closed_Image onclick="this.style.display='none'; Codehighlighter1_514_737_Closed_Text.style.display='none'; Codehighlighter1_514_737_Open_Image.style.display='inline'; Codehighlighter1_514_737_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_514_737_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_514_737_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">26</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;StopWatch&nbsp;myWatch;<br></span><span style="COLOR: #008080">27</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;myWatch.initiate();<br></span><span style="COLOR: #008080">28</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;<strong>myWatch.process_event(&nbsp;EvStartStop()&nbsp;);<br></strong></span><span style="COLOR: #008080">29</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;<strong>myWatch.process_event(&nbsp;EvStartStop()&nbsp;);</strong><br></span><span style="COLOR: #008080">30</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;<strong>myWatch.process_event(&nbsp;EvStartStop()&nbsp;);<br></strong></span><span style="COLOR: #008080">31</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;<strong>myWatch.process_event(&nbsp;EvReset()&nbsp;);<br></strong></span><span style="COLOR: #008080">32</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">33</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">34</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span></div>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><br></span></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp; 现在我们有了所有的状态，并在适当的位置增加了所有的迁移动作，同时我们也向StopWatch发送了一些事件。这个状态机会尽职尽责的按我们的希望进行状态迁移，但依然现在还没有其它的动作。</span> </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><br></span></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><strong><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt">1.3 State-local<span style="FONT-FAMILY: 宋体">存储</span> </span></strong></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><br><strong></strong><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp; 下一步我们将让这个Stop&nbsp;watch真正的记录时间了。根据stop&nbsp;watch所处不同的状态，我们需要不同的变量。</span> </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="MARGIN-TOP: 0pt; TEXT-INDENT: -21pt; MARGIN-BOTTOM: 0pt; MARGIN-LEFT: 21pt" class=p0><span style="FONT-FAMILY: 'Wingdings'; FONT-SIZE: 10.5pt">l&nbsp;</span> <span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt">Stopped<span style="FONT-FAMILY: 宋体">状态：需要一个保存逝去时间的变量。</span> </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="MARGIN-TOP: 0pt; TEXT-INDENT: -21pt; MARGIN-BOTTOM: 0pt; MARGIN-LEFT: 21pt" class=p0><span style="FONT-FAMILY: 'Wingdings'; FONT-SIZE: 10.5pt">l </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt">Running<span style="FONT-FAMILY: 宋体">状态：需要一个保存逝去时间的变量，还需要一个保存上一次启动的时间点的变量。</span> </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp; 无论状态机在什么状态下，我们都必须观察逝去时间这个变量。此外，当我们向状态机发送EvReSet事件时，这个变量应该被置为0。其它的变量只是状态机在Running状态时需要。无论何时我们进入Running状态时，它应该被置为系统时钟的当前时间。当我们退出Running状态时，我们仅仅从系统时钟的当前时间减去开始时间（进入时记录的时间），将结果加到逝去时间里就可以了。</span> </p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080">&nbsp;1</span><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><strong><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">ctime</span><span style="COLOR: #000000">&gt;</span></strong><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Stopped;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Active&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Active,&nbsp;StopWatch,&nbsp;Stopped&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img id=Codehighlighter1_107_378_Open_Image onclick="this.style.display='none'; Codehighlighter1_107_378_Open_Text.style.display='none'; Codehighlighter1_107_378_Closed_Image.style.display='inline'; Codehighlighter1_107_378_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_107_378_Closed_Image onclick="this.style.display='none'; Codehighlighter1_107_378_Closed_Text.style.display='none'; Codehighlighter1_107_378_Open_Image.style.display='inline'; Codehighlighter1_107_378_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_107_378_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_107_378_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff"><strong>public</strong></span><span style="COLOR: #000000"><strong>&nbsp;:<br></strong></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;&nbsp;sc::transition</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;EvReset,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactions;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"><br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img id=Codehighlighter1_216_217_Open_Image onclick="this.style.display='none'; Codehighlighter1_216_217_Open_Text.style.display='none'; Codehighlighter1_216_217_Closed_Image.style.display='inline'; Codehighlighter1_216_217_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_216_217_Closed_Image onclick="this.style.display='none'; Codehighlighter1_216_217_Closed_Text.style.display='none'; Codehighlighter1_216_217_Open_Image.style.display='inline'; Codehighlighter1_216_217_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;<strong>Active()&nbsp;:&nbsp;elapsedTime_(&nbsp;</strong></span><span style="COLOR: #000000"><strong>0.0</strong></span><span style="COLOR: #000000"><strong>&nbsp;)</strong>&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_216_217_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_216_217_Open_Text><span style="COLOR: #000000"><strong>{}</strong></span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img id=Codehighlighter1_254_279_Open_Image onclick="this.style.display='none'; Codehighlighter1_254_279_Open_Text.style.display='none'; Codehighlighter1_254_279_Closed_Image.style.display='inline'; Codehighlighter1_254_279_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_254_279_Closed_Image onclick="this.style.display='none'; Codehighlighter1_254_279_Closed_Text.style.display='none'; Codehighlighter1_254_279_Open_Image.style.display='inline'; Codehighlighter1_254_279_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><span style="COLOR: #0000ff">double</span><span style="COLOR: #000000">&nbsp;&nbsp;ElapsedTime()&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span></strong><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_254_279_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_254_279_Open_Text><strong><span style="COLOR: #000000">{&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;elapsedTime_;&nbsp;}</span></strong></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img id=Codehighlighter1_310_335_Open_Image onclick="this.style.display='none'; Codehighlighter1_310_335_Open_Text.style.display='none'; Codehighlighter1_310_335_Closed_Image.style.display='inline'; Codehighlighter1_310_335_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_310_335_Closed_Image onclick="this.style.display='none'; Codehighlighter1_310_335_Closed_Text.style.display='none'; Codehighlighter1_310_335_Open_Image.style.display='inline'; Codehighlighter1_310_335_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><span style="COLOR: #0000ff">double</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span></strong><span style="COLOR: #000000"><strong>&nbsp;ElapsedTime()</strong>&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_310_335_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_310_335_Open_Text><strong><span style="COLOR: #000000">{&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;elapsedTime_;&nbsp;}</span></strong></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff"><strong>private</strong></span><span style="COLOR: #000000"><strong>&nbsp;:<br></strong></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff"><strong>double</strong></span><span style="COLOR: #000000"><strong>&nbsp;&nbsp;elapsedTime_&nbsp;;<br></strong></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Running&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Running,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img id=Codehighlighter1_436_875_Open_Image onclick="this.style.display='none'; Codehighlighter1_436_875_Open_Text.style.display='none'; Codehighlighter1_436_875_Closed_Image.style.display='inline'; Codehighlighter1_436_875_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_436_875_Closed_Image onclick="this.style.display='none'; Codehighlighter1_436_875_Closed_Text.style.display='none'; Codehighlighter1_436_875_Open_Image.style.display='inline'; Codehighlighter1_436_875_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_436_875_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_436_875_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff"><strong>public</strong></span><span style="COLOR: #000000"><strong>&nbsp;:<br></strong></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;&nbsp;sc::transition</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;EvStartStop,&nbsp;Stopped&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;reactions;<br></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"><br></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img id=Codehighlighter1_560_561_Open_Image onclick="this.style.display='none'; Codehighlighter1_560_561_Open_Text.style.display='none'; Codehighlighter1_560_561_Closed_Image.style.display='inline'; Codehighlighter1_560_561_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_560_561_Closed_Image onclick="this.style.display='none'; Codehighlighter1_560_561_Closed_Text.style.display='none'; Codehighlighter1_560_561_Open_Image.style.display='inline'; Codehighlighter1_560_561_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;<strong>Running()&nbsp;:&nbsp;startTime_(&nbsp;std::time(&nbsp;</strong></span><strong><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;)&nbsp;</span></strong><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_560_561_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_560_561_Open_Text><span style="COLOR: #000000"><strong>{}</strong></span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;<strong>&nbsp;</strong></span><span style="COLOR: #000000"><strong>~</strong></span><span style="COLOR: #000000"><strong>Running()<br></strong></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img id=Codehighlighter1_582_830_Open_Image onclick="this.style.display='none'; Codehighlighter1_582_830_Open_Text.style.display='none'; Codehighlighter1_582_830_Closed_Image.style.display='inline'; Codehighlighter1_582_830_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_582_830_Closed_Image onclick="this.style.display='none'; Codehighlighter1_582_830_Closed_Text.style.display='none'; Codehighlighter1_582_830_Open_Image.style.display='inline'; Codehighlighter1_582_830_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_582_830_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_582_830_Open_Text><span style="COLOR: #000000"><strong>{<br></strong></span><span style="COLOR: #008080">26</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000"><strong>//</strong></span><span style="COLOR: #008000"><strong>&nbsp;与派生类可以访问它的基类相似，<br></strong></span><span style="COLOR: #008080">27</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000"><strong>//</strong></span><span style="COLOR: #008000"><strong>context&lt;&gt;()&nbsp;用来获得一个状态的直接或间接的上下文的访问权。<br></strong></span><span style="COLOR: #008080">28</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>&nbsp;</strong></span><span style="COLOR: #008000"><strong>//</strong></span><span style="COLOR: #008000"><strong>&nbsp;这可以是直接或间接的外层状态或状态机本身<br></strong></span><span style="COLOR: #008080">29</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;(例如，像这样:&nbsp;context&lt;&nbsp;StopWatch&nbsp;&gt;()).</span></strong><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">30</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>context</strong></span><strong><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">().ElapsedTime()&nbsp;</span><span style="COLOR: #000000">+=</span></strong><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">31</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>std::difftime(&nbsp;std::time(&nbsp;</strong></span><span style="COLOR: #000000"><strong>0</strong></span><span style="COLOR: #000000"><strong>&nbsp;),&nbsp;startTime_&nbsp;);<br></strong></span><span style="COLOR: #008080">32</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">&nbsp;&nbsp;&nbsp;&nbsp;<strong>}</strong></span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">33</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff"><strong>private</strong></span><span style="COLOR: #000000"><strong>&nbsp;:<br></strong></span><span style="COLOR: #008080">34</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;<strong>&nbsp;std::&nbsp;time_t&nbsp;&nbsp;startTime_;<br></strong></span><span style="COLOR: #008080">35</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">;</span></div>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0></span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp; 这个状态机现在可以测量时间了，但是我们还不能看到结果。</span> </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">在这里，State-local&nbsp;storage的优势还没有完成显现出来。在FAQ项目&#8220;State-local&nbsp;storage酷在哪里？&#8221;中，会通过与一个没有用State-local&nbsp;storage的Stop&nbsp;Watch的比较来说明。</span> </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体"><br></span></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><strong><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">1.4 在状态机外得到状态信息</span> </span></strong><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体"><br></span></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp; 为了取得测量的时间，我们需要一个从状态机外得到状态信息的机制。按我们现在的状态机设计，可以有两种方法。为简单起见，我们在这里用一个低效的方式：state_cast&lt;&gt;()(在StopWatch2.cpp中我们会用一个稍复杂一点的替代方法)（<span style="COLOR: #000080">译者注：在StopWatch2.cpp中是向状态机发送一个取得逝去时间的事件，从事件成员量中将逝去时间带回来</span> ），从字面意思就可以看出，它在语义上与dynamic_cast有点相似。例如，当我们调用myWatch.state_cast&lt;const&nbsp;Stpped&amp;&gt;()时，当状态机在Stopped状态时，我们会得到一个Stopped状态类的引用。否则，会抛出std::bad_cast异常。我们可以利用这个功能来实现一个StopWatch的成员函数，让它的结果返回逝去的时间。然而，我们不是先问一下状态机在什么状态，然后再去用不同的方法计算逝去时间，而是将计算放到Stopped和Running状态中，用一个接口来获得逝去逝去时间。</span> </span><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; MARGIN-BOTTOM: 0pt" class=p0>&nbsp;</p>
<div class=highlighter>
<ol class=highlighter-cpp>
    <li><strong><span class=preprocessor>#include&nbsp;&lt;iostream&gt;&nbsp;</span> </strong>
    <li class=alt><span></span>
    <li><span class=comment>//&nbsp;...&nbsp;</span>
    <li class=alt><span></span>
    <li><strong><span class=keyword>struct</span> <span>&nbsp;IElapsedTime&nbsp;</span> </strong>
    <li class=alt><strong><span>{&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;</span> <span class=keyword>virtual</span> <span>&nbsp;</span> <span class=datatypes>double</span> <span>&nbsp;ElapsedTime()&nbsp;</span> <span class=keyword>const</span> <span>&nbsp;=&nbsp;0;&nbsp;</span> </strong>
    <li class=alt><strong><span>};&nbsp;</span> </strong>
    <li><span></span>
    <li class=alt><span class=keyword>struct</span> <span>&nbsp;Active;&nbsp;</span>
    <li><span class=keyword>struct</span> <span>&nbsp;StopWatch&nbsp;:&nbsp;sc::state_machine&lt;&nbsp;StopWatch,&nbsp;Active&nbsp;&gt;&nbsp;</span>
    <li class=alt><span>{&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span> <strong><span class=datatypes>double</span> <span>&nbsp;ElapsedTime()&nbsp;</span> <span class=keyword>const</span> <span>&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;{&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>return</span> <span>&nbsp;state_cast&lt;&nbsp;</span> <span class=keyword>const</span> <span>&nbsp;IElapsedTime&nbsp;&amp;&nbsp;&gt;().ElapsedTime();&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;}&nbsp;</span> </strong>
    <li><span>};&nbsp;</span>
    <li class=alt><span></span>
    <li><span class=comment>//&nbsp;...&nbsp;</span>
    <li class=alt><span></span>
    <li><span class=keyword>struct</span> <span>&nbsp;Running&nbsp;:&nbsp;<strong>IElapsedTime,</strong> &nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;sc::simple_state&lt;&nbsp;Running,&nbsp;Active&nbsp;&gt;&nbsp;</span>
    <li><span>{&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;</span> <span class=keyword>public</span> <span>:&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>typedef</span> <span>&nbsp;sc::transition&lt;&nbsp;EvStartStop,&nbsp;Stopped&nbsp;&gt;&nbsp;reactions;&nbsp;</span>
    <li class=alt><span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;Running()&nbsp;:&nbsp;startTime_(&nbsp;std::time(&nbsp;0&nbsp;)&nbsp;)&nbsp;{}&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;~Running()&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>context&lt;&nbsp;Active&nbsp;&gt;().ElapsedTime()&nbsp;=&nbsp;ElapsedTime();&nbsp;</strong> </span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>virtual</span> <span>&nbsp;</span> <span class=datatypes>double</span> <span>&nbsp;ElapsedTime()&nbsp;</span> <span class=keyword>const</span> <span>&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>return</span> <span>&nbsp;context&lt;&nbsp;Active&nbsp;&gt;().ElapsedTime()&nbsp;+&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::difftime(&nbsp;std::time(&nbsp;0&nbsp;),&nbsp;startTime_&nbsp;);&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>private</span> <span>:&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::</span> <span class=datatypes>time_t</span> <span>&nbsp;startTime_;&nbsp;</span> </strong>
    <li><span><strong>&nbsp;&nbsp;&nbsp;&nbsp;};</strong> &nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>struct</span> <span>&nbsp;Stopped&nbsp;:<strong>&nbsp;IElapsedTime,</strong> &nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sc::simple_state&lt;&nbsp;Stopped,&nbsp;Active&nbsp;&gt;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>typedef</span> <span>&nbsp;sc::transition&lt;&nbsp;EvStartStop,&nbsp;Running&nbsp;&gt;&nbsp;reactions;&nbsp;</span>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>virtual</span> <span>&nbsp;</span> <span class=datatypes>double</span> <span>&nbsp;ElapsedTime()&nbsp;</span> <span class=keyword>const</span> <span>&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>return</span> <span>&nbsp;context&lt;&nbsp;Active&nbsp;&gt;().ElapsedTime();&nbsp;</span> </strong>
    <li><span><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</strong> &nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=datatypes>int</span> <span>&nbsp;main()&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StopWatch&nbsp;myWatch;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myWatch.initiate();&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>std::cout&nbsp;&lt;&lt;&nbsp;myWatch.ElapsedTime()&nbsp;&lt;&lt;&nbsp;</strong> </span><strong><span class=string>"\n"</span> </strong><span><strong>;</strong> &nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myWatch.process_event(&nbsp;EvStartStop()&nbsp;);&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>std::cout&nbsp;&lt;&lt;&nbsp;myWatch.ElapsedTime()&nbsp;&lt;&lt;&nbsp;</strong> </span><strong><span class=string>"\n"</span> <span>;&nbsp;</span> </strong>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myWatch.process_event(&nbsp;EvStartStop()&nbsp;);&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>std::cout&nbsp;&lt;&lt;&nbsp;myWatch.ElapsedTime()&nbsp;&lt;&lt;&nbsp;</strong> </span><strong><span class=string>"\n"</span> <span>;&nbsp;</span> </strong>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myWatch.process_event(&nbsp;EvStartStop()&nbsp;);&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>std::cout&nbsp;&lt;&lt;&nbsp;myWatch.ElapsedTime()&nbsp;&lt;&lt;&nbsp;</strong> </span><strong><span class=string>"\n"</span> <span>;&nbsp;</span> </strong>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myWatch.process_event(&nbsp;EvReset()&nbsp;);&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>std::cout&nbsp;&lt;&lt;&nbsp;myWatch.ElapsedTime()&nbsp;&lt;&lt;&nbsp;</strong> </span><strong><span class=string>"\n"</span> <span>;&nbsp;</span> </strong>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span class=keyword>return</span> <span>&nbsp;0;&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span> </li>
</ol>
</div>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; TEXT-INDENT: 21pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"></span></p>
<p style="TEXT-ALIGN: justify; MARGIN-TOP: 0pt; TEXT-INDENT: 21pt; MARGIN-BOTTOM: 0pt" class=p0><span style="FONT-FAMILY: '宋体'; FONT-SIZE: 10.5pt"><span style="FONT-FAMILY: 宋体">为了确实看到被测量的时间，你应该想办法在main()中单步执行。StopWatch例子将这个程序扩展为一个交互式的终端程序了。</span></span></p>
</div><img src ="http://www.cppblog.com/shaker/aggbug/123599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2010-08-16 14:53 <a href="http://www.cppblog.com/shaker/archive/2010/08/16/123599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Boost的状态机库教程(2)</title><link>http://www.cppblog.com/shaker/archive/2010/08/16/123598.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Mon, 16 Aug 2010 06:45:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2010/08/16/123598.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/123598.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2010/08/16/123598.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/123598.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/123598.html</trackback:ping><description><![CDATA[<p><span style="COLOR: #000000"><strong>1 基础主题：秒表</strong><br>&nbsp;&nbsp;&nbsp; 下面我们要为一个机械秒表建模一个状态机。这样一个秒表通常会有两个按钮。<br>&nbsp;&nbsp;&nbsp;&nbsp; * Start/Stop<br>&nbsp;&nbsp;&nbsp;&nbsp; * Reset<br>&nbsp;&nbsp;&nbsp;&nbsp; 同时有两种状态：<br>&nbsp;&nbsp;&nbsp;&nbsp; * Stoped: 表针停留在上次停止时的位置：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o 按下Reset按钮，表针回退到0的位置。秒表保持在Stoped状态不变。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o 按下Start/Stop按钮，秒表转到Running状态。<br>&nbsp;&nbsp;&nbsp;&nbsp; * Running: 表针在移动，并持续显示过去的时间：</span><br><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o 按下Reset按钮，表针回退到0的位置，秒表转到停止状态。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o 按下Start/Stop按钮，转到Stoped状态。<br>&nbsp;&nbsp;&nbsp; 下面是其UML图：</span><br><br><span style="COLOR: #800000"></span><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/boost_statechart_pic2.jpg" width=682 height=231><br><br><span style="COLOR: #800000"><strong><span style="COLOR: #000000">1.1 定义状态和事件</span></strong><br><span style="COLOR: #000000">两个按钮可以建模为两个事件。进而，定义出必要的状态和初始状态。我们从下面的代码开始，以前的代码片段会陆续加入其中：</span></span></p>
<p><span style="COLOR: #800000"><span style="COLOR: #000000">&nbsp;</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">state_machine.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">simple_state.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sc&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;boost::statechart;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img id=Codehighlighter1_211_212_Open_Image onclick="this.style.display='none'; Codehighlighter1_211_212_Open_Text.style.display='none'; Codehighlighter1_211_212_Closed_Image.style.display='inline'; Codehighlighter1_211_212_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_211_212_Closed_Image onclick="this.style.display='none'; Codehighlighter1_211_212_Closed_Text.style.display='none'; Codehighlighter1_211_212_Open_Image.style.display='inline'; Codehighlighter1_211_212_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;EvStartStop&nbsp;:&nbsp;sc::</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;EvStartStop&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_211_212_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_211_212_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br><img id=Codehighlighter1_253_254_Open_Image onclick="this.style.display='none'; Codehighlighter1_253_254_Open_Text.style.display='none'; Codehighlighter1_253_254_Closed_Image.style.display='inline'; Codehighlighter1_253_254_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_253_254_Closed_Image onclick="this.style.display='none'; Codehighlighter1_253_254_Closed_Text.style.display='none'; Codehighlighter1_253_254_Open_Image.style.display='inline'; Codehighlighter1_253_254_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;EvReset&nbsp;:&nbsp;sc::</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;EvReset&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_253_254_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_253_254_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Active;<br><img id=Codehighlighter1_331_332_Open_Image onclick="this.style.display='none'; Codehighlighter1_331_332_Open_Text.style.display='none'; Codehighlighter1_331_332_Closed_Image.style.display='inline'; Codehighlighter1_331_332_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_331_332_Closed_Image onclick="this.style.display='none'; Codehighlighter1_331_332_Closed_Text.style.display='none'; Codehighlighter1_331_332_Open_Image.style.display='inline'; Codehighlighter1_331_332_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;StopWatch&nbsp;:&nbsp;sc::state_machine</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;StopWatch,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_331_332_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_331_332_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Stopped;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;这里的simple_state类模板可以接受4个参数：<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;-&nbsp;第3个参数指定内部的初始状态，如果有一个这样的状态的话。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;在这里，Active有一个内部状态（Stoped），&nbsp;所以将这个内部<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;初始状态传给它的基类。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;-&nbsp;第4个参数指定是否保留和保留什么类型历史<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Active是最外层的状态，因此要把它所属的状态机类传给它</span><span style="COLOR: #008000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Active&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_600_601_Open_Image onclick="this.style.display='none'; Codehighlighter1_600_601_Open_Text.style.display='none'; Codehighlighter1_600_601_Closed_Image.style.display='inline'; Codehighlighter1_600_601_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_600_601_Closed_Image onclick="this.style.display='none'; Codehighlighter1_600_601_Closed_Text.style.display='none'; Codehighlighter1_600_601_Open_Image.style.display='inline'; Codehighlighter1_600_601_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;Active,&nbsp;StopWatch,&nbsp;Stopped&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_600_601_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_600_601_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Stopped&nbsp;和&nbsp;Running&nbsp;都把Active作为它们的上下文，这使他们嵌入到了Active状态中。</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_715_716_Open_Image onclick="this.style.display='none'; Codehighlighter1_715_716_Open_Text.style.display='none'; Codehighlighter1_715_716_Closed_Image.style.display='inline'; Codehighlighter1_715_716_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_715_716_Closed_Image onclick="this.style.display='none'; Codehighlighter1_715_716_Closed_Text.style.display='none'; Codehighlighter1_715_716_Open_Image.style.display='inline'; Codehighlighter1_715_716_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Running&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Running,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_715_716_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_715_716_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br><img id=Codehighlighter1_772_773_Open_Image onclick="this.style.display='none'; Codehighlighter1_772_773_Open_Text.style.display='none'; Codehighlighter1_772_773_Closed_Image.style.display='inline'; Codehighlighter1_772_773_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_772_773_Closed_Image onclick="this.style.display='none'; Codehighlighter1_772_773_Closed_Text.style.display='none'; Codehighlighter1_772_773_Open_Image.style.display='inline'; Codehighlighter1_772_773_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Stopped&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Stopped,&nbsp;Active&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_772_773_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_772_773_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;因为状态的上下文必须是一个完整的类型（不能单单是声明），<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;所以状态机必须要在&#8220;外层状态&#8221;之间先定义。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;也就是说，我们需要从状态机开始，然后是最外层的状态，然后是其内部的状态，如此反复。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;我们可以用广度或深度方式，再或是以两都混合的方式来进行定义。</span><span style="COLOR: #008000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_925_982_Open_Image onclick="this.style.display='none'; Codehighlighter1_925_982_Open_Text.style.display='none'; Codehighlighter1_925_982_Closed_Image.style.display='inline'; Codehighlighter1_925_982_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_925_982_Closed_Image onclick="this.style.display='none'; Codehighlighter1_925_982_Closed_Text.style.display='none'; Codehighlighter1_925_982_Open_Image.style.display='inline'; Codehighlighter1_925_982_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_925_982_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_925_982_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;StopWatch&nbsp;myWatch;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;myWatch.initiate();<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span></div>
<p>这个代码已经可以编译了，但不会发生任何可察觉的事件。<br></p>
</span></span><img src ="http://www.cppblog.com/shaker/aggbug/123598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2010-08-16 14:45 <a href="http://www.cppblog.com/shaker/archive/2010/08/16/123598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Boost的状态机库教程(1) </title><link>http://www.cppblog.com/shaker/archive/2010/08/16/123597.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Mon, 16 Aug 2010 06:42:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2010/08/16/123597.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/123597.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2010/08/16/123597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/123597.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/123597.html</trackback:ping><description><![CDATA[<strong>介绍</strong> <br>&nbsp;&nbsp;&nbsp; Boost状态机库一个应用程序框架，你可以用它将UML状态图快速的转换为可执行的c++代码，而不需要任何的代码生成器。它支持几乎所有的UML特征，可以直接了当的转换，并且转换后的c++代码就像对状态机进行一次文本描述一样具体可读性。<br><br><strong>如何阅读这个教程</strong> <br>&nbsp; &nbsp; 这个教程是以线性阅读的方式进行的章节设计。如果你是第一次看这个教程的话，你可以从头开始读，到你觉得了解的东西对你手头的任务来说已经足够时就停止。具体可以这样：<br>&nbsp; &nbsp; * 如果你的任务是要实现一个小的、简单的，并且有很少几个状态的状态机，那么下面的&#8220;初级主题：秒表&#8221;里所讲的就差不多够你用的了。<br>&nbsp; &nbsp; * 如果你要做一个有很多状态的大型状态机，你可以看一下&#8220;中级主题：数码相机&#8221;，那里的讲解可能对你有帮助。<br>&nbsp;&nbsp;&nbsp; * 最后，如果你是一个要创建异常复杂状态机的用户，或者是一个想要评估一个Boost状态机的设计师的话，你就要看一下&#8220;高级主题&#8221;部分。并且，我还强烈建议你看一下Rationle里的Limitions部分。<br><br><strong>Hello World!</strong> <br>&nbsp;&nbsp;&nbsp; 我们将要从一个最简单程序开始我们的第一步，状态图如下：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/boost_statechart_pic1.jpg" width=456 height=115><br>对于这个状态图，我们的实现代码如下： <br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080">&nbsp;1</span><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">state_machine.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">statechart</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">simple_state.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;&nbsp;sc&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;boost::statechart;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;为了避免写public，下面声明的类型全部为struct。<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;如果你不在乎的话可以把它们都改成class。<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">10</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;我们需要先声明一下初始状态，这是因为我们要在定义状态机时使用它<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;但又不得不在状态机这后定义它。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">12</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Greeting;<br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Boost.Statechart大量应用模板模式。<br></span><span style="COLOR: #008080">16</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;派生类必须将自己做为基类模板的第一个参数。<br></span><span style="COLOR: #008080">17</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">18</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;状态机必须要知道当其初始化后进行的第一个状态。<br></span><span style="COLOR: #008080">19</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;这就是为什么Greeting要做为每二个模板参数。<br></span><span style="COLOR: #008080">20</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;（译者注：也就是说Greeting状态是Machine状态机初始化后进入的第一个状态）</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">21</span><span style="COLOR: #008000"><img id=Codehighlighter1_499_500_Open_Image onclick="this.style.display='none'; Codehighlighter1_499_500_Open_Text.style.display='none'; Codehighlighter1_499_500_Closed_Image.style.display='inline'; Codehighlighter1_499_500_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_499_500_Closed_Image onclick="this.style.display='none'; Codehighlighter1_499_500_Closed_Text.style.display='none'; Codehighlighter1_499_500_Open_Image.style.display='inline'; Codehighlighter1_499_500_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Machine&nbsp;:&nbsp;sc::state_machine</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Machine,&nbsp;Greeting&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_499_500_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_499_500_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;对于每一个状态，我们需要为其指明：它属于哪一个状态机，它位于状态图的哪个位置。<br></span><span style="COLOR: #008080">24</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;我们用simple_state&lt;&gt;的上下文参数就可以完成这些指定了。<br></span><span style="COLOR: #008080">25</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;对于我们目前的这个简单的状态机来说，上下文就是状态机（Machine)<br></span><span style="COLOR: #008080">26</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;所以，Machine必须要做为simple_state的第二个模块参数。<br></span><span style="COLOR: #008080">27</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;（关于上下文参数的详细解释在下一个例子中有）</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">28</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;&nbsp;Greeting&nbsp;:&nbsp;sc::simple_state</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;Greeting,&nbsp;Machine&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">29</span><span style="COLOR: #000000"><img id=Codehighlighter1_747_1012_Open_Image onclick="this.style.display='none'; Codehighlighter1_747_1012_Open_Text.style.display='none'; Codehighlighter1_747_1012_Closed_Image.style.display='inline'; Codehighlighter1_747_1012_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_747_1012_Closed_Image onclick="this.style.display='none'; Codehighlighter1_747_1012_Closed_Text.style.display='none'; Codehighlighter1_747_1012_Open_Image.style.display='inline'; Codehighlighter1_747_1012_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_747_1012_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_747_1012_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">30</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;一旦状态机进行一个状态的时候，它就要创建一个相应状态类的对象（类实例）<br></span><span style="COLOR: #008080">31</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;只要状态机保持在这个状态下，这个对象就会一直存在。<br></span><span style="COLOR: #008080">32</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;最后，当状态机离开这个状态时，对象被销毁。<br></span><span style="COLOR: #008080">33</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;所以，一个状态的进入动作就是这个状态类的构造器，而它的退出动作则是它的析构类。&nbsp;&nbsp;&nbsp;Greeting()&nbsp;{&nbsp;std::cout&nbsp;&lt;&lt;&nbsp;&nbsp;"Hello&nbsp;World!\n"&nbsp;;&nbsp;}&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;进入</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">34</span><span style="COLOR: #008000"><img id=Codehighlighter1_965_1003_Open_Image onclick="this.style.display='none'; Codehighlighter1_965_1003_Open_Text.style.display='none'; Codehighlighter1_965_1003_Closed_Image.style.display='inline'; Codehighlighter1_965_1003_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_965_1003_Closed_Image onclick="this.style.display='none'; Codehighlighter1_965_1003_Closed_Text.style.display='none'; Codehighlighter1_965_1003_Open_Image.style.display='inline'; Codehighlighter1_965_1003_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Greeting()&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_965_1003_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_965_1003_Open_Text><span style="COLOR: #000000">{&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Bye&nbsp;Bye&nbsp;World!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;退出</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">35</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif"></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">36</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">37</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;main()<br></span><span style="COLOR: #008080">38</span><span style="COLOR: #000000"><img id=Codehighlighter1_1028_1485_Open_Image onclick="this.style.display='none'; Codehighlighter1_1028_1485_Open_Text.style.display='none'; Codehighlighter1_1028_1485_Closed_Image.style.display='inline'; Codehighlighter1_1028_1485_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_1028_1485_Closed_Image onclick="this.style.display='none'; Codehighlighter1_1028_1485_Closed_Text.style.display='none'; Codehighlighter1_1028_1485_Open_Image.style.display='inline'; Codehighlighter1_1028_1485_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_1028_1485_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1028_1485_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">39</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;Machine&nbsp;myMachine;<br></span><span style="COLOR: #008080">40</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;构造完状态机后，它并未开始运行。我们要通过调用它的initiate()来启动它。<br></span><span style="COLOR: #008080">41</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;同时，它也将触发它的初始状态（Greeting）的构造。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">42</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">&nbsp;&nbsp;myMachine.initiate();<br></span><span style="COLOR: #008080">43</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;当我们离开main()函数时，myMachine将被销毁，这将导致它销毁它内部的所有活动的状态类。<br></span><span style="COLOR: #008080">44</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;（译者注：为什么会说所有？这是因为一个状态机可以同时</span><span style="COLOR: #008000">保持在多个状态中，可以参考&#8220;高级主题&#8221;部分）</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">45</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">46</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span></div>
这个程序会显示&#8220;<span class=string>Hello&nbsp;World!&#8221;和&#8220;</span> <span class=string>Bye&nbsp;Bye&nbsp;World!</span> <span class=string>&#8221;，然后退出。</span><img src ="http://www.cppblog.com/shaker/aggbug/123597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2010-08-16 14:42 <a href="http://www.cppblog.com/shaker/archive/2010/08/16/123597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]RGB与YUV转换</title><link>http://www.cppblog.com/shaker/archive/2010/03/26/110607.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Fri, 26 Mar 2010 12:27:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2010/03/26/110607.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/110607.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2010/03/26/110607.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/110607.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/110607.html</trackback:ping><description><![CDATA[<p>1 前言</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自然界的颜色千变万化，为了给颜色一个量化的衡量标准，就需要建立色彩空间模型来描述各种各样的颜色，由于人对色彩的感知是一个复杂的生理和心理联合作用 的过程，所以在不同的应用领域中为了更好更准确的满足各自的需求，就出现了各种各样的色彩空间模型来量化的描述颜色。我们比较常接触到的就包括 RGB / CMYK / YIQ / YUV / HSI等等。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于数字电子多媒体领域来说，我们经常接触到的色彩空间的概念，主要是RGB , YUV这两种（实际上，这两种体系包含了许多种具体的颜色表达方式和模型，如sRGB, Adobe RGB, YUV422, YUV420 &#8230;）, RGB是按三基色加光系统的原理来描述颜色，而YUV则是按照 亮度，色差的原理来描述颜色。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 即使只是RGB YUV这两大类色彩空间，所涉及到的知识也是十分丰富复杂的，自知不具备足够的相关专业知识，所以本文主要针对工程领域的应用及算法进行讨论。</p>
<p>2 YUV相关色彩空间模型</p>
<p>2.1 YUV 与 YIQ YcrCb</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于YUV模型，实际上很多时候，我们是把它和YIQ / YCrCb模型混为一谈的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实际上,YUV模型用于PAL制式的电视系统，Y表示亮度，UV并非任何单词的缩写。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; YIQ模型与YUV模型类似，用于NTSC制式的电视系统。YIQ颜色空间中的I和Q分量相当于将YUV空间中的UV分量做了一个33度的旋转。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; YCbCr颜色空间是由YUV颜色空间派生的一种颜色空间，主要用于数字电视系统中。从RGB到YCbCr的转换中，输入、输出都是8位二进制格式。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三者与RGB的转换方程如下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGB -&gt; YUV：</p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实际上也就是：</p>
<p>Y=0.30R+0.59G+0.11B ， U=0.493(B－Y) ， V=0.877(R－Y)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGB -&gt; YIQ：</p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGB -&gt; YCrCb：</p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从公式中，我们关键要理解的一点是，UV / CbCr信号实际上就是蓝色差信号和红色差信号，进而言之，实际上一定程度上间接的代表了蓝色和红色的强度，理解这一点对于我们理解各种颜色变换处理的过程会有很大的帮助。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们在数字电子多媒体领域所谈到的YUV格式，实际上准确的说，是以YcrCb色彩空间模型为基础的具有多种存储格式的一类颜色模型的家族（包括 YUV444 / YUV422 / YUV420 / YUV420P等等）。并不是传统意义上用于PAL制模拟电视的YUV模型。这些YUV模型的区别主要在于UV数据的采样方式和存储方式，这里就不详述。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而在Camera Sensor中，最常用的YUV模型是 YUV422格式，因为它采用4个字节描述两个像素，能和RGB565模型比较好的兼容。有利于Camera Sensor和Camera controller的软硬件接口设计。</p>
<p>3 YUV2RGB快速算法分析</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里指的YUV实际是YcrCb了 8&nbsp; ) YUV2RGB的转换公式本身是很简单的，但是牵涉到浮点运算，所以，如果要实现快速算法，算法结构本身没什么好研究的了，主要是采用整型运算或者查表来加快计算速度。<br>首先可以推导得到转换公式为：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; R = Y + 1.4075 *（V-128）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; G = Y &#8211; 0.3455 *（U &#8211;128） &#8211; 0.7169 *（V &#8211;128）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B = Y + 1.779 *（U &#8211; 128）</p>
<p>3.1 整型算法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要用整型运算代替浮点运算，当然是要用移位的办法了，我们可以很容易得到下列算法：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u = YUVdata[UPOS] - 128;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v = YUVdata[VPOS] - 128;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdif = v + ((v * 103) &gt;&gt; 8);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invgdif = ((u * 88) &gt;&gt; 8) +((v * 183) &gt;&gt; 8);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bdif = u +( (u*198) &gt;&gt; 8);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r = YUVdata[YPOS] + rdif;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = YUVdata[YPOS] - invgdif;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b = YUVdata[YPOS] + bdif;</p>
<p>为了防止出现溢出，还需要判错计算的结果是否在0-255范围内，做类似下面的判断。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (r&gt;255)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r=255;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (r&lt;0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r=0;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要从RGB24转换成RGB565数据还要做移位和或运算：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGBdata[1] =( (r &amp; 0xF8)&nbsp; | ( g &gt;&gt; 5) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGBdata[0] =( ((g &amp; 0x1C) &lt;&lt; 3) | ( b &gt;&gt; 3) );</p>
<p>3.2 部分查表法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 查表法首先可以想到的就是用查表替代上述整型算法中的乘法运算。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdif = fac_1_4075[u];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invgdif = fac_m_0_3455[u] + fac_m_0_7169[v];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bdif = fac_1_779[u];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里一共需要4个1维数组，下标从0开始到255，表格共占用约1K的内存空间。uv可以不需要做减128的操作了。在事先计算对应的数组元素的值的时候计算在内就好了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于每个像素，部分查表法用查表替代了2次减法运算和4次乘法运算，4次移位运算。但是，依然需要多次加法运算和6次比较运算和可能存在的赋值操作，相对第一种方法运算速度提高并不明显。</p>
<p>3.3 完全查表法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么是否可以由YUV直接查表得到对应的RGB值呢？乍一看似乎不太可能，以最复杂的G的运算为例，因为G与YUV三者都相关，所以类似 G=YUV2G[Y][U][V]这样的算法，一个三维下标尺寸都为256的数组就需要占用2的24次方约16兆空间，绝对是没法接受的。所以目前多数都 是采用部分查表法。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但是，如果我们仔细分析就可以发现，对于G我们实际上完全没有必要采用三维数组，因为Y只与UV运算的结果相关，与UV的个体无关，所以我们可以采用二次查表的方法将G的运算简化为对两个二维数组的查表操作，如下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; G = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ]；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而RB本身就只和YU或YV相关，所以这样我们一共需要4个8*8的二维表格，需要占用4乘2的16次方共256K内存。基本可以接受。但是对于手机这样的嵌入式运用来说，还是略有些大了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 进一步分析，我们可以看到，因为在手机等嵌入式运用上我们最终是要把数据转换成RGB565格式送到LCD屏上显示的，所以，对于RGB三分量来说，我们 根本不需要8bit这么高的精度，为了简单和运算的统一起见，对每个分量我们其实只需要高6bit的数据就足够了，所以我们可以进一步把表格改为4个 6*6的二维表格，这样一共只需要占用16K内存！在计算表格元素值的时候还可以把最终的溢出判断也事先做完。最后的算法如下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y = (YUVdata[Y1POS] &gt;&gt; 2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u = (YUVdata[UPOS] &gt;&gt; 2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v = (YUVdata[VPOS] &gt;&gt; 2);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r = yv2r_table[ y ][ v ];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b = yu2b_table[ y ][ u ];<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGBdata[1] =( (r &amp; 0xF8)&nbsp; | ( g &gt;&gt; 5) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGBdata[0] =( ((g &amp; 0x1C) &lt;&lt; 3) | ( b &gt;&gt; 3) );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这样相对部分查表法，我们增加了3次移位运算，而进一步减少了4次加法运算和6次比较赋值操作。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在计算表格元素数值的时候，要考虑舍入和偏移等因数使得计算的中间结果满足数组下标非负的要求，需要一定的技巧。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 采用完全查表法，相对于第一种算法，最终运算速度可以有比较明显的提高，具体性能能提高多少，要看所在平台的CPU运算速度和内存存取速度的相对比例。内 存存取速度越快，用查表法带来的性能改善越明显。在我的PC上测试的结果性能大约能提高35%。而在某ARM平台上测试只提高了约15%。</p>
<p>3.4 进一步的思考</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实际上，上述算法：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGBdata[1] =( (r &amp; 0xF8)&nbsp; | ( g &gt;&gt; 5) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGBdata[0] =( ((g &amp; 0x1C) &lt;&lt; 3) | ( b &gt;&gt; 3) );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 中的 (r &amp; 0xF8) 和 ( b &gt;&gt; 3) 等运算也完全可以在表格中事先计算出来。另外，YU / YV的取值实际上不可能覆盖满6*6的范围，中间有些点是永远取不到的无输入，RB的运算也可以考虑用5*5的表格。这些都可能进一步提高运算的速度，减 小表格的尺寸。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外，在嵌入式运用中，如果可能尽量将表格放在高速内存如SRAM中应该比放在SDRAM中更加能发挥查表法的优势。</p>
<p>4 RGB2YUV ?</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目前觉得这个是没法将3维表格的查表运算化简为2维表格的查表运算了。只能用部分查表法替代其中的乘法运算。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外，多数情况下，我们需要的还是YUV2RGB的转换，因为从Sensor得到的数据通常我们会用YUV数据，此外JPG和MPEG实际上也是基于YUV格式编码的，所以要显示解码后的数据需要的也是YUV2RGB的运算 8 ）运气运气。</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/ALENTAM/archive/2008/03/13/2178020.aspx">http://blog.csdn.net/ALENTAM/archive/2008/03/13/2178020.aspx</a></p><img src ="http://www.cppblog.com/shaker/aggbug/110607.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2010-03-26 20:27 <a href="http://www.cppblog.com/shaker/archive/2010/03/26/110607.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个简易的采集系统</title><link>http://www.cppblog.com/shaker/archive/2009/11/08/100426.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Sun, 08 Nov 2009 15:14:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2009/11/08/100426.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/100426.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2009/11/08/100426.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/100426.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/100426.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 练手之作,顺便实现一些自己的想法,见笑见笑!~<br><a href="http://www.cppblog.com/images/cppblog_com/shaker/BlackHole29.PNG"><img style="WIDTH: 300px; HEIGHT: 225px" border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/shaker/BlackHole29.PNG" width=300 height=225></a>&nbsp;&nbsp;<a href='http://www.cppblog.com/shaker/archive/2009/11/08/100426.html'>阅读全文</a><img src ="http://www.cppblog.com/shaker/aggbug/100426.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2009-11-08 23:14 <a href="http://www.cppblog.com/shaker/archive/2009/11/08/100426.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用wget加速Ubuntu更新</title><link>http://www.cppblog.com/shaker/archive/2009/06/18/88013.html</link><dc:creator>shaker(太子)</dc:creator><author>shaker(太子)</author><pubDate>Thu, 18 Jun 2009 10:43:00 GMT</pubDate><guid>http://www.cppblog.com/shaker/archive/2009/06/18/88013.html</guid><wfw:comment>http://www.cppblog.com/shaker/comments/88013.html</wfw:comment><comments>http://www.cppblog.com/shaker/archive/2009/06/18/88013.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/shaker/comments/commentRss/88013.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaker/services/trackbacks/88013.html</trackback:ping><description><![CDATA[在白天Ubuntu的更新管理器或apt-get更新总是慢吞吞的，我用的是官方源，但直接用Firefox去&#8220;<a  href="http://archive.ubuntu.com/ubuntu/" target="_blank"><font color="#22229c">http://archive.ubuntu.com/ubuntu/</font></a>&#8221;下载却很快，用扩展DTA都能接近满速，看来更新管理器或apt-get不是多线程，速度是慢点，干脆用Firefox去下载好了。<br>
<br>
获得更新deb地址列表：<br>
首先要获得deb包的下载地址，有个笨点的方法就是使用更新管理器，然后在下载窗口点击取消，然后就在出错窗口复制获得下载列表，还要修改一下。用命令更快捷，结果折腾一番，运行下面的命令即把需要更新的deb包的列表输出<br>
<br>
sudo apt-get -y --print-uris dist-upgrade | grep http | awk '{print $1}' | sed 's/'\''//g'<br>
<br>
每次都要打这么长的命令是很恼人的，添加一个alias到&#8220;~/.bashrc&#8221;里去<br>
<br>
alias sgdl="sudo apt-get -y --print-uris dist-upgrade | grep http | awk '{print \$1}' | sed 's/'\''//g'"<br>
<br>
有点变态的别名，主要是单引号转义，以后每次运行<br>
<br>
sgdl &gt; deblist<br>
<br>
输出到文件deblist中去。&#8220;sgdl&#8221;助记&#8220;sudo get deb list&#8221;。<br>
<br>
下载deb文件：<br>
获得列表然后就是下载啦，用Firefox打开deblist，然后Ctrl+A全选，用Flashgot选择&#8220;使用Flashgot下载所选连接&#8221;，当
前调用的下载管理器为DTA，在DTA里选择下载所有连接，设置好下载目录，然后开足火力猛拖。又或者使用wget，更简单<br>
<br>
wget -i deblist<br>
<br>
如果按了Ctrl+C中断，下次加上&#8220;-c&#8221;选项续传<br>
<br>
wget -c -i deblist<br>
<br>
链接包并更新：<br>
下载好后，到apt-get的缓存目录建立deb的链接<br>
<br>
sudo ln -s ~/debfiles/*.deb /var/cache/apt/archives/<br>
<br>
这里debfiles为下载deb的文件夹。最后就是运行一下更新命令啦。<br>
<br>
sudo apt-get upgrade<br>
<br>
作者：雾之大陆<br>
出处：<a  href="http://muzuiget.blog.ubuntu.org.cn/" target="_blank"><font color="#22229c">http://muzuiget.blog.ubuntu.org.cn/</font></a><img src ="http://www.cppblog.com/shaker/aggbug/88013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaker/" target="_blank">shaker(太子)</a> 2009-06-18 18:43 <a href="http://www.cppblog.com/shaker/archive/2009/06/18/88013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>