<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Computer, Electron and Technology &#187; shell</title>
	<atom:link href="http://www.donevii.com/post/tag/shell/feed" rel="self" type="application/rss+xml" />
	<link>http://www.donevii.com</link>
	<description>关注技术、移动互联网以及一切 GEEK &#38; NERD 的事情</description>
	<lastBuildDate>Wed, 21 Dec 2011 10:49:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>每天看 svn 库变更的一个小 shell 脚本</title>
		<link>http://www.donevii.com/post/940.html</link>
		<comments>http://www.donevii.com/post/940.html#comments</comments>
		<pubDate>Fri, 06 Nov 2009 10:07:36 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.donevii.com/post/940.html</guid>
		<description><![CDATA[#!/bin/bash TODAY=/tmp/$(date +%Y%m%d) CONTENT=$TODAY/update_content_sina.tmp if [ ! -d $TODAY ]; then mkdir $TODAY fi if [ -f $CONTENT ]; then rm $CONTENT fi svn up ~/job/code/php/sinahouse/ &#62;&#62; $TODAY/svn_update_list.tmp LIST=`cat $TODAY/svn_upd... ]]></description>
			<content:encoded><![CDATA[<p>#!/bin/bash</p>
<p>TODAY=/tmp/$(date +%Y%m%d)<br />
CONTENT=$TODAY/update_content_sina.tmp</p>
<p>if [ ! -d $TODAY ]; then<br />
mkdir $TODAY<br />
fi</p>
<p>if [ -f $CONTENT ]; then<br />
rm $CONTENT<br />
fi</p>
<p>svn up ~/job/code/<a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">php</a>/sinahouse/ &gt;&gt; $TODAY/svn_update_list.tmp<br />
LIST=`cat $TODAY/svn_update_list.tmp | grep &#8216;.php&#8217; | awk &#8216;{print $2}&#8217;`</p>
<p>for L in $LIST; do<br />
svn diff -r PREV $L &gt;&gt; $CONTENT<br />
done</p>
<p>/usr/bin/vim $CONTENT</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/940.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>清除指定squid缓存文件的脚本</title>
		<link>http://www.donevii.com/post/758.html</link>
		<comments>http://www.donevii.com/post/758.html#comments</comments>
		<pubDate>Mon, 09 Feb 2009 10:28:11 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[测试]]></category>
		<category><![CDATA[类]]></category>
		<category><![CDATA[缓存]]></category>

		<guid isPermaLink="false">http://www.donevii.com/post/758.html</guid>
		<description><![CDATA[用wget来清空squid缓存 可以使用以下命令来清空squid的缓存： 代码:/usr/bin/wget -O squid.log -S &#8211;header=&#8221;ragma: no-cache&#8221;&#160; url 代码: squidclient -m PURGE -p 80 &#8220;http://you.video.sina.com.cn/index.html&#8... ]]></description>
			<content:encoded><![CDATA[<p>用wget来清空squid缓存</p>
<p>可以使用以下命令来清空squid的缓存：</p>
<p>代码:<br />/usr/bin/wget -O squid.log -S &#8211;header=&#8221;ragma: no-<a href="http://www.donevii.com/post/tag/cache" class="st_tag internal_tag" rel="tag" title="Posts tagged with cache">cache</a>&#8221;&nbsp; url</p>
<p>代码:</p>
<p>squidclient -m PURGE -p 80 &#8220;http://you.video.sina.com.cn/index.<a href="http://www.donevii.com/post/tag/html" class="st_tag internal_tag" rel="tag" title="Posts tagged with html">html</a>&#8221;</p>
<p>代码:</p>
<p>http://www.cdn.com/api/purge.<a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">php</a>?action=purge&amp;host=61.55.111.111&amp;url=http://www.md5.cn/</p>
<p>一款老外的程序，可以批量清除某类URL的Squid缓存，支持正则表达式。</p>
<p>　　下载网址：http://www.wa.apana.org.au/~dean/squidpurge/</p>
<p>　　编译：<br />代码:<br />wget http://www.wa.apana.org.au/~dean &#8230; 20040201-src.tar.gz<br />tar zxvf purge-20040201-src.tar.gz<br />cd purge<br />make<br />　　清除Squid缓存示例：<br />　　1、清除 URL 以“.mp3”结尾的缓存文件（例如 http://www.s135.com/abc.mp3、http://www.s135.com/01/a.mp3）<br />代码:<br />./purge -p localhost:80 -P 1 -se &#8216;\.mp3$&#8217;<br />　　2、清除URL中包含s135.com的所有缓存：<br />代码:<br />./purge -p localhost:80 -P 1 -se &#8216;s135.com&#8217;<br />　　我喜欢将程序推到后台去执行，让它慢慢地去清Squid缓存，同时将输出内容记录到purge.log文件：<br />代码:<br />./purge -p localhost:80 -P 1 -se &#8216;s135.com&#8217; &gt; purge.log 2&gt;&amp;1</p>
<p>　Squid web缓存加速软件目前已经是新浪、搜狐、网易等各大网站广泛应用。Squid会在设置的缓存目录下建立多个目录，每一个目录下又建立多个目录，然后才在最里层的目录中存放缓存文件（object）。squid会根据用户请求网页的URL进行哈希，生成缓存文件，存放在某一个目录中。squid启动之后，将在内存中建立一个哈希表，记录硬盘中缓存文件配置的情形。</p>
<p>　　对于类似http://you.video.sina.com.cn/index.html之类的网页，squid只会生成一个缓存文件。可以用squid附带的squidclient工具清除：</p>
<p>代码:<br />squidclient -m PURGE -p 80 &#8220;http://you.video.sina.com.cn/index.html&#8221;<br />　　而对于带有参数的网页，例如新浪播客的Flash播放器http://vhead.<a href="http://www.donevii.com/post/tag/blog" class="st_tag internal_tag" rel="tag" title="Posts tagged with blog">blog</a>.sina.com.cn/pl &#8230; 9852&amp;uid=1278987704，因“?”后面的参数不同，导致URL也不同，squid会生成多个缓存文件，哈希分散存放在不同的目录。如果修改了这个outer_player.swf文件，要更新squid缓存就要去清除不同目录下及内存中的很多个缓存文件，十分麻烦，于是我编写了一个Linux下的shell脚本，去完成这件麻烦的事：</p>
<p>　　脚本文件名：clear_squid_cache.sh（8月2日修正了UC网友“城市中的寂寞”反馈的BUG）</p>
<p>代码:<br />#!/bin/sh<br />squidcache_path=&#8221;/data1/squid/var/cache&#8221;<br />squidclient_path=&#8221;/usr/local/squid/bin/squidclient&#8221;<br />grep -a -r $1 $squidcache_path/* | strings | grep &#8220;http:&#8221; | awk -F&#8217;http:&#8217; &#8216;{print &#8220;http:&#8221;$2;}&#8217; &gt; cache_list.txt<br />for url in `cat cache_list.txt`; do<br />$squidclient_path -m PURGE -p 80 $url<br />done<br />　　注意：请赋予clear_squid_cache.sh可执行权限（命令：chmod +x ./clear_squid_cache.sh）。请确保脚本所在目录可写。</p>
<p>　　设置：<br />　　squidcache_path= 表示squid缓存目录的路径<br />　　squidclient_path= 表示squidclient程序所在的路径，默认为squid安装目录下的bin/squidclient</p>
<p>　　用法：<br />　　1、清除所有Flash缓存（扩展名.swf）：<br />　　<br />代码:<br />./clear_squid_cache.sh swf<br />　　2、清除URL中包含sina.com.cn的所有缓存：<br />　　<br />代码:<br />./clear_squid_cache.sh sina.com.cn<br />　　3、清除文件名为zhangyan.jpg的所有缓存：<br />　　<br />代码:<br />./clear_squid_cache.sh zhangyan.jpg<br />　　效率：<br />　　经测试，在DELL 2950上清除26000个缓存文件用时2分钟左右。平均每秒可清除缓存文件177个。</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/758.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>实现和IE浏览器交互的几种方法的介绍</title>
		<link>http://www.donevii.com/post/327.html</link>
		<comments>http://www.donevii.com/post/327.html#comments</comments>
		<pubDate>Mon, 21 May 2007 02:53:22 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[ie]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[浏览器]]></category>
		<category><![CDATA[类]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=327</guid>
		<description><![CDATA[内容 实现和IE浏览器交互的几种方法的介绍 &#8212;- 1．引言 &#8212;- 如何实现对IE浏览器中对象的操作是一个很有实际意义问题，通过和IE绑定的DLL我们可以记录IE浏览过的网页的顺序，分析用户... ]]></description>
			<content:encoded><![CDATA[<p>内容 <br />实现和IE浏览器交互的几种方法的介绍 <br />&#8212;- 1．引言 </p>
<p>&#8212;- 如何实现对IE浏览器中对象的操作是一个很有实际意义问题，通过和IE绑定的DLL我们可以记录IE浏览过的网页的顺序，分析用户的使用行为和模式。我们可以对网页的内容进行过滤和翻译，可以自动填写网页中经常需要用户填写的Form内容等等,我们所有的例子代码都是通过VC来表示的，采用的原理是通过和IE对象的接口的交互来实现对IE的访问。实际上是采用COM的技术，我们知道COM是和语言无关的一种二进制对象交互的模式，所以实际上我们下面所描述的内容都可以用其他的语言来实现，比如VB，DELPHI，C++ Builder等等。 </p>
<p>&#8212;- 2．IE实例遍历实现 </p>
<p>&#8212;- 首先我们来看系统是如何知道当前有多少个IE的实例在运行。 </p>
<p>&#8212;- 我们知道在Windows体系结构下，一个应用程序可以通过操作系统的运行对象表来和这些应用的实例进行交互。但是IE当前的实现机制是不在运行对象表中进行注册，所以需要采用其他的方法。我们知道可以通过ShellWindows集合来代表属于shell的当前打开的窗口的集合，而IE就是属于shell的一个应用程序。 </p>
<p>&#8212;- 下面我们描述一下用VC实现对当前 IE实例的进行遍历的方法。IShellWindows是关于系统shell的一个接口，我们可以定义一个如下的接口变量： </p>
<p>SHDocVw::IShellWindowsPtr m_spSHWinds;<br />然后创建变量的实例：<br />&nbsp;&nbsp;&nbsp;m_spSHWinds.CreateInstance<br />&nbsp;&nbsp;&nbsp;(__uuidof(SHDocVw::ShellWindows));<br />通过IShellWindows接口的方法GetCount<br />可以得到当前实例的数目：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long nCount = m_spSHWinds- &gt;GetCount();<br />通过IShellWindows接口的方法Item<br />可以得到每一个实例对象<br />&nbsp;&nbsp;&nbsp;&nbsp;IDispatchPtr spDisp;<br />&nbsp;&nbsp;&nbsp;&nbsp;_variant_t va(i, VT_I4);<br />&nbsp;&nbsp;&nbsp;&nbsp;spDisp = m_spSHWinds-&gt;Item(va);<br />然后我们可以判断实例对象是不是<br />属于IE浏览器对象，通过下面的语句实现：<br />&nbsp;&nbsp;&nbsp;&nbsp;SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);<br />&nbsp;&nbsp;&nbsp;&nbsp;assert(spBrowser != NULL)</p>
<p>&#8212;-在得到了IE浏览器对象以后，我们可以调用IWebBrowser2Ptr接口的方法来得到当前的文档对象的指针： MSHTML::IHTMLDocument2Ptr spDoc(spBrowser-&gt;GetDocument()); </p>
<p>&#8212;- 然后我们就可以通过这个接口对这个文档对象进行操作，比如通过Gettitle得到文档的标题。 </p>
<p>&#8212;- 我们在浏览网络的时候，一般总会同时开很多IE的实例，如果这些页面都是很好的话，我们可能想保存在硬盘上，这样，我们需要对每一个实例进行保存，而如果我们采用上面的原理，我们可以得到每一个IE的实例及其网页对象的接口，这样就可以通过一个简单的程序来批量的保存当前的所有打开的网页。采用上面介绍的方法实现了对当前IE实例的遍历，但是我们希望得到每一个IE实例所产生的事件，这就需要通过DLL的机制来实现。 </p>
<p>&#8212;- 3．和IE相绑定的DLL的实现 </p>
<p>&#8212;- 我们介绍一下如何建立和IE进行绑定的DLL的实现的过程。为了和IE的运行实例进行绑定，我们需要建立一个能够和每一个IE实例进行绑定的DLL。IE的启动过程是这样的，当每一个IE的实例启动的时候，它都会在注册表中去寻找这个的一个CLSID，具体的注册表的键位置为： </p>
<p>HKEY_LOCALL_MACHINESOFTWAREMicrosoftWindows<br />CurrentVersionExplorerBrowser Helper Objects</p>
<p>&#8212;- 当在这个键位置下存在CLSIDs的时候，IE会通过使用CoCreateInstance()方法来创建列在该键位置下的每一个对象的实例。注意对象的CLSIDs必须用子键而非启动过程是这样的，当每一个IE的实例启动的时候名字值的形式表现，比如{DD41D66E-CE4F-11D2-8DA9-00A0249EABF4} 就是一个有效的子键。我们使用DLL的形式而非EXE的形式的原因是因为DLL和IE实例运行在同一个进程空间里面。每一个这种形式的DLL必须实现接口IObjectWithSite，其中方法SetSite必须被实现。通过这个方法，我们自己的DLL就可以得到一个指向IE COM对象的IUnknown的指针，实际上通过这个指针我们就可以通过COM对象中的方法QueryInterface来遍历所有可以得到的接口，这是COM的基本的机制。当然我们需要的只是IWebBrowser2这个接口。 </p>
<p>&#8212;- 实际上我们建立的是一个COM对象，DLL只不过是COM对象的一种表现形式。我们建立的COM对象需要建立和实现的方法有： </p>
<p>&#8212;-1． IOleObjectWithSite接口的方法SetSite必须实现。实际上IE实例通过这个方法向我们的COM对象传递一个接口的指针。假设我们有一个接口指针的变量，不妨设为： </p>
<p>&#8212;-CComQIPtr&lt; IWebBrowser2, &amp;IID_IWebBrowser2 &gt; m_myWebBrowser2; </p>
<p>&#8212;- 我们就可以在方法SetSite中把这个传进来的接口指针赋给m_myWebBrowser2。 2． 在我们得到了指向IE COM对象的接口后，我们需要把自己的DLL和IE实例所发生的事件相关连,为了实现这个目的，需要介绍两个接口： </p>
<p>&#8212;-（1） IConnectionPointContainer。： </p>
<p>&#8212;-CComQIPtr&lt; IWebBrowser2, &amp;这里使用这个接口的目的是用来根据它得到的IID来建立和DLL的一个特定的连接。比如我们可以进行如下的定义： </p>
<p>CComQIPtr&lt; IConnectionPointContainer,<br />&amp;IID_IConnectionPointContainer &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />spCPContainer(m_myWebBrowser2);</p>
<p>&#8212;-然后，我们需要把所有IE中发生的事件和我们的DLL进行通讯，可以使用 IConnectPoint。 </p>
<p>&#8212;-（2） IConnectPoint。通过这个接口，客户可以对连接的对象开始或者是终止一个advisory循环。IConnectPoint有两个主要的方法，一个为Advice，另一个为Unadvise。对于我们的应用来说，Advise是用来在每一个IE发生的事件和DLL之间建立一个通道。而Unadvise就是用来终止以前用Advise建立的通知关系。比如我们可以定义IConnectPoint接口如下： CComPtr&lt; IConnectionPoint &gt; spConnectionPoint; </p>
<p>&#8212;- 然后，我们要使所有在IE实例中发生的事件和我们的DLL相关，可以使用 如下的方法： </p>
<p>hr = spCPContainer-&gt;FindConnectionPoint(<br />DIID_DWebBrowserEvents2, &amp;spConnectionPoint);</p>
<p>&#8212;-然后我们通过IConnectPoint接口的方法Advice使每当IE有一个新的事件发生的时候，都能够让我们的DLL知道。可以用如下的语句实现： </p>
<p>hr = spConnectionPoint- &gt;Advise(<br />(IDispatch*)this, &amp;m_dwIDCode);</p>
<p>&#8212;-在把IE实例中的事件和我们的DLL之间建立联系以后，我们可以通过IDispatch接口的Invoke()方法来处理所有的IE的事件。 </p>
<p>&#8212;-3． IDispatch接口的Invoke()方法。IDispatch是从IUnknown中继承的一个接口的类型，通过COM接口提供的任何服务都可以通过IDispatch接口来实现。IDispatch::Invoke的工作方式同vtbl幕后的工作方式是类似的，Invoke将实现一组按索引来访问的函数，我们可以对Invoke方法进行动态的定制以提供不同的服务。Invoke方法的表示如下： </p>
<p>STDMETHOD(Invoke)(DISPID dispidMember,REFIID<br />riid, LCID lcid, WORD wFlags,<br />DISPPARAMS * pdispparams, VARIANT * pvarResult,<br />EXCEPINFO * pexcepinfo, UINT * puArgErr);</p>
<p>&#8212;-其中，DISPID是一个长整数，它标识的是一个函数。对于IDispatch的某一个特定的实现，DISPID都是唯一的。IDispatch的每一个实现都有其自己的IID,这里dispidMemeber实际上是可以认为是和IE实例所发生的每一个事件相关的方法，比如：DISPID_BEFORENAVIGATE2，DISPID_NAVIGATECOMPLETE2等等。 这个方法中另外一个比较重要的参数是DISPPARAMS，它的结构如下： </p>
<p>typedef struct tagDISPPARAMS<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VARIANTARG* rgvarg;<br />//VARIANTARG是同VARAIANT相同的，可以在<br />&nbsp;&nbsp;&nbsp;&nbsp;//OAIDL.IDL中找到。所以实际上rgvarg是一个参数数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//组<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DISPID*&nbsp;&nbsp;rgdispidNameArgs;&nbsp;&nbsp;//命名参数的DISPID<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned int cArgs;&nbsp;&nbsp;&nbsp;&nbsp;//表示数组中元素的个数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned int CnameArgs;&nbsp;&nbsp;//命名元素的个数<br />&nbsp;&nbsp;&nbsp;}DISPPARAMS</p>
<p>&#8212;-要注意的是每一个参数的类型都是VARIANTARG，所以在IE和我们DLL之间可以传递的参数类型的数目是有限的。只有那些能够被放到VARIANTARG结构中的类型才可以通过调度接口进行传递。 比如对于事件DISPID_NAVIGATECOMPLETE2来说：第一个参数表示IE在访问的URL的值，类型是VT_BYREF|VT_VARIANT。注意DISPID_NAVIGATECOMPLETE2等DISPID已经在VC中被定义，我们可以直接进行使用。 如上说述，我们在方法Invoke中可以得到所有IE实例所发生的事件，我们可以把这些数据放到文件中进行事后的分析，也可以放到一个列表框中实时的显示。 </p>
<p>&#8212;- 4．微软的HTML文档对象模型和应用分析 </p>
<p>&#8212;- 下面我们来看如何得到网页文档的接口：网页文档的接口为IHTMLDocument2，可以通过调用IE COM对象的get_Document方法来得到网页的接口。使用如下的语句： </p>
<p>hr = m_spWebBrowser2- &gt;get_Document(&amp;spDisp);<br />CComQIPtr&lt; IHTMLDocument2, <br />&amp;IID_IHTMLDocument2 &gt; spHTML;<br />spHTML = spDisp;</p>
<p>&#8212;- 这样我们就得到了网页对象的接口，然后我们就可以对网页进行分析，比如通过IHTMLDocument2提供的方法get_URL我们可以得到和该网页相关的URL的地址值，通过get_forms方法可以该网页中所有的Form对象的集合。实际上W3C组织已经制定了一个DOM（Document Objec Model）标准，当然这个标准不仅仅是针对HTML，同时还是针对XML制定的。W3C组织只是定义了网页对象的接口，不同的公司可以采用不同的语言和方法进行具体的实现。按照W3C组织定义的网页对象被认为是动态的，即用户可以动态的对网页对象里面所包含的每一个对象进行操作。这里的对象可以是指一个输入框，也可以是图象和声音等对象。同时按照W3C的正式文档的说明，网页对象是可以动态增加和删除的。事实上，很少有厂商实现了DOM定义的所有功能。微软对网页对象的定义也基本上是按照这个标准实现的。但是当前的接口还不支持动态的增加和删除元素，但是可以对网页中的基本元素进行属性的修改。比如IHTMLElementCollection表示网页中一些基本的元素的集合，IHTMLElement表示网页中的一个基本的元素。而象IHTMLOptionElement接口就表示一个特定的元素Option。基本的元素都有setAttribute和geAttribute方法来动态的设置和得到元素的名称和值。 </p>
<p>&#8212;- 较为常见的一个应用是我们能够分析网页中是否有需要填写的Forms，如果这个网址的Forms以前已经填写过而且数据我们已经保存下来的话，我们就可以把数据自动放到和该URL下的Forms的相关的位置中去。另外，我们可以总结网页上需要填写的Form的数据项，先对这些数据项进行赋值，以后碰到有相同的数据项的时候就自动把我们赋值的内容填写进去。实际上Form是对象，Form中包含的元素，比如INPUT，OPTION，SELECT等类型的输入元素都是对象。 </p>
<p>&#8212;- 另外一个可以想到的应用是自动对网页中的文本进行翻译，因为我们可以修改网页中任何对象的属性，所以我们可以把里面不属于本国语言的部分自动翻译成本国语言，当然真正的实现还要靠自然语言理解方面技术的突破，但是IE浏览器的接口和对象的形式使我们能够灵活的控制整个IE，无论是从事件对象还是到网页对象。 </p>
<p>&#8212;- 5．小结 </p>
<p>&#8212;- 上面我们分析了如何得到所有IE的实例，同时介绍了和IE实例相捆绑的DLL的详细的实现机制，同时对网页的对象化进行了分析。并且介绍了几个相关的应用和实现的方法及存在的技术问题。IE是一个组件化的以COM为基础的浏览器，它具有强大的功能，同时为应用开发者留下了广阔的空间，当然它也存在体积比较大，速度相对比较慢的缺点。但是它的体系结构代表了微软先进的创新的技术，因此具有强大的生命力。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/327.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Internet Explorer Toolbar (Deskband) Tutorial</title>
		<link>http://www.donevii.com/post/316.html</link>
		<comments>http://www.donevii.com/post/316.html#comments</comments>
		<pubDate>Sat, 24 Mar 2007 13:50:29 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=316</guid>
		<description><![CDATA[转至http://www.codeproject.com Download Toolbar Binary &#8211; 20Kb Download Source &#8211; 21 Kb Introduction Having recieved a number of requests for a tutorial of sorts on developing Internet Explorer Toolbars with the RBDeskband and CWindowImpl wiz... ]]></description>
			<content:encoded><![CDATA[<p>转至<a href="http://www.codeproject.com">http://www.codeproject.com</a></p>
<ul class="download">
<li><a href="http://www.codeproject.com/atl/IEToolbarTutorial/MotleyFool_dll.zip" class="broken_link">Download Toolbar Binary &#8211; 20Kb</a> </li>
<li><a href="http://www.codeproject.com/atl/IEToolbarTutorial/MotleyFool_src.zip" class="broken_link"><font color="#800080">Download Source &#8211; 21 Kb</font></a> </li>
</ul>
<p><img height="190" alt="The Motley Fool Quote IE Toolbar" src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure15.jpg" width="607" /> </p>
<h2>Introduction </h2>
<p nd="1">Having recieved a number of requests for a tutorial of sorts on developing Internet Explorer Toolbars with the RBDeskband and CWindowImpl wizards that I created, I have come up with a simple sample toolbar which can be used as a reference when developing your own toolbars or explorer bars. The tutorial will walk you through the stages of developing a toolbar for <a href="http://www.donevii.com/post/tag/ie" class="st_tag internal_tag" rel="tag" title="Posts tagged with ie">IE</a> that is very similar to the Address bar that is already present in <a href="http://www.donevii.com/post/tag/ie" class="st_tag internal_tag" rel="tag" title="Posts tagged with ie">IE</a>. I wanted to do a tutorial that would provide a realistic sample and would produce an end result that could be used by others after the tutorial was finish. So, the tutorial is going to show you how to develop an <a href="http://www.donevii.com/post/tag/ie" class="st_tag internal_tag" rel="tag" title="Posts tagged with ie">IE</a> toolbar to get stock quote information from The Motley Fool website. So with that, let us get started. </p>
<h2>Prequisites </h2>
<p nd="2">This tutorial assumes that you already know how to program in C++ and know some information about ATL and COM. To work through this tutorial, you will need the following installed on your development machine: </p>
<ul>
<li nd="3">Visual C++6 installed </li>
<li nd="4">RBDeskBand ATL Object Wizard (Version 2.0) [<a href="http://www.codeproject.com/atl/rbdeskband.asp"><font color="#800080">get it here</font></a>] </li>
<li nd="5">CWindowImpl ATL Object Wizard [<a href="http://www.codeproject.com/atl/rbcwindowimpl.asp"><font color="#800080">get it here</font></a>] </li>
</ul>
<h2>The Framework </h2>
<p nd="6">The IE toolbar consists of a COM component supporting IDeskband and a few other necessary interfaces for which IE looks for when loading registered toolbars, explorer bars and deskbands. The RBDeskband ATL Object Wizard provides most of the framework for this article. What we will need to do is create our project, a new COM object to house our toolbar, and a few CWindowImpl classes using the CWindowImpl ATL Object Wizard. Then connecting these parts together we will produce the IE toolbar in the picture at the top of the article. Visually the toolbar consists of an editbox and a toolbar with one button on it. In actuality the toolbar consists of the fore mentioned and a non visible window that is used to reflect messages to the Toolbar window, which will process or forward messges to itself and the edit box. </p>
<h2>Creating The <a href="http://www.donevii.com/post/tag/shell" class="st_tag internal_tag" rel="tag" title="Posts tagged with shell">Shell</a> </h2>
<p nd="7">We will not work through the steps in creating the shell for our toolbar. </p>
<h3>Creating The Project </h3>
<ul>
<li nd="8">If you have not done so already, start Visual C++6. </li>
<li nd="9">Then, from the File menu select New menu item; the New Dialog pops up. </li>
<li nd="10">In the New Dialog, select the Projects tab, if not already selected. </li>
<li nd="11">Select ATL COM AppWizard from the list view, if not already selected. </li>
<li nd="12">In the Project name, type &quot;MotleyFool&quot;. See Figure 1. </li>
<li nd="13">Click the OK Button. </li>
</ul>
<p><center nd="14"><img height="400" alt="Figure 1. New Dialog." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure1.jpg" width="561" name="Figure1" /> <br />Figure 1. New Dialog. </center>
<ul>
<li nd="15">The ATL COM AppWizard will kick in. </li>
<li nd="16">Clicking the Finish Button, accepting the default AppWizard attributes. See Figure 2. </li>
<li nd="17">The New Project Information Dialog will present itself requesting confirmation of your project settings. </li>
<li nd="18">Click the OK Button. </li>
</ul>
<p><center nd="19"><img height="384" alt="Figure 2. ATL COM AppWizard" src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure2.jpg" width="477" name="Figure2" /> <br />Figure 2. ATL COM AppWizard. </center><br />
<h3>Creating The DeskBand Object </h3>
<p>Now that we have our project container we need to add our IDeskBand derived component so that the DLL actually exposes something. </p>
<ul>
<li nd="21">From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked. </li>
<li nd="22">In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed. </li>
<li nd="23">Next select the DeskBand item from the Objects list. </li>
<li nd="24">Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3. </li>
<li nd="25">On the Names property page, type &quot;StockBar&quot; into the Short Name field. See Figure 4. </li>
<li nd="26">Select the DeskBand ATL Object Wizard property page </li>
<li nd="27">Check the Internet Explorer Toolbar checkbox. See Figure 5. </li>
<li nd="28">Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our DeskBand&#8217;s base implementation. </li>
</ul>
<p><center nd="29"><img height="257" alt="Figure 3. ATL Object Wizard." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure3.jpg" width="413" name="Figure3" /> <br />Figure 3. ATL Object Wizard. </center><center nd="30"><img height="279" alt="Figure 4. ATL Object Wizard Properties - Names." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure4.jpg" width="433" name="Figure4" /> <br />Figure 4. ATL Object Wizard Properties &#8211; Names. </center><center nd="31"><img height="279" alt="Figure 5. ATL Object Wizard Properties - DeskBand ATL Object Wizard." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure5.jpg" width="433" name="Figure5" /> <br />Figure 5. ATL Object Wizard Properties &#8211; DeskBand ATL Object Wizard </center>
<p>Now our project has the DeskBand implementation that we will modify to produce the toolbar pictured at the top of the article. First we will create the window classes we will need and then come back to the Desbkand object and update it to use our window classes. </p>
<h2>Creating The Window Classes </h2>
<p nd="32">So back in the Framework section we said that we would need three window classes. One for the Edit Box, one for the toolbar, and one for message reflection back to the toolbar. Let us now create these window classes. </p>
<h3>The Edit Window </h3>
<p nd="33">We need to create a derived <a href="http://www.donevii.com/post/tag/class" class="st_tag internal_tag" rel="tag" title="Posts tagged with class">class</a> from the standard EDIT button window <a href="http://www.donevii.com/post/tag/class" class="st_tag internal_tag" rel="tag" title="Posts tagged with class">class</a> because we are going to be adding methods to our <a href="http://www.donevii.com/post/tag/class" class="st_tag internal_tag" rel="tag" title="Posts tagged with class">class</a> to help support functionality of the toolbar. This is one reason why we cannot use a CContainedWindow object directly. </p>
<ul>
<li nd="34">From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked. </li>
<li nd="35">In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed. </li>
<li nd="36">Next select the CWindowImpl item from the Objects list. </li>
<li nd="37">Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3. </li>
<li nd="38">On the Names property page, type &quot;EditQuote&quot; into the Short Name field. </li>
<li nd="39">Select the CWindowImpl property page. See Figure 6. </li>
<li nd="40">Select the SUPERCLASS radio button from the DECLAR_WND_* group. </li>
<li nd="41">In the Window Class Name field, type &quot;EDITQUOTE&quot;. </li>
<li nd="42">In the Original Class Name list, select the EDIT listbox item. See Figure 7. </li>
<li nd="43">Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation. </li>
</ul>
<p><center nd="44"><img height="279" alt="Figure 6. ATL Object Wizard Properties - Names." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure6.jpg" width="433" name="Figure6" /> <br />Figure 6. ATL Object Wizard Properties &#8211; Names. </center><center nd="45"><img height="279" alt="Figure 7. ATL Object Wizard Properties - Names." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure7.jpg" width="433" name="Figure7" /> <br />Figure 7. ATL Object Wizard Properties &#8211; CWindowImpl. </center><br />
<h3>The Toolbar Window </h3>
<p nd="46">We need to create a derived class from the standard TOOLBARCLASSNAME window class because we are going to be adding methods to our class to help support functionality of the toolbar. It will also be the parent for the edit box and the window which the IE host will request from our DeskBand. </p>
<ul>
<li nd="47">From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked. </li>
<li nd="48">In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed. </li>
<li nd="49">Next select the CWindowImpl item from the Objects list. </li>
<li nd="50">Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3. </li>
<li nd="51">On the Names property page, type &quot;MFToolbar&quot; into the Short Name field. </li>
<li nd="52">Select the CWindowImpl property page. See Figure 8. </li>
<li nd="53">Select the SUPERCLASS radio button from the DECLAR_WND_* group. </li>
<li nd="54">In the Window Class Name field, type &quot;MOTLEYFOOLTOOLBAR&quot;. </li>
<li nd="55">In the Original Class Name list, select the TOOLBARCLASSNAME listbox item. See Figure 9. </li>
<li nd="56">Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation. </li>
</ul>
<p><center nd="57"><img height="279" alt="Figure 8. ATL Object Wizard Properties - Names." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure8.jpg" width="433" name="Figure8" /> <br />Figure 8. ATL Object Wizard Properties &#8211; Names. </center><center nd="58"><img height="279" alt="Figure 9. ATL Object Wizard Properties - Names." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure9.jpg" width="433" name="Figure9" /> <br />Figure 9. ATL Object Wizard Properties &#8211; CWindowImpl. </center><br />
<h3>The Reflection Window </h3>
<p nd="59">We need to create a reflection window. It&#8217;s just a CWindowImpl window implmented class. We are going to be adding a small bit of functionality just to create the toolbar object and be able to access the toolbar member from our deskband class. </p>
<ul>
<li nd="60">From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked. </li>
<li nd="61">In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed. </li>
<li nd="62">Next select the CWindowImpl item from the Objects list. </li>
<li nd="63">Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3. </li>
<li nd="64">On the Names property page, type &quot;ReflectionWnd&quot; into the Short Name field. See Figure 10. </li>
<li nd="65">We will not change any of the CWindowImpl property page values this time. </li>
<li nd="66">Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation. </li>
</ul>
<p><center nd="67"><img height="279" alt="Figure 10. ATL Object Wizard Properties - Names." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure10.jpg" width="433" name="Figure10" /> <br />Figure 10. ATL Object Wizard Properties &#8211; Names. </center><br />
<h2>Adding The Details </h2>
<p nd="68">Now that we have our window classes available we can add our functionality for our toolbar to the appropriate window classes. Let us start with the deepest window class and work our way back out. </p>
<h3>The EditQuote Details </h3>
<p nd="69">For the EditQuote implementation, we need to be able to process keystrokes from the user and let the host that created our deskband object know our edit box has focus. To accomplish the first part, we need to look ahead and see that our DeskBand object will be implementing the IInputObject interface. So the host will query for that interface and know that we want to recieve messages and be given the chance to recieve focus. When the host sends our band messages to process they come through the IInputObject::TranslateAccelerator method. Our DeskBand will implement this method and it is best if our edit box, which will process the message, copy the TranslateAcceleratorIO method definition so our deskband can forward the message easily through a logical method call. </p>
<p><center nd="70"><img height="503" alt="Figure 11. FileView Pane." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure11.jpg" width="408" name="Figure11" /> <br />Figure 11. FileView Pane. </center>
<p>In the FileView pane (See Figure 11), double click the EditQuote.h item under Header Files. This will open the header file in the editing area. We now need to define the method definition for TranslateAcceleratorIO. To do this, add below the virtual CEditQuote destructor the following line of code: </p>
<pre lang="c++" nd="71">STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg);</pre>
<p>Now Open the EditQuote.cpp source file and add the implementation of TranslateAcceleratorIO to the file </p>
<pre nd="72" langu="c++">STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){   TranslateMessage(lpMsg);   DispatchMessage(lpMsg);   <span class="cpp-keyword">return</span> S_OK;}</pre>
<p>Now our DeskBand implementation can call this message and the edit box will process the key strokes properly. But wait, our edit box should notify the toolbar to load the quote details entered if the key stroke is the enter key. For this, we will need to define a message id and send that message to the parent window to process. In the EditQuote.h header file below the include statement, add the definition of our message id as shown below in bold. </p>
<pre lang="c++"><span class="cpp-preprocessor" nd="73">#include &lt;commctrl.h&gt;</span><strong><span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> WM_GETQUOTE = WM_USER + <span class="cpp-literal">1024</span>;</strong>			</pre>
<p>In our EditQuote.cpp file we will add code to our TranslateAcceleratorIO method to process the enter key. Add the code below in bold to the EditQuote.cpp file. </p>
<pre lang="c++" nd="74">STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){<strong>   <span class="cpp-keyword">int</span> nVirtKey = (<span class="cpp-keyword">int</span>)(lpMsg-&gt;wParam);   <span class="cpp-keyword">if</span> (VK_RETURN == nVirtKey)   {      <span class="cpp-comment">// remove system beep on enter key by setting key code to 0</span>      lpMsg-&gt;wParam = <span class="cpp-literal">0</span>;      ::PostMessage(GetParent(), WM_GETQUOTE, <span class="cpp-literal">0</span>, <span class="cpp-literal">0</span>);      <span class="cpp-keyword">return</span> S_OK;   }</strong>   TranslateMessage(lpMsg);   DispatchMessage(lpMsg);   <span class="cpp-keyword">return</span> S_OK;}</pre>
<p>Now our edit box will notify the parent when the user presses the enter key so that the parent can retrieve the requested ticker symbol details, this part will be implemented when we get to the toolbar details. </p>
<p nd="75">The first part of the Edit boxes implementation is finished. Now we need to be able for the edit box to have the deskband notify the host that we have focus or that we don&#8217;t have focus any longer. To do this we will need to add a method for the deskband to pass us it&#8217;s address so that we can call a method of the deskband class. These next steps will involve adding code to the CEditQuote class and to our Deskband class implementation. </p>
<p nd="76">Open the EditQuote.h file and add a forward reference to the CStockBar class so that we can defined our methods and members in our class header without knowing the implementation details of our deskband class, add the line in bold. </p>
<pre lang="c++" nd="78"><span class="cpp-preprocessor" nd="77">#include &lt;commctrl.h&gt;</span><span class="cpp-keyword">const</span> <span class="cpp-keyword">int</span> WM_GETQUOTE = WM_USER + <span class="cpp-literal">1024</span>;<strong><span class="cpp-keyword">class</span> CStockBar;</strong></pre>
<p>For our class to notify the host that our deskband has focus, we need to add a message handler for EN_SETFOCUS. Add the command code handler code below in bold to your EditQuote.h file. </p>
<pre lang="c++" nd="79">   BEGIN_MSG_MAP(CEditQuote)<strong>      COMMAND_CODE_HANDLER(EN_SETFOCUS, OnSetFocus)</strong>   END_MSG_MAP()</pre>
<p>Then add the method definition for OnSetFocus to the header file below the commented out handler prototypes as follows below in bold. </p>
<pre lang="c++"><span class="cpp-comment">// Handler prototypes:</span><span class="cpp-comment">// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</span><span class="cpp-comment">// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; bHandled);</span><span class="cpp-comment">// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled);</span><strong>   LRESULT OnSetFocus(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; bHandled);</strong></pre>
<p>Before we implement the OnSetFocus method, we need to define a method for our deskband to tells of it&#8217;s address and to retain that address for later use. Add the following lines of code to your EditQuote.h file below the TranslateAcceleratorIO definition. </p>
<pre lang="c++" nd="80">   <span class="cpp-keyword">void</span> SetBand(CStockBar* pBand);<span class="cpp-keyword">private</span>:   CStockBar* m_pBand;</pre>
<p>Now we can move to your EditQuote.cpp source file and implement the message handler, the SetBand method, and update the TranslateAcceleratorIO method for focus change. At the top of the EditQuote.cpp file add the following includes to the include list as shown below in bold. </p>
<pre lang="c++"><span class="cpp-preprocessor" nd="81">#include &quot;stdafx.h&quot;</span><span class="cpp-preprocessor" nd="82">#include &quot;EditQuote.h&quot;</span><strong>#include &quot;MotleyFool.h&quot;<span class="cpp-preprocessor">#include &quot;StockBar.h&quot;</span></strong></pre>
<p>Now when we can use the methods of the CStockBar class in our code. Add to the end of the constructor, the initalization of m_pBand. Don&#8217;t forget the colon operator. </p>
<pre lang="c++" nd="83">CEditQuote::CEditQuote()<strong>: m_pBand(NULL)</strong>{}</pre>
<p>Next we will add the SetBand implementation to our CEditQuote class. Notice that since it is not a com object we don&#8217;t call AddRef or Release on it. It&#8217;s just a pointer to the class and when it&#8217;s destroyed our CEditQuote instance will also be destroyed. We could have also done this inline in our header file. </p>
<pre lang="c++" nd="84"><span class="cpp-keyword">void</span> CEditQuote::SetBand(CStockBar* pBand){   m_pBand = pBand;}</pre>
<p>Next we need to add our message handler for our EN_SETFOCUS message. Add the code below to the end of the EditQuote.cpp source file. </p>
<pre lang="c++" nd="85">LRESULT CEditQuote::OnSetFocus(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; bHandled){   <span class="cpp-comment">//Notify host that our band has the focus so TranslateAcceleratorIO </span>   <span class="cpp-comment">//messages are directed towards our band.</span>   <span class="cpp-keyword">if</span> (m_pBand) m_pBand-&gt;FocusChange(TRUE);   <span class="cpp-keyword">return</span> <span class="cpp-literal">0</span>;}</pre>
<p>We have one more section of code to add to our CEditQuote implementation then we can move to our CStockBar class to define and implement the FocusChange method. Add the following code to the CEditQuote TranslateAcceleratorIO method as shown in bold. We add this code so the host knows that we are no longer needing messages. </p>
<pre lang="c++" nd="86">STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){   <span class="cpp-keyword">int</span> nVirtKey = (<span class="cpp-keyword">int</span>)(lpMsg-&gt;wParam);   <span class="cpp-keyword">if</span> (VK_RETURN == nVirtKey)   {      <span class="cpp-comment">// remove system beep on enter key by setting key code to 0</span>      lpMsg-&gt;wParam = <span class="cpp-literal">0</span>;      ::PostMessage(GetParent(), WM_GETQUOTE, <span class="cpp-literal">0</span>, <span class="cpp-literal">0</span>);      <span class="cpp-keyword">return</span> S_OK;   }<strong>   <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> (WM_KEYDOWN == lpMsg-&gt;message &amp;&amp; nVirtKey == VK_TAB)   {      <span class="cpp-comment">// we no longer need messages forwarded to our band</span>      <span class="cpp-keyword">if</span> (m_pBand) m_pBand-&gt;FocusChange(FALSE);      <span class="cpp-keyword">return</span> S_FALSE;   }</strong>   TranslateMessage(lpMsg);   DispatchMessage(lpMsg);   <span class="cpp-keyword">return</span> S_OK;}</pre>
<p>Open the StockBar.h header file and add the definition of FocusChange to it as shown below in bold. </p>
<pre lang="c++" nd="87"><span class="cpp-comment">// IStockBar</span><span class="cpp-keyword">public</span>:<strong>   <span class="cpp-keyword">void</span> FocusChange(BOOL bHaveFocus);</strong></pre>
<p>Now open the StockBar.cpp source file and add the implementation of FocusChange to it at the bottom. </p>
<pre lang="c++" nd="88"><span class="cpp-keyword">void</span> CStockBar::FocusChange(BOOL bHaveFocus){   <span class="cpp-keyword">if</span> (m_pSite)   {      IUnknown* pUnk = NULL;      <span class="cpp-keyword">if</span> (SUCCEEDED(QueryInterface(IID_IUnknown, (LPVOID*)&amp;pUnk)) &amp;&amp; pUnk != NULL)      {         m_pSite-&gt;OnFocusChangeIS(pUnk, bHaveFocus);         pUnk-&gt;Release();         pUnk = NULL;      }   }}</pre>
<p>We have finished off the work needed for the edit box to work properly in our toolbar. Now we need to build our toolbar up so that it has a button and contains our edit box. Then we will add the nessecities to our reflection window and update our IDeskBand to provide the correct information to our host. We are almost there. If you were to compile the project and run it, it would except that the band would look like the following in figure X. </p>
<h3>The MFToolbar Details </h3>
<p nd="89">For the implementation of the MFToolbar window, we need to be able to have it do the following things. It must be able to process the WM_GETQUOTE message from the EditQuote window, communicate with the <a href="http://www.donevii.com/post/tag/web" class="st_tag internal_tag" rel="tag" title="Posts tagged with web">web</a> browser in which the toolbar is located, create the buttons and place the child <a href="http://www.donevii.com/post/tag/windows" class="st_tag internal_tag" rel="tag" title="Posts tagged with windows">windows</a> on itself, forward messages to the EditQuote child window and size itself appropriately to the users actions. </p>
<p nd="90">So, the first thing we should do since our toolbar is going to contain an instance of CEditQuote is include the header file for the CEditQuote class. We will do this by opening the MFToolbar.h file and inserting the include statement for the CEditQuote class as shown in bold below. </p>
<pre lang="c++"><span class="cpp-preprocessor" nd="91">#include &lt;commctrl.h&gt;</span><strong>#include &quot;EditQuote.h&quot;</strong>		</pre>
<p>Next we need to add a member to our toolbar class for the CEditQuote class. We will do this by adding a private section to the end of our class and defining a member variable as shown below in bold. </p>
<pre lang="c++" nd="92">   CMFToolbar();   <span class="cpp-keyword">virtual</span> ~CMFToolbar();<strong><span class="cpp-keyword">private</span>:   CEditQuote m_EditWnd;</strong></pre>
<p>Now that we have our member defined for our EditQuote window, we need to forward window messages to it so that keyboard inputs are processed appropriately. We do this by updating the toolbar message map to chain messages to our member as shown below in bold. </p>
<pre lang="c++" nd="93">   BEGIN_MSG_MAP(CMFToolbar)<strong>      CHAIN_MSG_MAP_MEMBER(m_EditWnd)</strong>   END_MSG_MAP()</pre>
<p>Looking forward, our deskband will need to get the EditQuote member to deterimine if it has focus and also to make it function. We could just expose the EditQuote member directly by having made it a public member instead of private, but by making it private we can expose a method that will expose our member giving us flexibility later to modify the class if the need should arise. So to expose the EditQuote member, we will add a fuction to our toolbar class to return the reference to the EditQuote member. In the toolbar header file, add the method definition and implementation below in bold to it. </p>
<pre lang="c++" nd="94">   CMFToolbar();   <span class="cpp-keyword">virtual</span> ~CMFToolbar();<strong>   <span class="cpp-keyword">inline</span> CEditQuote&amp; GetEditBox() {<span class="cpp-keyword">return</span> m_EditWnd;};</strong></pre>
<p>Now we will create our toolbar window. Our toolbar consists of the EditQuote box and a button with an icon and text on it. To house the icon, our toolbar will need an image list handle to send to the toolbar window. So we need to add a few things to our toolbar header file before we go and implement the toolbar&#8217;s creation. The first thing we will add is the member variable for our image list. Add the line in bold below to your toolbar header file. </p>
<pre lang="c++" nd="95"><span class="cpp-keyword">private</span>:   CEditQuote m_EditWnd;<strong>   HIMAGELIST m_hImageList;</strong></pre>
<p>Then we will add a message handler to our toolbar&#8217;s message map and define the message handlers function definition to our header file and the follow lines of code in bold to your header file. </p>
<pre lang="c++" nd="96">   BEGIN_MSG_MAP(CMFToolbar)      CHAIN_MSG_MAP_MEMBER(m_EditWnd)<strong>      MESSAGE_HANDLER(WM_CREATE, OnCreate)</strong>   END_MSG_MAP()<span class="cpp-comment">// Handler prototypes:</span><span class="cpp-comment">//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled);</span><strong>   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</strong></pre>
<p>Before we can implement our toolbar&#8217;s creation, we need to create a icon resource that our toolbar button will use next to its text. So go to the resource view and add a new icon to the project resources. You can do this by right clicking on &quot;MotleyFool resources&quot; and selecting &quot;Insert&#8230;&quot; from the context menu. In the Insert Resource dialog box, select Icon from the Resource type list and click the New button. This will insert a blank icon resource into your project. Rename the icon&#8217;s resource ID by right clicking on the icon resource in the resource view and selecting the properties menu item from the context menu. Change the id to IDI_MOTLEY. Then draw or graciously borrow an icon from The Motley Fool to use on the toolbar. I graciously borrowed the icon from their website and adapted it into the icon. </p>
<p>Now we can implement it our toolbars creation. Open the MFToolbar source file and implement the details of the toolbar creation as described below. </p>
<p>First we need to include the project resource file so we can use the icon ID in our code. Add the line in bold below to our toolbar&#8217;s source file as shown. </p>
<pre lang="c++"><span class="cpp-preprocessor" nd="97">#include &quot;stdafx.h&quot;</span><strong>#include &quot;resource.h&quot;</strong><span class="cpp-preprocessor" nd="98">#include &quot;MFToolbar.h&quot;</span></pre>
<p>Next we need to update our constructor implementation. We need to initialize our handle to the image list by setting it to NULL. Don&#8217;t forget the colon. </p>
<pre lang="c++" nd="99">CMFToolbar::CMFToolbar()<strong>: m_hImageList(NULL)</strong>{}</pre>
<p>Next we need to update our destructor, it should destroy the image list and destroy the window if it has not yet been destroyed. </p>
<pre lang="c++" nd="100">CMFToolbar::~CMFToolbar(){<strong>   ImageList_Destroy(m_hImageList);   <span class="cpp-keyword">if</span> (IsWindow()) DestroyWindow();</strong>}</pre>
<p>Before we can implement our toolbar&#8217;s creation, we need to add a resource symbol to our project for the toolbar button&#8217;s ID. We could just use a <code><span class="cpp-preprocessor" nd="101">#define</span></code> statement at the top of the source file, but for cleanliness and since we are already including the resource.h file, we will add it to our resource file. Go to the &quot;View&quot; menu and select &quot;Resource Symbols&quot; menu item. Click the &quot;New&quot; button on the Resource Symbols dialog. Then enter a name of &quot;IDM_GETQUOTE&quot; and click OK. Then close the Resource Symbols dialog. </p>
<p>Now we can create our toolbar, we defined the OnCreate method in our header file and need to now implement it. Add the following function and its implementation to the end of the toolbar source file. </p>
<div class="precollapse" id="premain24" style="WIDTH: 100%"><img id="preimg24" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="24" alt="" /><span id="precollapse24" style="MARGIN-BOTTOM: 0px; CURSOR: hand" nd="102" preid="24"> Collapse</span></div>
<pre lang="c++" id="pre24" style="MARGIN-TOP: 0px" nd="103">LRESULT CMFToolbar::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled){   <span class="cpp-comment">// buttons with images and text</span>   SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, <span class="cpp-literal">0</span>, (LPARAM)TBSTYLE_EX_MIXEDBUTTONS);   <span class="cpp-comment">// Sets the size of the TBBUTTON structure.</span>   SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, <span class="cpp-keyword">sizeof</span>(TBBUTTON), <span class="cpp-literal">0</span>);   <span class="cpp-comment">// Set the maximum number of text rows and bitmap size.</span>   SendMessage(m_hWnd, TB_SETMAXTEXTROWS, <span class="cpp-literal">1</span>, <span class="cpp-literal">0L</span>);   <span class="cpp-comment">// add our button's caption to the toolbar window</span>   TCHAR* pCaption = _T(&quot;Get Quote&quot;);   <span class="cpp-keyword">int</span> iIndex = ::SendMessage(m_hWnd, TB_ADDSTRING, <span class="cpp-literal">0</span>,(LPARAM)pCaption);   <span class="cpp-comment">// load our button's icon and create the image list to house it.</span>   HICON hMotley = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_MOTLEY));   m_hImageList = ImageList_Create(<span class="cpp-literal">16</span>,<span class="cpp-literal">16</span>, ILC_COLOR16, <span class="cpp-literal">1</span>, <span class="cpp-literal">0</span>);   <span class="cpp-keyword">int</span> iImageIndex = ImageList_AddIcon(m_hImageList, hMotley);   DestroyIcon(hMotley);   <span class="cpp-comment">// Set the toolbar's image</span>   ::SendMessage(m_hWnd, TB_SETIMAGELIST, <span class="cpp-literal">0</span>, (LPARAM)m_hImageList);   <span class="cpp-comment">// add the button for the toolbar to the window</span>   TBBUTTON Button;   ZeroMemory((<span class="cpp-keyword">void</span>*)&amp;Button, <span class="cpp-keyword">sizeof</span>(TBBUTTON));   Button.idCommand = IDM_GETQUOTE;   Button.fsState = TBSTATE_ENABLED;   Button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT;   Button.dwData = <span class="cpp-literal">0</span>;   Button.iString = iIndex;   Button.iBitmap = <span class="cpp-literal">0</span>;   ::SendMessage(m_hWnd, TB_INSERTBUTTON, <span class="cpp-literal">0</span>, (LPARAM)&amp;Button);   <span class="cpp-comment">// create our EditQuote window and set the font.</span>   RECT rect = {<span class="cpp-literal">0</span>,<span class="cpp-literal">0</span>,<span class="cpp-literal">0</span>,<span class="cpp-literal">0</span>};   m_EditWnd.Create(m_hWnd, rect, NULL, WS_CHILD|WS_VISIBLE, WS_EX_CLIENTEDGE);   m_EditWnd.SetFont(<span class="cpp-keyword">static_cast</span>&lt;HFONT&gt;(GetStockObject(DEFAULT_GUI_FONT)));   <span class="cpp-keyword">return</span> <span class="cpp-literal">0</span>;}</pre>
<p>If you try to compile at this point, you will see that there are unresolved externals for the image list method calls. We need to add a library to the project. To do this select the &quot;Project|Settings&quot; menu item. On the Project Settings dialog, Select All Configurations from the &quot;Settings For&quot; combo box. Then select the &quot;Link&quot; tab and append to the &quot;Object/Library modules&quot; edit box &quot;comctl32.lib&quot;. Then click OK. If you compile the project now, it will compile successfully and the image list unresolved externals will disappear. </p>
<p>We still have a few things we need to do to the Toolbar window. It needs to process Command messages, resopnd to WM_GETQUOTE messages, and resize itself. Let&#8217;s conquer the latter first. </p>
<p>To orgainze the tooblar correctly, we should have the toolbar responsd to WM_SIZE messages. To do this, we will add to our tooblar header file a message handler for the WM_SIZE message and add a function definition for OnSize which WM_SIZE messages will be sent to. Open our toolbar header file and add the lines in bold below to it as shown. </p>
<pre lang="c++" nd="104">   BEGIN_MSG_MAP(CMFToolbar)      CHAIN_MSG_MAP_MEMBER(m_EditWnd)      MESSAGE_HANDLER(WM_CREATE, OnCreate)<strong>      MESSAGE_HANDLER(WM_SIZE, OnSize)</strong>   END_MSG_MAP()<span class="cpp-comment">// Handler prototypes:</span><span class="cpp-comment">//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled);</span>   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);<strong>   LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</strong></pre>
<p>Now we need to implement our OnSize function. Open the toolbar source file and add the function implementation below to the end of the file. </p>
<div class="precollapse" id="premain26" style="WIDTH: 100%"><img id="preimg26" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="26" alt="" /><span id="precollapse26" style="MARGIN-BOTTOM: 0px; CURSOR: hand" nd="105" preid="26"> Collapse</span></div>
<pre lang="c++" id="pre26" style="MARGIN-TOP: 0px" nd="106">LRESULT CMFToolbar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled){   <span class="cpp-comment">// based on the size of the window area minus the size of the toolbar button, </span>   <span class="cpp-comment">// indent the toolbar so that we can place the edit box before the toolbar </span>   <span class="cpp-comment">// button. This will right justify the toolbar button in the toolbar and the </span>   <span class="cpp-comment">// edit box will use the vaction space to the left of the button but after the </span>   <span class="cpp-comment">// toolbar text as it's usable space.</span>   RECT wndRect, btnRect;   GetClientRect(&amp;wndRect);   ::SendMessage(m_hWnd, TB_GETITEMRECT, <span class="cpp-literal">0</span>, (LPARAM)&amp;btnRect);   wndRect.right -= (btnRect.right - btnRect.left);   SendMessage(TB_SETINDENT, wndRect.right - wndRect.left);   <span class="cpp-comment">// put a small spacing gap between the edit box's right edge and the toolbar button's left edge</span>   wndRect.right -= <span class="cpp-literal">3</span>;   m_EditWnd.MoveWindow(&amp;wndRect, FALSE);   <span class="cpp-keyword">return</span> <span class="cpp-literal">0</span>;}</pre>
<p>We still need to respond to user input for the toolbar button and from the edit box when the user presses the enter key. What we want the toolbar to do is tell the web browser host to navigate to the motely fool website and retrieve the stock quotes requested. First we need for the Deskband object to tell our toolbar window what the web browser instance is so that the toolbar window can communicate with it. To do this, we will add a private member variable and a public method in which the deskband can set the web browser instance. Our window will then use the member variable set to tell the web browser where to navigate and what to retrieve. </p>
<p>To do this, open the toolbar header file and add the lines in bold to the file. </p>
<pre lang="c++" nd="107">   CMFToolbar();   <span class="cpp-keyword">virtual</span> ~CMFToolbar();   <span class="cpp-keyword">inline</span> CEditQuote&amp; GetEditBox() {<span class="cpp-keyword">return</span> m_EditWnd;};<strong>   <span class="cpp-keyword">void</span> SetBrowser(IWebBrowser2* pBrowser);</strong><span class="cpp-keyword">private</span>:   CEditQuote m_EditWnd;   HIMAGELIST m_hImageList;<strong>   IWebBrowser2* m_pBrowser;</strong></pre>
<p>Now, open the toolbar source file. We will update the constructor and initialize our member variable to null. Then we will update the toolbar destructor and release the member variable if it hasn&#8217;t been. Then we will implement the SetBrowser method. </p>
<p>Initialize the web browser member variable. </p>
<pre lang="c++" nd="108">CMFToolbar::CMFToolbar(): m_hImageList(NULL)<strong>, m_pBrowser(NULL)</strong>{}</pre>
<p>Release the web browser object if held. </p>
<pre lang="c++" nd="109">CMFToolbar::~CMFToolbar(){   ImageList_Destroy(m_hImageList);   SetBrowser(NULL);   <span class="cpp-keyword">if</span> (IsWindow()) DestroyWindow();}</pre>
<p>Implement SetBrowser() </p>
<pre lang="c++" nd="110"><span class="cpp-keyword">void</span> CMFToolbar::SetBrowser(IWebBrowser2* pBrowser){   <span class="cpp-keyword">if</span> (m_pBrowser) m_pBrowser-&gt;Release();   m_pBrowser = pBrowser;   <span class="cpp-keyword">if</span> (m_pBrowser) m_pBrowser-&gt;AddRef();}</pre>
<p>If you try and compile the project, you will notice that IWebBrowser2 is undefine in our header file. This is because we need to update our stdafx.h header file to include system files that define IWebBrowser2. To do this, open stdafx.h and add the following lines in bold to the file, then recompile. </p>
<pre lang="c++" nd="111"><span class="cpp-keyword">extern</span> CComModule _Module;<span class="cpp-preprocessor" nd="112">#include &lt;atlcom.h&gt;</span><span class="cpp-preprocessor" nd="113">#include &lt;atlwin.h&gt;</span><strong><span class="cpp-comment">//</span><span class="cpp-comment">// These are needed for IDeskBand</span><span class="cpp-comment">//</span><span class="cpp-preprocessor">#include &lt;shlguid.h&gt;</span><span class="cpp-preprocessor">#include &lt;shlobj.h&gt;</span></strong></pre>
<p>Now we can add message handlers for WM_COMMAND and WM_GETQUOTE to our toolbar class to handle the toolbar button being pressed and the enter key being pressed in the edit box by the user. To do this, we will need to add to our toolbar header file message handlers and function definitions for WM_COMMAND and WM_GETQUOTE. We will also need to add a private method which both will call if they need to to preform the same functionality (better than repeating code that does the same thing). So let&#8217;s add the message handlers to the header file. </p>
<div class="precollapse" id="premain32" style="WIDTH: 100%"><img id="preimg32" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="32" alt="" /><span id="precollapse32" style="MARGIN-BOTTOM: 0px; CURSOR: hand" nd="114" preid="32"> Collapse</span></div>
<pre lang="c++" id="pre32" style="MARGIN-TOP: 0px" nd="115">   BEGIN_MSG_MAP(CMFToolbar)      CHAIN_MSG_MAP_MEMBER(m_EditWnd)      MESSAGE_HANDLER(WM_CREATE, OnCreate)      MESSAGE_HANDLER(WM_SIZE, OnSize)<strong>      MESSAGE_HANDLER(WM_COMMAND, OnCommand)      MESSAGE_HANDLER(WM_GETQUOTE, OnGetQuote)</strong>   END_MSG_MAP()<span class="cpp-comment">// Handler prototypes:</span><span class="cpp-comment">//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled);</span>   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);   LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);<strong>   LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);   LRESULT OnGetQuote(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</strong></pre>
<p>Now we can add the function delcaration for our GetQuote privaet method. </p>
<pre lang="c++" nd="116"><span class="cpp-keyword">private</span>:   CEditQuote m_EditWnd;   HIMAGELIST m_hImageList;   IWebBrowser2* m_pBrowser;<strong>   <span class="cpp-keyword">void</span> GetQuote();</strong></pre>
<p>Now let&#8217;s switch to our source file and implement our message handler functions and the GetQuote method. Add the code below to the end of the toolbar source file. </p>
<div class="precollapse" id="premain34" style="WIDTH: 100%"><img id="preimg34" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="34" alt="" /><span id="precollapse34" style="MARGIN-BOTTOM: 0px; CURSOR: hand" nd="117" preid="34"> Collapse</span></div>
<pre lang="c++" id="pre34" style="MARGIN-TOP: 0px" nd="118">LRESULT CMFToolbar::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled){   <span class="cpp-keyword">if</span> (!HIWORD(wParam))   {      <span class="cpp-keyword">long</span> lSite = LOWORD(wParam);      <span class="cpp-keyword">if</span> ( lSite == IDM_GETQUOTE)      {         GetQuote();         <span class="cpp-keyword">return</span> <span class="cpp-literal">0</span>;      }   }   <span class="cpp-keyword">return</span> -<span class="cpp-literal">1</span>;}LRESULT CMFToolbar::OnGetQuote(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled){   GetQuote();   <span class="cpp-keyword">return</span> <span class="cpp-literal">0</span>;}<span class="cpp-keyword">void</span> CMFToolbar::GetQuote(){   <span class="cpp-comment">// if we have a web browser pointer then try to navigate to The Motley Fool site to retrieve stock quotes.</span>   <span class="cpp-keyword">if</span> (m_pBrowser)   {      VARIANT vEmpty;      VariantInit(&amp;vEmpty);      m_pBrowser-&gt;Stop();      _bstr_t bsSite;      <span class="cpp-comment">// if the user has entered stock quotes then append them to the url</span>      <span class="cpp-keyword">if</span> (m_EditWnd.GetWindowTextLength())      {         BSTR bstrTickers = NULL;         m_EditWnd.GetWindowText(&amp;bstrTickers);         bsSite = &quot;http:<span class="cpp-comment">//quote.fool.com/news/symbolnews.asp?Symbols=&quot;;</span>         bsSite += bstrTickers;         SysFreeString(bstrTickers);      }      <span class="cpp-comment">// if the user has not entered any stock quotes then just take them to The Motley Fool website.</span>      <span class="cpp-keyword">else</span>         bsSite = &quot;http:<span class="cpp-comment">//www.fool.com&quot;;</span>      <span class="cpp-comment">// have the webrowser navigate to the site URL requested depending on user input.</span>      m_pBrowser-&gt;Navigate(bsSite, &amp;vEmpty, &amp;vEmpty, &amp;vEmpty, &amp;vEmpty);   }}</pre>
<p>If you try to compile, you will notice that _bstr_t is undefined. That is because the class is defined in comdef.h. We need to add this to our stdafx.h header file so that we can use it as well as any other class in our project (which we will need to for IInputObject). Open the stdafx.h header file and add the lines in bold to the file as indicated. </p>
<pre lang="c++"><span class="cpp-preprocessor" nd="119">#include &lt;shlobj.h&gt;</span><strong><span class="cpp-comment">// needed for IInputObject and _bstr_t</span><span class="cpp-preprocessor">#include &lt;comdef.h&gt;</span></strong></pre>
<p>Our implementation of the toolbar window is complete. Now we can move on to the Reflection window which creates our toolbars and forwards command messages to it. </p>
<h3>The Reflection Window Details </h3>
<p>For the Reflection Window, it&#8217;s only purpose is to create the toolbar window (which it doesn&#8217;t need to really do, but by doing so eases message forwarding) and forward messages to it. The reflection window is not visible, it&#8217;s just a layer added so that message from the toolbar get to the toolbar. If we didn&#8217;t have this window present, toolbar messages would get sent to the parent window (which we do not control) and we would never get them. This is not good since we need to respond to WM_COMMAND messages from the toolbar. Thus the need for the reflection window. So let&#8217;s create the toolbar window and the message forwarding for it. </p>
<p>Open the ReflectionWnd.h header file. We will need to include the toolbar header file and add a private member variable to our reflection window to create it and to pass it to the message chain. First things first, add the include statement below so we can use the CMFToolbar class. </p>
<pre lang="c++"><span class="cpp-preprocessor">#include &lt;commctrl.h&gt;</span><strong>#include &quot;MFToolbar.h&quot;</strong></pre>
<p>Next add a private member variable to the end of the reflection window class for the toolbar as shown below. </p>
<pre lang="c++">	CReflectionWnd();   <span class="cpp-keyword">virtual</span> ~CReflectionWnd();<strong><span class="cpp-keyword">private</span>:   CMFToolbar m_ToolbarWnd;</strong></pre>
<p>Next update the reflection window message map to forward messages to the toolbar window as shown below. </p>
<pre lang="c++">   BEGIN_MSG_MAP(CReflectionWnd)<strong>      CHAIN_MSG_MAP_MEMBER(m_ToolbarWnd)</strong>   END_MSG_MAP()</pre>
<p>We will also need a public function for our deskband class to get at our toolbar window. We will do the same as we did with the EditQuote window by providing a function to get at the member variable indirectly. Add the line of code in bold below to the header file as indicated. </p>
<pre lang="c++">   CReflectionWnd();   <span class="cpp-keyword">virtual</span> ~CReflectionWnd();<strong>   <span class="cpp-keyword">inline</span> CMFToolbar&amp; GetToolBar() { <span class="cpp-keyword">return</span> m_ToolbarWnd;};</strong></pre>
<p>Lastly, we need to create the toolbar window and will do so in the WM_CREATE message handler for our reflection window. Add the code below in bold to the reflection window header file. Then we will implement the OnCreate method in the source file. </p>
<pre lang="c++">   BEGIN_MSG_MAP(CReflectionWnd)<strong>      MESSAGE_HANDLER(WM_CREATE, OnCreate)</strong>      CHAIN_MSG_MAP_MEMBER(m_ToolbarWnd)   END_MSG_MAP()<span class="cpp-comment">// Handler prototypes:</span><span class="cpp-comment">//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; bHandled);</span><span class="cpp-comment">//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL&amp; bHandled);</span><strong>   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled);</strong></pre>
<p>Now open the ReflectionWnd.cpp source file and add the implementation of OnCreate to its end. </p>
<pre lang="c++"><span class="cpp-keyword">const</span> DWORD DEFAULT_TOOLBAR_STYLE =       <span class="cpp-comment">/*Window styles:*/</span> WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | WS_TABSTOP |      <span class="cpp-comment">/*Toolbar styles:*/</span> TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_LIST | TBSTYLE_CUSTOMERASE |                          TBSTYLE_WRAPABLE |      <span class="cpp-comment">/*Common Control styles:*/</span> CCS_TOP | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE;LRESULT CReflectionWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; bHandled){   RECT rect;   GetClientRect(&amp;rect);   m_ToolbarWnd.Create(m_hWnd, rect, NULL, DEFAULT_TOOLBAR_STYLE);   <span class="cpp-keyword">return</span> <span class="cpp-literal">0</span>;}</pre>
<p>You will notice that we defined a constant for the toolbar style. This was done to make the code more readable. </p>
<p>The only thing left to do to the reflection window code is update the destructor to destory the window if it&#8217;s still present. </p>
<pre lang="c++">CReflectionWnd::~CReflectionWnd(){<strong>   <span class="cpp-keyword">if</span> (IsWindow()) DestroyWindow();</strong>}</pre>
<p>&nbsp;</p>
<h2>Finishing Off The Deskband Toolbar </h2>
<p>All that&#8217;s left is for our deskband to create the toolbar window, have the host use the toolbar window, remove the unused IPersistStream implementation, implement IInputObject (for focus control) and do some code tweaking. So lets wrap this toolbar up. Open the StockBar.h header file. Remove the following lines of code that are in bold since we moved them to our stdafx.h for our other classes to also use. </p>
<pre lang="c++"><span class="cpp-preprocessor">#include &quot;resource.h&quot;       // main symbols</span><strong><span class="cpp-comment">//</span><span class="cpp-comment">// These are needed for IDeskBand</span><span class="cpp-comment">//</span><span class="cpp-preprocessor">#include &lt;shlguid.h&gt;</span><span class="cpp-preprocessor">#include &lt;shlobj.h&gt;</span></strong></pre>
<p>Next remove the following line from the class delcaration. </p>
<pre lang="c++"><span class="cpp-keyword">public</span> IPersistStream,</pre>
<p>The top of the class declaration should now look like this, </p>
<pre lang="c++"><span class="cpp-keyword">class</span> ATL_NO_VTABLE CStockBar :    <span class="cpp-keyword">public</span> CComObjectRootEx&lt;CComSingleThreadModel&gt;,   <span class="cpp-keyword">public</span> CComCoClass&lt;CStockBar, &amp;CLSID_StockBar&gt;,   <span class="cpp-keyword">public</span> IDeskBand,   <span class="cpp-keyword">public</span> IObjectWithSite,   <span class="cpp-keyword">public</span> IDispatchImpl&lt;IStockBar, &amp;IID_IStockBar, &amp;LIBID_MOTLEYFOOLLib&gt;{</pre>
<p>Next scroll down to the COM Map and remove the following two lines of code, </p>
<pre lang="c++">   COM_INTERFACE_ENTRY(IPersist)   COM_INTERFACE_ENTRY(IPersistStream)</pre>
<p>Your COM Map should now look like this, </p>
<pre lang="c++">BEGIN_COM_MAP(CStockBar)   COM_INTERFACE_ENTRY(IStockBar)   COM_INTERFACE_ENTRY(IOleWindow)   COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)   COM_INTERFACE_ENTRY(IObjectWithSite)   COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)   COM_INTERFACE_ENTRY(IDispatch)END_COM_MAP()</pre>
<p>Scroll down the header file further and remove the sections of function declarations for IPersist and IPersistStream, which includes the following lines. </p>
<pre lang="c++"><span class="cpp-comment">// IPersist</span><span class="cpp-keyword">public</span>:   STDMETHOD(GetClassID)(CLSID *pClassID);<span class="cpp-comment">// IPersistStream</span><span class="cpp-keyword">public</span>:   STDMETHOD(IsDirty)(<span class="cpp-keyword">void</span>);   STDMETHOD(Load)(IStream *pStm);   STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty);   STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize);</pre>
<p>There should now be nothing related to IPersist or IPersistStream between the IDockingWindow and IStockBar function declaration sections. </p>
<p>Now we need to remove the IPersist and IPersistStream function implementations from the StockBar.cpp source file. Find the GetClassID, IsDirty, Load, Save, and GetSizeMax function implementations and remove them from the file. They should be directly above the FocusChange Method we added earlier. </p>
<p>Now we can start adding code to our deskband. Open the stockbar.h header file and add the include for the reflection window class as shown below in bold. </p>
<pre lang="c++"><span class="cpp-preprocessor">#include &quot;resource.h&quot;       // main symbols</span><strong>#include &quot;ReflectionWnd.h&quot;</strong></pre>
<p>Next, find the protected section at the end of the file and replace the line </p>
<pre lang="c++">   HWND m_hWnd;</pre>
<p>with </p>
<pre lang="c++">   CReflectionWnd m_ReflectWnd;</pre>
<p>If you try to compile, you will find that it will be unsuccessful since we have removed m_hWnd and have not removed all occurances of m_hWnd from the class source file. We will replace all occurances with more appropriate code for our Reflection window and toolbar window. Open the StockBar.cpp source file, Remove the following line from the class constructor </p>
<pre lang="c++">   m_hWnd(NULL),</pre>
<p>your class constructor should now look as follows with a SetBand call added, </p>
<pre lang="c++">CStockBar::CStockBar():    m_dwBandID(<span class="cpp-literal">0</span>),    m_dwViewMode(<span class="cpp-literal">0</span>),    m_bShow(FALSE),    m_bEnterHelpMode(FALSE),    m_hWndParent(NULL),    m_pSite(NULL){	m_ReflectWnd.GetToolBar().GetEditBox().SetBand(<span class="cpp-keyword">this</span>);}</pre>
<p>Next, update the RegisterAndCreateWindow function by replacing the temporary m_hWnd construction with the Reflection Window construction. Your RegisterAndCreateWindow implementation should look as follows: </p>
<pre lang="c++">BOOL CStockBar::RegisterAndCreateWindow(){   RECT rect;   ::GetClientRect(m_hWndParent, &amp;rect);   m_ReflectWnd.Create(m_hWndParent, rect, NULL, WS_CHILD);   <span class="cpp-comment">// The toolbar is the window that the host will be using so it is the window that is important.</span>   <span class="cpp-keyword">return</span> m_ReflectWnd.GetToolBar().IsWindow();}</pre>
<p>As we scroll through the code, we should fix some other things. A toolbar has a default height of 22 so we need to update our GetBandInfo method so that all the y measurements are 22 not 20. We also want our Integral sizing to be non sizeable so we need to set the DBIM_INTEGRAL x and y values to 0. While we are at it, we should fix the title of our toolbar so it says &quot;The Motley Fool&quot;. You&#8217;ll find this constant defined near the top of the source file, update it now. </p>
<p>We will now update the GetWindow call so that the toolbar window handle is returned and not the invalid m_hWnd variable. Update your GetWindow method so it looks as follows, </p>
<pre lang="c++">STDMETHODIMP CStockBar::GetWindow(HWND* phwnd){   HRESULT hr = S_OK;   <span class="cpp-keyword">if</span> (NULL == phwnd)   {      hr = E_INVALIDARG;   }   <span class="cpp-keyword">else</span>   {<strong>      *phwnd = m_ReflectWnd.GetToolBar().m_hWnd;</strong>   }   <span class="cpp-keyword">return</span> hr;}</pre>
<p>Now we need to update teh CloseDW method so that it does not destory our window buy hide it. We do this much like the MFC CToolbar class does, the class destructor will destroy the window. Your CloseDW method should look as follows, </p>
<pre lang="c++">STDMETHODIMP CStockBar::CloseDW(<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">long</span> dwReserved){   ShowDW(FALSE);   <span class="cpp-keyword">return</span> S_OK;}</pre>
<p>Working our way through our class implementation, we will update the next method that needs updating. Update the ShowDW class to show or hide the toolbar window which the host is using. Your ShowDW class should look as follows, </p>
<pre lang="c++">STDMETHODIMP CStockBar::ShowDW(BOOL fShow){   m_bShow = fShow;   m_ReflectWnd.GetToolBar().ShowWindow(m_bShow ? SW_SHOW : SW_HIDE);   <span class="cpp-keyword">return</span> S_OK;}</pre>
<p>We are almost done modifying the CStockBar class we need to do one last bit of updating. We need to modify the SetSite implementation to release the browser window that the toolbar may be using if we have a IInputObjectSite object and we need to query the OleCommandTarget&#8217;s ServiceProvider for the IWebBrowser2 interface which we will then set to our toolbar. The modified parts of the SetSite method implementation are below in bold. </p>
<div class="precollapse" id="premain58" style="WIDTH: 100%"><img id="preimg58" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="58" alt="" /><span id="precollapse58" style="MARGIN-BOTTOM: 0px; CURSOR: hand" preid="58"> Collapse</span></div>
<pre lang="c++" id="pre58" style="MARGIN-TOP: 0px">STDMETHODIMP CStockBar::SetSite(IUnknown* pUnkSite){<span class="cpp-comment">//If a site is being held, release it.</span>   <span class="cpp-keyword">if</span>(m_pSite)   {<strong>      m_ReflectWnd.GetToolBar().SetBrowser(NULL);</strong>      m_pSite-&gt;Release();      m_pSite = NULL;   }   <span class="cpp-comment">//If punkSite is not NULL, a new site is being set.</span>   <span class="cpp-keyword">if</span>(pUnkSite)   {      <span class="cpp-comment">//Get the parent window.</span>      IOleWindow  *pOleWindow = NULL;      m_hWndParent = NULL;      <span class="cpp-keyword">if</span>(SUCCEEDED(pUnkSite-&gt;QueryInterface(IID_IOleWindow, (LPVOID*)&amp;pOleWindow)))      {         pOleWindow-&gt;GetWindow(&amp;m_hWndParent);         pOleWindow-&gt;Release();      }      <span class="cpp-keyword">if</span>(!::IsWindow(m_hWndParent))         <span class="cpp-keyword">return</span> E_FAIL;      <span class="cpp-keyword">if</span>(!RegisterAndCreateWindow())         <span class="cpp-keyword">return</span> E_FAIL;      <span class="cpp-comment">//Get and keep the IInputObjectSite pointer.</span><strong>      <span class="cpp-keyword">if</span>(FAILED(pUnkSite-&gt;QueryInterface(IID_IInputObjectSite, (LPVOID*)&amp;m_pSite)))      {         <span class="cpp-keyword">return</span> E_FAIL;      }        IWebBrowser2* s_pFrameWB = NULL;      IOleCommandTarget* pCmdTarget = NULL;      HRESULT hr = pUnkSite-&gt;QueryInterface(IID_IOleCommandTarget, (LPVOID*)&amp;pCmdTarget);      <span class="cpp-keyword">if</span> (SUCCEEDED(hr))      {         IServiceProvider* pSP;         hr = pCmdTarget-&gt;QueryInterface(IID_IServiceProvider, (LPVOID*)&amp;pSP);         pCmdTarget-&gt;Release();         <span class="cpp-keyword">if</span> (SUCCEEDED(hr))         {            hr = pSP-&gt;QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&amp;s_pFrameWB);            pSP-&gt;Release();            _ASSERT(s_pFrameWB);            m_ReflectWnd.GetToolBar().SetBrowser(s_pFrameWB);            s_pFrameWB-&gt;Release();         }      }</strong>   }   <span class="cpp-keyword">return</span> S_OK;}</pre>
<p>If you try to compile and use the toolbar right now, it will function partially. Tabbing and input control will not work correctly since we have yet to implement IInputObject for our deskband. Let&#8217;s do that now since it&#8217;s the last bit of code we will write for our simple deskband. You may also notice that the Toolbars context menu and View|Toolbars menus still say CStockBar Class. we will fix this problem in the Finishing Touches section below. </p>
<h3>IInputObject Implementation </h3>
<p>To get tabbing and input control to work correctly for any deskband is quite simple. You need but to implement IInputObject. The host will query our deskband to see if this interface is implemented and if it is will call the methods to see if we require input focus and let us also process messages from the user through the host. To do this, open the stockbar.h header file. To the stockbar class declaration add the line below in bold, </p>
<pre lang="c++"><span class="cpp-keyword">class</span> ATL_NO_VTABLE CStockBar :    <span class="cpp-keyword">public</span> CComObjectRootEx&lt;CComSingleThreadModel&gt;,   <span class="cpp-keyword">public</span> CComCoClass&lt;CStockBar, &amp;CLSID_StockBar&gt;,   <span class="cpp-keyword">public</span> IDeskBand,   <span class="cpp-keyword">public</span> IObjectWithSite,<strong>   <span class="cpp-keyword">public</span> IInputObject,</strong>    <span class="cpp-keyword">public</span> IDispatchImpl&lt;IStockBar, &amp;IID_IStockBar, &amp;LIBID_MOTLEYFOOLLib&gt;{</pre>
<p>Next scroll down to the COM Map and add an entry for IInputObject as shown below in bold, </p>
<pre lang="c++">BEGIN_COM_MAP(CStockBar)   COM_INTERFACE_ENTRY(IStockBar)<strong>   COM_INTERFACE_ENTRY(IInputObject)</strong>   COM_INTERFACE_ENTRY(IOleWindow)   COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)   COM_INTERFACE_ENTRY(IObjectWithSite)   COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)   COM_INTERFACE_ENTRY(IDispatch)END_COM_MAP()</pre>
<p>Next add the following section of function declarations to your header file, I placed mine before the IStockBar section. </p>
<pre lang="c++"><span class="cpp-comment">// IInputObject</span><span class="cpp-keyword">public</span>:   STDMETHOD(HasFocusIO)(<span class="cpp-keyword">void</span>);   STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg);   STDMETHOD(UIActivateIO)(BOOL fActivate, LPMSG lpMsg);</pre>
<p>All that remains is to implement these three functions. Add the function implementations below to the end of the stockbar.cpp source file. </p>
<div class="precollapse" id="premain62" style="WIDTH: 100%"><img id="preimg62" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="62" alt="" /><span id="precollapse62" style="MARGIN-BOTTOM: 0px; CURSOR: hand" preid="62"> Collapse</span></div>
<pre lang="c++" id="pre62" style="MARGIN-TOP: 0px">STDMETHODIMP CStockBar::HasFocusIO(<span class="cpp-keyword">void</span>){   <span class="cpp-comment">// if any of the windows in our toolbar have focus then return S_OK else S_FALSE.</span>   <span class="cpp-keyword">if</span> (m_ReflectWnd.GetToolBar().m_hWnd == ::GetFocus())      <span class="cpp-keyword">return</span> S_OK;   <span class="cpp-keyword">if</span> (m_ReflectWnd.GetToolBar().GetEditBox().m_hWnd == ::GetFocus())     <span class="cpp-keyword">return</span> S_OK;   <span class="cpp-keyword">return</span> S_FALSE;}STDMETHODIMP CStockBar::TranslateAcceleratorIO(LPMSG lpMsg){   <span class="cpp-comment">// the only window that needs to translate messages is our edit box so forward them.</span>   <span class="cpp-keyword">return</span> m_ReflectWnd.GetToolBar().GetEditBox().TranslateAcceleratorIO(lpMsg);}STDMETHODIMP CStockBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg){   <span class="cpp-comment">// if our deskband is being activated then set focus to the edit box.</span>   <span class="cpp-keyword">if</span>(fActivate)   {      m_ReflectWnd.GetToolBar().GetEditBox().SetFocus();   }   <span class="cpp-keyword">return</span> S_OK;}</pre>
<p>Our toolbar is functionaly done, compile, run it and see. It works as described and is fairly simple. Let&#8217;s put some finishing UI touches on it for IE and our users to use. </p>
<h2>Finishing Touches </h2>
<p>The are only 2 finishing touches to make, One is to fix the context menu text. The other is to add button support to the main IE toolbar. Let&#8217;s do them in order. </p>
<p>To fix the context menu text problem, open the StockBar.rgs project file and change all occurances of &quot;StockBar Class&quot; to &quot;The Motley Fool Quotes&quot;. Compile it, run it, and see. While you only need to change one of them, it&#8217;s nicer if they all match. </p>
<p>Now let&#8217;s add button support for our toolbar. Update the stockbar.rgs file contents by appending the text below to it&#8217;s contents. </p>
<div class="precollapse" id="premain63" style="WIDTH: 100%"><img id="preimg63" style="CURSOR: hand" height="9" src="http://www.codeproject.com/images/minus.gif" width="9" preid="63" alt="" /><span id="precollapse63" style="MARGIN-BOTTOM: 0px; CURSOR: hand" preid="63"> Collapse</span></div>
<pre id="pre63" style="MARGIN-TOP: 0px">HKLM{   Software   {      Microsoft      {         <span class="cpp-string">'Internet Explorer'</span>         {            Extensions            {               ForceRemove	{A26ABCF0-1C8F-<span class="cpp-literal">46e7</span>-A67C-0489DC21B9CC} = s <span class="cpp-string">'The Motley Fool Quotes'</span>               {                  val BandClsid = s <span class="cpp-string">'{A6790AA5-C6C7-4BCF-A46D-0FDAC4EA90EB}'</span>                  val ButtonText = s <span class="cpp-string">'The Motley Fool'</span>                  val Clsid = s <span class="cpp-string">'{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}'</span>                  val <span class="cpp-string">'Default Visible'</span> = s <span class="cpp-string">'Yes'</span>                  val <span class="cpp-string">'Hot Icon'</span> = s <span class="cpp-string">'%MODULE%,425'</span>                  val Icon = s <span class="cpp-string">'%MODULE%,425'</span>                  val MenuStatusBar = s <span class="cpp-string">'The Motley Fool Stock Quote Toolbar'</span>                  val MenuText = s <span class="cpp-string">'The Motley Fool'</span>               }            }         }      }   }}</pre>
<p>The replace the 425 with the id from resource.h of IDI_MOTLEY. Also replace the BandClsid value with the GUID of our toolbar, the above values represent the source code for the article. Now compile the toolbar again. Then start IE and right click on the Standard Buttons toolbar, Select &quot;Customize&quot; from the context menu. Scroll down the Available toolbar buttons listbox and find &quot;The Motley Fool&quot; item, See Figure 12. Select it and click the Add button in the middle of the dialog. The item will move to the right as in Figure 13. Click the Close Button. You&#8217;ll see the button added as shown in the before figure 14 and after figure 15. </p>
<p><center><img height="282" alt="Figure 12. Customize Toolbar - Available Toolbar Buttons." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure12.jpg" width="542" name="Figure12" /> <br />Figure 12. CustomizeToolbar &#8211; Available Toolbar Buttons. </center><center><img height="282" alt="Figure 13. Customize Toolbar - Current Toolbar Buttons." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure13.jpg" width="542" name="Figure13" /> <br />Figure 13. Customize Toolbar &#8211; Current Toolbar Buttons. </center><center><img height="190" alt="Figure 14. IE Standard Buttons - Before." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure14.jpg" width="607" name="Figure14" /> <br />Figure 14. IE Standard Buttons &#8211; Before. </center><center><img height="190" alt="Figure 15. IE Standard Buttons - After." src="http://www.codeproject.com/atl/IEToolbarTutorial/Figure15.jpg" width="607" name="Figure15" /> <br />Figure 15. IE Standard Buttons &#8211; After. </center><br />
<h2>Conclusion </h2>
<p>While this tutorial is long hopefully the explaination was clear. From writing this tutorial it is easy to see that the RBDeskband ATL Object Wizard has some room for improvement but provided enough of a base for us to develop our simple example. In the end you can see that the toolbar we created is much like the Address bar. The differences lie in how MS implemented theirs versus how I implemented mine. As always feedback is welcome. Enjoy. </p>
<p><!-- Article Ends --><script src="/script/togglePre.js" type="text/javascript"></script><br />
<h2>About Erik Thompson</h2>
<div style="OVERFLOW: hidden">
<table border="0">
<tbody>
<tr valign="top">
<td class="smallText" nowrap="nowrap"><img src="http://www.codeproject.com/script/profile/images/{889A4A05-021A-4EBB-BBA5-CC7AFD49E71D}.jpg" alt="" /></p>
<p>            <img src="http://www.codeproject.com/script/images/sitebuild_icon.gif" alt="" /> Site Builder</td>
<td class="smallText">Erik lives in Redmond, Washington. He works as a Senior Software Engineer specializing in C++, COM, ATL and the middle-tier and now .NET. When he isn&#8217;t coding for work, he can be found trying to extend Internet Explorer with yet another Desk band or simplifying his development process with ATL Object Wizards.</p>
<p>            He spends his free time snowboarding, mountain biking, reading, dining out at those hidden finds.
<p class="smallText">Click <a href="http://www.codeproject.com/script/profile/whos_who.asp?vt=arts&amp;id=78">here</a> to view Erik Thompson&#8217;s online profile.</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>
<table cellpadding="4" width="100%" border="0">
<tbody>
<tr valign="top">
<td width="100%">
<h2>Other popular ATL articles:</h2>
<ul>
<li><a href="http://www.codeproject.com/atl/com_atl.asp">Beginner&#8217;s Tutorial: COM/ATL Simple Project</a>
<div class="smallText">The purpose of this tutorial is to give you an idea on how to create a COM <a href="http://www.donevii.com/post/tag/server" class="st_tag internal_tag" rel="tag" title="Posts tagged with server">Server</a> using ATL, and then being able to call the <a href="http://www.donevii.com/post/tag/server" class="st_tag internal_tag" rel="tag" title="Posts tagged with server">server</a> from both a Visual C++ and Visual Basic program.</div>
</li>
<li><a href="http://www.codeproject.com/atl/atl_underthehood_.asp">ATL Under the Hood &#8211; Part 1</a>
<div class="smallText">In this series of tutorials I am going to discuss some of the inner workings of ATL and the techniques that ATL uses.</div>
</li>
<li><a href="http://www.codeproject.com/atl/MouseGestures.asp">Mouse Gestures for Internet Explorer</a>
<div class="smallText">Adding mouse gesture recognition to Internet Explorer.</div>
</li>
<li><a href="http://www.codeproject.com/atl/udtdemo.asp">Using User Defined Types in COM &amp; ATL</a>
<div class="smallText">A Step by Step tutorial on SAFEARRAYs and UDTs in COM</div>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/316.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Shell编程 &#8211; 傻瓜教程2</title>
		<link>http://www.donevii.com/post/315.html</link>
		<comments>http://www.donevii.com/post/315.html#comments</comments>
		<pubDate>Sat, 24 Mar 2007 13:41:29 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[测试]]></category>
		<category><![CDATA[类]]></category>
		<category><![CDATA[缓存]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=315</guid>
		<description><![CDATA[&#160;本文例子代码下载(19K)(codeproject.com) &#160;&#160;&#160; 在这篇指南的第一部分，我给了大家一个编写外壳扩展的介绍，并且演示了一个一次操作一个简单文件的上下文菜单扩展。在第二部分中... ]]></description>
			<content:encoded><![CDATA[<p>&nbsp;<a href="http://263.csdn.net/FileBBS/files/2001_9/T_618_1.zip" class="broken_link">本文例子代码下载(19K)(codeproject.com)</a>
<p>&nbsp;&nbsp;&nbsp; 在这篇指南的<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>，我给了大家一个编写外壳扩展的介绍，并且演示了一个一次操作一个简单文件的上下文菜单扩展。在第二部分中，我将要演示如何在一个操作中操作多个文件。这个扩展是一个注册和卸载COM服务器的实用工具。它还演示了如何使用ATL对话框类<code>CDialogImpl</code>。我将通过解释一些特殊的注册表键来讲第二部分，通过这些键你可以使你的扩展被<em>任何</em>文件调用，而不是那些预先选择的类型(.TXT)。</p>
<p>&nbsp;&nbsp;&nbsp; 第二部分假设你已经阅读了<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>，所以你知道了上下文菜单扩展的基本知识。除此之外，你还必须理解COM，ATL和STL的基本知识。</p>
<h2>上下文菜单扩展的开始-它能做什么？</h2>
<p>&nbsp;&nbsp;&nbsp; 这个外壳扩展将使你注册和卸载那些在EXE,DLL和OCX里的COM服务器。不像我们在<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>所做的那样，这个扩展将对所有你右键点击事件发生时所有选中的文件进行操作。</p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">使用</span><span lang="EN-US">AppWizard </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">开始</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">运行</span><span lang="EN-US">AppWizard </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，做一个新的</span><span lang="EN-US">ATL COM wizard app</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。我们叫它</span><code>DllReg</code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。在向导中保持所有默认选项，单击完成。我们现在就有了一个空的将会生成</span><span lang="EN-US">DLL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">项目，但是我们必须添加自己的外壳扩展</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">对象。在</span><span lang="EN-US">ClassView</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">树中，右键单击</span> <code>DllReg classes</code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">项，选择</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">New ATL Object</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在</span><span lang="EN-US">ATL Object </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">向导，第一面板已经选择了</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">Simple Object</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，只要单击下一步就行了。在第二面板中，在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">Short Name</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">编辑控件中输入</span><code>DllRegShlExt</code> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，然后单击确定（面板中的其它的编辑框将会自动完成）。这就创建了一个类名为</span><code>CDllRegShlExt</code> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的类，它包含了实现一个</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">对象的基本代码。我们将向这个类添加我们的代码。</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">初始化接口</span></h2>
<p>&nbsp;&nbsp;&nbsp; 在这个扩展中，我们的<code>IShellExtInit::Initialize()</code>实现将会相当不同。有两个原因，第一我们将列举所有选中的文件；第二，我们将测试我们选中的文件是否有注册(register)和卸载(unregister)函数的出口。我们将仅仅考虑那些同时有<code>DllRegisterServer()</code>和<code>DllUnregisterServer()</code>出口的文件。其他的都将被忽略掉。</p>
<p>&nbsp;&nbsp;&nbsp; 我们将使用列表控件和STL的字符串与列表类，所以你必须首先在<code>stdafx.h</code> 文件中添加如下行：</p>
<pre>#include &lt;commctrl.h&gt;#include &lt;string&gt;#include &lt;list&gt;#include &lt;atlwin.h&gt;typedef std::list&lt;std::basic_string&lt;TCHAR&gt; &gt; string_list;</pre>
<p>&nbsp;&nbsp;&nbsp; 我们的<code>CDllRegShlExt</code>类也将需要一些成员变量：</p>
<pre>protected:    HBITMAP     m_hRegBmp;    HBITMAP     m_hUnregBmp;    string_list m_lsFiles;    TCHAR       m_szDir[MAX_PATH];</pre>
<p><code>&nbsp;&nbsp;&nbsp;</code> <code>CDllRegShlExt</code>的构造函数中将加载两幅上下文菜单中使用的位图：</p>
<pre>CDLLRegShlExt::CDLLRegShlExt(){    m_hRegBmp = LoadBitmap ( _Module.GetModuleInstance(),                             MAKEINTRESOURCE(IDB_REGISTERBMP) );    m_hUnregBmp = LoadBitmap ( _Module.GetModuleInstance(),                               MAKEINTRESOURCE(IDB_UNREGISTERBMP) );}</pre>
<p>&nbsp;&nbsp;&nbsp; 在你将<code>IShellExtInit</code>添加到了被<code>CDllRegShlExt</code>实现的接口列表中之后(关于这个操作请参见<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>)，我们开始写<code>Initialize()</code>函数。</p>
<p><code>&nbsp; Initialize()</code>将执行如下步骤：</p>
<ol>
<li>改变当前目录为在资源浏览器窗口中正在被查看的目录； </li>
<li>列举所有被选中的文件； </li>
<li>对每一个文件，试图使用<code>LoadLibrary()</code>加载它； </li>
<li>如果<code>LoadLibrary()</code>成功，看该文件是否有<code>DllRegisterServer()</code>和<code>DllUnregisterServer()</code>的函数出口； </li>
<li>如果两个出口都被找到了，添加该文件的的文件名到我们能操作的文件列表中，<code>m_lsFiles</code>。 </li>
</ol>
<pre>HRESULT CDllRegShlExt::Initialize (     LPCITEMIDLIST pidlFolder,    LPDATAOBJECT pDataObj,    HKEY hProgID ){TCHAR     szFile    [MAX_PATH];TCHAR     szFolder  [MAX_PATH];TCHAR     szCurrDir [MAX_PATH];TCHAR*    pszLastBackslash;UINT      uNumFiles;HDROP     hdrop;FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };STGMEDIUM stg = { TYMED_HGLOBAL };HINSTANCE hinst;bool      bChangedDir = false;HRESULT (STDAPICALLTYPE* pfn)();</pre>
<p>&nbsp;&nbsp;&nbsp; 非常多的局部变量！第一步是从传进去的<code>pDataObj</code>参数中获得一个HDROP。这和<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>的扩展有些相似。</p>
<pre>    // Read the list of folders from the data object.  They're stored in HDROP    // format, so just get the HDROP handle and then use the drag 'n' drop APIs    // on it.    if ( FAILED( pDO-&gt;GetData ( &amp;etc, &amp;stg )))        return E_INVALIDARG;    // Get an HDROP handle.    hdrop = (HDROP) GlobalLock ( stg.hGlobal );    if ( NULL == hdrop )        {        ReleaseStgMedium ( &amp;stg );        return E_INVALIDARG;        }    // Determine how many files are involved in this operation.    uNumFiles = DragQueryFile ( hdrop, 0xFFFFFFFF, NULL, 0 );</pre>
<p>&nbsp;&nbsp;&nbsp; 接下来要做的就是一个获取下一个文件名的for循环(使用<code>DragQueryFile()</code>)并试图用<code>LoadLibrary()</code>装载它。在该文的实际例子工程当中预先做了一些目录改变的工作。在这儿我把它忽略了，因为它有点儿太长了。</p>
<pre>    for ( UINT uFile = 0; uFile &lt; uNumFiles; uFile++ )        {        // Get the next filename.        if ( 0 == DragQueryFile ( hdrop, uFile, szFile, MAX_PATH ))            continue;        // Try &amp; load the DLL.        hinst = LoadLibrary ( szFile );                if ( NULL == hinst )            continue;</pre>
<p>&nbsp;&nbsp;&nbsp; 下一步，我们将看看它是否有两个必要函数的出口。</p>
<pre>        // Get the address of DllRegisterServer();        (FARPROC&amp;) pfn = GetProcAddress ( hinst, &quot;DllRegisterServer&quot; );        // If it wasn't found, skip the file.        if ( NULL == pfn )            {            FreeLibrary ( hinst );            continue;            }        // Get the address of DllUnregisterServer();        (FARPROC&amp;) pfn = GetProcAddress ( hinst, &quot;DllUnregisterServer&quot; );        // If it was found, we can operate on the file, so add it to        // our list of files (m_lsFiles).        if ( NULL != pfn )            {            m_lsFiles.push_back ( szFile );            }        FreeLibrary ( hinst );        }   // end for</pre>
<p>&nbsp;&nbsp;&nbsp; 最后一步就是(在最后一个if块中)添加文件名到<code>m_lsFiles</code>中。<code>m_lsFiles</code>是一个保存字符串的STL列表集。这个列表在稍后，就是当我们遍历所有文件注册和卸载的时候将被用到。</p>
<p>&nbsp;&nbsp;&nbsp; 在<code>Initialize()</code>的最后要做的就是释放资源并返回恰当的值给Explorer。</p>
<pre>    // Release resources.    GlobalUnlock ( stg.hGlobal );    ReleaseStgMedium ( &amp;stg );    // If we found any files we can work with, return S_OK.  Otherwise,    // return E_INVALIDARG so we don't get called again for this right-click    // operation.    return ( m_lsFiles.size() &gt; 0 ) ? S_OK : E_INVALIDARG;}</pre>
<p>&nbsp;&nbsp;&nbsp; 如果你看一眼例子项目代码的话，你会发现我不得不都过查看文件的文件名来计算出哪个目录正在被查看。你也许会纳闷为什么我不用<code>pidlFolder</code>参数。虽然在<code>pidlFolder</code>的文档中，它被解释为&ldquo;包含正在显示上下文菜单的项目的文件夹的项目标志列表(the item identifier list for the folder that contains the item whose context menu is being displayed)(很抱歉我不能把这句话翻译好，贴出原文供参考)&rdquo;。可是，我在Windows 98 上测试的时候，这个参数总是为NULL，所以它毫无用处。</p>
<h2>添加我们的菜单项</h2>
<p>&nbsp;&nbsp;&nbsp; 接下来的是<code>IContextMenu</code>方法。和以前一样，你需要添加<code>IContextMenu</code>到<code>CDllRegShlExt</code>实现的接口列表中。再一次的，做这些的步骤在<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>中。</p>
<p>&nbsp;&nbsp;&nbsp; 我们将添加两个菜单项到菜单中，一个为注册选中的文件，一个是卸载它们。这些项看起来如下：</p>
<p><img height="72" src="http://www.codeproject.com/shell/ShellExtGuide2/ShellExtGuide2_1.jpg" width="233" border="0" alt="" /></p>
<p>&nbsp;&nbsp;&nbsp; 我们的<code>QueryContextMenu()</code>实现和<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>一样开始。我们检查<code>uFlags</code>，如果<code>CMF_DEFAULTONLY</code>标志存在的话立即返回。&nbsp;</p>
<pre>HRESULT CDLLRegShlExt::QueryContextMenu (    HMENU hmenu,    UINT  uMenuIndex,    UINT  uidFirstCmd,    UINT  uidLastCmd,    UINT  uFlags ){UINT uCmdID = uidFirstCmd;    // If the flags include CMF_DEFAULTONLY then we shouldn't do anything.    if ( uFlags &amp; CMF_DEFAULTONLY )        {        return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );        }</pre>
<p>&nbsp;&nbsp;&nbsp; 下面，我们添加&quot;Register servers&quot;菜单项。这儿有些新东西：我们给菜单项设置了位图。这和WinZip的菜单有点儿相似，也在菜单命令旁边显示一个小图标。</p>
<pre>    // Add our register/unregister items.    InsertMenu ( hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION, uCmdID++,                 _T(&quot;Register <a href="http://www.donevii.com/post/tag/server" class="st_tag internal_tag" rel="tag" title="Posts tagged with server">server</a>(s)&quot;) );    // Set the bitmap for the register item.    if ( NULL != m_hRegBmp )        {        SetMenuItemBitmaps ( hmenu, uMenuIndex, MF_BYPOSITION, m_hRegBmp, NULL );        }    uMenuIndex++;</pre>
<p>&nbsp;&nbsp;&nbsp; <code>SetMenuItemBitmaps()</code>API函数我们宰菜单旁显示一个小齿轮的方法。注意<code>uCmdID</code>是自增加的，这样下一次我们调用<code>InsertMenu()</code>，它的命令ID将会比前一个大1。在这步骤的最后，<code>uMenuIndex</code> 被增加是因为我们的第二个菜单项将被显示在第一个之后。</p>
<p>&nbsp;&nbsp;&nbsp; 接着说第二个菜单项。它和第一个非常相似。</p>
<pre>    InsertMenu ( hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION, uCmdID++,                 _T(&quot;Unregister server(s)&quot;) );    // Set the bitmap for the unregister item.    if ( NULL != m_hUnregBmp )        {        SetMenuItemBitmaps ( hmenu, uMenuIndex, MF_BYPOSITION, m_hUnregBmp, NULL );        }</pre>
<p>&nbsp;&nbsp;&nbsp; 最后，我们告诉Explorer我们添加了几个菜单项。</p>
<pre>    return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 2 );</pre>
<h2>提供敏感帮助和动词</h2>
<p>&nbsp;&nbsp;&nbsp; 和前面的一样，当Explorer需要显示敏感帮助或者获得动词的时候，<code>GetCommandString()</code>方法被调用。和前一个稍稍不同的是我们添加了2个菜单项，所以我们必须首先检查<code>uCmdID</code>参数来知道Explorer正在呼叫哪个菜单项。</p>
<pre>#include &lt;atlconv.h&gt;HRESULT CDLLRegShlExt::GetCommandString (     UINT  uCmdID,    UINT  uFlags,     UINT* puReserved,    LPSTR szName,    UINT  cchMax ){LPCTSTR szPrompt;    USES_CONVERSION;    if ( uFlags &amp; GCS_HELPTEXT )        {        switch ( uCmdID )            {            case 0:                szPrompt = _T(&quot;Register all selected COM servers&quot;);            break;            case 1:                szPrompt = _T(&quot;Unregister all selected COM servers&quot;);            break;            default:                return E_INVALIDARG;            break;            }</pre>
<p>&nbsp;&nbsp;&nbsp; 如果<code>uCmdID</code>为0，那么我们正在调用第一个(register)。如果为1，则在调用第二个(unregister)。在确定帮助字符串之后，我们将它拷贝到提供的缓存当中，必要的话，先将它转换成Unicode形式。</p>
<pre>        // Copy the help text into the supplied buffer.  If the <a href="http://www.donevii.com/post/tag/shell" class="st_tag internal_tag" rel="tag" title="Posts tagged with shell">shell</a> wants        // a Unicode string, we need to case szName to an LPCWSTR.        if ( uFlags &amp; GCS_UNICODE )            {            lstrcpynW ( (LPWSTR) szName, T2CW(szPrompt), cchMax );            }        else            {            lstrcpynA ( szName, T2CA(szPrompt), cchMax );            }        }</pre>
<p>&nbsp;&nbsp;&nbsp; 在这个扩展中，我同样也写了代码提供一个动词。然而，我在Windows 98下测试的时候，Explorer从来不调用<code>GetCommandString()</code>来获取一个动词。我甚至写了一个在DLL中调用<code>ShellExecute()</code>的测试程序然后试图使用动词，但是它还是不工作。我不知道这个情况在Windows NT下是否会有不同。这儿，我忽略了那些动词相关的代码，如果你感兴趣的话，你可以在例子项目中找到。</p>
<h2>执行用户的选择</h2>
<p>&nbsp;&nbsp;&nbsp; 当用户点击我们菜单中的一个时，Explorer调用我们的<code>InvokeCommand()</code>方法。<code>InvokeCommand()</code>首先检查了<code>lpVerb</code>的高位字(high word)。如果它是非零的，则它是被调用的动词的名称，因为我们知道动词不能正常工作(至少在Win 98下)，我们将它忽略了。否则，如果它的低位字(low word)是0或1，那么我们知道其中有一个菜单项目被点击了。</p>
<pre>HRESULT CDllRegShlExt::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo ){    // If lpVerb really points to a string, ignore this function call and bail out.    if ( 0 != HIWORD( pInfo-&gt;lpVerb ))        return E_INVALIDARG;    // Check that lpVerb is one of our commands (0 or 1)    switch ( LOWORD( pInfo-&gt;lpVerb ))        {        case 0:        case 1:            {            CProgressDlg dlg ( &amp;m_lsFiles, pInfo );            dlg.DoModal();            return S_OK;            }        break;        default:            return E_INVALIDARG;        break;        }}</pre>
<p>&nbsp;&nbsp;&nbsp; 如果<code>lpVerb</code>是0或1，我们创建一个对话框（从ATL类CDialogImpl继承），然后向它传递文件名列表。</p>
<p>&nbsp;&nbsp;&nbsp; 所有实际的工作都在<code>CProgressDlg</code>类中完成。它的<code>OnInitDialog()</code>函数初始化列表控件，然后调用<code>CProgressDlg::DoWork()</code>。<code>DoWork()</code>遍历在<code>CDllRegShlExt::Initialize()</code>中生成的文件名列表，然后调用文件中的合适的函数。基本代码如下；并不完全，因为我删掉了错误检查和填充列表控件的部分。不过这已经足够向大家演示如何遍历一个文件列表并执行每一个。</p>
<pre>void CProgressDlg::DoWork(){HRESULT (STDAPICALLTYPE* pfn)();string_list::const_iterator it, itEnd;HINSTANCE hinst;LPCSTR    pszFnName;HRESULT   hr;WORD      wCmd;    wCmd = LOWORD ( m_pCmdInfo-&gt;lpVerb );    // We only support 2 commands, so check the value passed in lpVerb.    if ( wCmd &gt; 1 )        return;    // Determine which function we'll be calling.  Note that these strings are    // not enclosed in the _T macro, since GetProcAddress() only takes an    // ANSI string for the function name.    pszFnName = wCmd ? &quot;DllUnregisterServer&quot; : &quot;DllRegisterServer&quot;;    for ( it = m_pFileList-&gt;begin(), itEnd = m_pFileList-&gt;end();          it != itEnd;          it++ )        {        // Try to load the next file.        hinst = LoadLibrary ( it-&gt;c_str() );        if ( NULL == hinst )            continue;        // Get the address of the register/unregister function.        (FARPROC&amp;) pfn = GetProcAddress ( hinst, pszFnName );        // If it wasn't found, go on to the next file.        if ( NULL == pfn )            continue;        // Call the function!        hr = pfn();</pre>
<p>&nbsp;&nbsp;&nbsp; 我需要解释一下那个<code>for</code>循环，因为STL集合类是有点令人胆战心惊的，如果你不习惯使用它的话。<code>m_pFileList</code>是一个指向在<code>CDllRegShlExt</code>类中的<code>m_lsFiles</code>列表的指针。（这个指针被传递给了<code>CProgressDlg</code>的构造器。）STL<code>列表</code>集有一个类型叫做<code>const_iterator</code>，这是一个相似于MFC中<code>POSITION</code>类型的抽象实体。一个<code>const_iterator</code>变量像一个列表中常量对象的指针，所以这个遍历器(iterator)可以使用<code>-&gt;</code>访问它本身。遍历器可以使用<code>++</code> 来自增实现在列表中前进。</p>
<p>&nbsp;&nbsp;&nbsp; 所以，这个<code>for</code>循环的初始化表达式调用<code>list::begin()</code>来获取一个遍历器&ldquo;指向&rdquo;列表中的第一个字符串，然后调用<code>list::end()</code>来获取一个遍历器&ldquo;指向&rdquo;列表的&ldquo;末尾&rdquo;，最后一个字符串的位置。 (我把这些词语放在引号里是为了强调指向，开始，和末尾的概念都是被<code>const_iterator</code>类型抽象了的，而且必须通过<code>const_iterator</code>的方法[像<code>begin()</code>]或者操作符[像<code>++</code>]。)这些遍历器被分别地赋给<code>it</code>和<code>itEnd</code>。 这个循环一直进行着，直到<code>it</code>等于<code>itEnd</code>；意思是，当<code>it</code>还没有到达列表的&ldquo;末尾&rdquo;时。这个遍历器<code>it</code>将会在循环过程每次自增加，这样它可以每次到达一个列表中的字符串。</p>
<p>&nbsp;&nbsp;&nbsp; 在遍历其中，表达式<code>it-&gt;c_str()</code> 使用<code>-&gt;</code>操作符。因为<code>it</code>像一个指向<code>string</code>的指针(记住，<code>m_pFileList</code>是一个STL <code>string</code>的列表)，<code>it-&gt;c_str()</code>在<code>it</code>当前所指向的<code>string</code>中调用<code>c_str()</code>函数。<code>c_str()</code>返回一个C类型的字符串指针，既然这样，就是一个<code>LPCTSTR</code>。</p>
<p>&nbsp;&nbsp;&nbsp; <code>DoWork()</code>的余下部分是释放内存和错误检查。你可以从例子项目的<code>ProgressDlg.cpp</code>文件中获取所有代码。</p>
<p>&nbsp;&nbsp;&nbsp; (我刚刚意识到叫一个变量为&quot;it&quot;，是多么的奇怪。很抱歉！) :)</p>
<h2>注册外壳扩展</h2>
<p>&nbsp;&nbsp;&nbsp; 这个<code>DllReg</code>扩展对可执行文件进行操作，所以我们注册它被EXE,DLL和OCX文件调用。和<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>中一样，我们可以在RGS脚本中做这些事，<code>DllRegShlExt.rgs</code>。下面是注册我们的扩展为一个对于上述扩展名文件的上下文菜单扩展必需的脚本。</p>
<pre>HKCR{    NoRemove dllfile    {        NoRemove shellex        {            NoRemove ContextMenuHandlers            {                ForceRemove DLLRegSvr = s '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}'            }        }    }    NoRemove exefile    {        NoRemove shellex        {            NoRemove ContextMenuHandlers            {                ForceRemove DLLRegSvr = s '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}'            }        }    }    NoRemove ocxfile    {        NoRemove shellex        {            NoRemove ContextMenuHandlers            {                ForceRemove DLLRegSvr = s '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}'            }        }    }}</pre>
<p>&nbsp;&nbsp;&nbsp; RGS文件的格式，以及关键词<code>NoRemove</code>和<code>ForceRemove</code>在<a href="http://www.csdn.net/develop/read_article.asp?id=10683" class="broken_link">第一部分</a>已经解释过了，如果你忘了他们的意思的话。&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 正如我们前一个扩展一样，在NT/2000下，我们需要添加我们的扩展到&ldquo;认证的(approved)&rdquo;扩展列表当中。实现这个过程的代码在 <code>DllRegisterServer()</code>和<code>DllUnregisterServer()</code>函数中。我不想展示这些代码，因为它仅仅是一些简单的注册表访问，但是你可以从例子项目中中到这些代码。</p>
<h2>看起来应该什么样呢？</h2>
<p>&nbsp;&nbsp;&nbsp; 当你点击我们其中的一个菜单的时候，对话框就会出现，显示操作的结果：</p>
<p><img height="273" src="http://www.codeproject.com/shell/ShellExtGuide2/ShellExtGuide2_2.jpg" width="450" border="0" alt="" /></p>
<p>&nbsp;&nbsp;&nbsp; 列表控件显示了每个文件的文件名和操作是否成功。当你选中一个项时，一个更详细的消息将被显示在下方。如果失败的话，将有调用失败的描述。</p>
<h2>注册扩展的其他方法</h2>
<p>&nbsp;&nbsp;&nbsp; 到现在为止，我们的扩展只被确定的文件类型调用。通过在<code>HKCR\*</code>下注册成为一个上下文菜单扩展使得被任何文件操作调用成为可能：</p>
<pre>HKCR{    NoRemove *    {        NoRemove shellex        {            NoRemove ContextMenuHandlers            {                ForceRemove DLLRegSvr = s '{8AB81E72-CB2F-11D3-8D3B-AC2F34F1FA3C}'            }        }    }}</pre>
<p>&nbsp;&nbsp;&nbsp; <code>HKCR\*</code>键被所有文件调用的外壳扩展。注意文档中所说的该扩展也被其他外壳对象所调用（文件，目录，虚拟文件夹，控制面板项等等），但是我在测试中所见到的并不是这样。这些扩展仅仅被文件系统中的文件所调用。</p>
<p>&nbsp;&nbsp;&nbsp; 在外壳版本4.71以上，还有一个叫做<code>HKCR\AllFileSystemObjects</code>的键。如果我们在这个键下注册，我们的扩展将被文件系统中所有的文件和目录调用，根目录除外。（根目录调用的扩展在<code>HKCR\Drive</code>下注册。)然而，当我在这个键下注册的时候我看到一些奇怪的现象。&ldquo;发送到&rdquo;菜单也使用这个键，而它混在了<code>DllReg</code>菜单中间：</p>
<p><img height="102" src="http://www.codeproject.com/shell/ShellExtGuide2/ShellExtGuide2_3.jpg" width="231" border="0" alt="" /></p>
<p>&nbsp;&nbsp;&nbsp; 你同样可以编写一个操作目录的上下文菜单扩展。要这样的例子的话，请看我的文章：<br />&nbsp;&nbsp; <a href="http://www.codeproject.com/tips/DirClean.asp" target="_blank">A Utility to Clean Up Compiler Temp Files(一个清除编译临时文件的实用工具)</a>。（译者：确实是个好玩艺 :)）</p>
<p>&nbsp;&nbsp;&nbsp; 最后，在外壳版本4.71以上，你可以使你的上下文菜单在用户右键单击一个正在查看目录（包括桌面）的资源管理器窗口背景时被调用。为了使你的扩展被这么调用，你必须在<code>HKCR\Directory\Background\shellex\ContextMenuHandlers</code>键下注册。使用这个方法，你可以向你的桌面上下文菜单中添加菜单项目或者其他任何目录。传递给<code>IShellExtInit::Initialize()</code>的参数有点儿不同，我会在我以后的文章中加以说明。</p>
<h2>待续&hellip;&hellip;</h2>
<p>&nbsp;&nbsp;&nbsp; 接着的第三部分我们将实践一种新的扩展，查询。它将显示一些外壳对象的弹出式描述。我还将向你展示如何在外壳扩展中使用MFC。</p>
<p>&nbsp;&nbsp;&nbsp; <span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman; mso-bidi-font-size: 12.0pt; mso-bidi-font-family: Times New Roman; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"></span><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">你可以从下面的网址获得这个和其他文章的最新版本：</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"><a href="http://home.inreach.com/mdunn/code/" target="_blank" class="broken_link">http://home.inreach.com/mdunn/code/</a></span> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/315.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shell编程 &#8211; 傻瓜教程1</title>
		<link>http://www.donevii.com/post/314.html</link>
		<comments>http://www.donevii.com/post/314.html#comments</comments>
		<pubDate>Sat, 24 Mar 2007 13:39:08 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[ror]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[类]]></category>
		<category><![CDATA[缓存]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=314</guid>
		<description><![CDATA[&#160;&#160;&#160; 外壳扩展(Shell Extention)是一个能向Windows外壳(资源管理器)添加一些功能的COM对象。这有很多的内容，但是却很少有关于它们的易懂的文档告诉我们如何去编写这些外壳(Shell)程序。... ]]></description>
			<content:encoded><![CDATA[<div class="postTitle"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">&nbsp;&nbsp;&nbsp; 外壳扩展</span><span lang="EN-US">(<a href="http://www.donevii.com/post/tag/shell" class="st_tag internal_tag" rel="tag" title="Posts tagged with shell">Shell</a> Extention)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是一个能向</span><span lang="EN-US"><a href="http://www.donevii.com/post/tag/windows" class="st_tag internal_tag" rel="tag" title="Posts tagged with windows">Windows</a></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">外壳</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">资源管理器</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">添加一些功能的</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">对象。这有很多的内容，但是却很少有关于它们的易懂的文档告诉我们如何去编写这些外壳</span><span lang="EN-US">(Shell)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">程序。如果你想做对外壳很深入的了解，我极力向你推荐</span><span lang="EN-US">Dino Esposito </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的非常好的一本书《</span><cite><span lang="EN-US">Visual C++ Windows Shell Programming</span></cite><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">》。但是对于那些没有这本书并且仅仅关心如何去编写外壳扩展的人，我写的一指南将会令你非常惊讶，如果并非如此的话也能给你理解如何编写外壳扩展提供很好的帮助。要阅读这一指南，确保你对</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">要相当熟悉。</span> </div>
<div class="postText">
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">第一部分包括了对外壳扩展的概要的介绍，并提供了一个上下文菜单扩展的例程来使你对以后的部分中充满兴趣。</span></p>
<h2 style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">什么是<em>外壳扩展</em>呢？</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">这有两部分，外壳和扩展</span><span lang="EN-US">(<em>extension</em>)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。外壳指的是资源管理器</span><span lang="EN-US">(Explorer)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，而扩展是指当一个预订的事件（如：右键单击一个</span><span lang="EN-US">.doc</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文档）发生时，被资源管理器调用的你写的代码。所以以个外壳扩展是一个向资源管理器添加特色的</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">对象。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">一个外壳扩展是一个进程中服务器，它实现了一些与资源管理器通信的借口。而在我看来，</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是快速实现一个扩展并使它运行的最简单的方法，因为你不用为一遍又一遍的写</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryInterface()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">AddRef()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">而大伤脑筋。而且在</span><span lang="EN-US">Windows NT/2000</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下调试扩展也变得更为容易。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">有很多种的扩展，每种扩展在不同的事件发生时被调用。下面是一些比较通用的类型和它们被调用的情况：</span></p>
<table style="WIDTH: 100%; mso-cellspacing: 1.5pt" cellpadding="0" width="100%" border="1">
<tbody>
<tr>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p style="TEXT-ALIGN: center" align="center"><strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">类型</span><span lang="EN-US"> <o:p></o:p></span></strong></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p style="TEXT-ALIGN: center" align="center"><strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">什么时候被调用</span><span lang="EN-US"> <o:p></o:p></span></strong></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 34%; PADDING-TOP: 0.75pt" width="34%">
<p style="TEXT-ALIGN: center" align="center"><strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">可以做什么</span><span lang="EN-US"><o:p></o:p></span></strong></p>
</td>
</tr>
<tr>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">上下文菜单</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">用户在文件或目录右键单击时。在外壳扩展</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">4.71</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">版本以上，在目录窗口的背景上右键单击也将被调用。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 34%; PADDING-TOP: 0.75pt" width="34%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">向上下文菜单添加项目。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
</tr>
<tr>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">属性单</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件的属性单被显示时。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 34%; PADDING-TOP: 0.75pt" width="34%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">向属性单添加一个属性页。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
</tr>
<tr>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">拖扔</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">用户右键拖动项目并把它扔在一个目录窗口活着桌面上时。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 34%; PADDING-TOP: 0.75pt" width="34%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">添加项目至上下文菜单。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
</tr>
<tr>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">扔</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">用户拖一个项目并把它扔到一个文件上时。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 34%; PADDING-TOP: 0.75pt" width="34%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">任何你想做的事。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
</tr>
<tr>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">查询信息</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">(</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">外壳版本</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">4.71+)<span style="COLOR: black"><o:p></o:p></span></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 33%; PADDING-TOP: 0.75pt" width="33%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">用户鼠标在一个文件或像我的电脑一样的其他外壳对象上悬停时。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
<td style="PADDING-RIGHT: 0.75pt; PADDING-LEFT: 0.75pt; PADDING-BOTTOM: 0.75pt; WIDTH: 34%; PADDING-TOP: 0.75pt" width="34%">
<p class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">返回一个资源管理器在工具条提示上的字符串。</span><span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana"><o:p></o:p></span></p>
</td>
</tr>
</tbody>
</table>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">到现在为止你可能为什么一个扩展看起来想在资源管理器里。如果你安装了</span><span lang="EN-US">WinZip</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">（有谁没有吗？），它就包括了许多种的外壳扩展，其中一个就是上下文句柄。下面世</span><span lang="EN-US">WinZip 8 </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">为了压缩文件添加到上下文菜单的截图：</span></p>
<p><img alt="" hspace="" src="http://www.codeproject.com/shell/ShellExtGuide1/ShellExGuide1_1.jpg" align="baseline" border="0" /></p>
<p style="TEXT-INDENT: 21pt"><span lang="EN-US">WinZip</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">包含了添加菜单项目的代码，并提供敏感帮助（显示在资源管理器状态条的文本），并在用户选择</span><span lang="EN-US">WinZip</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">命令之一时起作用。</span></p>
<p style="TEXT-INDENT: 21pt"><span lang="EN-US">WinZip</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">还包含了拖和扔的句柄。这个类型和上下文菜单扩展非常类似，但是它仅仅在用户通过鼠标右键拖动一个文件时才被调用。下面是</span><span lang="EN-US">WinZip</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的拖扔句柄如何添加上下文菜单：</span></p>
<p><img alt="" hspace="" src="http://www.codeproject.com/shell/ShellExtGuide1/ShellExGuide1_2.jpg" align="baseline" border="0" /></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">还有很多种其他类型（微软一直往新版本的</span><span lang="EN-US">Windows</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">里添加更多内容）。到现在，我们已经看到了上下文菜单扩展，因为它非常容易编写，我们将很容易的看到它的结果（很快就能满意）。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在我们开始编码以前，有一些提示，它将使我们做起来更加容易。当你促成一个外壳扩展被资源管理器调用的时候，它将在内存中呆上一小会儿，从而使它不能立即被重建</span><span lang="EN-US">(rebuild)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。为了使资源管理器更加频繁的卸载这些扩展，创建这个注册表键：</span></p>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-size: 10.0pt">HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\AlwaysUnloadDLL</span></code><span lang="EN-US" style="FONT-SIZE: 9pt; mso-bidi-font-size: 10.0pt"><o:p></o:p></span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">并把它的默认值设为</span><span lang="EN-US">&rdquo;1&rdquo;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。在</span><span lang="EN-US">Windows 9x</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">系列中，这是最好的方法。在</span><span lang="EN-US">NT/2000</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，到如下的键：</span></p>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-size: 10.0pt">HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer</span></code><span lang="EN-US" style="FONT-SIZE: 9pt; mso-bidi-font-size: 10.0pt"><o:p></o:p></span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">创建一个叫做</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">DesktopProcess</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的双字节值，使它的值为</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。这使得桌面和任务栏运行在一个进程中，后发的资源管理器运行在它自己的进程里。这就意味着你可以使用一个单独的资源管理器窗口来调试，并且当你关掉它的时候，你的</span><span lang="EN-US">DLL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">也会自动的被卸载，避免了该文件仍然在使用得问题。要使得你的注册表修改生效的话，你必须注销并且重新登录。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我将稍晚一些解释如何在</span><span lang="EN-US">Win 9x</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下进行调试。</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">开始一个上下文菜单扩展</span><span lang="EN-US"> &ndash; </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">它能做什么</span><span lang="EN-US">?</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">让我们开始简单的做一个扩展，它仅仅弹出一个消息框表示它已经在工作了。我们将对扩展名为</span><span lang="EN-US">.txt</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的文件设置一个钩子，这样当用户右键单击一个文本文件的时候，我们的扩展就能被调用了。</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">使用</span><span lang="EN-US">AppWizard </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">开始</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">好了，现在是我们开始的时候了。那是什么？我还没有告诉你如何使用神秘的外壳扩展接口？不要担心，我将在接下来的过程中为你解释。我发现如果一个概念被解释，有一个例子更容易明白，通过例子代码你很快就能理解。我将会先解释任何东西，然后给出代码，但是我发现还是不容易吸收。总之，启动你的</span><span lang="EN-US">MSVC</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">吧，我们要开始了。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">运行</span><span lang="EN-US">AppWizard </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，做一个新的</span><span lang="EN-US">ATL COM wizard app</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。我们叫它</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">SimpleExt</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。在向导中保持所有默认选项，单击完成。我们现在就有了一个空的将会生成</span><span lang="EN-US">DLL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">项目，但是我们必须添加自己的外壳扩展</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">对象。在</span><span lang="EN-US">ClassView</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">树中，右键单击</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">SimpleExt classes</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">项，选择</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">New ATL Object</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在</span><span lang="EN-US">ATL Object </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">向导，第一面板已经选择了</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">Simple Object</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，只要单击下一步就行了。在第二面板中，在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">Short Name</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">编辑控件中输入</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">SimpleShlExt</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，然后单击确定（面板中的其它的编辑框将会自动完成）。这就创建了一个类名为</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">CSimpleShlExt</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的类，它包含了实现一个</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">对象的基本代码。我们将向这个类添加我们的代码。</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">初始化接口</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">当我们的外壳扩展被装载的时候，资源管理器调用我们的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryInterface()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数获取一个指向</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IShellExtInit</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接口的指针。这个接口只有一个方法，</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">Initialize()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，它的原型如下：</span></p>
<pre><span lang="EN-US">HRESULT IShellExtInit::Initialize (</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>LPCITEMIDLIST pidlFolder,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>LPDATAOBJECT pDataObj,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp; </span><span style="mso-spacerun: yes">&nbsp;&nbsp;</span>HKEY hProgID );</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">资源管理器使用这个方法给我们不同的信息。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">pidlFolder</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是包含有正在被作用的文件的文件夹的</span><span lang="EN-US">PIDL(PIDL[<strong>p</strong>ointer to an <strong>ID</strong> <strong>l</strong>ist]</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是唯一标志外壳中任一对象（无论是否是文件系统对象）的数据结构。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">pDataObj</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是一个</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IDataObject</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接口指针，通过它我们可以获得被作用的文件的文件名。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">hProgID</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是一个打开的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">HKEY</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，通过它我们可以访问包含有我们的</span><span lang="EN-US">DLL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">注册数据的注册表键。在这个简单的扩展中，我们只需要用到</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">pDataObj</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">参数。</span></p>
<p><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">添加这个接口方法到我们的</span><span lang="EN-US">COM </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">对象中，先打开</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">SimpleShlExt.h</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件，并添加如下用红色书写的代码行：</span></p>
<pre><span lang="EN-US" style="COLOR: red">#include &lt;shlobj.h&gt;<o:p></o:p></span></pre>
<pre><span lang="EN-US" style="COLOR: red">#include &lt;comdef.h&gt;</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><a href="http://www.donevii.com/post/tag/class" class="st_tag internal_tag" rel="tag" title="Posts tagged with class">class</a> ATL_NO_VTABLE CSimpleShlExt : </span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</span>public CComObjectRootEx&lt;CComSingleThreadModel&gt;,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>public CComCoClass&lt;CSimpleShlExt, &amp;CLSID_SimpleShlExt&gt;,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>public IDispatchImpl&lt;ISimpleShlExt, &amp;IID_ISimpleShlExt, &amp;LIBID_SIMPLEEXTLib&gt;,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span></span><span lang="EN-US" style="COLOR: red">public IShellExtInit</span></pre>
<pre><span lang="EN-US">{</span></pre>
<pre><span lang="EN-US">BEGIN_COM_MAP(CSimpleShlExt)</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>COM_INTERFACE_ENTRY(ISimpleShlExt)</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>COM_INTERFACE_ENTRY(IDispatch)</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span></span><span lang="EN-US" style="COLOR: red">COM_INTERFACE_ENTRY(IShellExtInit)</span></pre>
<pre><span lang="EN-US">END_COM_MAP()</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">这个</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">COM_MAP</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是说明了</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">如何实现它的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryInterface()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。这个列表告诉</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">其他使用</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryInterface()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的程序可以从我们这儿获得什么。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接着，在类的声明当中，添加</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">Initialize()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数。此外，我们还需要一个保存文件名的变量：</span></p>
<pre><span lang="EN-US">protected:</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>TCHAR m_szFile [MAX_PATH];</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US">public:</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// IShellExtInit</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>STDMETHOD(Initialize)(LPCITEMIDLIST, LPDATAOBJECT, HKEY);</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接下来，在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">SimpleShlExt.cpp</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件中，添加该函数的定义：</span></p>
<pre><span lang="EN-US">HRESULT CSimpleShlExt::Initialize ( </span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</span>LPCITEMIDLIST pidlFolder,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>LPDATAOBJECT pDataObj,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>HKEY hProgID )</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们所要做的就是获得被右键单击的文件的文件名，并把它显示在一个消息框中。如果有很多个文件被选中，你可以通过</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">pDataObj</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接口指针访问它们。但是为了保持该例子的简单性，我只要获得第一个文件的文件名。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件名被保存为与你使用</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">WS_EX_ACCEPTFILES</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">样式拖和扔一个文件到窗口时用到的一个相同的格式。那就意味着，我们获得文件名使用了相同的</span><span lang="EN-US">API:</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'"> DragQueryFile()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。我们通过获得包含在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IDataObject</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">中的数据的句柄开始这个函数：</span></p>
<pre><span lang="EN-US">{</span></pre>
<pre><span lang="EN-US">FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };</span></pre>
<pre><span lang="EN-US">STGMEDIUM stg = { TYMED_HGLOBAL };</span></pre>
<pre><span lang="EN-US">HDROP<span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp; </span>hDrop;</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// Look for CF_HDROP data in the data object.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>if ( FAILED( pDataObj-&gt;GetData ( &amp;fmt, &amp;stg )))</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Nope! Return an &quot;invalid argument&quot; error back to Explorer.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return E_INVALIDARG;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// Get a pointer to the actual data.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>hDrop = (HDROP) GlobalLock ( stg.hGlobal );</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// Make sure it worked.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>if ( NULL == hDrop )</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return E_INVALIDARG;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">要注意，错误检查是极其重要的，尤其是指针。因为我们的扩展运行在资源管理器的进程空间当中，如果我们的程序毁坏的话，同样会让资源管理器也毁坏的。在</span><span lang="EN-US">Win 9x</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下，这可能就意味着重新启动。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">现在，我们有了一个</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">HDROP</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">句柄，我们可以获得我们需要的文件名了。</span></p>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// Sanity check &ndash; make sure there is at least one filename.</span></pre>
<pre><span lang="EN-US">UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"> <span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;</span>if ( 0 == uNumFiles )</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>GlobalUnlock ( stg.hGlobal );</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ReleaseStgMedium ( &amp;stg );</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return E_INVALIDARG;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US">HRESULT hr = S_OK;</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// Get the name of the first file and store it in our member variable m_szFile.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>if ( 0 == DragQueryFile ( hDrop, 0, m_szFile, MAX_PATH ))</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>hr = E_INVALIDARG;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>GlobalUnlock ( stg.hGlobal );</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>ReleaseStgMedium ( &amp;stg );</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>return hr;</span></pre>
<pre><span lang="EN-US">}</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">如果我们返回</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">E_INVALIDAR</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，在右键单击事件发生时，资源管理器将不会再调用我们的扩展。如果我们返回</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">S_OK</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，那么资源管理器将会再次调用</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryInterface()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">来获得我们将要添加的另一个接口指针：</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IContextMenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和上下文菜单交互的接口</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">一旦资源管理器初始化了我们的扩展，它将会调用</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IContextMenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的方法让我们添加菜单项目、敏感帮助并完成用户的选择。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">向我们的扩展中添加</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IContextMenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接口和添加</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IShellExtInit</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">相类似。打开</span><span lang="EN-US">SimpleShlExt.h</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">并添加一下红颜色的代码：</span></p>
<pre><span lang="EN-US">class ATL_NO_VTABLE CSimpleShlExt : </span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</span>public CComObjectRootEx&lt;CComSingleThreadModel&gt;,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>public CComCoClass&lt;CSimpleShlExt, &amp;CLSID_SimpleShlExt&gt;,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>public IDispatchImpl&lt;ISimpleShlExt, &amp;IID_ISimpleShlExt, &amp;LIBID_SIMPLEEXTLib&gt;,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>public IShellExtInit,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span></span><span lang="EN-US" style="COLOR: red">public IContextMenu</span></pre>
<pre><span lang="EN-US">{</span></pre>
<pre><span lang="EN-US">BEGIN_COM_MAP(CSimpleShlExt)</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>COM_INTERFACE_ENTRY(ISimpleShlExt)</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>COM_INTERFACE_ENTRY(IDispatch)</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>COM_INTERFACE_ENTRY(IShellExtInit)</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span></span><span lang="EN-US" style="COLOR: red">COM_INTERFACE_ENTRY(IContextMenu)</span></pre>
<pre><span lang="EN-US">END_COM_MAP()</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接着添加</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IContextMenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">方法的原型：</span></p>
<pre><span lang="EN-US">public:</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// IContextMenu</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>STDMETHOD(GetCommandString)(UINT, UINT, UINT*, LPSTR, UINT);</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO);</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>STDMETHOD(QueryContextMenu)(HMENU, UINT, UINT, UINT, UINT);</span></pre>
<h3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">更改上下文菜单</span></h3>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IContextMenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">有</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">个方法。第一个，</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryContextMenu()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，让我们更改菜单。它的原型为：</span></p>
<pre><span lang="EN-US">HRESULT IContextMenu::QueryContextMenu (</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>HMENU hmenu,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uMenuIndex, </span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uidFirstCmd,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uidLastCmd,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uFlags );</span></pre>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">hmenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是上下文菜单的句柄。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uMenuIndex</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是我们开始添加我们的菜单项目的开始位置。</span> <code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uidFirstCmd</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span> <code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uidLastCmd</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是我们可以给菜单项目使用的命令</span><span lang="EN-US">ID</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">值的范围。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uFlags</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">指出为什么资源管理器正在调用</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryContextMenu()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，这我们将在以后看到。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">有关它的返回值你将会得到不同的答案，如果你问不同的人的话。</span><span lang="EN-US">Dino Esposito </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的书上说它使被</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryContextMenu()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">添加的菜单项目的号码。</span><span lang="EN-US">MSDN</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">上关于</span><span lang="EN-US">VC 6</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">部分说它是最后一个被添加的菜单项目的命令</span><span lang="EN-US">ID</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">加上</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。最新的</span><span lang="EN-US">MSDN</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文档有如下说明：</span></p>
<p style="MARGIN-LEFT: 36pt; MARGIN-RIGHT: 36pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">设置代码的值</span><span lang="EN-US">[</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">由</span><span lang="EN-US">HRESULT</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">返回的</span><span lang="EN-US">]</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">为被分配的最大的命令</span><span lang="EN-US">ID</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">偏移加上</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。例如，假定</span><span lang="EN-US">idCmdFirst</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">被设置为</span><span lang="EN-US">5</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，你添加了</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">个菜单项目分别使用命令</span><span lang="EN-US">ID</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">为</span><span lang="EN-US">5</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">、</span><span lang="EN-US">7</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><span lang="EN-US">8</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。它的返回值将是</span><span lang="EN-US">MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 &#8211; 5 + 1)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span><span lang="EN-US"> </span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">到我现在所写的所有代码中，我接受了</span><span lang="EN-US">Dino</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的解释，这样工作的很好。事实上，他的制作返回值的方法和在线</span><span lang="EN-US">MSDN</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的方法是相同的，在你使用</span><span lang="EN-US">uidFirstCmd</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">开始添加你的菜单项目时开始计数，每添加一个增加</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span><span lang="EN-US"> </span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们的简单的扩展将仅仅添加一个菜单项目，所以</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">QueryContextMenu()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数相当简单：</span></p>
<pre><span lang="EN-US">HRESULT CSimpleShlExt::QueryContextMenu (</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>HMENU hmenu,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uMenuIndex, </span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uidFirstCmd,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uidLastCmd,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uFlags )</span></pre>
<pre><span lang="EN-US">{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>if ( uFlags &amp; CMF_DEFAULTONLY )</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>InsertMenu ( hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, _T(&quot;SimpleShlExt Test Item&quot;) );</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 1 );</span></pre>
<pre><span lang="EN-US">}</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们首先要做的就是检查</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uFlags</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。你可以在</span><span lang="EN-US">MSDN</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">查询所有的标志列表，但是对于上下文菜单扩展来说，只有一样是重要的：</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">CMF_DEFAULTONLY</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。这个标志告诉名字空间扩展仅仅添加默认菜单项目。如果这个标志在的话，外壳扩展将不会添加任何菜单项目。这就是为什么当</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">CMF_DEFAULTONLY</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">存在的时候我们立即返回</span><span lang="EN-US">0</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的原因。如果该标志不存在，我们更改菜单（使用</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">hmenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">句柄），然后返回</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">告诉外壳我们添加了一个菜单项目。</span></p>
<h3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">在状态条显示敏感帮助</span></h3>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IContextMenu</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">中下一个可以调用的方法是</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GetCommandString()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。如果用户在资源管理器窗口中右键单击了一个文本文件的时候，或者选中一个文本文件，然后单击&ldquo;文件&rdquo;菜单，状态条上将显示敏感帮助。我们的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GetCommandString()</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数将会返回一个让资源管理器显示得字符串。</span></p>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GetCommandString()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数原型如下：</span></p>
<pre><span lang="EN-US">HRESULT IContextMenu::GetCommandString (</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT idCmd,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT uFlags,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT *pwReserved,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>LPSTR pszName,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT cchMax );</span></pre>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">idCmd</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是一个基于</span><span lang="EN-US">0</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的指明哪个菜单项目被选中的数。因为我们仅仅添加了一个菜单项，</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">idCmd</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">将总是为</span><span lang="EN-US">0</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。但是如果我们添加了，我是说，</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">个的话，</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">idCmd</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">将会是</span><span lang="EN-US">0,1</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">或者</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uFlags</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是另一个标志组。我将会在后面进行描述。我们可以忽略</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">pwReserved</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">pszName</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是一个指向一个被外壳所拥有的缓存的指针，该缓存保存被显示的帮助字符串。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">cchMax</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是缓存的大小。返回值是</span><span lang="EN-US">HRESULT</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">常量，例如</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">S_OK</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">或</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">E_FAIL</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span></p>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GetCommandString()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">同样能被用来获得菜单项的&ldquo;动词&rdquo;。&ldquo;动词&rdquo;是一个标志作用于文件的动作的字符串，它是独立于语言的。有关</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">ShellExecute()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的文档作了更多的说明，有关&ldquo;动词&rdquo;的主题更适合在另一篇文章说明，这儿简要说明的是列在注册表中的动词（比如说</span><span lang="EN-US">&rdquo;open&rdquo;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><span lang="EN-US">&rdquo;print&rdquo;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">），或者那些有上下文菜单扩展动态创建的&ldquo;动词&rdquo;。这使得在外壳扩展中实现的行为可以被</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">ShellExecute()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">调用。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">总之，我提及所有这些的原因是我们不得不确定为什么</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GetCommandString()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">被调用。如果资源管理器需要一个敏感帮助字符串的时候，我们就提供。如果资源管理器请求一个&ldquo;动词&rdquo;的话，我们将忽略它。这是</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uFlags</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">起作用的地方。如果</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">uFlags</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GCS_HELPTEXT</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的位被设置的话，那么资源管理器将请求敏感帮助。附加的，如果</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GCS_UNICODE</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">位被设置，我们必须返回一个</span><span lang="EN-US">Unicode</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">字符串。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">GetCommandString()</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的代码看起来应该像下面这样：</span></p>
<pre><span lang="EN-US">#include &lt;atlconv.h&gt;<span style="mso-spacerun: yes">&nbsp; </span>// for ATL string conversion macros</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US">HRESULT CSimpleShlExt::GetCommandString (</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>idCmd,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>uFlags,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT* pwReserved,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>LPSTR pszName,</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>UINT<span style="mso-spacerun: yes">&nbsp; </span>cchMax )</span></pre>
<pre><span lang="EN-US">{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>USES_CONVERSION;</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// Check idCmd, it must be 0 since we have only one menu item.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>if ( 0 != idCmd )</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return E_INVALIDARG;</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// If Explorer is asking for a help string, copy our string into the</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// supplied buffer.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>if ( uFlags &amp; GCS_HELPTEXT )</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>LPCTSTR szText = _T(&quot;This is the simple shell extension's help&quot;);</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if ( uFlags &amp; GCS_UNICODE )</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// We need to cast pszName to a Unicode string, and then use the</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Unicode string copy API.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>lstrcpynW ( (LPWSTR) pszName, T2CW(szText), cchMax );</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>else</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// Use the ANSI string copy API to return the help string.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>lstrcpynA ( pszName, T2CA(szText), cchMax );</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return S_OK;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>return E_INVALIDARG;</span></pre>
<pre><span lang="EN-US">}</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">没什么奇特的；我只是把字符串编码并且把它转换为合适的字符集。如果你以前从来都没有使用过</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">变换宏，你干脆先看看它们，因为这将我使更容易理解传递一个</span><span lang="EN-US">Unicode</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">字符串到</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">方法和</span><span lang="EN-US">OLE</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数中。在上面的代码中，我使用了</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">T2CW</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">T2CA</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">分别将</span><span lang="EN-US">TCHAR</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">字符串转换为</span><span lang="EN-US">Unicode</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><span lang="EN-US">ANSI</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。在函数头部的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">USES_CONVERSION</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">宏声明了一个变换宏使用的局部变量。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">一个需要注意的重要事项是</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">lstrcpyn()</span></code><span lang="EN-US">API</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数保证了目标字符串是以</span><span lang="EN-US">null</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">结束的。这是它和</span><span lang="EN-US">CRT</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">strncpy()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的不同之处。如果源字符串的长度大于或等于</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">cchMax</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">时，</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'"> strncpy()</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">并不添加结束符</span><span lang="EN-US">null</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。我建议你总是使用</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">lstrcpyn()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，这样你就不用不得不在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">strncpy()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">之后添加检查来保证字符串是</span><span lang="EN-US">null</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">结束的。</span></p>
<h3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">执行用户的选择</span></h3>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">最后一个</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">IContextMenu</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">方法是</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">InvokeCommand()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。这个方法将在用户单击我们添加的那个菜单项目时被调用。它的原型如下：</span></p>
<pre><span lang="EN-US">HRESULT IContextMenu::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo );</span></pre>
<p style="TEXT-INDENT: 21pt"><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">CMINVOKECOMMANDINFO</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">结构里有很多的信息，但是根据我们现在的意图，我们只需要关心</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">lpVerb</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">hwnd</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">lpVerb</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">有双重的任务&mdash;&mdash;它既可以是被调用的&ldquo;动词&rdquo;的名称，也可以是一个用以告诉我们哪个菜单项被选中地索引。</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">hwnd</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是资源管理器窗口的句柄，在那儿，用户调用了我们的扩展。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们检查</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">lpVerb</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，因为我们只添加了一个菜单项，所以如果它为</span><span lang="EN-US">0</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，则我们的菜单被点击了。我能想到的最简单的事就是弹出一个消息框，所以我们就这么做。这个消息框显示了选中的文件的文件名，证明它的确是在工作。</span></p>
<pre><span lang="EN-US">HRESULT CSimpleShlExt::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )</span></pre>
<pre><span lang="EN-US">{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// If lpVerb really points to a string, ignore this function call and bail out.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>if ( 0 != HIWORD( pCmdInfo-&gt;lpVerb ))</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return E_INVALIDARG;</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>// Get the command index - the only valid one is 0.</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>switch ( LOWORD( pCmdInfo-&gt;lpVerb ))</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>case 0:</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>TCHAR szMsg [MAX_PATH + 32];</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>wsprintf ( szMsg, _T(&quot;The selected file was:\n\n%s&quot;), m_szFile );</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>MessageBox ( pCmdInfo-&gt;hwnd, szMsg, _T(&quot;SimpleShlExt&quot;),</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&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>MB_ICONINFORMATION );</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return S_OK;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>break;</span></pre>
<pre><span lang="EN-US">&nbsp;<o:p></o:p></span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>default:</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return E_INVALIDARG;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>break;</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">}</span></pre>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">注册外壳扩展</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">到现在为止，我们已经实现了我们所有的</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接口。但是&hellip;&hellip;如何使资源管理器使用我们的扩展呢？</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">自动生成了注册我们的</span><span lang="EN-US">DLL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">为一个</span><span lang="EN-US">COM</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">服务器的代码，但是它仅仅是让其它程序来使用我们的</span><span lang="EN-US">DLL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。为了告诉资源管理器我们的扩展存在，我们必须在保持文本文件的注册表键下注册它：</span></p>
<p><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">HKEY_CLASSES_ROOT\txtfile</span></code></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在那个键下面，一个叫做</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">ShellEx</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的键保存了一个对于文本文件将被调用的外壳扩展列表。在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">ShellEx</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下，</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">ContextMenuHandlers</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">键保存了一个上下文菜单扩展的列表。每一个扩展在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">ContextMenuHandlers</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下创建一个字键，并把他的默认值设置为它的</span><span lang="EN-US">GUID</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。所以，为我们的扩展，我们创建如下键：</span></p>
<p><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">HKEY_CLASSES_ROOT\txtfile\ShellEx\ContextMenuHandlers\SimpleShlExt</span></code></p>
<p><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">并把它的默认值设置为我们的</span><span lang="EN-US">GUID</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">：</span></p>
<p><span lang="EN-US">&quot;{5E2121EE-0300-11D4-8D3B-444553540000}&quot;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">然而，你不用自己做这件事。如果你在</span><span lang="EN-US">FileView</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">页查看你得文件列表时，你会发现</span><span lang="EN-US">SimpleShlExt.rgs</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。这是一个由</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">解析的文本文件，它告诉</span><span lang="EN-US">ATL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">当这个服务器被注册时该添加什么键，当被反注册时又该删除什么键。下面我们指定了要添加的注册表入口：</span></p>
<pre><span lang="EN-US">HKCR</span></pre>
<pre><span lang="EN-US">{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>NoRemove txtfile</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>NoRemove ShellEx</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>NoRemove ContextMenuHandlers</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ForceRemove SimpleShlExt = s '{5E2121EE-0300-11D4-8D3B-444553540000}'</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="mso-spacerun: yes">&nbsp;</span>}</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>}</span></pre>
<pre><span lang="EN-US">}</span></pre>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">它以</span><span lang="EN-US">&quot;HKCR&quot;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">&mdash;&mdash;</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">HKEY_CLASSES_ROOT</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的缩写&mdash;&mdash;开头，每一行是注册表键名称。关键词</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">NoRemove</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">意味着当该服务器被反注册时该键不能被删除。最后一行有点复杂。关键词</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">ForceRemove</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">意思是如果该键存在，那么在该键被写之前先删除它。这一行剩下的部分指定了一个将被保存在</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">SimpleShlExt</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">键的默认值中的字符串</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">那就是</span><span lang="EN-US">&rdquo;s&rdquo;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的意思</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。</span></p>
<p style="TEXT-INDENT: 18pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在这儿，我需要说明一点。我们注册扩展时的键是</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">HKCR\txtfile</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。然而，这个名称</span><span lang="EN-US">&quot;txtfile&quot; </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">并不是一个永久的或预先知道的。如果你查看一下</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">HKCR\.txt</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，那个键的默认值是这个名称被保存的地方。这就两个侧面效果：</span></p>
<ul type="disc">
<li class="MsoNormal" style="mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">我们将不能可靠的使用</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">RGS</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">脚本，因为</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">&quot;txtfile&quot;</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">可能不是正确的键名。</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> <o:p></o:p></span></li>
<li class="MsoNormal" style="mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list 36.0pt; mso-list: l0 level1 lfo1"><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">其他的一些文本编辑器可能被安装，它们同</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">.TXT</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">文件相关联。如果它们改变了</span><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> </span><code><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">HKCR\.txt</span></code><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">键的默认值，所有存在的外壳扩展都将会停止工作。</span><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"> <o:p></o:p></span></li>
</ul>
<p style="TEXT-INDENT: 18pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">看起来，这的确是我设计的缺陷。我想微软也在考虑同样的事，因为最近创建的扩展，像</span><span lang="EN-US">QueryInfo</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">扩展，是在</span><span lang="EN-US">.txt</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">键下注册的。</span></p>
<p style="TEXT-INDENT: 18pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">好了，说明到这儿。有一个最终的注册细节。在</span><span lang="EN-US">Win NT/2000</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下，我们必须自己将我们的扩展方到一个&ldquo;被认可的&rdquo;扩展列表当中。如果我们不这么做的话，那些非管理员用户将不会壮在我们的扩展。这个列表被保存在：</span></p>
<p><code><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-size: 10.0pt">HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved</span></code><span lang="EN-US" style="FONT-SIZE: 9pt; mso-bidi-font-size: 10.0pt"><o:p></o:p></span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在这个键下，我们创建一个字符串值它的名称是我们的</span><span lang="EN-US">GUID</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。字符串的内容可以是任何东西。做这些事情的代码在我们的</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">DllRegisterServer()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">和</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">DllUnregisterServer()</span></code><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">函数当中。我并不想把这些呆马列在这儿，因为这只是简单的注册表访问。你可以从本文的例子项目当中找到它们。</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">调试外壳扩展</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">最终，你写成了这个相当不容易的扩展，然后你将会调试它。打开你的项目设置</span><span lang="EN-US">(Project-&gt;Settings)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，到</span><span lang="EN-US"><a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">Debug</a></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">栏，在</span><span lang="EN-US">&quot;Executable for debug session&quot;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">编辑框中输入资源管理器的全路径，例如：</span><span lang="EN-US">&quot;C:\windows\explorer.exe&quot;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">。如果你使用的是</span><span lang="EN-US">NT</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">或</span><span lang="EN-US">2000</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，而且你已经设置过了</span><code><span lang="EN-US" style="FONT-FAMILY: 'Courier New'">DesktopProcess</span></code><span lang="EN-US"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">注册表项，那么在你按</span><span lang="EN-US">F5</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">开始调试的时候，会有一个新的资源管理器窗口打开。只要你在那个窗口工作，以后重建</span><span lang="EN-US">DLL</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">时你将不会有问题，因为当你关掉窗口时，你的扩展也被卸载了。</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">在</span><span lang="EN-US">Windows 9x</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下，恐怕你不得不在调试之前关闭你的外壳。单击&ldquo;开始&rdquo;</span><span lang="EN-US">-&gt;</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">&ldquo;关闭系统&rdquo;。按住</span><span lang="EN-US">Ctrl+Alt+Shift</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">然后点击&ldquo;取消&rdquo;。这将关闭资源管理器，然后你看见任务栏消失了。切换到</span><span lang="EN-US">MSVC</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">然后按</span><span lang="EN-US">F5</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">开始调试。按</span><span lang="EN-US">Shift+F5</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">关闭资源管理器停止调试。当你做完调试的时候，你可以运行</span><span lang="EN-US">Explorer</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">重新正常启动你的外壳。</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">它看起来是什么样的？</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下面是我们添加的项目看起来的样子：</span></p>
<p><img alt="" hspace="" src="http://www.codeproject.com/shell/ShellExtGuide1/ShellExGuide1_3.jpg" align="baseline" border="0" /></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">这就是我们的菜单！</span></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下面是有敏感帮助时资源管理器的状态栏的样子：</span></p>
<p><img alt="" hspace="" src="http://www.codeproject.com/shell/ShellExtGuide1/ShellExGuide1_4.jpg" align="baseline" border="0" /></p>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">而下面是消息框的样子，它显示了被选中的文件的文件名：</span></p>
<p><img alt="" hspace="" src="http://www.codeproject.com/shell/ShellExtGuide1/ShellExGuide1_5.jpg" align="baseline" border="0" /></p>
<p><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">本例程代码下载地址</span><span lang="EN-US">(11K)</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">：</span><span lang="EN-US">http://www.codeproject.com/shell/ShellExtGuide1/ShellExtGuide1_demo.zip</span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">下一部分&hellip;&hellip;</span></h2>
<p style="TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">接着的第二部分，一个新的上下文菜单扩展将会告诉你如何同时对多个文件进行操作。</span></p>
<p style="MARGIN-LEFT: 21pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">你可以从下面的网址获得这个和其他文章的最新版本：</span><span lang="EN-US"><a href="http://home.inreach.com/mdunn/code/" target="_blank" class="broken_link">http://home.inreach.com/mdunn/code/</a> </span></p>
<p><span lang="EN-US">&nbsp;<o:p></o:p></span></p>
<h2><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">关于翻译：</span></h2>
<p><span lang="EN-US"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">这是我第一次翻译文章，文章来自著名的</span><span lang="EN-US">http://www.codeproject.com/</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，翻译之前我看了</span><span lang="EN-US">csdn</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">的开发文档，发现还是空白，所以就像把它翻译了，也许有对它感兴趣的人。文章总共有</span><span lang="EN-US">9</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">个部分。我没有太多的时间，只翻译了第一部分，也许能起到抛砖引玉的作用，让那些对外壳扩展不了解的人入个门，入了门的多个参考。更多的文章大家可以从</span><span lang="EN-US"><a href="http://www.codeproject.com/shell/">http://www.codeproject.com/shell/</a> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">找到。例子代码，原文也可以从那儿找到。我的</span><span lang="EN-US">email</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">是</span><span lang="EN-US">mefish@163.net</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana">，头一次翻译，做得不好，任何意见、建议、鲜花、掌声、石头、带酒的啤酒瓶都将受到热烈欢迎&hellip;&hellip;</span></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/314.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IE编程 &#8211; ToolBar</title>
		<link>http://www.donevii.com/post/312.html</link>
		<comments>http://www.donevii.com/post/312.html#comments</comments>
		<pubDate>Sat, 24 Mar 2007 13:36:25 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[c/c++/c#]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[类]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=312</guid>
		<description><![CDATA[关键字：Band，Desk Band，Explorer Band，Tool Band，浏览器栏，工具栏，桌面工具栏 一、引言　　最近，由于工作的要求，我需要在 IE 上做一些开发工作。于是在 MSDN 上翻阅了一些资料，根据 MSDN 上... ]]></description>
			<content:encoded><![CDATA[<p><strong>关键字</strong>：Band，Desk Band，Explorer Band，Tool Band，浏览器栏，工具栏，桌面工具栏</p>
<p><strong>一、引言</strong><br />　　最近，由于工作的要求，我需要在 <a href="http://www.donevii.com/post/tag/ie" class="st_tag internal_tag" rel="tag" title="Posts tagged with ie">IE</a> 上做一些开发工作。于是在 MSDN 上翻阅了一些资料，根据 MSDN 上的说明我用 ATL 胜利完成了&ldquo;资本家老板&rdquo;分配的任务。<br />（并且在白天睡觉的过程中梦到了老板给我加工资啦&#8230;&#8230;）<br />现在，我把 MSDN 上的原文资料，经过翻译整理并把一个 ATL 的实现奉贤给 VCKBASE 上的朋友们。
<ul>
<li><a href="http://www.vckbase.com/document/viewdoc/?id=1457#二、概念"><font color="#800080">概念</font></a> </li>
<li><a href="http://www.vckbase.com/document/viewdoc/?id=1457#三、原理"><font color="#800080">原理</font></a><br />    <a href="http://www.vckbase.com/document/viewdoc/?id=1457#3.1　基本_band_对象"><font color="#800080">基本band 对象</font></a><br />    <a href="http://www.vckbase.com/document/viewdoc/?id=1457#3.2　必须实现的_COM_接口"><font color="#800080">必须实现的 COM 接口</font></a><br />    &nbsp;&nbsp;&nbsp; <a href="http://www.vckbase.com/document/viewdoc/?id=1457#IPersistStream"><font color="#800080">IPersistStream</font></a><br />    &nbsp;&nbsp;&nbsp; <a href="http://www.vckbase.com/document/viewdoc/?id=1457#IObjectWithSite"><font color="#800080">IObjectWithSite</font></a><br />    &nbsp;&nbsp;&nbsp; <a href="http://www.vckbase.com/document/viewdoc/?id=1457#IDeskBand"><font color="#800080">IDeskBand、IDockingWindow、IOleWindow</font></a><br />    <a href="http://www.vckbase.com/document/viewdoc/?id=1457#3.3　选择实现的_COM_接口"><font color="#800080">选择实现的 COM 接口</font></a><br />    <a href="http://www.vckbase.com/document/viewdoc/?id=1457#3.4　Band_对象注册"><font color="#800080">Band 对象注册</font></a> </li>
<li><a href="http://www.vckbase.com/document/viewdoc/?id=1457#四、_ATL_实现"><font color="#800080">ATL 实现</font></a> </li>
</ul>
<p><strong><a name="二、概念"><font color="#000000">二、概念</font></a></strong><br />　　在翻译的过程中，有两个词汇非常不好理解。第一个词是 Band 对象，词典中翻译为&ldquo;镶边、裙子边、带子、乐队&#8230;&#8230;&rdquo;我的英文水平有限，实在不知道应该翻译为什么词汇更合适。于是我毅然决然地决定：在如下的论述中，依然使用 band 这个词！（什么？没听明白？我的意思就是说，我不翻译这个词了）但到底 Band 对象应该如何理解那？请看图一：</p>
<p><img height="399" src="http://www.vckbase.com/document/journal/vckbase42/images/yfbands1.jpg" width="613" border="0" alt="" /><br />图一</p>
<p>　　图一中画红圈的地方，分别称作&ldquo;垂直的浏览器栏&rdquo;、&ldquo;水平的浏览器栏&rdquo;、&ldquo;工具栏&rdquo;和&ldquo;桌面工具栏&rdquo;。这些&ldquo;栏&rdquo;，都可以在 IE 的&ldquo;查看&rdquo;菜单中或鼠标右键的上下文快捷方式菜单中显示或隐藏起来。这些界面窗口的实现，其实就是实现一种 COM 接口对象，而这个对象叫 band。这个概念实在是只能意会而无法言传的，我总不能在文章中把它翻译为&ldquo;总是靠在 IE 主窗口边上的对象&rdquo;吧？^_^<br />　　另外，还有一个词叫 site。这个很好翻译，叫&ldquo;站点&rdquo;！。呵呵，我敢打包票，如果你要能理解这个翻译在计算机类文章中的含义，那就只能恭喜你了，你的智慧太高了。（都是学计算机软件的人，做人的差距咋就这么大呢？）在本篇文章中，site 可以这样理解：IE 的主框架四周，就好比是&ldquo;汽车站&rdquo;，那些 band 对象，就好比是&ldquo;汽车&rdquo;。band 汽车总是可以停靠在&ldquo;汽车站&rdquo;上。所以，site 就是&ldquo;站点&rdquo;，它也是 COM 接口的对象（IObjectWithSite、IInputObjectSite）。</p>
<p><strong><a name="三、原理"><font color="#000000">三、原理</font></a></strong></p>
<p><em><a name="3.1　基本_band_对象"><font color="#000000">3.1　基本 band 对象</font></a></em><br />　　Band 对象，从 <a href="http://www.donevii.com/post/tag/shell" class="st_tag internal_tag" rel="tag" title="Posts tagged with shell">Shell</a> 4.71(IE 5.0) 开始提供支持。Band 是一个 COM 对象，必须放在一个容器中去使用，当然使用它们就好象使用普通窗口是一样的。IE 就是一个容器，桌面 <a href="http://www.donevii.com/post/tag/shell" class="st_tag internal_tag" rel="tag" title="Posts tagged with shell">Shell</a> 也是一个容器，它们提供不同的函数功能，但基本的实现是相似的。<br />　　Band 对象分三种类型，浏览器栏 band（Explorer bands）、工具栏 band（Tool Bands）和桌面工具栏(Desk bands)，而浏览器栏 band 又有两种表现形式：垂直和水平的。那么 IE 和 Shell 如何区分并加载这些 bands 对象呢？方法是：你要对不同的 band 对象，在注册表中注册不同的组件类型（CATID）。</p>
<table cellspacing="1" width="83%" border="1">
<tbody>
<tr>
<td width="22%">
<p align="center"><strong><span lang="en-us">Band </span>样式</strong></p>
</td>
<td width="25%">
<p align="center"><strong>组件类型</strong></p>
</td>
<td width="51%">
<p align="center"><strong>CATID</strong></p>
</td>
</tr>
<tr>
<td align="center" width="22%">垂直的浏览器栏</td>
<td align="center" width="25%"><font face="宋体" size="3"><span lang="en-us">CATID_InfoBand</span></font></td>
<td align="center" width="51%">00021493-0000-0000-C000-000000000046</td>
</tr>
<tr>
<td align="center" width="22%">水平的浏览器栏</td>
<td align="center" width="25%"><font face="宋体" size="3"><span lang="en-us">CATID_CommBand</span></font></td>
<td align="center" width="51%">00021494-0000-0000-C000-000000000046</td>
</tr>
<tr>
<td align="center" width="22%">桌面的工具栏</td>
<td align="center" width="25%"><font face="宋体" size="3"><span lang="en-us">CATID_DeskBand</span></font></td>
<td align="center" width="51%">00021492-0000-0000-C000-000000000046</td>
</tr>
</tbody>
</table>
<p>　　IE 工具栏不使用组件类型注册，而是使用在注册进行 CLSID 的登记方式。详细情况见 3.3。<br />　　在例子程序中，实现了全部四个类型的 band 对象，垂直浏览器栏(CVerticalBar)显示了一个 <a href="http://www.donevii.com/post/tag/html" class="st_tag internal_tag" rel="tag" title="Posts tagged with html">HTML</a> 文件，并且实现了对 IE 主窗口浏览网页的导航等功能；水平的浏览器栏(CHorizontalBar)是一个编辑窗，它同步显示当前网页的 BODY 源文件内容；IE 工具栏(CToolBar)最简单，只是添加了一个空的工具栏；桌面工具栏(CDeskBar)实现了一个单行编辑窗口，你可以在上面输入命令行或文件名称，回车后它会执行 Shell 的打开动作。</p>
<p><em><a name="3.2　必须实现的_COM_接口"><font color="#000000">3.2　必须实现的 COM 接口</font></a></em><br />　　Band 对象是 IE 或 Shell 的进程内服务器，所以它被包装在 DLL 中。而作为 COM 对象，它必须要实现 IUnknown 和 IClassFactory 接口。（大家可以不同操心，因为我们用 ATL 写程序，这两个接口是不用我们自己写代码的。）另外，Band 对象还必须实现 IDeskBand、IObjectWithSite 和 IPersistStream 三个接口：<br />　　<a name="IPersistStream"><font color="#000000">IPersistStream</font></a> 是持续性接口的一种。当 IE 加载 band 对象的时候，它通过这个接口的 Load 方法传递属性值给对象，让其进行初始化；而当卸载前，IE 则调用这个接口的 Save 方法保存对象的属性。用 ATL 实现这个接口很简单： </p>
<pre><a href="http://www.donevii.com/post/tag/class" class="st_tag internal_tag" rel="tag" title="Posts tagged with class">class</a> ATL_NO_VTABLE Cxxx : 	......	public IPersistStreamInitImpl, // 添加继承	......{public:	BOOL m_bRequiresSave; // IPersistStreamInitImpl 所必须的变量......BEGIN_COM_MAP(CVerticalBar)	......	COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)	COM_INTERFACE_ENTRY2(IPersistStream, IPersistStreamInit)	COM_INTERFACE_ENTRY(IPersistStreamInit)	......END_COM_MAP()BEGIN_PROP_MAP(Cxxx)...... // 添加需要持续性的属性END_PROP_MAP()		</pre>
<p>　　上面的代码，其实实现的是 IPersistStreamInit 接口，不过没有关系，因为 IPersistStreamInit 派生自 IPersistStream，实例化了派生类，自然就实例化了基类。在例子程序中，我只在桌面工具栏对象中添加了持续性属性，用来保存和初始化&ldquo;命令行&rdquo;。另外 COM_INTERFACE_ENTRY2(A，B)表示的含义是：如果想查询A接口的指针，则提供B接口指针来代替。为什么可以这样那？因为B接口派生自A接口，那么B接口的前几个函数必然就是A接口的函数了，自然B接口的地址其实和A接口的地址是一样的了。<br />　　<a name="IObjectWithSite"><font color="#000000">IObjectWithSite</font></a> 是 IE 用来对插件进行管理和通讯用的一个接口。必须要实现这个接口的2个函数：SetSite() 和 GetSite()。当 IE 加载 band 对象和释放 band 对象的时候，都要调用 SetSite()函数，那么在这个函数里正好是写初始化和释放操作代码的地方：
<pre>STDMETHODIMP Cxxx::SetSite(IUnknown *pUnkSite){	if( NULL == pUnkSite )	// 释放 band 的时候	{		// 如果加载的时候，保存了一些接口		// 那么现在：释放它	}	else	// 加载 band 的时候	{		m_hwndParent = NULL;	// 装载 band 的父窗口(就是带有标题的那个框架窗口)		// 这个窗口的句柄，是调用 IUnknown::QueryInterface() 得到 IOleWindow		// 然后调用 IOleWindow::GetWindow() 而获得的。		CComQIPtr&lt; IOleWindow, &amp;IID_IOleWindow &gt; spOleWindow(pUnkSite);		if( spOleWindow )	spOleWindow-&gt;GetWindow(&amp;m_hwndParent);		if( !m_hwndParent )	return E_FAIL;				// 现在，正好是建立子窗口的时机。		// 注意，子窗口建立的时候，不要使用 WS_VISIBLE 属性		... ...		// 在例子程序中，用 CAxWindow 实现了一个能包容ActiveX的容器窗口(垂直浏览器栏)		// 在例子程序中，用 WIN API 函数 CreateWindow 实现了标准窗口(水平浏览器栏、工具栏)		// 在例子程序中，用 CWindowImpl 实现了一个包容窗口(桌面工具栏)		/*********************************************************/		   以下部分，根据 band 对象特有的功能，是可以选择实现的		**********************************************************/				// 如果子窗口实现了用户输入，那么必须实现 IInputObject 接口，		// 而该接口是被 IE 的 IInputObjectSite 调用的，因此在你的对象		// 中，应该保存 IInputObjectSite 的接口指针。		// 在类的头文件中，定义：		// CComQIPtr&lt; IInputObjectSite, &amp;IID_IInputObjectSite &gt; m_spSite;		m_spSite = pUnkSite;	// 保存 IInputObjectSite 指针		if( !m_spSite )		return E_FAIL;		// 你需要控制 IE 的主框架吗？		// 那么在类的头文件中，定义：		// CComQIPtr&lt; IWebBrowser2, &amp;IID_IWebBrowser2 &gt; m_spFrameWB;		// 然后，先取得 IServiceProvider,再取得 IWebBrowser2		CComQIPtr &lt; IServiceProvider, &amp;IID_IServiceProvider&gt; spSP(pUnkSite);		if( !spSP )	return E_FAIL;		spSP-&gt;QueryService( SID_SWebBrowserApp, &amp;m_spFrameWB );		if( !m_spFrameWB)	return E_FAIL;		// 如果你取得了 IE 主框架的 IWebBrowser2 指针		// 那么，当它发生了什么事情，你难道不想知道吗？		// 定义：CComPtr m_spCP;		CComQIPtr&lt; IConnectionPointContainer,			&amp;IID_IConnectionPointContainer&gt; spCPC( m_spFrameWB );		if( spCPC )		{			spCPC-&gt;FindConnectionPoint( DIID_DWebBrowserEvents2, &amp;m_spCP );			if( m_spCP )			{				m_spCP-&gt;Advise( reinterpret_cast&lt; IDispatch * &gt;( this ), &amp;m_dwCookie );			}		}		// 咳~~~ 不说了，看源码去吧。这里能干的事情太多了... ...	}	return S_OK;}		</pre>
<p><a name="IDeskBand"><font color="#000000">IDeskBand</font></a> 是一个特殊的 band 对象接口，有一个方法函数：GetBarInfo()；<br />IDockingWindow 是 IDeskBank 的基类，有3个方法函数：ShowDW()、CloseDW()、ResizeBorderDW()；<br />IOleWindow 又是 IDockingWindow 的基类，有2个方法函数：GetWindow()、ContextSensitiveHelp()； </p>
<p>　　首先声明 IDeskBand ,然后要实现 IDeskBand 接口的共6个函数，这些函数比较简单，不同类型的 band 对象，其实现方法也都基本一致：
<pre>class ATL_NO_VTABLE Cxxx : 	......	public IDeskBand,	......{......BEGIN_COM_MAP(Cxxx)	......	COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)	......END_COM_MAP()// IOleWindowSTDMETHODIMP Cxxx::GetWindow(HWND * phwnd){	// 取得 band 对象的窗口句柄	// m_hWnd 是建立窗口时候保存的	*phwnd = m_hWnd;		return S_OK;}STDMETHODIMP Cxxx::ContextSensitiveHelp(BOOL fEnterMode){	// 上下文帮助，参考 IContextMenu 接口	return E_NOTIMPL;}// IDockingWindowSTDMETHODIMP CVerticalBar::ShowDW(BOOL bShow){	// 显示或隐藏 band 窗口	if( m_hWnd )		::ShowWindow( m_hWnd, bShow ? SW_SHOW : SW_HIDE);	return S_OK;}STDMETHODIMP CVerticalBar::CloseDW(DWORD dwReserved){	// 销毁 band 窗口	if( ::IsWindow( m_hWnd ) )		::DestroyWindow( m_hWnd );	m_hWnd = NULL;    return S_OK;}STDMETHODIMP CVerticalBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown* punkToolbarSite, BOOL fReserved){	// 当框架窗口的边框大小改变时	return E_NOTIMPL;}// IDeskBandSTDMETHODIMP CVerticalBar::GetBandInfo(DWORD dwBandID, DWORD dwViewMode,  DESKBANDINFO* pdbi){	         // 取得 band 的基本信息，你需要填写 pdbi 参数作为返回	if( NULL == pdbi )		return E_INVALIDARG;	// 如果将来需要调用 IOleCommandTarget::Exec() 则需要保存这2个参数	m_dwBandID = dwBandID;	m_dwViewMode = dwViewMode;	if(pdbi-&gt;dwMask &amp; DBIM_MINSIZE)	{	// 最小尺寸		pdbi-&gt;ptMinSize.x = 10;		pdbi-&gt;ptMinSize.y = 10;	}	if(pdbi-&gt;dwMask &amp; DBIM_MAXSIZE)	{	// 最大尺寸 (-1 表示 4G)		pdbi-&gt;ptMaxSize.x = -1;		pdbi-&gt;ptMaxSize.y = -1;	}	if(pdbi-&gt;dwMask &amp; DBIM_INTEGRAL)	{		pdbi-&gt;ptIntegral.x = 1;		pdbi-&gt;ptIntegral.y = 1;	}	if(pdbi-&gt;dwMask &amp; DBIM_ACTUAL)	{		pdbi-&gt;ptActual.x = 0;		pdbi-&gt;ptActual.y = 0;	}	if(pdbi-&gt;dwMask &amp; DBIM_TITLE)	{	// 窗口标题		wcscpy(pdbi-&gt;wszTitle,L&quot;窗口标题&quot;);	}	if(pdbi-&gt;dwMask &amp; DBIM_MODEFLAGS)	{		pdbi-&gt;dwModeFlags = DBIMF_VARIABLEHEIGHT;	}	if(pdbi-&gt;dwMask &amp; DBIM_BKCOLOR)	{	// 如果使用默认的背景色，则移除该标志		pdbi-&gt;dwMask &amp;= ~DBIM_BKCOLOR;	}	return S_OK;}		</pre>
<p><em><a name="3.3　选择实现的_COM_接口"><font color="#000000">3.3　选择实现的 COM 接口</font></a></em><br />　　有两个接口不是必须实现的，但也许很有用：IInputObject 和 IContextMenu。如果 band 对象需要接收用户的输入，那么必须实现 IInputObject 接口。IE 实现了 IInputObjectSite 接口，当容器中有多个输入窗口时，它调用 IInputObject 接口方法去负责管理用户的输入焦点。<br />在浏览器栏中需要实现3个函数：UIActivateIO()、HasFocusIO()、TranslateAcceleratorIO()。<br />当浏览器栏激活或失去活性的时候，IE 调用 UIActivateIO 函数，当激活的时候，浏览器栏一般调用 SetFocus 去设置它自己窗口的焦点。当 IE 需要判断哪个窗口有焦点的时候，它调用 HasFocusIO 。当浏览器栏的窗口或其子窗口有输入焦点时，则应返回 S_OK，否则返回 S_FALSE。TranslateAcceleratorIO 允许对象处理加速键，例子程序中没有实现，所以直接返回 S_FALSE。
<pre>STDMETHODIMP CExplorerBar::UIActivateIO(BOOL fActivate, LPMSG pMsg){    if(fActivate)        SetFocus(m_hWnd);    return S_OK;}STDMETHODIMP CExplorerBar::HasFocusIO(void){    if(m_bFocus)        return S_OK;    return S_FALSE;}STDMETHODIMP CExplorerBar::TranslateAcceleratorIO(LPMSG pMsg){    return S_FALSE;}      </pre>
<p>　　Band 对象能够通过包容器的 IOleCommandTarget::Exec() 调用执行命令。而 IOleCommandTarget 接口指针，则可以通过调用包容器的 IInputOjbectSite::QueryInterface（IID_IOleCommandTarget,&#8230;） 函数得到。CGID_DeskBand 是命令组，当一个 band 对象的 GetBandInfo 被调用的时候，包容器通过 dwBandID 参数指定一个 ID 给 band 对象，对象要保存住这个ID，以便调用 IOleCommandTarget::Exec()的时候使用。ID 的命令有：
<ul>
<li>DBID_BANDINFOCHANGED<br />    Band 的信息变化。设置参数 pvaIn 为 band ID， 该 ID 就是最近一次调用 GetBandInfo 所得到的值，容器会调用 band 对象的 GetBandInfo 函数来更新请求信息。 </li>
<li>DBID_MAXIMIZEBAND <br />    最大化 band。设置参数 pvaIn 为 band ID，该 ID 就是最近一次调用 ?GetBandInfo ?所得到的值。 </li>
<li>DBID_SHOWONLY <br />    打开或关闭容器中其它的 bands。 设置参数 pvaIn 为VT_UNKNOWN 类型，它可以是如下的值：<br />    　<br />
<table class="clsStd" width="727" border="1">
<tbody>
<tr>
<th width="62"><font face="宋体" size="3">值</font></th>
<th width="650"><font face="宋体" size="3">描述</font></th>
</tr>
<tr>
<td align="center" width="62"><font face="宋体" size="3">pUnk</font></td>
<td width="650"><font face="宋体" size="3"><span lang="en-us">band </span>对象的 <strong>IUnknown</strong> 指针，其它的桌面<span lang="en-us"> bands </span>将被隐藏</font></td>
</tr>
<tr>
<td align="center" width="62"><font face="宋体" size="3">0</font></td>
<td width="650"><font face="宋体" size="3">隐藏所有的桌面<span lang="en-us"> bands</span></font></td>
</tr>
<tr>
<td align="center" width="62"><font face="宋体" size="3">1</font></td>
<td width="650"><font face="宋体" size="3">显示所有的桌面 <span lang="en-us">bands</span></font></td>
</tr>
</tbody>
</table>
<p>    </li>
<li>DBID_PUSHCHEVRON<br />    在菜单项左边显示&ldquo;v&rdquo;的选择标志。容器发送一个 RB_PUSHCHEVRON 消息，当 band 对象接收到通知消息 RBN_CHEVRONPUSHED 提示它显示一个&quot;v&quot;的标志。设置 IOleCommandTarget::Exec 函数中 nCmdExecOpt 参数为 band ID，该 ID 是最近一次调用 GetBandInfo ?所得到的值，设置 IOleCommandTarget::Exec 函数中 pvaIn 参数为 VT_I4 类型，这是应用程序定义的一个值，它通过通知消息 RBN_CHEVRONPUSHED 中lAppValue 回传给 band 对象。 </li>
</ul>
<p><em><a name="3.4　Band_对象注册"><font color="#000000">3.4　Band 对象注册</font></a></em><br />　　Band 对象必须注册为一个 OLE 进程内的服务器，并且支持 apartment 线程公寓。注册表中默认键的值是表示菜单的文字。对于浏览器栏，它加到 IE 菜单的&ldquo;查看\浏览器栏&rdquo;中；对于工具栏 band ，它加到 IE 菜单的&ldquo;查看\工具栏&rdquo;中；对于桌面 band， 它加到系统任务栏的快捷菜单中。在菜单资源中，可以使用&ldquo;&amp;&rdquo;指明加速键。</p>
<p>通常，一个基本的 band 对象的注册表项目是：</p>
<p><strong>HKEY_CLASSES_ROOT <br />CLSID <br /><em>{你的 band 对象的 CLSID}</em></strong> <br />　　(Default) = 菜单的文字 <br />　　InProcServer32 <br />　　　(Default) = DLL 的全路径文件名 <br />　　　ThreadingModel= Apartment</p>
<p>工具栏 bands 还必须把它们的 CLSID 注册到 IE 的注册表中。</p>
<p>在 <strong>HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar</strong> 下给出 CLSID 作为键名，而其键值是被忽略的。</p>
<p><strong>HKEY_LOCAL_MACHINE <br />Software <br />Microsoft <br />Internet Explorer <br />Toolbar </strong><br />　　{你的 band 对象的 CLSID}</p>
<p>　　还有几个可选的注册表项目(例子程序并不是这样实现的)。比如，你想让浏览器栏显示 HTML 的话，必须要如下设置注册表： </p>
<p><strong>HKEY_CLASSES_ROOT <br />CLSID <br /><em>{你的 Band 对象的 CLSID} </em><br />Instance <br />CLSID <br />　　</strong>(Default) = {4D5C8C2A-D075-11D0-B416-00C04FB90376}</p>
<p>同时，如果要指定一个本地的 HTML 文件，那么要如下设置： </p>
<p><strong>HKEY_CLASSES_ROOT <br />CLSID <br /><em>{你的 Band 对象的 CLSID}</em> <br />Instance <br />InitPropertyBag <br />　　</strong>Url</p>
<p>　　另外，还可以指定浏览器栏的宽和高，当然，它是依赖于这个栏是纵向还是横向的。其实这个项目无所谓，因为当用户调整了浏览器栏的大小后，会自动保存在注册表中的。</p>
<p><strong>HKEY_CURRENT_USER <br />Software <br />Microsoft <br />Internet Explorer <br />Explorer Bars <br />{你的 Band 对象的 CLSID} <br />　　</strong>BarSize</p>
<p>　　BarSize 键的类型必须是 REG_BINARY 类型，它有8个字节。左起前4个字节，是用16进制表示的像素宽度或高度，后4个字节保留，你应该设置为0。下面是一个可以在浏览器栏上显示 HTML 文件的全部注册表项目的例子，默认宽度为291（0&#215;123）个像素点： </p>
<p><strong>HKEY_CLASSES_ROOT <br />CLSID <br /><em>{你的 Band 对象的 CLSID} </em></strong><br />　(Default) = 菜单文字 <br />　<strong>InProcServer32 </strong><br />　　(Default) = DLL 的全路径文件名 <br />　　ThreadingModel= Apartment<br /><strong>Instance <br />CLSID </strong><br />　　(Default) = {4D5C8C2A-D075-11D0-B416-00C04FB90376}<br /><strong>InitPropertyBag</strong> <br />　　Url= 你的 HTML 文件名</p>
<p><strong>HKEY_CURRENT_USER <br />Software <br />Microsoft <br />Internet Explorer <br />Explorer Bars <br />{你的 Band 对象的 CLSID} </strong><br />　　BarSize= 23 01 00 00 00 00 00 00</p>
<p>　　对于注册表的设置，用 ATL 实现其实是异常简单的。打开工程的 xxx.rgs 文件，并手工编辑一下就可以了。 下面这个文件源码，是例子程序中 IE 工具栏的注册表样式，HKLM 是需要手工添加的，因为它不使用组件类型方式注册。而对于其它类型的 band 对象只要在类声明中添加： </p>
<pre>BEGIN_CATEGORY_MAP(Cxxx)			// 向注册表中注册 COM 类型	IMPLEMENTED_CATEGORY(CATID_InfoBand)	// 垂直样式的浏览器栏END_CATEGORY_MAP()		</pre>
<p>IE 工具栏类型 band 对象的&ldquo;.rgs&rdquo;文件
<pre>HKCR	// 这个项目是 ATL 帮你生成的，你只要手工修改&ldquo;菜单上的文字&rdquo;就可以了{	Bands.ToolBar.1 = s ''ToolBar Class''	{		CLSID = s ''{ 你的 CLSID }''	}	Bands.ToolBar = s ''ToolBar Class''	{		CLSID = s ''{ 你的 CLSID }''		CurVer = s ''Bands.ToolBar.1''	}	NoRemove CLSID	{		ForceRemove { 你的 CLSID } = s ''用在菜单上的文字(&amp;T)''		{			ProgID = s ''Bands.ToolBar.1''			VersionIndependentProgID = s ''Bands.ToolBar''			ForceRemove ''Programmable''			InprocServer32 = s ''%MODULE%''			{				val ThreadingModel = s ''Apartment''			}			''TypeLib'' = s ''{xxxx-xxxx-xxxxxxxxxxxxxxx}''		}	}}HKLM	// 这个项目是手工添加的IE工具栏所特有的{	Software	{		Microsoft		{			''Internet Explorer''			{				NoRemove Toolbar				{					ForceRemove val { 你的 CLSID } = s ''随便给个说明性文字串''				}			}		}	}}		</pre>
<p><strong><a name="四、_ATL_实现"><font color="#000000">四、 ATL 实现</font></a></strong><br />　　下载代码后(VC 6.0 工程)，请参照前面的说明仔细阅读，代码中也有一些关键点的注释。如果想运行，则可以用 regsvr32.exe 进行注册，然后打开 IE 浏览器或资源浏览器就可以看到效果了。如果想自己实践一下，可以按照如下的步骤构造工程：</p>
<p>4.1　建立一个 ATL DLL 工程<br />4.2　添加 New ATL Object&#8230;，选择 Internet Explorer Object，选这个类型的目的是让向导给我们添加 IObjectWithSite 的支持。如果你使用的是 .net 环境，则不要忘记选择支持这个接口。</p>
<p><img height="257" src="http://www.vckbase.com/document/journal/vckbase42/images/yfbands2.jpg" width="413" border="0" alt="" /></p>
<p>4.3　输入对象名称，比如我想建立一个垂直的浏览器栏，不妨叫它 VerBar</p>
<p><img height="260" src="http://www.vckbase.com/document/journal/vckbase42/images/yfbands3.jpg" width="421" border="0" alt="" /></p>
<p>4.4　线程模型必须选择 Apartment，接口类型的选择无所谓，看你想不想支持 IDispatch 接口功能了。在例子程序中的垂直浏览器栏中，由于想更简单的操纵 IE 和从 IE 中接受事件（连接点），选择 Dual 是必要的。聚合选项，你只要别选择 Only 就可以了。</p>
<p><img height="260" src="http://www.vckbase.com/document/journal/vckbase42/images/yfbands4.jpg" width="421" border="0" alt="" /></p>
<p>4.5　展现你无穷的智慧，开始输入程序吧。如果是 <a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">Debug</a> 方式编译，可能会出现一个连接错误，报告找不到_AtlAxCreateControl，那么你要在菜单 Project\Settings&#8230;\Link 中增加对 Atl.lib 的连接。或者使用 #pragma comment ( lib, &quot;atl&quot; )加入连接库。<br />4.6　如果想调试代码，在菜单 Project\Settings&#8230;\Debug 中输入 IE 的路径名称，比如：&ldquo;C:\Program Files\Internet Explorer\IEXPLORE.EXE&rdquo;，然后就可以跟踪断点调试了。 编译和调试桌面工具栏的 band 对象，是非常麻烦的，因为计算机启动时自动运行 Shell，而 Shell 就会加载活动的桌面对象。</p>
<p><strong>五、结束语</strong><br />好了，到这里，就到这里了。祝大家学习快乐^_^</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/312.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>免费软件套装</title>
		<link>http://www.donevii.com/post/283.html</link>
		<comments>http://www.donevii.com/post/283.html#comments</comments>
		<pubDate>Mon, 08 Jan 2007 12:41:52 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[software & hardware]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ror]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[类]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=283</guid>
		<description><![CDATA[在 CB 上看到的&#8230;&#8230; 办公 OpenOffice&#160;- office suitePC Suite 602&#160;- office suiteAbiWord &#8211; text editorAtlantis Nova &#8211; text editorMicrosoft PowerPoint Viewer&#160;- power point files viewerAdobe Reader &#8211; pdf readerF... ]]></description>
			<content:encoded><![CDATA[<div class="entry">
<h1>在 CB 上看到的&hellip;&hellip;</h1>
<h1>办公</h1>
<p><a href="http://www.openoffice.org/">OpenOffice</a>&nbsp;- office suite<br /><a href="http://www.software602.com/products/pcs/">PC Suite 602</a>&nbsp;- office suite<br /><a href="http://www.abisource.com/">AbiWord</a> &#8211; text editor<br /><a href="http://www.atlantiswordprocessor.com/">Atlantis Nova</a> &#8211; text editor<br /><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=048DC840-14E1-467D-8DCA-19D2A8FD7485&amp;displaylang=en" target="_blank">Microsoft PowerPoint Viewer</a>&nbsp;- power point files viewer<br /><a href="http://www.adobe.com/products/acrobat/readstep2.html"><font color="#810081">Adobe Reader</font></a> &#8211; pdf reader<br /><a href="http://www.foxitsoftware.com/">Foxit PDF Reader</a> &#8211; pdf reader<br /><a href="http://sector7g.wurzel6.de/pdfcreator/index_en.htm">PDFCreator</a> &#8211; create pdf documents<br /><a href="http://www.dbtalk.net/doc-convertor/" target="_blank">Doc Convertor</a>&nbsp;- document convertor<br /><a href="http://joshmadison.net/software/convert/">Convert</a> &#8211; unit convertor<br /><a href="http://www.xyntec.com/converber.htm">Converber</a> &#8211; unit convertor<br /><a href="http://www.mozilla.org/projects/calendar/sunbird/">Sunbird</a> &#8211; calendar/organizer<br /><a href="http://www.essentialpim.com/">EssentialPIM Free</a> &#8211; calendar/organizer<br /><a href="http://www.phraseexpress.com/">PhraseExpress</a> &#8211; speed up your writing<br /><a href="http://atnotes.free.fr/">ATnotes</a> &#8211; create notes on the desktop</p>
<h1>解压缩</h1>
<p><a href="http://www.7-zip.org/">7-Zip</a>&nbsp;- compression program<br /><a href="http://www.izarc.org/">IZArc</a>&nbsp;- compression program<br /><a href="http://www.tugzip.com/">TugZIP</a>&nbsp;- compression program<br /><a href="http://www.larshederer.homepage.t-online.de/english.htm" target="_blank" class="broken_link">CabPack</a> &#8211; compression program<br /><a href="http://www.legroom.net/modules.php?op=modload&amp;name=Open_Source&amp;file=index&amp;page=software&amp;app=uniextract" target="_blank">Universal Extractor</a> &#8211; extract files from any type of archive</p>
<h1>互联网</h1>
<p><a href="http://www.mozilla.com/firefox/">Firefox</a> &#8211; <a href="http://www.donevii.com/post/tag/web" class="st_tag internal_tag" rel="tag" title="Posts tagged with web">web</a> browser<br /><a href="http://www.microsoft.com/windows/ie/default.mspx" target="_blank">Internet Explorer</a>- web browser<br /><a href="http://www.maxthon.com/">Maxthon</a> &#8211; web browser<br /><a href="http://www.opera.com/">Opera</a> &#8211; web browser<br /><a href="http://www.avantbrowser.com/">Avant Browser</a> &#8211; web browser<br /><a href="http://www.mozilla.com/thunderbird/">Thunderbird</a> &#8211; email client<br /><a href="http://www.poptray.org/">PopTray</a> &#8211; check for emails<br /><a href="http://www.freedownloadmanager.org/">Free Download Manager</a> &#8211; download manager<br /><a href="http://www.flashget.com/" target="_blank">FlashGet</a>&nbsp;- download manager<br /><a href="http://www.wellget.com/">WellGet</a> &#8211; download manager<br /><a href="http://www.westbyte.com/dm/">Download Master</a> &#8211; download manager<br /><a href="http://users.ugent.be/~bpuype/wget/" target="_blank">WGET</a> &#8211; commandline download manager<br /><a href="http://www.httrack.com/">HTTrack</a> &#8211; offline browser<br /><a href="http://www.webreaper.net/">WebReaper</a> &#8211; offline browser<br /><a href="http://www.yeahreader.com/" target="_blank">Yeah Reader</a>&nbsp;- RSS reader<br /><a href="http://www.curiostudio.com/" target="_blank">GreatNews</a>&nbsp;- RSS reader<br /><a href="http://www.rssowl.org/" target="_blank">RSSOwl</a> &#8211; RSS reader</p>
<h1>P2P</h1>
<p><a href="http://www.utorrent.com/">&micro;Torrent</a> &#8211; torrent client<br /><a href="http://azureus.sourceforge.net/">Azureus</a> &#8211; torrent client<br /><a href="http://www.bitcomet.com/">BitComet</a> &#8211; torrent client<br /><a href="http://pingpong-abc.sourceforge.net/">ABC</a> &#8211; torrent client<br /><a href="http://www.bittornado.com/">BitTornado</a> &#8211; torrent client<br /><a href="http://www.emule-project.net/">eMule</a> &#8211; p2p client<br /><a href="http://www.slsknet.org/">SoulSeek</a> &#8211; p2p client<br /><a href="http://www.shareaza.com/" target="_blank">Shareaza</a> &#8211; p2p client<br /><a href="http://www.dcpp.net/">DC++</a> &#8211; Direct Connect network client<br /><a href="http://phoenixlabs.org/pg2/" target="_blank" class="broken_link">PeerGuardian</a> &#8211; IP blocker</p>
<h1>聊天</h1>
<p><a href="http://www.miranda-im.org/">Miranda</a> &#8211; chat client<br /><a href="http://messenger.msn.com/">MSN Messenger</a> &#8211; chat client<br /><a href="http://messenger.yahoo.com/">Yahoo Messenger</a> &#8211; chat client<br /><a href="http://www.qip.ru/">QIP</a> &#8211; chat client<br /><a href="http://gaim.sourceforge.net/">Gaim</a> &#8211; chat client<br /><a href="http://jajc.jrudevels.org/">JAJC</a> &#8211; chat client<br /><a href="http://hydrairc.com/">HydraIRC</a> &#8211; IRC client<br /><a href="http://www.talkative-irc.com/" target="_blank">Talkative IRC</a> &#8211; IRC client<br /><a href="http://icechat.net/">IceChat</a> &#8211; IRC client<br /><a href="http://www.skype.com/">Skype</a> &#8211; VOIP client<br /><a href="http://www.google.com/talk/">Google Talk</a> -&nbsp;VOIP client<br /><a href="http://www.voipstunt.com/en/index.html">VoipStunt</a> &#8211; VOIP client <br /><a href="http://www.gizmoproject.com/" target="_blank" class="broken_link">Gizmo</a> &#8211; VOIP client<br /><a href="http://www.wengo.com/" target="_blank">Wengo</a> &#8211; VOIP client</p>
<h1>安全</h1>
<p><a href="http://free.grisoft.com/">AVG Free</a> &#8211; antivirus<br /><a href="http://www.avast.com/">Avast Home Free</a> &#8211; antivirus<br /><a href="http://www.free-av.com/">AntiVir PersonalEdition</a> &#8211; antivirus<br /><a href="http://www.bitdefender.com/site/Main/view/Download-Free-Products.html?menu_id=21">BitDefender Free</a> &#8211; antivirus<br /><a href="http://clamwin.com/">ClamWin</a> &#8211; antivirus<br /><a href="http://www.cyberdefender.com/products.html" target="_blank">CyberDifender</a>&nbsp;- Internet Security Suite<br /><a href="http://www.lavasoftusa.com/software/adaware/">Ad-aware</a> &#8211; anti-spyware<br /><a href="http://www.spybot.info/">Spybot: Search &amp; Destroy</a> &#8211; anti-spyware<br /><a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=435BFCE7-DA2B-4A6A-AFA4-F7F14E605A0D&amp;displaylang=en" target="_blank">Windows Defender</a> &#8211; anti-spyware<br /><a href="http://www.javacoolsoftware.com/" target="_blank">SpywareBlaster</a>&nbsp;- anti-spyware<br /><a href="http://www.spywareterminator.com/" target="_blank">Spyware Terminator</a> &#8211; anti-spyware<br /><a href="http://www.microsoft.com/technet/sysinternals/utilities/RootkitRevealer.mspx" target="_blank">Tootkit Reveaker</a>&nbsp;- rootkit detection utility<br /><a href="http://winpooch.free.fr/page/home.php?lang=en&amp;page=home" class="broken_link">Winpooch</a>&nbsp;- system protection<br /><a href="http://www.hijackfree.com/en/hijackfree/">HiJack Free</a> &#8211; system protection<br /><a href="http://www.spywareinfo.com/~merijn/" target="_blank">HighJackThis</a> &#8211; hijackers detector and remover<br /><a href="http://www.filehippo.com/download_kerio_personal_firewall/?468" target="_blank" class="broken_link">Kerio Personal Firewall</a> &#8211; firewall<br /><a href="http://www.filehippo.com/download_sygate_personal_firewall/" target="_blank">Sygate Personal Firewall</a>&nbsp;- firewall<br /><a href="http://www.zonelabs.com/store/content/company/products/znalm/freeDownload.jsp?dc=12bms&amp;ctry=〈=bg" target="_blank">ZoneAlarm</a>&nbsp;- firewall<br /><a href="http://axcrypt.axantum.com/" target="_blank">AxCrypt</a> &#8211; file encryption<br /><a href="http://www.scar5.com/" target="_blank">Simple File Shredder</a> &#8211; securely delete files<br /><a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank">PuTTy</a>&nbsp;- SSH client<br /><a href="http://keepass.info/" target="_blank">KeePass</a> &#8211; password manager<br /><a href="http://locknote.steganos.com/" target="_blank">LockNote</a> &#8211; password manager<br /><a href="http://zeraha.org/dload.php?action=file&amp;file_id=42" target="_blank">nPassword</a> &#8211; password manager<br /><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=4b4aba06-b5f9-4dad-be9d-7b51ec2e5ac9&amp;DisplayLang=en" target="_blank">Microsoft Baseline Security Analyzer</a> &#8211; identify security misconfigurations</p>
<h1>网络</h1>
<p><a href="http://www.hamachi.cc/">Hamachi</a> &#8211; VPN client<br /><a href="http://www.realvnc.com/">RealVNC</a> &#8211; remote control<br /><a href="http://ultravnc.sourceforge.net/" target="_blank">UltraVNC</a> &#8211; remote control<br /><a href="http://www.ethereal.com/">Ethereal</a> &#8211; local area network administration<br /><a href="http://www.mikrotik.com/thedude.php" target="_blank">The Dude</a> &#8211; network administration<br /><a href="http://www.wireshark.org/" target="_blank">Wireshark</a> &#8211; network administration<br /><a href="http://www.angryziber.com/ipscan/">Angry IP Scanner</a> &#8211; IP scanner<br /><a href="http://www.ks-soft.net/ip-tools.eng/" target="_blank">IP-Tools</a>&nbsp;- IP scanner<br /><a href="http://www.nsauditor.com/network_tools/free_port_scanner.html" target="_blank">Free Port Scanner</a> &#8211; IP scanner<br /><a href="http://readerror.gmxhome.de/">NetMeter</a> &#8211; network bandwidth monitoring</p>
<h1>服务器</h1>
<p><a href="http://filezilla.sourceforge.net/">FileZilla</a> &#8211; FTP client<br /><a href="http://filezilla.sourceforge.net/">FileZilla Server</a> &#8211; FTP <a href="http://www.donevii.com/post/tag/server" class="st_tag internal_tag" rel="tag" title="Posts tagged with server">server</a><br /><a href="http://www.encrypted-ftp.com/">EFTP</a> &#8211; FTP client/server<br /><a href="http://www.apachefriends.org/en/xampp-windows.html" target="_blank">XAMPP</a> &#8211; integrated server package of Apache, mySQL, <a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">PHP</a> and Perl<br /><a href="http://www.en.wampserver.com/" target="_blank">WAMP</a> &#8211; Apache, PHP5 and MySQL server</p>
<h1>音频</h1>
<p><a href="http://www.foobar2000.com/">Foobar2000</a> &#8211; audio player<br /><a href="http://www.winamp.com/">WinAmp</a> &#8211; audio player<br /><a href="http://www.mpesch3.de/">1by1</a> &#8211; audio player<br /><a href="http://www.jetaudio.com/">JetAudio</a> &#8211; audio player<br /><a href="http://support.xmplay.com/">XMPlay</a> &#8211; audio player<br /><a href="http://xion.r2.com.au/" target="_blank">Xion</a> &#8211; audio player<br /><a href="http://koti.welho.com/hylinen/apollo/" target="_blank">Apollo</a> &#8211; audio player<br /><a href="http://www.mediamonkey.com/" target="_blank">MediaMonkey</a> &#8211; music organizer<br /><a href="http://users.otenet.gr/~jtcliper/tgf/" target="_blank" class="broken_link">The GodFather</a> &#8211; music organizer<br /><a href="http://www.dbpoweramp.com/">dBpowerAMP</a> &#8211; audio converter<br /><a href="http://audacity.sourceforge.net/">Audacity</a> &#8211; audio converter<br /><a href="http://www.nch.com.au/wavepad/index_b.html?ref=google&amp;ref2=c18wavepadmp3&amp;ref3=sale">WavePad</a> &#8211; audio converter<br /><a href="http://www.kreatives.org/kristal/">Kristal Audio Engine</a> &#8211; audio editor<br /><a href="http://www.exactaudiocopy.de/">Exact Audio Copy</a> &#8211; CD ripper<br /><a href="http://www.audiograbber.com-us.net/">Audiograbber</a> &#8211; CD ripper<br /><a href="http://sourceforge.net/projects/cdexos/">CDex</a> &#8211; CD ripper<br /><a href="http://massid3lib.sourceforge.net/">Mp3 Tag Tools</a> &#8211; tag editor<br /><a href="http://www.mp3tag.de/en/" target="_blank">Mp3tag</a> &#8211; tag editor<br /><a href="http://lazorsoftware.com/">Taggin&rsquo; MP3</a> &#8211; tag editor<br /><a href="http://www.monkeysaudio.com/">Monkey&rsquo;s Audio</a> &#8211; APE compressor/decompressor<br /><a href="http://www.mptrim.com/" target="_blank">mpTrim</a>&nbsp;- mp3 editor<br /><a href="http://www.mptrim.com/WavTrim.html" target="_blank">WavTrim</a>&nbsp;- wave editor<br /><a href="http://www.guerillasoft.co.uk/encspot/" target="_blank">EncSpot Basic</a> &#8211; analyse mp3 files</p>
<h1>视频</h1>
<p><a href="http://www.microsoft.com/windows/windowsmedia/default.mspx" target="_blank">Windows Media Player</a> &#8211; audio/video player<br /><a href="http://www.videolan.org/">VLC</a> &#8211; video player<br /><a href="http://sourceforge.net/projects/guliverkli/">Media Player Classic</a> &#8211; video player<br /><a href="http://mv2.czweb.org/">MV2Player</a> &#8211; video player<br /><a href="http://www.crystalplayer.com/">CrystalPlayer 1.95</a> &#8211; video player<br /><a href="http://www.inmatrix.com/" target="_blank">Zoom Player</a> &#8211; video player<br /><a href="http://www.gomplayer.com/" target="_blank">GOM Player</a> &#8211; video player<br /><a href="http://www.urusoft.net/products.php?lang=1">viPlay</a> &#8211; video player<br /><a href="http://dsplayer.de/dspweb/">DSPlayer</a> &#8211; video player<br /><a href="http://www.virtualdub.org/">VirtualDub</a> &#8211; video editor<br /><a href="http://www.camstudio.org/">CamStudio</a> &#8211; video screen recording<br /><a href="http://www.bobyte.com/AviSplit/">AviSplit</a> &#8211; Avi splitter<br /><a href="http://www.geovid.com/Video_mp3_Extractor/">Video mp3 Extractor</a> &#8211; rip audio from video files<br /><a href="http://www.ipod-video-converter.org/" target="_blank">Free iPod Converter</a> &#8211; convert all popular video formats to iPod video<br /><a href="http://www.team-mediaportal.com/" target="_blank">MediaPortal</a> &#8211; turning your PCinto a Media Center<br /><a href="http://members.home.nl/thefilmmachine/" target="_blank">The FilmMachine</a></p>
<h1>图像</h1>
<p><a href="http://www.gimp.org/">Gimp</a> &#8211; image editor<br /><a href="http://www.photofiltre.com/" target="_blank">PhotoFiltre</a> &#8211; image editor<br /><a href="http://www.getpaint.net/">Paint.net</a> &#8211; image editor<br /><a href="http://www.ambientdesign.com/artrage.html" target="_blank">ArtRage</a>&nbsp;- image editor<br /><a href="http://www.artweaver.de/index.php?id=59,141,0,0,1,0" target="_blank">Artweaver</a> &#8211; image editor<br /><a href="http://www.irfanview.com/">IrfanView</a> -&nbsp;image viewer<br /><a href="http://www.picasa.com/">Picasa</a> -&nbsp;image viewer<br /><a href="http://www.xnview.com/">XnView</a> &#8211; image viewer<br /><a href="http://faststone.org/">FastStone Image Viewer</a> -&nbsp;image viewer<br /><a href="http://www.futurix.co.uk/imager/" target="_blank">FuturixImager</a>&nbsp;-&nbsp;image viewer<br /><a href="http://www.fookes.com/ezthumbs/">Easy Thumbnails</a> &#8211; create thumbnails from images<br /><a href="http://www.jojosoftware.de/jojothumb/english/default.htm" target="_blank">JoJoThumb</a> &#8211; create thumbnails from images<br /><a href="http://www.eunq.com/" target="_blank">iWebAlbum</a>&nbsp;- create web photo albums<br /><a href="http://jalbum.net/" target="_blank">JAlbum</a> &#8211; create web photo albums<br /><a href="http://www.bosseye.com/boxshot/index.htm" target="_blank">3D Box Shot Maker</a>&nbsp;- design quality box shot<br /><a href="http://faststone.org/" target="_blank">FastStone Capture</a>&nbsp;- screen capture<br /><a href="http://www.ntwind.com/software/winsnap.html" target="_blank">WinSnap</a>&nbsp;- screen capture</p>
<h1>
<h1>3D</h1>
<p><a href="http://www.blender.org/cms/Home.2.0.html">Blender3D</a> &#8211; 3D renderer<br /><a href="http://www.3delight.com/index.htm" class="broken_link">3Delight Free</a> &#8211; 3D renderer<br /><a href="http://sketchup.google.com/product_suf.html" target="_blank" class="broken_link">SketchUp</a> &#8211; 3D modeling<br /><a href="http://usa.autodesk.com/adsk/servlet/index?siteID=123112&amp;id=7639525" target="_blank">Maya Learning Edition</a> &#8211; 3D modeling</p>
<h1><a href="http://www.donevii.com/post/tag/%e5%bc%80%e5%8f%91" class="st_tag internal_tag" rel="tag" title="Posts tagged with 开发">开发</a></h1>
<p><a href="http://www.autoitscript.com/autoit3/">AutoIt</a> &#8211; task automation<br /><a href="http://www.autoitscript.com/autoit3/scite/downloads.php">SciTE4AutoIt3</a> -&nbsp;text editor&nbsp;for AutoIt<br /><a href="http://www.autohotkey.com/" target="_blank">AutoHotkey</a>&nbsp;- task automation<br /><a href="http://www.mpsoftware.dk/">PHP Designer</a> &#8211; PHP editor<br /><a href="http://notepad-plus.sourceforge.net/">Notepad++</a> &#8211; text editor<br /><a href="http://context.cx/component/option,com_docman/Itemid,48/" class="broken_link">ConTEXT Editor</a> &#8211; text editor<br /><a href="http://www.pspad.com/en/">PSPad</a> &#8211; text editor<br /><a href="http://foxeditor.sourceforge.net/" target="_blank">FoxEditor</a>&nbsp;- text editor<br /><a href="http://www.crimsoneditor.com/" target="_blank">Crimson Editor</a>&nbsp;- source code editor<br /><a href="http://www.elfima.com/enotepad.php" target="_blank" class="broken_link">Elfima Notepad</a>&nbsp;- text editor<br /><a href="http://www.flos-freeware.ch/notepad2.html" target="_blank">Notepad2</a>&nbsp;- text editor<br /><a href="http://www.nvu.com/">Nvu</a> &#8211; HTML editor<br /><a href="http://www.alleycode.com/" target="_blank">Alleycode</a>&nbsp;- HTML editor<br /><a href="http://www.blocknote.net/" target="_blank">BlockNote</a>&nbsp;- web page editor<br /><a href="http://www.weaverslave.ws/weaverslave.31.html" target="_blank">Weaverslave</a> &#8211; web page editor</p>
<h1>CD/DVD</h1>
<p><a href="http://www.deepburner.com/">DeepBurner</a> &#8211; CD/DVD burner<br /><a href="http://www.cdburnerxp.se/">CDBurner XP Pro</a> &#8211; CD/DVD burner<br /><a href="http://www.burnatonce.net/">BurnAtOnce</a> &#8211; CD/DVD burner<br /><a href="http://www.nch.com.au/burn/index.html">Express Burn</a> &#8211; CD/DVD burner<br /><a href="http://www.zillasoft.ws/">Zilla CD-DVD Rip&rsquo;n&rsquo;Burn</a> &#8211; CD/DVD <br />刻录<br /><a href="http://www.imgburn.com/">ImgBurn</a> &#8211; ISO, BIN burner<br /><a href="http://www.daemon-tools.cc/">Daemon tools</a> &#8211; virtual CD/DVD<br /><a href="http://en.wikipedia.org/wiki/DVD_Decrypter/" class="broken_link">DVD Decrypter</a> &#8211; DVD ripper<br /><a href="http://www.dvdshrink.org/">DVD Shrink</a> &#8211; DVD ripper<br /><a href="http://www.cdspeed2000.com/" target="_blank">Nero CD-DVD Speed</a>&nbsp;- CD/DVD info and quality test<br />解码</p>
<p><a href="http://www.headbands.com/gspot/" target="_blank">GSpot</a>&nbsp;- codec information<br /><a href="http://ac3filter.net/">AC3Filter</a> &#8211; audio codec<br /><a href="http://www.koepi.org/">Xvid</a> &#8211; video codec<br /><a href="http://www.codecguide.com/">QuickTime Alternative</a> &#8211; video codec<br /><a href="http://www.codecguide.com/">Real Alternative</a> &#8211; video codec<br /><a href="http://www.free-codecs.com/download/K_Lite_Codec_Pack.htm" target="_blank">K-Lite Codec Pack</a> &#8211; all codecs</p>
<h1>系统工具</h1>
<p><a href="http://ccleaner.com/">CCleaner</a> &#8211; system cleaner<br /><a href="http://www.xp-antispy.org/">xp-AntiSpy</a> &#8211; OS setup<br /><a href="http://www.jv16.org/">jv16 Powertools</a> &#8211; system utilities<br /><a href="http://www.xtort.net/xtort/xpsyspad.php" target="_blank">XP SysPad</a> &#8211; system monitoring utility<br /><a href="http://www.whatsrunning.net/whatsrunning/" class="broken_link">What&rsquo;s Running</a> &#8211; process guard<br /><a href="http://www.resplendence.com/">Registrar Lite</a> &#8211; registry editor<br /><a href="http://www.pkostov.com/wipcfg.html" target="_blank">WinIPConfig</a> &#8211; replacement for &ldquo;ipconfig.exe&rdquo; and &ldquo;route.exe&rdquo;<br /><a href="http://ccollomb.free.fr/unlocker/index.htm" class="broken_link">Unlocker</a> &#8211; file eraser<br /><a href="http://www.heidi.ie/eraser/" target="_blank">Eraser</a> &#8211; secure file eraser<br /><a href="http://www.undelete-plus.com/" target="_blank">Undelete Plus</a> &#8211; file recovery<br /><a href="http://www.freecommander.com/" target="_blank">freeCommander</a> &#8211; file manager<br /><a href="http://www.explorerxp.com/" target="_blank">ExplorerXP</a>&nbsp;- file manager<br /><a href="http://dff.nazrashid.com/" target="_blank" class="broken_link">Duplicate File Finder</a> &#8211; find all duplicate files<br /><a href="http://www.antp.be/">Ant Renamer</a> &#8211; file renaming<br /><a href="http://www.den4b.com/" target="_blank">ReNamer</a> &#8211; file renaming<br /><a href="http://www.vlsoftware.net/exico/">Icons From File</a> &#8211; icos extractor<br /><a href="http://www.elgorithms.com/downloads/chaosmd5.php">Chaos MD5</a> &#8211; MD5 generator<br /><a href="http://www.beeblebrox.org/hashtab/" target="_blank" class="broken_link">HashTab</a>&nbsp;- MD5, SHA1 and CRC-32 file hashes<br /><a href="http://www.rainlendar.net/cms/index.php" target="_blank">Rainlendar Lite</a> &#8211; desktop calendar<br /><a href="http://www.singerscreations.com/">Weather Watcher</a> &#8211; weather firecast<br /><a href="http://www.urusoft.net/home.php?lang=1">Subtitle Workshop</a> &#8211; subtitles editor<br /><a href="http://www.antp.be/software/moviecatalog/">Ant Movie Catalog</a> &#8211; movie organizer<br /><a href="http://www.lyrasoftware.com/" target="_blank">Disclib</a> &#8211; CD organizer<br /><a href="http://www.dexpot.de/">Dexpot</a> &#8211; virtual desktops<br /><a href="http://www.runtime.org/">DriveImage XML</a> &#8211; create partition images<br /><a href="http://mozbackup.jasnapaka.com/">MozBackup</a> &#8211; backup and restore bookmarks, etc.<br /><a href="http://www.2brightsparks.com/syncback/">SyncBack</a> &#8211; system backup<br /><a href="http://www.worldtimeserver.com/atomic-clock/" target="_blank">Atomic Cock Sync</a> &#8211; syncronize your clock<br /><a href="http://www.ornj.net/citrus/" target="_blank">Citrus Alarm Clock</a> &#8211; alarm clock<br /><a href="http://www.ntwind.com/software/taskswitchxp.html?" target="_blank">TaskSwitchXP</a> &#8211; Alt-Tab replacement<br /><a href="http://www.launchy.net/" target="_blank">Launchy</a> -&nbsp;application launcher<br /><a href="http://ca.geocities.com/ivanheckman@rogers.com/" target="_blank" class="broken_link">allSnap</a> &#8211; make all windows snap<br /><a href="http://www.microsoft.com/technet/sysinternals/default.mspx" target="_blank">Sysinternals Tools</a> &#8211; various system tools<br /><a href="http://www.tcbmi.com/strokeit/" target="_blank">StrokeIt</a>&nbsp;- mouse gestures<br /><a href="http://netprofiles.danielmilner.com/" target="_blank">Net Profiles</a> &#8211; create profiles of your network settings<br /><a href="http://www.angusj.com/resourcehacker/" target="_blank">ResourceHacker</a> &#8211; view, modify, rename, add, delete<br /><a href="http://www.sun.com/" target="_blank">Java Runtime Environment</a> &#8211; <a href="http://www.donevii.com/post/tag/java" class="st_tag internal_tag" rel="tag" title="Posts tagged with java">java</a> for Windows</p>
<h1>UI设计</h1>
<p><a href="http://www.punksoftware.com/rocketdock" target="_blank">RocketDock</a>&nbsp;- application launcher<br /><a href="http://www.avedesk.org/" target="_blank">AveDesk</a> &#8211; desktop enhancer<br /><a href="http://www.virtualplastic.net/scrow/iphile.html" target="_blank" class="broken_link">IconPhile</a>&nbsp;- customize windows&rsquo;s system icons<br /><a href="http://www.stardock.com/products/cursorxp/" target="_blank">CursorXP Free</a> &#8211; change mouse cursors<br /><a href="http://landvermesser.tripod.com/MacSound.html" target="_blank" class="broken_link">MacSound</a> &#8211; volume control<br /><a href="http://www.neowin.net/forum/index.php?showtopic=157465" target="_blank">LClock</a>&nbsp;- Windows Longhorn clock<br /><a href="http://www.majorgeeks.com/download.php?det=2790" target="_blank">Y&rsquo;z Dock</a> &#8211; application launcher<br /><a href="http://www.winmatrix.com/forums/index.php?showtopic=1161" target="_blank">Y&rsquo;z Shadow</a> &#8211; shadow effect to the&nbsp;windows<br /><a href="http://www.winmatrix.com/forums/index.php?showtopic=1161" target="_blank">Y&rsquo;z Toolbar</a> &#8211; change the toolbar icons in Explorer and Internet Explorer<br /><a href="http://www.freewebs.com/nerdcave/taskbarshuffle.htm" target="_blank">Taskbar Shuffle</a> &#8211; rearrange the programs on&nbsp;the taskbar by dragging<br /><a href="http://www.visualtasktips.com/" target="_blank">Visual Task Tips</a> &#8211; thumbnail preview image for each task in the taskbar<br /><a href="http://eng.softq.org/badges.htm" target="_blank">Badges</a>&nbsp;- put badges on any folder or file<br /><a href="http://eng.softq.org/folderico" target="_blank">Folderico</a>&nbsp;- change icons of the folders<br /><a href="http://www.foldermarker.com/" target="_blank">Folder Marker</a> &#8211; mark your folders<br /><a href="http://eng.softq.org/Folder2mypc" target="_blank">Folder2MyPC</a> &#8211; add favourite locations to My Computer<br /><a href="http://www.microsoft.com/windowsxp/downloads/powertoys/xppowertoys.mspx" target="_blank">Microsoft TweakUI</a> &#8211; system settings<br /><a href="http://www.crystalxp.net/bricopack/" target="_blank">BricoPacks</a> &#8211; <a href="http://www.donevii.com/post/tag/shell" class="st_tag internal_tag" rel="tag" title="Posts tagged with shell">shell</a> packs<br /><a href="http://www.trucsenvrac.com/home/shellpacks.html" target="_blank">ShellPacks</a> &#8211; shell packs<br /><a href="http://www.deviantart.com/deviation/27940418/" target="_blank">Tango Shell Patcher</a> &#8211; shell patcher<br /><a href="http://xpero.msfn.org/" target="_blank" class="broken_link">XPize</a> &#8211; GUI enhancer<br /><a href="http://www.softpedia.com/get/System/OS-Enhancements/Vista-Transformation-Pack.shtml">Vista Transformation Pack</a>&nbsp;- complete visual style<br /><a href="http://www.msfn.org/board/index.php?showtopic=71604" target="_blank">Vista Sound Scheme</a> &#8211; Windows Vista sound scheme<br /><a href="http://www.softpedia.com/get/Desktop-Enhancements/Themes/Royale-Theme-for-WinXP.shtml">Royale Theme</a>&nbsp;- visual style</p>
<h1>硬件检测</h1>
<p><a href="http://www.cpuid.com/cpuz.php" target="_blank">CPU-Z</a>&nbsp;- cpu information<br /><a href="http://crystalmark.info/software/CrystalCPUID/index-e.html" target="_blank">CrystalCPUID</a> &#8211; cpu information<br /><a href="http://cbid.amdclub.ru/" target="_blank">Central Brain Identifier</a> &#8211; cpu information<br /><a href="http://www.lavalys.com/" target="_blank">Everest</a> &#8211; system information<br /><a href="http://www.sisoftware.co.uk/index.html?dir=&amp;location=home&amp;langx=en&amp;a=" target="_blank">SiSoft Sandra</a>&nbsp;- system information<br /><a href="http://www.almico.com/speedfan.php">SpeedFan</a>&nbsp;- hardware monitor<br /><a href="http://www.memtest86.com/" target="_blank">Memtest86</a> &#8211; memory test<br /><a href="http://www.maxtor.com/portal/site/Maxtor/menuitem.3c67e325e0a6b1f6294198b091346068/?channelpath=%2Fen_us%2FSupport%2FSoftware%20Downloads%2FAll%20Downloads&amp;downloadID=22" target="_blank">PowerMax</a> &#8211; HDD test<br /><a href="http://www.futuremark.com/products/3dmark06/" target="_blank">3Dmark 06</a>&nbsp;- 3D game performance benchmark<br /><a href="http://www.softpedia.com/get/System/Benchmarks/AquaMark.shtml" target="_blank">Aquamark</a>&nbsp;- performance benchmark<br /><a href="http://www.daionet.gr.jp/~masa/rthdribl/" target="_blank">rthdribl</a> &#8211; 3D benchmark<br /><a href="http://www.beepa.com/" target="_blank">Fraps</a>&nbsp;-&nbsp;3D benchmark, fps viewer and screen recorder<br /><a href="http://www.mersenne.org/freesoft.htm">Prime 95</a>&nbsp;- cpu benchmarking<br /><a href="http://files.extremeoverclocking.com/file.php?f=36" target="_blank">SuperPI</a>&nbsp;- cpu benchmarking<br /><a href="http://cpu.rightmark.org/download.shtml">CPU Rightmark</a>&nbsp;- cpu overclock<br /><a href="http://www.thecoolest.zerobrains.com/CoreTemp/" target="_blank" class="broken_link">Core Temp</a>&nbsp;- cpu temperature<br /><a href="http://www.techpowerup.com/downloads/8" target="_blank">ATiTool</a>&nbsp;- video overclock<br /><a href="http://www.guru3d.com/article/atitraytools/189/" target="_blank">ATI Tray Tools</a> &#8211; Radeon tweaker<br /><a href="http://www.3dcenter.org/atuner/" target="_blank" class="broken_link">aTuner</a>&nbsp;- GeForce and Radeontweaker<br /><a href="http://www.guru3d.com/index.php?page=rivatuner" target="_blank">RivaTuner</a> &#8211; video overclock<br /><a href="http://www.construnet.hu/nokia/Monitors/TEST/monitor_test.html" target="_blank" class="broken_link">Nokia Monitor Test</a>&nbsp;- monitor adjustmets<br /><a href="http://udpix.free.fr/" target="_blank">UDPixel</a> &#8211; fix dead pixels</p>
<h1>游戏</h1>
<p><a href="http://www.123freesolitaire.com/" target="_blank">123 Free Solitaire</a>&nbsp;- solitaire games collection<br /><a href="http://www.neowin.net/forum/index.php?showtopic=471360" target="_blank">Arcade Pack</a>&nbsp;- classic arcade games<br /><a href="http://www.liveforspeed.net/" target="_blank">Live For Speed</a> &#8211; online racing simulator<br /><a href="http://www.nongnu.org/enigma/" target="_blank">Enigma</a> &#8211; puzzle game<br /><a href="http://www.freeciv.org/index.php/Freeciv" target="_blank">Freeciv</a> &#8211; multiplayer strategy game<br /><a href="http://tuxracer.sourceforge.net/" target="_blank">Tux Racer</a> &#8211; race down steep, snow-covered mountains</p>
<h1>教育</h1>
<p><a href="http://www.speqmath.com/" target="_blank">SpeQ Mathematics</a>&nbsp;- mathematics program<br /><a href="http://www.gnome.org/projects/dia/" target="_blank">Dia</a> &#8211; diagram creation program<br /><a href="http://earth.google.com/">Google Earth</a> &#8211; explore the world<br /><a href="http://sourceforge.net/projects/nasa-exp/" target="_blank">NASA World Wind</a> &#8211; 3D virtual globe<br /><a href="http://www.shatters.net/celestia/" target="_blank">Celestia</a> &#8211; explore the space<br /><a href="http://www.stellarium.org/" target="_blank">Stellarium</a> &#8211; planetarium</p>
<h1>杂类</h1>
<p><a href="http://www.nliteos.com/" target="_blank">nLite</a> &#8211; Build your own custom Windows disk.<br /><a href="http://www.microsoft.com/downloads/details.aspx?familyid=6d58729d-dfa8-40bf-afaf-20bcb7f01cd1&amp;displaylang=en" target="_blank">VirtualPC</a> &#8211; create virtual machines<br /><a href="http://www.grabmotion.com/" target="_blank">grabMotion</a>&nbsp;- webcam capture<br /><a href="http://www.splinterware.com/" target="_blank">iDailyDiary</a> &#8211; simple page-for-a-day diary<br /><a href="http://www.gold-software.com/PivotStickfigureAnimator-review5412.htm" target="_blank">Pivot Stickfigure Animator</a> &#8211; create stick-figure animations<br /><a href="http://www.debugmode.com/wink/" target="_blank">Wink</a> &#8211; create presentations<br /><a href="http://www.scribus.net/" target="_blank">Scribus</a> &#8211; professional page layout<br /><a href="http://freemind.sourceforge.net/wiki/index.php/Main_Page" target="_blank">FreeMind</a> &#8211; midn mapping software<br /><a href="http://windowslivewriter.spaces.live.com/blog/cns!D85741BB5E0BE8AA!174.entry" target="_blank" class="broken_link">Windows Live Writer</a> &#8211; WYSIWYG blog authoring</p>
<h1>墙纸</h1>
<p><a href="http://blogs.msdn.com/mswanson/articles/wallpaper...." target="_blank" class="broken_link">Michael Swanson</a>&nbsp;- 1920 x 1200; 1600 x 1200; amazing wallpapers<br /><a href="http://www.arkhipov.com/Wallpaper/Wallpaper.aspx" target="_blank" class="broken_link">Mikhail Arkhipov</a>&nbsp;- 1920 x 1200; 1600 x 1200; amazing wallpapers</p>
</h1>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/283.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>组件注册命令 Regsvr32 的各种用法解析</title>
		<link>http://www.donevii.com/post/168.html</link>
		<comments>http://www.donevii.com/post/168.html#comments</comments>
		<pubDate>Thu, 02 Nov 2006 08:03:00 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=168</guid>
		<description><![CDATA[Windows系统提供的Regsvr32命令也许很多朋友都见过可能还不知道怎么用，它可是一个很实用的功能。 一、能够帮你轻松修复IE浏览器 很多经常上网的朋友都有过这样的遭遇：IE不能打开新的窗口... ]]></description>
			<content:encoded><![CDATA[<p>Windows系统提供的Regsvr32命令也许很多朋友都见过可能还不知道怎么用，它可是一个很实用的功能。 </p>
<p>一、能够帮你轻松修复IE浏览器 <br />很多经常上网的朋友都有过这样的遭遇：IE不能打开新的窗口，用鼠标点击超链接也没有任何反应。这时重装IE一般能解决问题。其实不必这么麻烦，使用Regsvr32命令就可以轻松搞定。 </p>
<p>在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;regsvr32  actxprxy.dll&rdquo;命令，点击&ldquo;确定&rdquo;按钮，这时会弹出一个信息对话框&ldquo;DllRegisterServer  in  actxprxy.dll  succeeded&rdquo;，点击&ldquo;确定&rdquo;；然后再在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;regsvr32  shdocvw.dll&rdquo;命令，单击&ldquo;确定&rdquo;即可。重新启动后IE已经被轻松修复了。 </p>
<p>二、解决Windows无法在线升级的问题 <br />Windows的漏洞很多，每隔一段时间就需要使用&ldquo;<a href="http://www.donevii.com/post/tag/windows" class="st_tag internal_tag" rel="tag" title="Posts tagged with windows">Windows</a>  Update&rdquo;升级程序进行在线升级，不过&ldquo;<a href="http://www.donevii.com/post/tag/windows" class="st_tag internal_tag" rel="tag" title="Posts tagged with windows">Windows</a>  Update&rdquo;经常出现无法使用的情况，这时，我们可以使用Regsvr32来解决这个问题。 </p>
<p>在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;regsvr32  wupdinfo.dll&rdquo;，点击&ldquo;确定&rdquo;按钮，这样在系统中就重新注册了&ldquo;Windows  Update&rdquo;组件，重新启动后问题已经解决。 </p>
<p>三、防范网络脚本病毒有新招 <br />网络脚本病毒嵌在网页中，上网时在不知不觉中机器就会感染上这种病毒。笔者认为单纯使用杀毒软件并不能有效地防范这些脚本病毒，必须从病毒传播的机理入手。网络脚本病毒的复制、传播都离不开FSO对象(File System  Object，文件系统对象)，因此禁用FSO对象就能有效地控制脚本病毒的传播。操作方法很简单： </p>
<p>在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;regsvr32  /u  scrrun.dll&rdquo;就可以禁用FSO对象；如果需要使用FSO对象，键入&ldquo;regsvr32  scrrun.dll&rdquo;命令即可。 </p>
<p>四、卸载Win  XP自带的&ldquo;鸡肋&rdquo;功能 <br />Win  XP以功能强大而著称，但有些功能却常常令人有&ldquo;鸡肋&rdquo;之感，比如Win  XP自带的ZIP功能和图片预览功能，不仅占用了系统资源，功能也远不如第三方软件强大。其实用Regsvr32命令可以很容易地卸载这些功能。 </p>
<p>在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;regsvr32  /u  zipfldr.dll&rdquo;，单击&ldquo;确定&rdquo;按钮，弹出卸载成功信息框后就完成了ZIP功能的卸载；要恢复ZIP功能，键入&ldquo;regsvr32  zipfldr.dll&rdquo;即可。同样，卸载图片预览功能也很简单，在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;regsvr32  /u  thumbvw.dll&rdquo;即可；如果要恢复该功能，只须键入&ldquo;regsvr32  thumbvw.dll&rdquo;。</p>
<p>五、让WMP播放器支持RM格式 <br />很多朋友喜欢用Windows  Media  Player(以下简称WMP)播放器，但是它不支持RM格式，难道非得安装其他播放软件吗？笔者有办法。 </p>
<p>以Win  XP为例，首先下载一个RM格式插件，解压缩后得到两个文件夹：Release(用于Windows  9x)和Release Unicode  (用于Windows  2000/XP)；将Release  Unicode文件夹下的RealMediaSplitter.ax文件拷贝到&ldquo;系统盘符\\WINDOWS\\System32\\&rdquo;目录下；在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;regsvr32  RealMediaSplitter.ax&rdquo;，点击&ldquo;确定&rdquo;即可。接着下载解码器，如Real  Alternative，安装后就能用WMP播放RM格式的影音文件了。 </p>
<p>RM格式插件下载地址：http://www.fyrose.com/realmediasplitter_20030729.zip </p>
<p>RM格式解码器下载地址：http://www.fyrose.com/realalt111.exe </p>
<p>你知道吗？Regsvr32命令 <br />Regsvr  32命令是Windows中控件文件(如扩展名为DLL、OCX、CPL的文件)的注册和反注册工具。 </p>
<p>格式：regsvr32 [/s] [/n] [/i[:cmdline]] DLLname</p>
<p>使用参数&#8212;&#8212;&#8211;解除服务器注册<br />使用参数[/s]&#8212;&#8212;&#8211;无声；不显示消息框<br />使用参数&#8212;&#8212;&#8212;调用DllInstall，给其传递一个可选[cmdline];跟/u参数一起使用时卸载DLL。<br />使用参数[/n]&#8212;&#8212;&#8211;不用调用DLLRegisterServer。这个参数必须跟/i一起使用。</p>
<p>简单实例 <br />要手工注册&ldquo;E:\CPCW.dll&rdquo;，只需在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;Regsvr32  E:\CPCW.dll&rdquo;，单击&ldquo;确定&rdquo;按钮后会弹出提示信息&ldquo;DllRegisterServer  in  CPCW.dll  succeeded&rdquo;，说明组件注册成功；如果要卸载此组件，在&ldquo;开始&rarr;运行&rdquo;中键入&ldquo;Regsvr32  /u  E:\CPCW.dll&rdquo;即可。 </p>
<p>实例1：IE无法打开新窗口</p>
<p>regsvr32 actxprxy.dll<br />regsvr32 shdocvw.dll</p>
<p>重启后如果还不能解决</p>
<p>regsvr32 mshtml.dll<br />regsvr32 urlmon.dll<br />regsvr32 msjava.dll<br />regsvr32 browseui.dll<br />regsvr32 oleaut32.dll<br />regsvr32 <a href="http://www.donevii.com/post/tag/shell" class="st_tag internal_tag" rel="tag" title="Posts tagged with shell">shell</a>32.dll</p>
<p>实例2：IE无法保存HTML格式文件</p>
<p>regsvr32 inetcomm.dll</p>
<p>实例3：MSN无法登陆</p>
<p>regsvr32 softpub.dll</p>
<p>实例4：windows默认的文件关联混乱</p>
<p>regsvr32 /i shdocvw.dll<br />regsvr32 /i shell.dll<br />regsvr32 /i shdoc401.dll</p>
<p>实例5：Window <a href="http://www.donevii.com/post/tag/server" class="st_tag internal_tag" rel="tag" title="Posts tagged with server">server</a> 2003中无法播放MP3</p>
<p>regsvr32 i3codeca.acm<br />regsvr32 i3codecx.ax</p>
<p>实例6：Windows添加/删除程序无法启动</p>
<p>regsvr32 mshtml.dll<br />regsvr32 /i shdocvw.dll<br />regsvr32 /i shell.dll</p>
<p>实例7 Windows搜索功能故障</p>
<p>regsvr32 urlmon.dll</p>
<p>实例8：禁止系统对媒体文件进行预览</p>
<p>regsvr32 /u shmedia.dll</p>
<p>恢复可用</p>
<p>regsvr32 shmedia.dll</p>
<p>实例9：卸载Win XP自带的zip功能</p>
<p>regsvr32 /u zipfldr.dll</p>
<p>实例10：禁用FSO对象</p>
<p>regsvr32 /u scrrun.dll</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/168.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FTP命令大全</title>
		<link>http://www.donevii.com/post/159.html</link>
		<comments>http://www.donevii.com/post/159.html#comments</comments>
		<pubDate>Tue, 31 Oct 2006 07:48:25 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[类]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=159</guid>
		<description><![CDATA[FTP命令非常使用，尤其是在UNIX系统下FTP命令是Internet用户使用最频繁的命令之一，不论是在DOS还是UNIX操作系统下使用FTP，都会遇到大量的FTP内部命令。熟悉并灵活应用FTP的内部命令，可以大大... ]]></description>
			<content:encoded><![CDATA[<p>FTP命令非常使用，尤其是在UNIX系统下FTP命令是Internet用户使用最频繁的命令之一，不论是在DOS还是UNIX操作系统下使用<br />FTP，都会遇到大量的FTP内部命令。熟悉并灵活应用FTP的内部命令，可以大大方便使用者，<br />并收到事半功倍之效。</p>
<p>　　FTP的命令行格式为： ftp -v -d -i -n -g [主机名] ，其中<br />　　-v 显示远程服务器的所有响应信息；<br />　　-d 使用调试方式；<br />　　-i 限制ftp的自动登录，即不使用；<br />　　-n etrc文件；<br />　　-g 取消全局文件名。</p>
<p>　　ftp使用的内部命令如下(中括号表示可选项):<br />　　1. ![cmd[args]]：在本地机中执行交互shell，exit回到ftp环境，如：!ls*.zip。<br />　　2. $ macro-ame[args]：执行宏定义macro-name。<br />　　3. account[password]：提供登录远程系统成功后访问系统资源所需的补充口令。<br />　　4. append local-file[remote-file]：将本地文件追加到远程系统主机，若未指定远程系统文件名，则使用本地文件名。<br />　　5. ascii：使用ascii类型传输方式。<br />　　6. bell：每个命令执行完毕后计算机响铃一次。<br />　　7. bin：使用二进制文件传输方式。<br />　　8. bye：退出ftp会话过程。<br />　　9. case：在使用mget时，将远程主机文件名中的大写转为小写字母。<br />　　10. cd remote-dir：进入远程主机目录。<br />　　11. cdup：进入远程主机目录的父目录。<br />　　12. chmod mode file-name：将远程主机文件file-name的存取方式设置为mode，如： chmod 777 a.out 。<br />　　13. close：中断与远程服务器的ftp会话(与open对应)。<br />　　14. cr：使用asscii方式传输文件时，将回车换行转换为回行。<br />　　15. delete remote-file：删除远程主机文件。<br />　　16. <a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">debug</a>[debug-value]：设置调试方式， 显示发送至远程主机的每条命令，如： deb up 3，若设为0，表示取消debug。<br />　　17. dir[remote-dir][local-file]：显示远程主机目录，并将结果存入本地文件local-file。<br />　　18. disconnection：同close。<br />　　19. form format：将文件传输方式设置为format，缺省为file方式。<br />　　20. get remote-file[local-file]： 将远程主机的文件remote-file传至本地硬盘的local-file。<br />　　21. glob：设置mdelete，mget，mput的文件名扩展，缺省时不扩展文件名，同命令行的-g参数。<br />　　22. hash：每传输1024字节，显示一个hash符号(#)。<br />　　23. help[cmd]：显示ftp内部命令cmd的帮助信息，如：help get。<br />　　24. idle[seconds]：将远程服务器的休眠计时器设为[seconds]秒。<br />　　25. image：设置二进制传输方式(同binary)。<br />　　26. lcd[dir]：将本地工作目录切换至dir。<br />　　27. ls[remote-dir][local-file]：显示远程目录remote-dir， 并存入本地文件local-file。<br />　　28. macdef macro-name：定义一个宏，遇到macdef下的空行时，宏定义结束。<br />　　29. mdelete[remote-file]：删除远程主机文件。<br />　　30. mdir remote-files local-file：与dir类似，但可指定多个远程文件，如： mdir *.o.*.zipoutfile 。<br />　　31. mget remote-files：传输多个远程文件。<br />　　32. mkdir dir-name：在远程主机中建一目录。<br />　　33. mls remote-file local-file：同nlist，但可指定多个文件名。<br />　　34. mode[modename]：将文件传输方式设置为modename， 缺省为stream方式。<br />　　35. modtime file-name：显示远程主机文件的最后修改时间。<br />　　36. mput local-file：将多个文件传输至远程主机。<br />　　37. newer file-name： 如果远程机中file-name的修改时间比本地硬盘同名文件的时间更近，则重传该文件。<br />　　38. nlist[remote-dir][local-file]：显示远程主机目录的文件清单，并存入本地硬盘的local-file。<br />　　39. nmap[inpattern outpattern]：设置文件名映射机制， 使得文件传输时，文件中的某些字符相互转换，如：nmap $1.$2.$3[$1，$2].[$2，$3]，则传输文件a1.a2.a3时，文件名变为a1，a2。该命令特别适用于远程主机为非UNIX机的情况。<br />　　40. ntrans[inchars[outchars]]：设置文件名字符的翻译机制，如ntrans1R，则文件名LLL将变为RRR。<br />　　41. open host[port]：建立指定ftp服务器连接，可指定连接端口。<br />　　42. passive：进入被动传输方式。<br />　　43. prompt：设置多个文件传输时的交互提示。<br />　　44. proxy ftp-cmd：在次要控制连接中，执行一条ftp命令，该命令允许连接两个ftp服务器，以在两个服务器间传输文件。第一条ftp命令必须为open，以首先建立两个服务器间的连接。<br />　　45. put local-file[remote-file]：将本地文件local-file传送至远程主机。<br />　　46. pwd：显示远程主机的当前工作目录。<br />　　47. quit：同bye，退出ftp会话。<br />　　48. quote arg1，arg2&#8230;：将参数逐字发至远程ftp服务器，如：quote syst。<br />　　49. recv remote-file[local-file]：同get。<br />　　50. reget remote-file[local-file]：类似于get，但若local-file存在，则从上次传输中断处续传。<br />　　51. rhelp[cmd-name]：请求获得远程主机的帮助。<br />　　52. rstatus[file-name]：若未指定文件名，则显示远程主机的状态，否则显示文件状态。<br />　　53. rename[from][to]：更改远程主机文件名。<br />　　54. reset：清除回答队列。<br />　　55. restart marker：从指定的标志marker处，重新开始get或put，如：restart 130。<br />　　56. rmdir dir-name：删除远程主机目录。<br />　　57. runique：设置文件名唯一性存储。<br />　　58. send local-file[remote-file]：同put。<br />　　59. sendport：设置PORT命令的使用。<br />　　60. site arg1，arg2&#8230;：将参数作为SITE命令逐字发送至远程ftp主机。<br />　　61. size file-name：显示远程主机文件大小，如：site idle 7200。<br />　　62. status：显示当前ftp状态。<br />　　63. struct[struct-name]：将文件传输结构设置为struct-name，缺省时使用stream结构。<br />　　64. sunique：将远程主机文件名存储设置为唯一(与runique对应)。<br />　　65. system：显示远程主机的操作系统类型。<br />　　66. tenex：将文件传输类型设置为TENEX机的所需的类型。<br />　　67. tick：设置传输时的字节计数器。<br />　　68. trace：设置包跟踪。<br />　　69. type[type-name]：设置文件传输类型为type-name，缺省为ascii，如：type binary，设置二进制传输方式。<br />　　70. umask[newmask]：将远程服务器的缺省umask设置为newmask，如：umask 3。<br />　　71. user user-name[password][account]：向远程主机表明自己的身份，需要口令时，必须输入口令，如：user anonymous my@email。<br />　　72. verbose：同命令行的-v参数，即设置详尽报告方式，ftp服务器的所有响应都将显示给用户，缺省为on。<br />　　73. ?[cmd]：同help。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/159.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

