<?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; debug</title>
	<atom:link href="http://www.donevii.com/post/tag/debug/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>Mac 下安装 PHP 扩展 vld &amp; xhprof</title>
		<link>http://www.donevii.com/post/974.html</link>
		<comments>http://www.donevii.com/post/974.html#comments</comments>
		<pubDate>Thu, 06 Jan 2011 03:26:57 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[vld]]></category>
		<category><![CDATA[xhprof]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=974</guid>
		<description><![CDATA[最近因为经常离线调试，所以开始重新在本机搭环境，还好 Mac 原本就自带了 PHP 。 [515][MacBookPro: /tmp]$ which php /usr/bin/php [516][MacBookPro: /tmp]$ php --version PHP 5.3.3 (cli) (built: Aug 22 2010 19:41:55) Copyright (... ]]></description>
			<content:encoded><![CDATA[<p>最近因为经常离线调试，所以开始重新在本机搭环境，还好 <a href="http://www.donevii.com/post/tag/mac" class="st_tag internal_tag" rel="tag" title="Posts tagged with mac">Mac</a> 原本就自带了 <a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">PHP</a> 。</p>
<pre name="code" class="shell">
[515][MacBookPro: /tmp]$ which php
/usr/bin/php
[516][MacBookPro: /tmp]$ php --version
PHP 5.3.3 (cli) (built: Aug 22 2010 19:41:55)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
</pre>
<p>既然有 php 那就先试试直接用 pecl 来安装。</p>
<pre name="code" class="shell">
sudo pecl install -f <a href="http://www.donevii.com/post/tag/vld" class="st_tag internal_tag" rel="tag" title="Posts tagged with vld">vld</a>
sudo pecl install -f <a href="http://www.donevii.com/post/tag/xhprof" class="st_tag internal_tag" rel="tag" title="Posts tagged with xhprof">xhprof</a>
</pre>
<p>不过安装 xhprof 时提示说要在扩展的目录里，查了一下 <a href="http://pecl.php.net/bugs/bug.php?id=16438&#038;edit=1">PECL Bug #16438</a> 里面说是 pecl 里 xhprof 包的问题。那么问题也就很好解决了，直接把源码包下载下来安装即可。</p>
<pre name="code" class="shell">
wget http://pecl.php.net/get/xhprof-0.9.2.tgz
tar zxf xhprof-0.9.2.tgz
cd xhprof-0.9.2/extension
phpize
./configure
make
make install
</pre>
<p>然后修改 /etc/php.ini 如果没有这个文件就 sudo cp /etc/php.ini.default /etc/php.ini。<br />
在 php.ini 中增加 extension=vld.so 和 extension=xhprof.so 和针对这两个扩展的详细配置，这个可以在网上搜到。</p>
<p>然后在 ~/.bash_profile 里增加 alias phpo=&#8217;php -dvld.active=1&#8242;<br />
以后再打 phpo xxxx.php 就可以看到 vld 的效果了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/974.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>require_once 和 require 的性能比较</title>
		<link>http://www.donevii.com/post/896.html</link>
		<comments>http://www.donevii.com/post/896.html#comments</comments>
		<pubDate>Wed, 08 Jul 2009 09:15:45 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[html]]></category>

		<guid isPermaLink="false">http://www.donevii.com/post/896.html</guid>
		<description><![CDATA[之前大家都是在程序里写上简单的 require_once 和 require 然后直接跑一遍 ab 来看时间，这回 Konstantin Rozinon 在 apache debug 模式下看了一下 lstat64 的操作数量，对比结果说 require_once 和 require 在时间... ]]></description>
			<content:encoded><![CDATA[<p>之前大家都是在程序里写上简单的 require_once 和 require 然后直接跑一遍 ab 来看时间，这回 Konstantin Rozinon 在 apache <a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">debug</a> 模式下看了一下 lstat64 的操作数量，对比结果说 require_once 和 require 在时间上相关非常非常小，但是在读文件时是用绝对路径还是相对路径对性能还是有一些影响，因为绝对路径会少一些 stat。</p>
<p>引用原文：<br /><small><code><span class="html">- When using absolute_path there are fewer stat() system calls.<br />- When using relative_path there are more stat() system calls because it has to start stat()ing from the current directory back up to / and then to the include/ directory.</span></code></small></p>
<p>个人习惯上还是推荐用 require_once，并且这个不是显示的写在各个文件中，而是在中心的 loader 里统一负责根据 <a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">php</a>5 的 __call 这个特性来去 require_once 相应的文件，一些性能上的损耗可以通过其它方式来弥补。比如 APC、XCache、Eacc 这些，opcode <a href="http://www.donevii.com/post/tag/cache" class="st_tag internal_tag" rel="tag" title="Posts tagged with cache">cache</a> 现在成了 <a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">PHP</a> 的必需品了。</p>
<p>原文：<a href="http://cn.php.net/require_once">点击进入</a></p>
<p>btw: zend studio 7 beta 真慢……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/896.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>管理者，请你远离产品开发/设计部门[转]</title>
		<link>http://www.donevii.com/post/740.html</link>
		<comments>http://www.donevii.com/post/740.html#comments</comments>
		<pubDate>Mon, 12 Jan 2009 13:03:53 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[life]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[技术]]></category>

		<guid isPermaLink="false">http://www.donevii.com/post/740.html</guid>
		<description><![CDATA[先说一个身边真正发生过的故事，可能大家会对故事情节感觉非常熟悉。 一家小型电子商务公司，管理者就是公司的创始人，他有些技术开发背景。因为产品面向海外市场，他也比较关注产品... ]]></description>
			<content:encoded><![CDATA[<p>先说一个身边真正发生过的故事，可能大家会对故事情节感觉非常熟悉。</p>
<p>一家小型电子商务公司，管理者就是公司的创始人，他有些技术开发背景。因为产品面向海外市场，他也比较关注产品设计与可用性。由于他对自己的技术、设计能力的自信，总是对开发部与设计部成员的能力持怀疑态度，经常插手他们的工作。</p>
<p>一次，开发人员就新产品需求、设计文档的要求，提出开发方案A。这位管理者看后，以其经验判断认为不理想，并给出方案B。开发人员觉得方案B有些问题，但一时又没有找到有说服力的例证，无奈只好以此方案进行开发。</p>
<p>果然，在开发过程中，由于管理者仓促间所提出方案，在设计上确实存在不合理的疏漏，导致项目出现了一些问题。当开发人员想方设法将问题一一解决后，突然发现，这个DEBUG后的开发方案B，已经变得与他们最初提出的方案A并无二致。</p>
<p>而此时，该项目已经严重超期，那位管理者还为此非常不满，认为是开发人员能力的问题导致的。此后，管理者对开发工作的介入变得更多，而开发人员也开始变<br />
化，一部分对领导的这种超权行为越来越不满意，矛盾变得更加激化，后面工作中的沟通变得更加困难；另一部分则变得越来越没有积极性，领导要求怎么做就怎么<br />
做。</p>
<p>刚好看到UCDChina.com中的一篇文章《<a href="http://ucdchina.com/blog/?p=4" target="_blank">管理者不应直接参与产品的开发与设计</a>》，感觉说得太有道理了。上面这个故事，可以用来充实文章的论据。</p>
<p>其实团队管理者关注团队产品的成败，是非常正常的心态。他们插手设计、开发工作，无非是希望把产品更得更好，动机是无庸质疑的。尽管如此，还是不建议管理<br />
者过多的介入具体的开发与设计工作，即使是领域专家型的管理者，过多的插手具体设计、开发工作，也得不到预期的结果，可能对于项目来说，往往事与愿违，由<br />
此产生的恶性干扰多于良性的指导，这是得不偿失的。</p>
<p>为什么会这样？原因很多：</p>
<p>1、因为管理者与团队成员的权重不同，有管理者参与的项目，往往不能非常公平地对待其它项目涉众。尽管，管理者本意是以其对项目的理解和自身的经验，为设<br />
计、开发团队提供一些指导和建议，至少也会增加一种思路。但往往事与愿违，管理者介入后，一般会导致所有项目涉众的思维模式，会被管理者所左右，就因为他<br />
是团队的管理者。</p>
<p>大家想想，是否经常遇到这样的情况，设计、开发人员深思熟虑后形成的方案，经常因为管理者的一点儿质疑，而被否决；而管理者的灵光一闪，都可能形成一个决<br />
策，如果其它团队成员想到推翻它，必须经过周密、详实的举证与论述，这本就不公平，对项目也绝对没有好处，这会影响到团队成员的思路，甚至导致他们逐渐推<br />
动思考的动力。</p>
<p>2、因为技术背景与对项目的关注点不同，管理者与设计、开发人员会处在不同层面，看问题角度肯定是不同的。其实，能从多个不同角度看待产品，这本来是好事，可以把问题考虑得更全面一些。但如果以管理者的角度，去干扰设计、开发中的问题，那就是另外一码儿事了。</p>
<p>《论语•泰伯》：“子曰：不在其位，不谋其政。”</p>
<p>这句话说得非常好，这不是推卸责任意思，而恰恰是出于更负责的角度考虑。为了便于理解，这里把“位”理解为“职位”。</p>
<p>每个职位有不同的职责，职责会影响人的立场，不同立场、知识背景的人理解、处理同一个问题，其结果肯定是不一样的。也许管理者认为自己可以做到“换位思考<br />
”，即便如此也是搁靴搔痒的状态，其结果绝对差强人意。比如，管理者明白不能让UI设计师去考虑代码优化的问题，那又为什么自己去犯同样的错误呢？</p>
<p>正所谓术业有专攻，专业的工作还是让专业的人去做，那才可能达到令人满意的结果。</p>
<p>3、有人说，在IT行业，许多管理者都是优秀程序员或策划、设计师出身，这种领域专家型的管理者插手做具体设计、开发工作，应该有对项目、对团队成员有帮助。</p>
<p>其实不然，前面提到的两点问题，对于这样的管理者也依然存在。而且，文章开头提到的那位管理者也曾经是开发人员，本身也是位不错的产品设计师。为什么团队成员在他的指导下，项目进展依然不顺利呢？</p>
<p>从事过产品设计、程序开发工作的朋友应该很清楚，这样的工作需要投入大量的时间与精力，这是一个反复尝试与迭代的过程。好的设计与优秀的编码，绝对不是通<br />
过纸上谈兵或灵光一闪就可以得到的（当然，这个世界是有天才存在的，也许他们拍拍脑袋就可以把产品设计得非常完美，程序编码也可以没有任何BUG，但毕竟<br />
这种天才少得没有说服力）。有的时候，即使写好伪代码，也不能百之百的确保业务逻辑没问题。</p>
<p>而团队的管理者，往往事务缠身，他们没有精力（也不应该）深入于其中任何一项具体工作，那样就会犯下过于关注细节的管理大忌。而浅尝辄止的心态，恰恰又是做好设计与开发工作的大忌。这样看来，管理者兼顾设计、开发工作，并取得好的结果，根本是一项不可能完成的任务。</p>
<p>当然，领域专家型的管理者是可遇而不可求的，他丰富的经验与思路都是对团队成员有帮助的，但仅此而已，具体的设计、开发工作还是应该让设计师和程序员来做。</p>
<p>基于上面分析，如果管理者仍执意要插手设计与开发工作，就必须保证自己的观点（或决策）是100%准确与全面的，这样才不会对项目有负面影响。</p>
<p>当然，这样的要求是不合理的，也没有人敢做此承诺，所以，管理者们还去做好本职工作吧，那里才是发挥你们特长的地方。好的管理者，要懂得放权，要对团队成员应该有足够的信任，相信他们的工作能力，也相信他们的工作态度。正所谓：用人不疑，疑人不用。</p>
<p>如果管理者实在想参与设计、开发工作，那就干脆转行吧。</p>
<p>转自：http://<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/s/<a href="http://www.donevii.com/post/tag/blog" class="st_tag internal_tag" rel="tag" title="Posts tagged with blog">blog</a>_564cabe30100bxmb.<a href="http://www.donevii.com/post/tag/html" class="st_tag internal_tag" rel="tag" title="Posts tagged with html">html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/740.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>解决 Zend Studio for Eclipse 6.x.x 启动时的 bug</title>
		<link>http://www.donevii.com/post/624.html</link>
		<comments>http://www.donevii.com/post/624.html#comments</comments>
		<pubDate>Fri, 14 Nov 2008 03:54:16 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[life]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.donevii.com/post/624.html</guid>
		<description><![CDATA[在 Zend Studio for Eclipse 时会有显示 Building PHP Project 的错误，解决的办法很简单，在 preference 里的 General 中设置 Startup and Shutdown ，把 Advanced Debugger UI Plug-in 和 PDT Debug Daemon Plug-in 的对号去掉既可... ]]></description>
			<content:encoded><![CDATA[<p>在 Zend Studio for Eclipse 时会有显示 Building <a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">PHP</a> Project 的错误，解决的办法很简单，在 preference 里的 General 中设置 Startup and Shutdown ，把 Advanced Debugger UI Plug-in 和 PDT <a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">Debug</a> Daemon Plug-in 的对号去掉既可。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/624.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>终于找到在 firefox 下替代 httpwatch 的软件了, httpfox</title>
		<link>http://www.donevii.com/post/544.html</link>
		<comments>http://www.donevii.com/post/544.html#comments</comments>
		<pubDate>Sun, 05 Oct 2008 11:20:39 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[life]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.donevii.com/post/544.html</guid>
		<description><![CDATA[一直不放弃 ie 就在 ff 上没有找到哪几个插件能代替我的无敌 debug 组合 debugbar + compain.JS + httpwatch + iedevtoolbar 现在可以用 firebug + httpwatch + yslow + web developer 来取代 ie 了，太爽了 httpfox 还是免费... ]]></description>
			<content:encoded><![CDATA[<p>一直不放弃 ie 就在 ff 上没有找到哪几个插件能代替我的无敌 <a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">debug</a> 组合 debugbar + compain.JS + httpwatch + iedevtoolbar</p>
<p>现在可以用 firebug + httpwatch + yslow + <a href="http://www.donevii.com/post/tag/web" class="st_tag internal_tag" rel="tag" title="Posts tagged with web">web</a> developer 来取代 ie 了，太爽了 httpfox 还是免费的，哈。</p>
<p><a href="http://www.flickr.com/photos/69642641@N00/311798834"><img src="http://farm1.static.flickr.com/118/311798834_24414f5b74.jpg" /></a></p>
<p>httpwatch</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/544.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[分享] 某知名手机平台的XML Parser源代码</title>
		<link>http://www.donevii.com/post/353.html</link>
		<comments>http://www.donevii.com/post/353.html#comments</comments>
		<pubDate>Sun, 25 Nov 2007 06:21:27 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[c/c++/c#]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[parser]]></category>
		<category><![CDATA[ror]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[平台]]></category>
		<category><![CDATA[手机]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://www.donevii.com/post/353.html</guid>
		<description><![CDATA[    今天心情不错~ 分享一下小弟06年在某手机公司写的XML parser. 虽然当时脑子里还没有FSM的概念, 但代码逻辑还算清晰, 颇有成就感! 结构比较简单, 按DOM方式把指定文件解析成节点树, 另外提... ]]></description>
			<content:encoded><![CDATA[<p>    今天心情不错~ 分享一下小弟06年在某手机公司写的XML <a href="http://www.donevii.com/post/tag/parser" class="st_tag internal_tag" rel="tag" title="Posts tagged with parser">parser</a>.<br />
虽然当时脑子里还没有FSM的概念, 但代码逻辑还算清晰, 颇有成就感!<br />
结构比较简单, 按DOM方式把指定文件解析成节点树, 另外提供几个简单的查找函数.<br />
部分功能等完善, 过段时间再发一份功能比较完善的C++版本.</p>
<h3><strong>PLX_XMLParser.h</strong></h3>
<p>#if _MSC_VER &gt; 1000<br />
#pragma once<br />
#endif</p>
<p>#ifndef __XMLPARSE_H<br />
#define __XMLPARSE_H</p>
<p>#include</p>
<p>//////////////////////////////<br />
// Configure</p>
<p>#define USE_INLINE_FUNCTION<br />
#define USE_FILEBUFFER</p>
<p>//////////////////////////////<br />
// Constants</p>
<p>typedef enum {<br />
XMLERR_OK       = 0&#215;0,<br />
XMLERR_EFILE,       // failed to open file<br />
XMLERR_ALRDOPEN,    // already opened<br />
XMLERR_EDOC,<br />
XMLERR_EPARSE,<br />
} XMLERR;</p>
<p>typedef enum {<br />
NODETYPE_UNKN    = 0&#215;0,<br />
NODETYPE_ELEM   = 0&#215;1,<br />
NODETYPE_TEXT   = 0&#215;2,<br />
NODETYPE_COMM   = 0&#215;4,<br />
NODETYPE_INST   = 0&#215;8, // Not support<br />
//NODETYPE_USEFUL = NODETYPE_ELEM|NODETYPE_TEXT,<br />
//NODETYPE_ALL    = NODETYPE_ELEM|NODETYPE_TEXT|NODETYPE_COMM|NODETYPE_INST,<br />
} NODETYPE;</p>
<p>typedef enum {<br />
DSTAT_UNOPEN    = 0&#215;0,<br />
DSTAT_OPENED    = 0&#215;1,<br />
} DOCSTAT;</p>
<p>typedef enum {<br />
ISTAT_STOP      = 0&#215;0,<br />
ISTAT_CONTINUE  = 0&#215;1,<br />
ISTAT_PASS      = 0&#215;2,<br />
} ITERSTAT;</p>
<p>enum {    MAXLEN_BSTR    = 256 };</p>
<p>//////////////////////////////<br />
// Structures</p>
<p>struct tagBString<br />
{<br />
LONG    m_lLength;<br />
union   {<br />
CHAR    m_paStr[1];<br />
LPCSTR  m_pszStr;<br />
};<br />
};</p>
<p>typedef struct tagBString       BSTRING;<br />
typedef struct tagBString       *LPBSTRING;<br />
typedef struct tagBString const *LPCBSTRING;</p>
<p>struct tagXMLAttrib;<br />
typedef struct tagXMLAttrib            XMLATTRIB;<br />
typedef struct tagXMLAttrib            *LPXMLATTRIB;<br />
typedef struct tagXMLAttrib    const    *LPCXMLATTRIB;</p>
<p>struct tagXMLAttrib<br />
{<br />
LPBSTRING   m_pbstrName;<br />
LPBSTRING   m_pbstrValue;<br />
LPXMLATTRIB    m_pNext;<br />
};</p>
<p>struct tagXMLNode;<br />
typedef struct tagXMLNode       XMLNODE;<br />
typedef struct tagXMLNode       *LPXMLNODE;<br />
typedef struct tagXMLNode const *LPCXMLNODE;</p>
<p>struct tagXMLNode<br />
{<br />
NODETYPE    m_eNodeType;<br />
LONG        m_lDepth;</p>
<p>LPBSTRING   m_pbstrTag;</p>
<p>LONG        m_lChildNum;<br />
LONG        m_lChildNum_Elem;</p>
<p>LPXMLNODE    m_pRoot;<br />
LPXMLNODE   m_pParent;<br />
LPXMLNODE   m_pFirstChild;<br />
LPXMLNODE   m_pLastChild;<br />
LPXMLNODE   m_pPrevSibling;<br />
LPXMLNODE   m_pNextSibling;</p>
<p>LONG        m_lAttribNum;<br />
LPXMLATTRIB m_pFirstAttrib;<br />
};</p>
<p>struct tagXMLDocument<br />
{<br />
DOCSTAT     m_eDocStat;<br />
LPXMLNODE   m_lpRootNode;<br />
};</p>
<p>typedef struct tagXMLDocument       XMLDOCUMENT;<br />
typedef struct tagXMLDocument       *LPXMLDOCUMENT;<br />
typedef struct tagXMLDocument const *LPCXMLDOCUMENT;</p>
<p>//////////////////////////////<br />
// Types</p>
<p>typedef ITERSTAT    (CALLBACK *LPFNNODEPROC)( LPCXMLNODE pNode, LPVOID pvParam );</p>
<p>//////////////////////////////<br />
// Macros</p>
<p>#if    defined(USE_INLINE_FUNCTION)</p>
<p>#define BSTR_C( pBStr )                     (&amp;((pBStr)-&gt;m_paStr[0]))<br />
#define BSTR_CAST( pvAnyType )              ((LPBSTRING)pvAnyType)<br />
#define    BSTR_LEN( pBStr )                   ((pBStr)-&gt;m_lLength)<br />
#define BSTR_ALLOC( pszStr )                AllocBString( pszStr, (NULL != (pszStr) ? ((LONG)strlen(pszStr)) : (0L)) )<br />
#define BSTR_ALLOCEX( pszStr, nLen )        AllocBString( pszStr, (LONG)nLen )<br />
#define BSTR_FREE( pBStr )                  free( pBStr )<br />
#define BSTR_SAFEFREE( pBStr )              if ( NULL != pBStr ) { free( pBStr ); pBStr = NULL; }<br />
#define BSTR_EQUAL( pBStrL, pBStrR ) \<br />
( (BSTR_LEN(pBStrL) == BSTR_LEN(pBStrR) &amp;&amp; 0 == strcmp(BSTR_C(pBStrL), BSTR_C(pBStrL))) ? \<br />
TRUE : FALSE )<br />
#define BSTR_EQUAL_STATIC( pBStr, szStatic ) \<br />
( (BSTR_LEN(pBStr) == (LONG)(sizeof(szStatic) &#8211; 1) &amp;&amp; 0 == strcmp(BSTR_C(pBStr), szStatic)) ? \<br />
TRUE : FALSE )<br />
#define BSTR_EQUAL_CSTR( pBStr, pszStr ) \<br />
( (BSTR_LEN(pBStr) == (LONG)strlen(pszStr) &amp;&amp; 0 == strcmp(BSTR_C(pBStr), pszStr)) ? \<br />
TRUE : FALSE )</p>
<p>#define    <a href="http://www.donevii.com/post/tag/xml" class="st_tag internal_tag" rel="tag" title="Posts tagged with xml">XML</a>_GetRootNode( pDoc )             ((NULL == (pDoc) || (pDoc)-&gt;m_eDocStat != DSTAT_OPENED) ? NULL : (pDoc)-&gt;m_lpRootNode)<br />
#define    XML_GetNodeType( pNode )             (NULL != (pNode) ? (pNode)-&gt;m_eNodeType : NODETYPE_UNKN)<br />
#define    XML_GetNodeDepth( pNode )            (NULL != (pNode) ? (pNode)-&gt;m_lDepth : (-1L))<br />
#define    XML_GetNodeParent( pNode )             (NULL != (pNode) ? (pNode)-&gt;m_pParent : NULL)<br />
#define    XML_GetNodeFirstChild( pNode )         (NULL != (pNode) ? (pNode)-&gt;m_pFirstChild : NULL)<br />
#define    XML_GetNodeLastChild( pNode )         (NULL != (pNode) ? (pNode)-&gt;m_pLastChild : NULL)<br />
#define    XML_GetNodeChildNum( pNode )         (NULL != (pNode) ? (pNode)-&gt;m_lChildNum : (0L))<br />
#define    XML_GetNodeChildNum_Elem( pNode )     (NULL != (pNode) ? (pNode)-&gt;m_lChildNum_Elem : (0L))<br />
#define    XML_GetNodePrevSibling( pNode )     (NULL != (pNode) ? (pNode)-&gt;m_pPrevSibling : NULL)<br />
#define    XML_GetNodeNextSibling( pNode )     (NULL != (pNode) ? (pNode)-&gt;m_pNextSibling : NULL)<br />
#define    XML_GetNodeTagName( pNode )         (NULL != (pNode) ? (pNode)-&gt;m_pbstrTag : NULL)<br />
#define    XML_GetNodeAttribNum( pNode )         (NULL != (pNode) ? (pNode)-&gt;m_lAttribNum : (0L))<br />
#define    XML_GetNodeFirstAttrib( pNode )     (NULL != (pNode) ? (pNode)-&gt;m_pFirstAttrib : NULL)<br />
#define    XML_GetNodeNextAttrib( pAttr )         (NULL != (pAttr) ? (pAttr)-&gt;m_pNext : NULL)<br />
#define XML_GetAttribValueBString( pAttr )  (NULL != (pAttr) ? (pAttr)-&gt;m_pbstrValue) : NULL)<br />
#define XML_GetAttribValueCString( pAttr )  (NULL != (pAttr) ? BSTR_C((pAttr)-&gt;m_pbstrValue) : NULL)<br />
#define XML_GetAttribValueLong( pAttr )     (NULL != (pAttr) ? (LONG)strtol(BSTR_C((pAttr)-&gt;m_pbstrValue), NULL, 0) : (0L))<br />
#define XML_GetAttribValueInt( pAttr )      (NULL != (pAttr) ? (int)strtol(BSTR_C((pAttr)-&gt;m_pbstrValue), NULL, 0) : (0))</p>
<p>#endif</p>
<p>//////////////////////////////<br />
// Function prototypes</p>
<p>#if defined(__cplusplus)<br />
extern &#8220;C&#8221; {<br />
#endif</p>
<p>size_t      strlen_when( LPCSTR lpszStr, CHAR ch );<br />
size_t        strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet );<br />
LPCSTR        strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet );<br />
LPCSTR        strchr_skipws( LPCSTR lpszStr );</p>
<p>LPBSTRING   AllocBString( LPCSTR lpszStr, LONG lLen );</p>
<p>XMLERR      XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve );<br />
XMLERR      XML_CloseDocument( LPXMLDOCUMENT pDoc );<br />
LPXMLNODE    XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen );<br />
LPXMLATTRIB    XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen );<br />
LPXMLNODE    XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL IncludeThis );<br />
LONG         XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam );</p>
<p>#if defined(__cplusplus)<br />
}   // extern &#8220;C&#8221; {<br />
#endif</p>
<p>#endif // #ifndef __XMLPARSE_H</p>
<h3>PLX_XMLParser.c</h3>
<p>#include &lt;assert.h&gt;<br />
#include &lt;fcntl.h&gt;<br />
#include &lt;io.h&gt;<br />
#if defined(<a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">DEBUG</a>) || defined(_<a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">DEBUG</a>)<br />
#include &lt;stdio.h&gt;<br />
#endif</p>
<p>#include &#8220;XMLParse.h&#8221;</p>
<p>//#pragma warning(disable:4305)</p>
<p>//////////////////////////////<br />
// Configure</p>
<p>//#define  USE_MEMORY_HEAP</p>
<p>#ifdef  USE_FILEBUFFER  // Whether use file system with os-layer buffer</p>
<p>#define INVALID_FILE_HANDLE         ((int)-1)<br />
#define FILE_HANDLE                 int</p>
<p>#define MODE_RDONLY                 (O_RDONLY)<br />
#define FILE_OPEN(pszFile,mode)     open( pszFile, mode )<br />
#define FILE_READ(hFile,pbuf,size)  read(hFile, (LPVOID)pbuf, size)<br />
#define FILE_SEEK(hFile,off,pos)    lseek( hFile, off, pos )<br />
#define FILE_CLOSE(hFile)           close( hFile )</p>
<p>#else</p>
<p>#define INVALID_FILE_HANDLE         ((FILE *)NULL)<br />
#define FILE_HANDLE                 FILE *</p>
<p>#define MODE_RDONLY                 (&#8220;r&#8221;)<br />
#define FILE_OPEN(pszFile,mode)     fopen( pszFile, mode )<br />
#define FILE_READ(hFile,pbuf,size)  fread((LPVOID)pbuf, size, 1, hFile)<br />
#define FILE_SEEK(hFile,off,pos)    fseek( hFile, off, pos )<br />
#define FILE_CLOSE(hFile)           fclose( hFile )</p>
<p>#endif</p>
<p>//////////////////////////////<br />
// Constants</p>
<p>enum {    MAXLEN_READBUF    = 1024 };</p>
<p>typedef enum {<br />
PSTAT_STOP      = 0&#215;0,<br />
PSTAT_INITIAL,<br />
PSTAT_FINAL,<br />
PSTAT_DECL_BEG,<br />
PSTAT_DECL_END,<br />
PSTAT_ELEM_BEG,<br />
PSTAT_ELEM_END,<br />
PSTAT_TEXT_BEG,<br />
PSTAT_TEXT_END,<br />
PSTAT_CDATA_BEG,<br />
PSTAT_CDATA_END,<br />
PSTAT_COMM_BEG,<br />
PSTAT_COMM_END,<br />
PSTAT_ERROR,<br />
} PARSESTAT;</p>
<p>//////////////////////////////<br />
// Macros</p>
<p>#define ZERO_MEMORY(p, size) \<br />
( memset((LPVOID)(p), 0&#215;0, (size_t)size) )</p>
<p>#define is_WhiteSpace(ch)   (((ch) == &#8216; &#8216;  || (ch) == &#8216;\t&#8217;) ? TRUE : FALSE)<br />
#define is_LineBreak(ch)    (((ch) == &#8216;\r&#8217; || (ch) == &#8216;\n&#8217;) ? TRUE : FALSE)<br />
#define is_LeftBracket(ch)    ((ch) == &#8216;&lt;&#8217; ? TRUE : FALSE)<br />
#define is_RightBracket(ch)    ((ch) == &#8216;&gt;&#8217; ? TRUE : FALSE)</p>
<p>#define is_BufferEmpty(ps)  ((ps)-&gt;m_lReadCursor &gt;= (ps)-&gt;m_lReadSize ? TRUE : FALSE)<br />
#define get_BufferChar(ps)  ((CHAR)((ps)-&gt;m_aReadBuf[(ps)-&gt;m_lReadCursor]))</p>
<p>#define is_FirstChild(pn)    ((pn)-&gt;m_pPrevSibling == NULL ? TRUE : FALSE)<br />
#define is_LastChild(pn)    ((pn)-&gt;m_pNextSibling == NULL ? TRUE : FALSE)</p>
<p>//////////////////////////////<br />
// Structures</p>
<p>struct tagXMLParseStat<br />
{<br />
PARSESTAT   m_eParseStat;<br />
LONG        m_lDepth;<br />
LPXMLNODE    m_pRootNode;<br />
LPXMLNODE    m_pLastNode;</p>
<p>FILE_HANDLE    m_hOpenFile;<br />
LONG        m_lFileCursor;<br />
LONG        m_lFileLength;</p>
<p>LONG        m_lLineNo;<br />
LONG        m_lReadCursor;<br />
LONG        m_lReadSize;<br />
BYTE        m_aReadBuf[MAXLEN_READBUF];<br />
};<br />
typedef struct tagXMLParseStat            XMLPARSESTAT;<br />
typedef struct tagXMLParseStat            *LPXMLPARSESTAT;<br />
typedef struct tagXMLParseStat    const    *LPCXMLPARSESTAT;</p>
<p>struct tagXMLIterator<br />
{<br />
LONG            m_lCount;<br />
LPFNNODEPROC    m_pfnProc;<br />
LPVOID          m_pvParam;<br />
LPXMLNODE       m_pStation;<br />
};<br />
typedef struct tagXMLIterator       XMLITERFATOR;<br />
typedef struct tagXMLIterator       *LPXMLITERFATOR;<br />
typedef struct tagXMLIterator const *LPCXMLITERFATOR;</p>
<p>/*struct tagMemoryPage<br />
{<br />
LONG    lGranu ;<br />
LONG    lSize;<br />
LPVOID  pvPage;<br />
BYTE    bUseFlags[1];<br />
};<br />
typedef struct tagMemoryPage        MEMORYPAGE;<br />
typedef struct tagMemoryPage        *LPMEMORYPAGE;<br />
typedef struct tagMemoryPage const  *LPCMEMORYPAGE;*/</p>
<p>//////////////////////////////<br />
// Function prototypes</p>
<p>#if defined(__cplusplus)<br />
extern &#8220;C&#8221; {<br />
#endif</p>
<p>static void        XML_FreeNodeTree( LPXMLNODE pNode );<br />
static void        XML_FreeAttribList( LPXMLATTRIB pAttrib );<br />
static void     XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator );<br />
static BOOL     XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam );</p>
<p>static BOOL        Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult );<br />
static int        Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf );<br />
static BOOL        Parser_ReadStream( LPXMLPARSESTAT pParseStat );<br />
static void        Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static void        Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );<br />
static BOOL        Parser_OnFinal( LPXMLPARSESTAT pParseStat );<br />
static BOOL        Parser_OnError( LPXMLPARSESTAT pParseStat );</p>
<p>//#if defined(USE_MEMORY_HEAP)<br />
//static LPVOID   MemoryHeap_Create( LONG lInitialGranu, LONG lInitialSize );<br />
//static BOOL     MemoryHeap_Destroy( LPVOID );<br />
//static LPVOID   MemoryHeap_Alloc( void );<br />
//static void     MemoryHeap_Free( LPVOID pvBlock );<br />
//#endif</p>
<p>#if defined(__cplusplus)<br />
}   // extern &#8220;C&#8221; {<br />
#endif</p>
<p>//////////////////////////////<br />
// Function implementations</p>
<p>#if defined(__cplusplus)<br />
extern &#8220;C&#8221; {<br />
#endif</p>
<p>/*********************************************************************\<br />
* Function: strlen_when<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
size_t strlen_when( LPCSTR lpszStr, CHAR ch )<br />
{<br />
register size_t nLen;<br />
assert( NULL != lpszStr );<br />
for ( nLen = 0; *lpszStr != ch &amp;&amp; *lpszStr != &#8216;\0&#8242;;    lpszStr++, nLen++ )<br />
;<br />
return nLen;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: strlen_notin<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
size_t strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet )<br />
{<br />
register size_t nLen;<br />
assert( NULL != lpszStr );<br />
for ( nLen = 0; *lpszStr != &#8216;\0&#8242; &amp;&amp; NULL == strchr(lpszSet, *lpszStr); lpszStr++, nLen++ )<br />
;<br />
return nLen;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: strchr_notin<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
LPCSTR strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet )<br />
{<br />
assert( NULL != lpszStr );<br />
for ( ; *lpszStr != &#8216;\0&#8242; &amp;&amp; NULL == strchr(lpszSet, *lpszStr); lpszStr++ )<br />
;<br />
return lpszStr;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: strchr_skipws<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
LPCSTR strchr_skipws( LPCSTR lpszStr )<br />
{<br />
assert( NULL != lpszStr );<br />
for ( ; *lpszStr != &#8216;\0&#8242; &amp;&amp; is_WhiteSpace(*lpszStr); lpszStr++ )<br />
;<br />
return lpszStr;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: AllocBString<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
LPBSTRING AllocBString( LPCSTR lpszStr, LONG lLen )<br />
{<br />
LPBSTRING pBStr = (LPBSTRING)malloc( sizeof(LONG) + lLen + 1 );<br />
assert( NULL != pBStr );</p>
<p>pBStr-&gt;m_lLength = lLen;<br />
strncpy( &amp;pBStr-&gt;m_paStr[0], lpszStr, lLen );<br />
pBStr-&gt;m_paStr[lLen] = &#8216;\0&#8242;;</p>
<p>return pBStr;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_OpenDocument<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
XMLERR XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve )<br />
{<br />
BOOL            bRet;<br />
FILE_HANDLE        hFile;<br />
XMLPARSESTAT    xmlParseStat;</p>
<p>assert( NULL != pDoc );<br />
assert( NULL != lpszFileName );</p>
<p>if ( pDoc-&gt;m_eDocStat == DSTAT_OPENED )<br />
return XMLERR_ALRDOPEN;</p>
<p>ZERO_MEMORY( &amp;xmlParseStat, sizeof(XMLPARSESTAT) );</p>
<p>hFile = FILE_OPEN( lpszFileName, MODE_RDONLY );<br />
if ( INVALID_FILE_HANDLE == hFile )<br />
return XMLERR_EFILE;</p>
<p>xmlParseStat.m_hOpenFile    = hFile;<br />
xmlParseStat.m_lFileCursor    = 0;<br />
xmlParseStat.m_lFileLength    = FILE_SEEK( hFile, 0, SEEK_END );<br />
FILE_SEEK( hFile, 0, SEEK_SET );</p>
<p>xmlParseStat.m_lDepth = 0;<br />
xmlParseStat.m_lLineNo = 1;<br />
bRet = Parser_RoutineStart( &amp;xmlParseStat, pDoc );<br />
if ( FALSE == bRet )<br />
{<br />
FILE_CLOSE( hFile );<br />
return XMLERR_EPARSE;<br />
}</p>
<p>pDoc-&gt;m_eDocStat    = DSTAT_OPENED;<br />
pDoc-&gt;m_lpRootNode    = xmlParseStat.m_pRootNode;<br />
FILE_CLOSE( hFile );<br />
return XMLERR_OK;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_CloseDocument<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
XMLERR XML_CloseDocument( LPXMLDOCUMENT pDoc )<br />
{<br />
if ( NULL != pDoc &amp;&amp; pDoc-&gt;m_eDocStat == DSTAT_OPENED )<br />
{<br />
XML_FreeNodeTree( pDoc-&gt;m_lpRootNode );<br />
pDoc-&gt;m_lpRootNode = NULL;<br />
pDoc-&gt;m_eDocStat = DSTAT_UNOPEN;<br />
}<br />
return XMLERR_OK;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_GetTagString<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
int Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf )<br />
{<br />
int        nLen;<br />
CHAR    ch;<br />
CHAR    chTerm;<br />
BOOL    bInclude;</p>
<p>// Should to ensure barket match Here!</p>
<p>nLen = 0;<br />
for ( ;; )<br />
{<br />
if ( is_BufferEmpty(pParseStat) &amp;&amp; FALSE == Parser_ReadStream(pParseStat) )<br />
goto __RET;</p>
<p>ch = get_BufferChar(pParseStat);<br />
if ( ch == &#8216;\n&#8217; )<br />
pParseStat-&gt;m_lLineNo++;</p>
<p>if ( !is_WhiteSpace(ch) &amp;&amp; !is_LineBreak(ch) )<br />
break;</p>
<p>pParseStat-&gt;m_lReadCursor++;<br />
}</p>
<p>if ( is_LeftBracket(ch) )<br />
{<br />
chTerm = &#8216;&gt;&#8217;;<br />
bInclude = TRUE;<br />
}<br />
else<br />
{<br />
chTerm = &#8216;&lt;&#8217;;<br />
bInclude = FALSE;<br />
}</p>
<p>for ( ;; )<br />
{<br />
if ( is_BufferEmpty(pParseStat) &amp;&amp; FALSE == Parser_ReadStream(pParseStat) )<br />
break;</p>
<p>ch = get_BufferChar(pParseStat);<br />
if ( ch == &#8216;\n&#8217; )<br />
pParseStat-&gt;m_lLineNo++;</p>
<p>if ( ch == chTerm )<br />
{<br />
if ( FALSE != bInclude )<br />
{<br />
lpszBuf[nLen++] = chTerm;<br />
pParseStat-&gt;m_lReadCursor++;<br />
}<br />
break;<br />
}</p>
<p>lpszBuf[nLen++] = ch;<br />
pParseStat-&gt;m_lReadCursor++;<br />
}</p>
<p>__RET:<br />
lpszBuf[nLen] = &#8216;\0&#8242;;<br />
return nLen;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_ReadStream<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
BOOL Parser_ReadStream( LPXMLPARSESTAT pParseStat )<br />
{<br />
size_t    nSize;</p>
<p>pParseStat-&gt;m_lReadCursor    = 0;<br />
pParseStat-&gt;m_lReadSize    = 0;<br />
nSize = FILE_READ( pParseStat-&gt;m_hOpenFile, (LPVOID)&amp;pParseStat-&gt;m_aReadBuf[0], MAXLEN_READBUF );<br />
if ( nSize &lt;= 0 )<br />
return FALSE;</p>
<p>pParseStat-&gt;m_lReadSize        = (LONG)nSize;<br />
pParseStat-&gt;m_lFileCursor  += (LONG)nSize;<br />
return TRUE;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_RoutineStart<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
BOOL Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult )<br />
{<br />
BOOL    bRet;<br />
CHAR    szTag[256];</p>
<p>assert( NULL != pParseStat );</p>
<p>pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
while ( pParseStat-&gt;m_eParseStat != PSTAT_STOP )<br />
{<br />
switch ( pParseStat-&gt;m_eParseStat )<br />
{<br />
case PSTAT_INITIAL:     Parser_OnInitial( pParseStat, &amp;szTag[0] );        break;</p>
<p>case PSTAT_DECL_BEG:    Parser_OnDeclBegin( pParseStat, &amp;szTag[0] );    break;<br />
case PSTAT_DECL_END:    Parser_OnDeclEnd( pParseStat, &amp;szTag[0] );        break;</p>
<p>case PSTAT_ELEM_BEG:    Parser_OnElemBegin( pParseStat, &amp;szTag[0] );    break;<br />
case PSTAT_ELEM_END:    Parser_OnElemEnd( pParseStat, &amp;szTag[0] );      break;</p>
<p>case PSTAT_TEXT_BEG:    Parser_OnTextBegin( pParseStat, &amp;szTag[0] );    break;<br />
case PSTAT_TEXT_END:    Parser_OnTextEnd( pParseStat, &amp;szTag[0] );        break;</p>
<p>case PSTAT_CDATA_BEG:    Parser_OnCDATABegin( pParseStat, &amp;szTag[0] );    break;<br />
case PSTAT_CDATA_END:    Parser_OnCDATAEnd( pParseStat, &amp;szTag[0] );        break;</p>
<p>case PSTAT_COMM_BEG:    Parser_OnCommBegin( pParseStat, &amp;szTag[0] );    break;<br />
case PSTAT_COMM_END:    Parser_OnCommEnd( pParseStat, &amp;szTag[0] );        break;</p>
<p>case PSTAT_FINAL:        bRet = Parser_OnFinal( pParseStat );            break;<br />
case PSTAT_ERROR:        bRet = Parser_OnError( pParseStat );            break;</p>
<p>default:<br />
assert( !&#8221;Unknown parsing status!&#8221; );<br />
break;<br />
}<br />
}<br />
return bRet;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnInitial<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
int     nLen;<br />
assert( NULL != lpszTag );</p>
<p>lpszTag[0] = &#8216;\0&#8242;;</p>
<p>nLen = Parser_GetTagString( pParseStat, lpszTag );<br />
if ( nLen &lt;= 0 )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_STOP;<br />
return;<br />
}</p>
<p>if ( lpszTag[0] == &#8216;&lt;&#8217;  )<br />
{<br />
if ( lpszTag[1] == &#8216;?&#8217;)<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_DECL_BEG;<br />
}<br />
else if ( !strncmp(&amp;lpszTag[1], &#8220;!&#8211;&#8221;, 3) )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_COMM_BEG;<br />
}<br />
else if ( lpszTag[1] == &#8216;/&#8217; )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_ELEM_END;<br />
}<br />
else if ( isalpha(lpszTag[1]) )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_ELEM_BEG;<br />
}<br />
else if ( !strncmp(&amp;lpszTag[1], &#8220;![CDATA[", 8) )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_CDATA_BEG;<br />
}<br />
else<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_ERROR;<br />
}<br />
}<br />
else if ( NULL != pParseStat-&gt;m_pLastNode )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_TEXT_BEG;<br />
}<br />
else<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_ERROR;<br />
}<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnFinal<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
BOOL Parser_OnFinal( LPXMLPARSESTAT pParseStat )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_STOP;<br />
return TRUE;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnError<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
BOOL Parser_OnError( LPXMLPARSESTAT pParseStat )<br />
{<br />
XML_FreeNodeTree( pParseStat-&gt;m_pRootNode );<br />
pParseStat-&gt;m_pRootNode     = NULL;<br />
pParseStat-&gt;m_eParseStat = PSTAT_STOP;<br />
TRACE( "[Xml Parser]: Syntax error @ %s #%ld.\n&#8221;, &#8220;&#8221;, pParseStat-&gt;m_lLineNo);<br />
return FALSE;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnDeclBegin<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
int nLenTag;</p>
<p>if ( NULL != pParseStat-&gt;m_pRootNode )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_ERROR;<br />
return;<br />
}</p>
<p>lpszTag = (LPSTR)strchr_skipws( (LPCSTR)(lpszTag + 2) );<br />
if ( lpszTag == &#8216;\0&#8242; )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_ERROR;<br />
return;<br />
}</p>
<p>nLenTag = (int)strlen_notin(lpszTag, &#8221; \t\r\n&gt;&#8221;);<br />
if ( nLenTag == 3 &amp;&amp; !strncmp(lpszTag, &#8220;xml&#8221;, 3) )<br />
{<br />
// Here, dispose version and coding infomation in XML document header<br />
}<br />
else if ( nLenTag == 14 &amp;&amp; !strncmp(lpszTag, &#8220;xml-stylesheet&#8221;, 3) )<br />
{<br />
// Unsupport<br />
}<br />
else<br />
{<br />
// Unknown declaretion<br />
}</p>
<p>pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnDeclEnd<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
// Do noting<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnElemBegin<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
int         nLenTag;<br />
int         nLenValue;<br />
LPSTR       lpszValue;<br />
LPXMLNODE   pNode;<br />
LPXMLATTRIB    pAttrib;<br />
LPXMLATTRIB pPrevAttr;</p>
<p>assert( is_LeftBracket(lpszTag[0]) );</p>
<p>// Multi-root node is not supproted<br />
if ( 0 == pParseStat-&gt;m_lDepth &amp;&amp; NULL != pParseStat-&gt;m_pRootNode )<br />
goto __ERROR;</p>
<p>pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));<br />
if ( NULL == pNode )<br />
goto __ERROR;</p>
<p>ZERO_MEMORY( pNode, sizeof(XMLNODE) );<br />
pNode-&gt;m_eNodeType    = NODETYPE_ELEM;<br />
pNode-&gt;m_lDepth        = pParseStat-&gt;m_lDepth;<br />
if ( NULL != pParseStat-&gt;m_pLastNode )<br />
{<br />
assert( pNode-&gt;m_lDepth &gt;= pParseStat-&gt;m_pLastNode-&gt;m_lDepth );<br />
if ( pNode-&gt;m_lDepth &gt; pParseStat-&gt;m_pLastNode-&gt;m_lDepth ) // new child<br />
{<br />
pNode-&gt;m_pParent = pParseStat-&gt;m_pLastNode;<br />
pParseStat-&gt;m_pLastNode-&gt;m_pFirstChild = pNode;<br />
}<br />
else if ( pNode-&gt;m_lDepth == pParseStat-&gt;m_pLastNode-&gt;m_lDepth ) // new sibling<br />
{<br />
pNode-&gt;m_pParent = pParseStat-&gt;m_pLastNode-&gt;m_pParent;<br />
pParseStat-&gt;m_pLastNode-&gt;m_pNextSibling = pNode;<br />
pNode-&gt;m_pPrevSibling = pParseStat-&gt;m_pLastNode;<br />
}</p>
<p>if ( NULL != pNode-&gt;m_pParent )<br />
{<br />
pNode-&gt;m_pParent-&gt;m_lChildNum++;<br />
pNode-&gt;m_pParent-&gt;m_lChildNum_Elem++;<br />
}<br />
}</p>
<p>if ( NULL == pParseStat-&gt;m_pRootNode )<br />
{<br />
pParseStat-&gt;m_pRootNode = pNode;<br />
}<br />
pNode-&gt;m_pRoot = pParseStat-&gt;m_pRootNode;</p>
<p>pParseStat-&gt;m_pLastNode    = pNode;</p>
<p>lpszTag++;<br />
nLenTag = (int)strlen_notin(lpszTag, &#8221; \t\r\n&gt;&#8221;);<br />
if ( nLenTag &lt;= 0 )<br />
goto __ERROR;</p>
<p>pNode-&gt;m_pbstrTag = BSTR_ALLOCEX(lpszTag, nLenTag);<br />
if ( NULL == pNode-&gt;m_pbstrTag )<br />
goto __ERROR;</p>
<p>lpszTag = (LPSTR)(lpszTag + nLenTag);</p>
<p>for ( pPrevAttr = NULL;; )<br />
{<br />
lpszTag = (LPSTR)strchr_skipws( lpszTag );</p>
<p>if ( is_RightBracket(*lpszTag) )<br />
{<br />
pParseStat-&gt;m_lDepth++; // Move down one layer<br />
pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
break;<br />
}<br />
else if ( !strncmp(lpszTag, &#8220;/&gt;&#8221;, 2) )<br />
{<br />
//pParseStat-&gt;m_lDepth&#8211;; //<br />
pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
break;<br />
}</p>
<p>nLenTag = (int)strlen_when( lpszTag, &#8216;=&#8217; );<br />
if ( nLenTag &lt;= 0 )<br />
goto __ERROR;</p>
<p>lpszValue = strchr( (LPCSTR)(lpszTag + nLenTag), &#8216;\&#8221;&#8216; );<br />
if ( NULL == lpszValue )<br />
goto __ERROR;</p>
<p>lpszValue++;<br />
nLenValue = (int)strlen_when( lpszValue, &#8216;\&#8221;&#8216; );</p>
<p>//if ( nLenValue &lt;= 0 )<br />
//    goto __ERROR;</p>
<p>pAttrib = (LPXMLATTRIB)malloc(sizeof(XMLATTRIB));<br />
if ( NULL == pAttrib )<br />
goto __ERROR;<br />
ZERO_MEMORY( pAttrib, sizeof(XMLATTRIB) );</p>
<p>pAttrib-&gt;m_pbstrName    = BSTR_ALLOCEX( lpszTag, nLenTag );<br />
pAttrib-&gt;m_pbstrValue    = BSTR_ALLOCEX( lpszValue, nLenValue );<br />
if ( NULL == pAttrib-&gt;m_pbstrName || NULL == pAttrib-&gt;m_pbstrValue )<br />
goto __ERROR;</p>
<p>if ( NULL == pNode-&gt;m_pFirstAttrib )<br />
pNode-&gt;m_pFirstAttrib = pAttrib;</p>
<p>if ( NULL != pPrevAttr )<br />
pPrevAttr-&gt;m_pNext = pAttrib;<br />
pPrevAttr = pAttrib;</p>
<p>pNode-&gt;m_lAttribNum++;<br />
lpszTag = lpszValue + nLenValue + 1;<br />
}</p>
<p>return;</p>
<p>__ERROR:<br />
XML_FreeNodeTree( pNode );<br />
pParseStat-&gt;m_eParseStat = PSTAT_ERROR;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnElemEnd<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
pParseStat-&gt;m_lDepth&#8211;;</p>
<p>if ( NULL != pParseStat-&gt;m_pLastNode )<br />
{<br />
if ( NULL != pParseStat-&gt;m_pLastNode-&gt;m_pParent )<br />
pParseStat-&gt;m_pLastNode-&gt;m_pParent-&gt;m_pLastChild = pParseStat-&gt;m_pLastNode;</p>
<p>if ( pParseStat-&gt;m_pLastNode-&gt;m_lDepth &gt; pParseStat-&gt;m_lDepth )<br />
pParseStat-&gt;m_pLastNode = pParseStat-&gt;m_pLastNode-&gt;m_pParent;<br />
}</p>
<p>if ( 0 == pParseStat-&gt;m_lDepth )<br />
pParseStat-&gt;m_eParseStat = PSTAT_FINAL;<br />
else<br />
pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnTextBegin<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
LPXMLNODE pNode;</p>
<p>pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));<br />
if ( NULL == pParseStat-&gt;m_pLastNode )<br />
goto __ERROR;</p>
<p>ZERO_MEMORY( pNode, sizeof(XMLNODE) );<br />
pNode-&gt;m_eNodeType    = NODETYPE_TEXT;<br />
pNode-&gt;m_lDepth        = pParseStat-&gt;m_lDepth;</p>
<p>if ( NULL != pParseStat-&gt;m_pLastNode )<br />
{<br />
assert( pNode-&gt;m_lDepth &gt;= pParseStat-&gt;m_pLastNode-&gt;m_lDepth );<br />
if ( pNode-&gt;m_lDepth &gt; pParseStat-&gt;m_pLastNode-&gt;m_lDepth )<br />
{<br />
pNode-&gt;m_pParent = pParseStat-&gt;m_pLastNode;<br />
pParseStat-&gt;m_pLastNode-&gt;m_pFirstChild = pNode;<br />
}<br />
else if ( pNode-&gt;m_lDepth == pParseStat-&gt;m_pLastNode-&gt;m_lDepth )<br />
{<br />
pNode-&gt;m_pParent = pParseStat-&gt;m_pLastNode-&gt;m_pParent;<br />
pParseStat-&gt;m_pLastNode-&gt;m_pNextSibling = pNode;<br />
pNode-&gt;m_pPrevSibling = pParseStat-&gt;m_pLastNode;<br />
}</p>
<p>if ( NULL != pNode-&gt;m_pParent )<br />
pNode-&gt;m_pParent-&gt;m_lChildNum++;</p>
<p>pNode-&gt;m_pRoot = pParseStat-&gt;m_pLastNode-&gt;m_pRoot;<br />
}</p>
<p>pParseStat-&gt;m_pLastNode    = pNode;</p>
<p>pNode-&gt;m_pbstrTag = BSTR_ALLOC(lpszTag);<br />
if ( NULL == pNode-&gt;m_pbstrTag )<br />
goto __ERROR;</p>
<p>pParseStat-&gt;m_lDepth++; // Move down one layer<br />
pParseStat-&gt;m_eParseStat = PSTAT_TEXT_END;<br />
return;</p>
<p>__ERROR:<br />
XML_FreeNodeTree( pNode );<br />
pParseStat-&gt;m_eParseStat = PSTAT_ERROR;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnTextEnd<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
// Move up one layer<br />
pParseStat-&gt;m_lDepth&#8211;;</p>
<p>if ( NULL != pParseStat-&gt;m_pLastNode &amp;&amp;<br />
pParseStat-&gt;m_pLastNode-&gt;m_lDepth &gt; pParseStat-&gt;m_lDepth )<br />
pParseStat-&gt;m_pLastNode = pParseStat-&gt;m_pLastNode-&gt;m_pParent;</p>
<p>pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnCommBegin<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnCommEnd<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnCDATABegin<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
pParseStat-&gt;m_eParseStat = PSTAT_INITIAL;<br />
// Should convert to text here<br />
}</p>
<p>/*********************************************************************\<br />
* Function: Parser_OnCDATAEnd<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )<br />
{<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_IterateTree<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator )<br />
{<br />
register ITERSTAT eStat;<br />
if ( NULL != pTree )<br />
{<br />
pIterator-&gt;m_pStation = pTree;<br />
eStat = pIterator-&gt;m_pfnProc( pTree, pIterator-&gt;m_pvParam );<br />
if ( eStat == ISTAT_STOP )<br />
return;<br />
if ( eStat != ISTAT_PASS )<br />
pIterator-&gt;m_lCount++;</p>
<p>XML_IterateTree( pTree-&gt;m_pFirstChild, pIterator );<br />
XML_IterateTree( pTree-&gt;m_pNextSibling, pIterator );<br />
}<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_ForEachNode<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
LONG XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam )<br />
{<br />
XMLITERFATOR    iter;</p>
<p>assert( NULL != pDoc );<br />
assert( NULL != pfnNodeProc );</p>
<p>if ( pDoc-&gt;m_eDocStat == DSTAT_UNOPEN || (NULL != pStartPoint &amp;&amp; pStartPoint-&gt;m_pRoot != pDoc-&gt;m_lpRootNode) )<br />
return 0;</p>
<p>iter.m_lCount   = 0;<br />
iter.m_pStation = NULL;<br />
iter.m_pvParam  = pvParam;<br />
iter.m_pfnProc  = pfnNodeProc;</p>
<p>pStartPoint = (NULL == pStartPoint ? pDoc-&gt;m_lpRootNode : pStartPoint);<br />
XML_IterateTree( pStartPoint, &amp;iter );<br />
return iter.m_lCount;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XMLCmpNode_EqualTag<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
ITERSTAT XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam )<br />
{<br />
if ( FALSE != BSTR_EQUAL(pNode-&gt;m_pbstrTag, BSTR_CAST(pvParam)) )<br />
return ISTAT_STOP;<br />
else<br />
return ISTAT_CONTINUE;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_GetNode<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
LPXMLNODE XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen )<br />
{<br />
BSTRING         bStr;<br />
XMLITERFATOR    iter;</p>
<p>assert( NULL != lpszTag );<br />
assert( NULL != pDoc );</p>
<p>if ( pDoc-&gt;m_eDocStat == DSTAT_UNOPEN || pStartPoint-&gt;m_pRoot != pDoc-&gt;m_lpRootNode )<br />
return NULL;</p>
<p>bStr.m_lLength  = lLen;<br />
bStr.m_pszStr   = lpszTag;</p>
<p>iter.m_lCount   = 0;<br />
iter.m_pfnProc  = &amp;XMLCmpNode_EqualTag;<br />
iter.m_pStation = NULL;<br />
iter.m_pvParam  = (LPVOID)&amp;bStr;</p>
<p>pStartPoint = (NULL == pStartPoint ? pDoc-&gt;m_lpRootNode : pStartPoint);<br />
XML_IterateTree( pStartPoint, &amp;iter );<br />
return (iter.m_pStation);<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_GetNodeAttrib<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
LPXMLATTRIB    XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen )<br />
{<br />
BSTRING     bStr;<br />
LPXMLATTRIB pAttrib;</p>
<p>assert( NULL != lpszAttr );<br />
assert( NULL != pNode );<br />
bStr.m_lLength  = lLen;<br />
bStr.m_pszStr   = lpszAttr;</p>
<p>for ( pAttrib = XML_GetNodeFirstAttrib(pNode); NULL != pAttrib; pAttrib = XML_GetNodeNextAttrib(pAttrib) )<br />
{<br />
if ( FALSE != BSTR_EQUAL(pAttrib-&gt;m_pbstrName, &amp;bStr) )<br />
break;<br />
}</p>
<p>return pAttrib;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_GetNodeSibling<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
LPXMLNODE XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL bIncludeThis )<br />
{<br />
BSTRING     bStr;</p>
<p>assert( NULL != lpszTag );<br />
assert( NULL != pNode );<br />
bStr.m_lLength  = lLen;<br />
bStr.m_pszStr   = lpszTag;</p>
<p>if ( FALSE != bIncludeThis &amp;&amp; FALSE != BSTR_EQUAL(pNode-&gt;m_pbstrTag, &amp;bStr) )<br />
return pNode;</p>
<p>for ( pNode = XML_GetNodeNextSibling(pNode); NULL != pNode; pNode = XML_GetNodeNextSibling(pNode) )<br />
{<br />
if ( FALSE != BSTR_EQUAL(pNode-&gt;m_pbstrTag, &amp;bStr) )<br />
break;<br />
}</p>
<p>return pNode;<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_FreeNodeTree<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void XML_FreeNodeTree( LPXMLNODE pNode )<br />
{<br />
if ( NULL != pNode )<br />
{<br />
BSTR_FREE( pNode-&gt;m_pbstrTag );</p>
<p>XML_FreeAttribList( pNode-&gt;m_pFirstAttrib );</p>
<p>if ( is_FirstChild(pNode) &amp;&amp; NULL != pNode-&gt;m_pParent )<br />
pNode-&gt;m_pParent-&gt;m_pFirstChild = pNode-&gt;m_pNextSibling;</p>
<p>if ( NULL != pNode-&gt;m_pNextSibling )<br />
pNode-&gt;m_pNextSibling-&gt;m_pPrevSibling = pNode-&gt;m_pPrevSibling;<br />
if ( NULL != pNode-&gt;m_pPrevSibling )<br />
pNode-&gt;m_pPrevSibling-&gt;m_pNextSibling = pNode-&gt;m_pNextSibling;</p>
<p>XML_FreeNodeTree( pNode-&gt;m_pFirstChild );<br />
XML_FreeNodeTree( pNode-&gt;m_pNextSibling );</p>
<p>free( pNode );<br />
}<br />
}</p>
<p>/*********************************************************************\<br />
* Function: XML_FreeAttribList<br />
* Purpose:<br />
* Params:<br />
* Return<br />
* Remarks<br />
**********************************************************************/<br />
void XML_FreeAttribList( LPXMLATTRIB pAttrib )<br />
{<br />
LPXMLATTRIB pNext;</p>
<p>while ( NULL != pAttrib )<br />
{<br />
pNext = pAttrib-&gt;m_pNext;<br />
BSTR_FREE( pAttrib-&gt;m_pbstrName );<br />
BSTR_FREE( pAttrib-&gt;m_pbstrValue );<br />
free( pAttrib );<br />
pAttrib = pNext;<br />
}<br />
}</p>
<p>#if defined(__cplusplus)<br />
}   // extern &#8220;C&#8221; {<br />
#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/353.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XCache &amp; XDebug on road</title>
		<link>http://www.donevii.com/post/349.html</link>
		<comments>http://www.donevii.com/post/349.html#comments</comments>
		<pubDate>Fri, 28 Sep 2007 08:03:37 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=349</guid>
		<description><![CDATA[终于配置上 XCache 和 XDebug 了，可惜的是 php-java-bridge 一直没搞好，只有双击运行 JavaBridge 后才行，唉，要是能内置到 PHP 里就好了。 继续研究 FastCGI &#38; Lighttpd 如果说之前在 UUSee 是向上研究，... ]]></description>
			<content:encoded><![CDATA[<p>终于配置上 XCache 和 XDebug 了，可惜的是 <a href="http://www.donevii.com/post/tag/php" class="st_tag internal_tag" rel="tag" title="Posts tagged with php">php</a>-<a href="http://www.donevii.com/post/tag/java" class="st_tag internal_tag" rel="tag" title="Posts tagged with java">java</a>-bridge 一直没搞好，只有双击运行 JavaBridge 后才行，唉，要是能内置到 PHP 里就好了。</p>
<p>继续研究 <a href="http://www.donevii.com/post/tag/fastcgi" class="st_tag internal_tag" rel="tag" title="Posts tagged with fastcgi">FastCGI</a> &amp; <a href="http://www.donevii.com/post/tag/lighttpd" class="st_tag internal_tag" rel="tag" title="Posts tagged with lighttpd">Lighttpd</a></p>
<p>如果说之前在 UUSee 是向上研究，既“抽象”、“架构”的话，那么来 IMobile 之后研究方向则是向下，研究底层，研究以前没注意到的更细节的地方了。</p>
<p>:)</p>
<p>Good days, good luck.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/349.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[超长篇] Inject Your Code to a Portable Executable File</title>
		<link>http://www.donevii.com/post/330.html</link>
		<comments>http://www.donevii.com/post/330.html#comments</comments>
		<pubDate>Thu, 24 May 2007 07:50:01 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ror]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=330</guid>
		<description><![CDATA[转至: http://www.codeguru.com/cpp/w-p/system/misc/article.php/c11393 Downloads pemaker1.zip &#8211; pemaker2.zip &#8211; pemaker3.zip &#8211; pemaker4.zip &#8211; pemaker5.zip &#8211; peviewer.zip &#8211; test1.zip &#8211; Windows NT 3.51 (I mean, Win3... ]]></description>
			<content:encoded><![CDATA[<p>转至: <a href="http://www.codeguru.com/cpp/w-p/system/misc/article.php/c11393">http://www.codeguru.com/cpp/w-p/system/misc/article.php/c11393</a></p>
<p><strong>Downloads</strong></p>
<li><a href="http://www.codeguru.com/dbfiles/get_file/pemaker1.zip?id=11393&amp;lbl=PEMAKER1_ZIP&amp;ds=20060302">pemaker1.zip</a> &#8211; </li>
<li><a href="http://www.codeguru.com/dbfiles/get_file/pemaker2.zip?id=11393&amp;lbl=PEMAKER2_ZIP&amp;ds=20060302">pemaker2.zip</a> &#8211; </li>
<li><a href="http://www.codeguru.com/dbfiles/get_file/pemaker3.zip?id=11393&amp;lbl=PEMAKER3_ZIP&amp;ds=20060302">pemaker3.zip</a> &#8211; </li>
<li><a href="http://www.codeguru.com/dbfiles/get_file/pemaker4.zip?id=11393&amp;lbl=PEMAKER4_ZIP&amp;ds=20060302">pemaker4.zip</a> &#8211; </li>
<li><a href="http://www.codeguru.com/dbfiles/get_file/pemaker5.zip?id=11393&amp;lbl=PEMAKER5_ZIP&amp;ds=20060302">pemaker5.zip</a> &#8211; </li>
<li><a href="http://www.codeguru.com/dbfiles/get_file/peviewer.zip?id=11393&amp;lbl=PEVIEWER_ZIP&amp;ds=20060302">peviewer.zip</a> &#8211; </li>
<li><a href="http://www.codeguru.com/dbfiles/get_file/test1.zip?id=11393&amp;lbl=TEST1_ZIP&amp;ds=20060302">test1.zip</a> &#8211; </li>
<p><a name="more"><font color="#000000"></font></a><a href="http://en.wikipedia.org/wiki/Windows_NT_3.51" target="new">Windows NT 3.51</a> (I mean, <a href="http://en.wikipedia.org/wiki/Windows_3.1" target="new">Win3.1</a>, <a href="http://en.wikipedia.org/wiki/Windows_95" target="new">Win95</a>, <a href="http://en.wikipedia.org/wiki/Windows_98" target="new">Win98</a> were not perfect <a href="http://en.wikipedia.org/wiki/Operating_System" target="new">OS</a>s). The MS-DOS data causes that your executable file to have the performance inside MS-DOS and <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/HTML/_core_.2f.stub.asp" target="new">the MS-DOS Stub program</a> lets it display: <strong>&quot;This program can not be run in MS-DOS mode&quot;</strong> or <strong>&quot;This program can be run only in <a href="http://www.donevii.com/post/tag/windows" class="st_tag internal_tag" rel="tag" title="Posts tagged with windows">Windows</a> mode&quot;</strong>, or some things like these comments when you try to run a Windows EXE file inside <a href="http://en.wikipedia.org/wiki/MS-DOS" target="new">MS-DOS 6.0</a>, where there is no footstep of Windows. Thus, this data is reserved for the code to indicate these comments in the <a href="http://en.wikipedia.org/wiki/MS-DOS" target="new">MS-DOS</a> <a href="http://en.wikipedia.org/wiki/Operating_System" target="new">operating system</a>. The most interesting part of the <a href="http://en.wikipedia.org/wiki/MS-DOS" target="new">MS-DOS</a> data is &quot;<strong>MZ</strong>&quot;! Can you believe, it refers to the name of &quot;<a href="http://en.wikipedia.org/wiki/Mark_Zbikowski" target="new">Mark Zbikowski</a>&quot;, one of the first Microsoft programmers?</p>
<p><font color="#000000"><img height="175" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=PEMAKER_GIF&amp;ds=20060302" width="452" alt="" /></font></p>
<h3>0 Preface</h3>
<p>You might demand to comprehend the ways a virus program injects its procedure into the interior of a portable executable file and corrupts it, or you are interested in implementing a packer or a protector to encrypt the data of your portable executable (PE) file. This article is committed to represent a brief discussion to realize the performance that is accomplished by EXE tools or some kinds of mal-ware.</p>
<p>You can employ this article&#8217;s source code to create your custom EXE builder. It could be used to make an EXE protector in the right way, or with the wrong intention, to spread a virus. However, my purpose of writing this article has been the first application, so I will not be responsible for the immoral usage of these methods.</p>
<h3>1 Prerequisites</h3>
<p>There are no specific mandatory prerequisites to follow the topics in this article. If you are familiar with a debugger and also the portable file format, I suggest you to drop to Sections 2 and 3; the whole of these sections has been made for people who don&#8217;t have any knowledge regarding the EXE file format or debuggers.</p>
<h3>2 Portable Executable File Format</h3>
<p>The Portable Executable file format was defined to provide the best way for the Windows Operating System to execute code and also to store the essential data that is needed to run a program&mdash;for example constant data, variable data, import library links, and resource data. It consists of MS-DOS file information, Windows NT file information, Section Headers, and Section images, as shown in Table 1.</p>
<h4>2.1 The MS-DOS data</h4>
<p>These data let you remember the first days of developing the Windows Operating System. You were at the beginning of a way to achieve a complete Operating System such as </p>
<p>To me, only the offset of the PE signature in the <a href="http://en.wikipedia.org/wiki/MS-DOS" target="new">MS-DOS</a> data is important, so I can use it to find the position of the <a href="http://en.wikipedia.org/wiki/Windows_NT" target="new">Windows NT</a> data. I just recommend that you take a look at Table 1, and then observe the structure of <tt>IMAGE_DOS_HEADER</tt> in the <em>&lt;winnt.h&gt;</em> header in the <em>&lt;Microsoft Visual Studio .net path&gt;\VC7\PlatformSDK\include\</em> folder or the <em>&lt;Microsoft Visual Studio 6.0 path&gt;\VC98\include\</em> folder. I do not know why the Microsoft team has forgotten to provide some comment about this structure in the <a href="http://msdn.microsoft.com/" target="new">MSDN</a> library!</p>
<pre><span class="codeKeyword">typedef</span> <span class="codeKeyword">struct</span> _IMAGE_DOS_HEADER { <span class="codeComment">// DOS .EXE header &quot;MZ&quot;</span>    WORD   e_magic;                <span class="codeComment">// Magic number</span>    WORD   e_cblp;                 <span class="codeComment">// Bytes on last page of file</span>    WORD   e_cp;                   <span class="codeComment">// Pages in file</span>    WORD   e_crlc;                 <span class="codeComment">// Relocations</span>    WORD   e_cparhdr;              <span class="codeComment">// Size of header in</span>                                   <span class="codeComment">// paragraphs</span>    WORD   e_minalloc;             <span class="codeComment">// Minimum extra paragraphs</span>                                   <span class="codeComment">// needed</span>    WORD   e_maxalloc;             <span class="codeComment">// Maximum extra paragraphs</span>                                   <span class="codeComment">// needed</span>    WORD   e_ss;                   <span class="codeComment">// Initial (relative) SS</span>                                   <span class="codeComment">// value</span>    WORD   e_sp;                   <span class="codeComment">// Initial SP value</span>    WORD   e_csum;                 <span class="codeComment">// Checksum</span>    WORD   e_ip;                   <span class="codeComment">// Initial IP value</span>    WORD   e_cs;                   <span class="codeComment">// Initial (relative) CS</span>                                   <span class="codeComment">// value</span>    WORD   e_lfarlc;               <span class="codeComment">// File address of relocation</span>                                   <span class="codeComment">// table</span>    WORD   e_ovno;                 <span class="codeComment">// Overlay number</span>    WORD   e_res[4];               <span class="codeComment">// Reserved words</span>    WORD   e_oemid;                <span class="codeComment">// OEM identifier</span>                                   <span class="codeComment">// (for e_oeminfo)</span>    WORD   e_oeminfo;              <span class="codeComment">// OEM information;</span>                                   <span class="codeComment">// e_oemid specific</span>    WORD   e_res2[10];             <span class="codeComment">// Reserved words</span>    LONG   <font color="#ff0000">e_lfanew</font>;               <span class="codeComment">// File address of the new</span>                                   <span class="codeComment">// exe header</span>  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;</pre>
<p><tt>e_lfanew</tt> is the offset that refers to the position of the Windows NT data. I have provided a program to obtain the header information from an EXE file and to display it to you. To use the program, just try:</p>
<h4>PE Viewer</h4>
<p><img height="314" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=PEVIEWER1_GIF&amp;ds=20060302" width="491" alt="" /></p>
<p><img height="363" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=PEVIEWER2_GIF&amp;ds=20060302" width="500" alt="" /><br />(<a href="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=PEVIEWER2_GIF&amp;ds=20060302" target="_blank">Full Size Image</a>)</p>
<p><img height="313" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=PEVIEWER3_GIF&amp;ds=20060302" width="500" alt="" /><br />(<a href="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=PEVIEWER3_GIF&amp;ds=20060302" target="_blank">Full Size Image</a>)</p>
<p>This sample is useful for the whole of this article.</p>
<p><strong>Table 1:</strong> Portable Executable file format structure</p>
<p>
<table cellspacing="2" cellpadding="2" border="2">
<tbody>
<tr valign="top">
<td rowspan="17">MS-DOS <br />            information</td>
<td rowspan="16"><tt>IMAGE_DOS_<br />            HEADER</tt></td>
<td>DOS EXE Signature</td>
<td rowspan="16">
<pre lang="text">00000000  ASCII <font color="#008000">&quot;MZ&quot;</font>00000002  DW 009000000004  DW 000300000006  DW 000000000008  DW 00040000000A  DW 00000000000C  DW FFFF0000000E  DW 000000000010  DW 00B800000012  DW 000000000014  DW 000000000016  DW 000000000018  DW 00400000001A  DW 00000000001C  DB 00b&amp;b&amp;0000003B  DB 000000003C  DD <font color="#ff0000">000000F0</font></pre>
</td>
</tr>
<tr valign="top">
<td><tt>DOS_PartPag</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_PageCnt</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_ReloCnt</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_HdrSize</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_MinMem</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_MaxMem</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_ReloSS</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_ExeSP</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_ChkSum</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_ExeIPP</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_ReloCS</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_TablOff</tt></td>
</tr>
<tr valign="top">
<td><tt>DOS_Overlay</tt></td>
</tr>
<tr valign="top">
<td><tt>b&amp;<br />            </tt>Reserved words<tt><br />            b&amp;</tt></td>
</tr>
<tr valign="top">
<td>Offset to PE signature</td>
</tr>
<tr valign="top">
<td>MS-DOS Stub <br />            Program</td>
<td colspan="2">
<pre lang="text">00000040  ..B:..B4.C!B8\LC!<font color="#008000">This program canno</font>00000060  <font color="#008000">t be run in DOS mode.</font>...$.......</pre>
</td>
</tr>
<tr valign="top">
<td rowspan="54">Windows NT <br />            information
<p><tt>IMAGE_<br />            NT_HEADERS</tt></p>
</td>
<td>Signature</td>
<td>PE signature (PE)</td>
<td>
<pre lang="text"><font color="#ff0000">000000F0</font>  ASCII <font color="#008000">&quot;PE&quot;</font></pre>
</td>
</tr>
<tr valign="top">
<td rowspan="7"><tt>IMAGE_<br />            FILE_HEADER</tt></td>
<td><tt>Machine</tt></td>
<td rowspan="7">
<pre lang="text">000000F4  DW 014C000000F6  DW 0003000000F8  DD 3B7D8410000000FC  DD 0000000000000100  DD 0000000000000104  DW 00E000000106  DW 010F</pre>
</td>
</tr>
<tr valign="top">
<td><tt>NumberOfSections</tt></td>
</tr>
<tr valign="top">
<td><tt>TimeDateStamp</tt></td>
</tr>
<tr valign="top">
<td><tt>PointerToSymbolTable</tt></td>
</tr>
<tr valign="top">
<td><tt>NumberOfSymbols</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfOptionalHeader</tt></td>
</tr>
<tr valign="top">
<td><tt>Characteristics</tt></td>
</tr>
<tr valign="top">
<td rowspan="46"><tt>IMAGE_<br />            OPTIONAL_<br />            HEADER32</tt></td>
<td><tt>MagicNumber</tt></td>
<td rowspan="30">
<pre lang="text">00000108  DW 010B0000010A  DB 070000010B  DB 000000010C  DD 0001280000000110  DD 00009C0000000114  DD 0000000000000118  DD 000124750000011C  DD 0000100000000120  DD 0001400000000124  DD 0100000000000128  DD 000010000000012C  DD 0000020000000130  DW 000500000132  DW 000100000134  DW 000500000136  DW 000100000138  DW 00040000013A  DW 00000000013C  DD 0000000000000140  DD 0001F00000000144  DD 0000040000000148  DD 0001D7FC0000014C  DW 00020000014E  DW 800000000150  DD 0004000000000154  DD 0000100000000158  DD 001000000000015C  DD 0000100000000160  DD 0000000000000164  DD 00000010</pre>
</td>
</tr>
<tr valign="top">
<td><tt>MajorLinkerVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>MinorLinkerVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfCode</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfInitializedData</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfUninitializedData</tt></td>
</tr>
<tr valign="top">
<td><tt>AddressOfEntryPoint</tt></td>
</tr>
<tr valign="top">
<td><tt>BaseOfCode</tt></td>
</tr>
<tr valign="top">
<td><tt>BaseOfData</tt></td>
</tr>
<tr valign="top">
<td><tt>ImageBase</tt></td>
</tr>
<tr valign="top">
<td><tt>SectionAlignment</tt></td>
</tr>
<tr valign="top">
<td><tt>FileAlignment</tt></td>
</tr>
<tr valign="top">
<td><tt>MajorOSVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>MinorOSVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>MajorImageVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>MinorImageVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>MajorSubsystemVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>MinorSubsystemVersion</tt></td>
</tr>
<tr valign="top">
<td><tt>Reserved</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfImage</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfHeaders</tt></td>
</tr>
<tr valign="top">
<td><tt>CheckSum</tt></td>
</tr>
<tr valign="top">
<td><tt>Subsystem</tt></td>
</tr>
<tr valign="top">
<td><tt>DLLCharacteristics</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfStackReserve</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfStackCommit</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfHeapReserve</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfHeapCommit</tt></td>
</tr>
<tr valign="top">
<td><tt>LoaderFlags</tt></td>
</tr>
<tr valign="top">
<td><tt>NumberOfRvaAndSizes</tt></td>
</tr>
<tr valign="top">
<td rowspan="16"><tt>IMAGE_<br />            DATA_DIRECTORY[16]</tt></td>
<td>Export Table</td>
</tr>
<tr valign="top">
<td>Import Table</td>
</tr>
<tr valign="top">
<td>Resource Table</td>
</tr>
<tr valign="top">
<td>Exception Table</td>
</tr>
<tr valign="top">
<td>Certificate File</td>
</tr>
<tr valign="top">
<td>Relocation Table</td>
</tr>
<tr valign="top">
<td><a href="http://www.donevii.com/post/tag/debug" class="st_tag internal_tag" rel="tag" title="Posts tagged with debug">Debug</a> Data</td>
</tr>
<tr valign="top">
<td>Architecture Data</td>
</tr>
<tr valign="top">
<td>Global Ptr</td>
</tr>
<tr valign="top">
<td>TLS Table</td>
</tr>
<tr valign="top">
<td>Load Config Table</td>
</tr>
<tr valign="top">
<td>Bound Import Table</td>
</tr>
<tr valign="top">
<td>Import Address Table</td>
</tr>
<tr valign="top">
<td>Delay Import Descriptor</td>
</tr>
<tr valign="top">
<td>COM+ Runtime Header</td>
</tr>
<tr valign="top">
<td>Reserved</td>
</tr>
<tr valign="top">
<td rowspan="13">Sections <br />            information</td>
<td rowspan="10"><tt>IMAGE_<br />            SECTION_<br />            HEADER[0]</tt></td>
<td><tt>Name[8]</tt></td>
<td rowspan="10">
<pre lang="text">000001E8  ASCII<font color="#008000">&quot;.text&quot;</font>000001F0  DD 000126B0000001F4  DD 00001000000001F8  DD 00012800000001FC  DD 0000040000000200  DD 0000000000000204  DD 0000000000000208  DW 00000000020A  DW 00000000020C  DD 60000020    CODE|EXECUTE|READ</pre>
</td>
</tr>
<tr valign="top">
<td><tt>VirtualSize</tt></td>
</tr>
<tr valign="top">
<td><tt>VirtualAddress</tt></td>
</tr>
<tr valign="top">
<td><tt>SizeOfRawData</tt></td>
</tr>
<tr valign="top">
<td><tt>PointerToRawData</tt></td>
</tr>
<tr valign="top">
<td><tt>PointerToRelocations</tt></td>
</tr>
<tr valign="top">
<td><tt>PointerToLineNumbers</tt></td>
</tr>
<tr valign="top">
<td><tt>NumberOfRelocations</tt></td>
</tr>
<tr valign="top">
<td><tt>NumberOfLineNumbers</tt></td>
</tr>
<tr valign="top">
<td><tt>Characteristics</tt></td>
</tr>
<tr valign="top">
<td><tt>b&amp;<br />            b&amp;<br />            b&amp;<br />            IMAGE_<br />            SECTION_<br />            HEADER[n]</tt></td>
<td colspan="2">
<pre lang="text">00000210  ASCII<font color="#008000">&quot;.data&quot;</font>; SECTION00000218  DD 0000101C ; VirtualSize = 0x101C0000021C  DD 00014000 ; VirtualAddress = 0x1400000000220  DD 00000A00 ; SizeOfRawData = 0xA0000000224  DD 00012C00 ; PointerToRawData = 0x12C0000000228  DD 00000000 ; PointerToRelocations = 0x00000022C  DD 00000000 ; PointerToLineNumbers = 0x000000230  DW 0000     ; NumberOfRelocations = 0x000000232  DW 0000     ; NumberOfLineNumbers = 0x000000234  DD C0000040 ; Characteristics =                        INITIALIZED_DATA|READ|WRITE00000238  ASCII<font color="#008000">&quot;.rsrc&quot;</font>; SECTION00000240  DD 00008960 ; VirtualSize = 0x896000000244  DD 00016000 ; VirtualAddress = 0x1600000000248  DD 00008A00 ; SizeOfRawData = 0x8A000000024C  DD 00013600 ; PointerToRawData = 0x1360000000250  DD 00000000 ; PointerToRelocations = 0x000000254  DD 00000000 ; PointerToLineNumbers = 0x000000258  DW 0000     ; NumberOfRelocations = 0x00000025A  DW 0000     ; NumberOfLineNumbers = 0x00000025C  DD 40000040 ; Characteristics =                        INITIALIZED_DATA|READ</pre>
</td>
</tr>
<tr valign="top">
<td><tt>SECTION[0]</tt></td>
<td colspan="2">
<pre lang="text">00000400  EA 22 DD 77 D7 23 DD 77  C*&quot;C.wC.#C.w00000408  9A 18 DD 77 00 00 00 00  E!.C.w....00000410  2E 1E C7 77 83 1D C7 77  ..C.wF..C.w00000418  FF 1E C7 77 00 00 00 00  C?.C.w....00000420  93 9F E7 77 D8 05 E8 77  b.E8C'wC..C(w00000428  FD A5 E7 77 AD A9 E9 77  C=B%C'w&amp;shy;B)C)w00000430  A3 36 E7 77 03 38 E7 77  B#6C'w.8C'w00000438  41 E3 E6 77 60 8D E7 77  AC#C&amp;w`BC'w00000440  E6 1B E6 77 2B 2A E7 77  C&amp;.C&amp;w+*C'w00000448  7A 17 E6 77 79 C8 E6 77  z.C&amp;wyC.C&amp;w00000450  14 1B E7 77 C1 30 E7 77  ..C'wC.0C'wb&amp;</pre>
</td>
</tr>
<tr valign="top">
<td><tt>b&amp;<br />            b&amp;<br />            b&amp;<br />            SECTION[n]</tt></td>
<td colspan="2">
<pre lang="text">b&amp;0001BF00  63 00 2E 00 63 00 68 00  c...c.h.0001BF08  6D 00 0A 00 43 00 61 00  m...C.a.0001BF10  6C 00 63 00 75 00 6C 00  l.c.u.l.0001BF18  61 00 74 00 6F 00 72 00  a.t.o.r.0001BF20  11 00 4E 00 6F 00 74 00  ..N.o.t.0001BF28  20 00 45 00 6E 00 6F 00   .E.n.o.0001BF30  75 00 67 00 68 00 20 00  u.g.h. .0001BF38  4D 00 65 00 6D 00 6F 00  M.e.m.o.0001BF40  72 00 79 00 00 00 00 00  r.y.....0001BF48  00 00 00 00 00 00 00 00  ........0001BF50  00 00 00 00 00 00 00 00  ........0001BF58  00 00 00 00 00 00 00 00  ........0001BF60  00 00 00 00 00 00 00 00  ........0001BF68  00 00 00 00 00 00 00 00  ........0001BF70  00 00 00 00 00 00 00 00  ........0001BF78  00 00 00 00 00 00 00 00  ........</pre>
</td>
</tr>
</tbody>
</table>
<h4>2.2 The Windows NT data</h4>
<p>As mentioned in the preceding section, <tt>e_lfanew</tt> storage in the MS-DOS data structure refers to the location of the Windows NT information. Hence, if you assume that the <tt>pMem</tt> pointer relates the start point of the memory space for a selected portable executable file, you can retrieve the MS-DOS header and also the Windows NT headers by the following lines, which you also can perceive in the PE viewer sample (<em>pelib.cpp</em>, <tt>PEStructure::OpenFileName()</tt>):</p>
<pre>IMAGE_DOS_HEADER        image_dos_header;IMAGE_NT_HEADERS        image_nt_headers;PCHAR pMem;b&amp;memcpy(&amp;image_dos_header, pMem,       <span class="codeKeyword">sizeof</span>(IMAGE_DOS_HEADER));memcpy(&amp;image_nt_headers,       pMem+image_dos_header.e_lfanew,       <span class="codeKeyword">sizeof</span>(IMAGE_NT_HEADERS));</pre>
<p><a name="more"><font color="#000000"></font></a><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_nt_headers_str.asp" target="new"><tt>IMAGE_NT_HEADERS</tt></a> structure definition. It makes it possible to grasp what the image NT header maintains to execute a code inside the Windows NT OS. Now, you are conversant with the Windows NT structure; it consists of the <font color="#008000">&quot;PE&quot;</font> Signature, the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_file_header_str.asp" target="new">File Header</a>, and the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_optional_header_str.asp" target="new">Optional Header</a>. Do not forget to take a glimpse at their comments in the <a href="http://msdn.microsoft.com/" target="new">MSDN</a> Library and in Table 1.</p>
<p>It seems to be very simple, the retrieval of the headers information. I recommend inspecting the MSDN library regarding the </p>
<p>One the whole, I consider merely, in most circumstances, the following cells of the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_nt_headers_str.asp" target="new"><tt>IMAGE_NT_HEADERS</tt></a> structure:</p>
<pre>FileHeader-&gt;NumberOfSectionsOptionalHeader-&gt;AddressOfEntryPointOptionalHeader-&gt;ImageBaseOptionalHeader-&gt;SectionAlignmentOptionalHeader-&gt;FileAlignmentOptionalHeader-&gt;SizeOfImageOptionalHeader-&gt;DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]              -&gt;VirtualAddressOptionalHeader-&gt;DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]              -&gt;Size</pre>
<p>You can observe the main purpose of these values clearly, and their role when the internal virtual memory space allocated for an EXE file by the Windows task manager if you pay attention to their explanations in <a href="http://msdn.microsoft.com/" target="new">MSDN</a> library, so I am not going to repeat the MSDN annotations here.</p>
<p>I should make a brief comment regarding the PE data directories, or <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_optional_header_str.asp" target="new"><tt>OptionalHeader</tt></a>-&gt; <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_data_directory_str.asp" target="new"><tt>DataDirectory[]</tt></a>, because I think there are a few aspects of interest concerning them. When you come to survey the Optional header through the Windows NT information, you will find that there are <em>16</em> directories at the end of the Optional Header, where you can find the consecutive directories, including their Relative Virtual Address and Size. I just mention here the notes from <em>&lt;winnt.h&gt;</em> to clarify these information:</p>
<pre><span class="codeComment">// Export Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_EXPORT          0<span class="codeComment">// Import Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_IMPORT          1<span class="codeComment">// Resource Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_RESOURCE        2<span class="codeComment">// Exception Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_EXCEPTION       3<span class="codeComment">// Security Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_SECURITY        4<span class="codeComment">// Base Relocation Table</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_BASERELOC       5<span class="codeComment">// Debug Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_DEBUG           6<span class="codeComment">// Architecture Specific Data</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7<span class="codeComment">// RVA of GP</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8<span class="codeComment">// TLS Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_TLS             9<span class="codeComment">// Load Configuration Directory</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10<span class="codeComment">// Bound Import Directory in headers</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11<span class="codeComment">// Import Address Table</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_IAT            12<span class="codeComment">// Delay Load Import Descriptors</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13<span class="codeComment">// COM Runtime descriptor</span><span class="codeKeyword">#define</span> IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14</pre>
<p>The last one (15) was reserved for use in the future; I have not yet seen any purpose for it, even in PE64.</p>
<p>For instance, if you want to perceive the relative virtual address (RVA) and the size of the resource data, it is enough to retrieve them by:</p>
<pre>DWORD dwRVA  = image_nt_headers.OptionalHeader-&gt;   DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]-&gt;VirtualAddress;DWORD dwSize = image_nt_headers.OptionalHeader-&gt;   DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]-&gt;Size;</pre>
<p>To comprehend more regarding the significance of data directories, I forward you to Section 3.4.3 of the <a href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx" target="new">Microsoft Portable Executable and the Common Object File Format Specification</a> document by Microsoft, and furthermore Section 6 of this document, where you discern the various types of sections and their applications. You will see the section&#8217;s advantage subsequently.</p>
<h4>2.3 The Section Headers and Sections</h4>
<p>You currently observe how the portable executable files declare the location and the size of a section on a disk storage file and inside the virtual memory space allocated for the program with <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_nt_headers_str.asp" target="new"><tt>IMAGE_NT_HEADERS</tt></a>-&gt; <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_optional_header_str.asp" target="new"><tt>OptionalHeader</tt></a>-&gt;<tt>SizeOfImage</tt> by the Windows task manager, as well the characteristics to demonstrate the type of the section. To better understand the Section header as my previous declaration, I suggest having a brief look at the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_section_header_str.asp" target="new"><tt>IMAGE_SECTION_HEADER</tt></a> structure definition in the MSDN library. For an EXE packer developer, <tt>VirtualSize</tt>, <tt>VirtualAddress</tt>, <tt>SizeOfRawData</tt>, <tt>PointerToRawData</tt>, and <tt>Characteristics</tt> cells have significant rules. When developing an EXE packer, you should be clever enough to play with them. There are somet hings to note when you modify them; you should take care to align the <tt>VirtualSize</tt> and <tt>VirtualAddress</tt> according to <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_optional_header_str.asp" target="new"><tt>OptionalHeader</tt></a>-&gt;<tt>SectionAlignment</tt>, as well as <tt>SizeOfRawData</tt> and <tt>PointerToRawData</tt> in line with <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_optional_header_str.asp" target="new"><tt>OptionalHeader</tt></a>-&gt;<tt>FileAlignment</tt>. Otherwise, you will corrupt your target EXE file and it will never run. Regarding <tt>Characteristics</tt>, I pay attention mostly to establish a section by <tt>IMAGE_SCN_MEM_READ</tt> | <tt>IMAGE_SCN_MEM_WRITE</tt> | <tt>IMAGE_SCN_CNT_INITIALIZED_DATA</tt>, I prefer that my new section has the ability to initialize such data during the running process, such as import table; besides, I need it to be able to modify itself by the loader with my settings in the section characteristics to read- and writeable.</p>
<p>Moreover, you should pay attention to the section names; you can know the purpose of each section by its name. I will just forward you to Section 6 of the <a href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx" target="new">Microsoft Portable Executable and the Common Object File Format Specification</a> documents. I believe it represents the totality of sections by their names; this is also included in Table 2.</p>
<p><strong>Table 2:</strong> Section names</p>
<p>
<table cellspacing="2" cellpadding="2" border="2">
<tbody>
<tr>
<td><font color="#008000">&quot;.text&quot;</font></td>
<td>Code Section</td>
</tr>
<tr>
<td><font color="#008000">&quot;CODE&quot;</font></td>
<td>Code Section of file linked by Borland Delphi or Borland Pascal</td>
</tr>
<tr>
<td><font color="#008000">&quot;.data&quot;</font></td>
<td>Data Section</td>
</tr>
<tr>
<td><font color="#008000">&quot;DATA&quot;</font></td>
<td>Data Section of file linked by Borland Delphi or Borland Pascal</td>
</tr>
<tr>
<td><font color="#008000">&quot;.rdata&quot;</font></td>
<td>Section for Constant Data </td>
</tr>
<tr>
<td><font color="#008000">&quot;.idata&quot;</font></td>
<td>Import Table</td>
</tr>
<tr>
<td><font color="#008000">&quot;.edata&quot; </font></td>
<td>Export Table</td>
</tr>
<tr>
<td><font color="#008000">&quot;.tls&quot;</font></td>
<td>TLS Table</td>
</tr>
<tr>
<td><font color="#008000">&quot;.reloc&quot;</font></td>
<td>Relocation Information</td>
</tr>
<tr>
<td><font color="#008000">&quot;.rsrc&quot;</font></td>
<td>Resource Information</td>
</tr>
</tbody>
</table>
<p>To comprehend the section headers and also the sections, you can run the sample PE viewer. With this PE viewer, you can realize only the application of the section headers in a file image, so to observe the main significance in the Virtual Memory, you should try to load a PE file by a debugger. The next section represents the main idea of using the virtual address and size in the virtual memory by using a debugger. The last note is about <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_nt_headers_str.asp" target="new"><tt>IMAGE_NT_HEADERS</tt></a>-&gt; <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_file_header_str.asp" target="new"><tt>FileHeader</tt></a>-&gt;<tt>NumberOfSections</tt>, that provides a number of sections in a PE file. Do not forget to adjust it whenever you remove or add some sections to a PE file. I am talking about section injection!</p>
<h3>3 Debugger, Disassembler and some Useful Tools</h3>
<p>In this part, you will become familiar with the necessary and essential equipment to develop your PE tools.</p>
<h4>3.1 Debuggers</h4>
<p>The first essential prerequisite to become a PE tools developer is to have enough experience with bug tracer tools. Furthermore, you should know most of the assembly instructions. To me, the Intel documents are the best references. You can obtain them from the Intel site for IA-32, and on top of that IA-64; the future belongs to IA-64 CPUs, Windows XP 64-bit, and also PE64!</p>
<ul>
<li><a href="http://www.intel.com/design/pentium4/manuals/index_new.htm#1" target="new">IA-32 Intel Architecture Software Developer&#8217;s Manuals</a> </li>
<li><a href="http://www.intel.com/software/products/compilers/docs/linux/ref/asm_lan_lx.htm#cover.htm" target="new">Intel Itanium Architecture Assembly Language Reference Guide</a> </li>
<li><a href="http://www.intel.com/cd/ids/developer/asmo-na/eng/19415.htm" target="new">The Intel Itanium Processor Developer Resource Guide</a> </li>
</ul>
<p>To trace a PE file, <a href="http://en.wikipedia.org/wiki/SoftICE" target="new">SoftICE</a> by <a href="http://www.compuware.com/" target="new">Compuware Corporation</a>, I knew it also as named <a href="http://en.wikipedia.org/wiki/Numega" target="new">NuMega</a> when I was at high school, is the best <a href="http://en.wikipedia.org/wiki/Debugger" target="new">debugger</a> in the world. It implements process tracing by using the <a href="http://en.wikipedia.org/wiki/Kernel_mode" target="new">kernel mode</a> method debugging without applying Windows debugging <a href="http://en.wikipedia.org/wiki/Application_programming_interface" target="new">application programming interface</a> (API) functions. In addition, I will introduce one perfect debugger in <a href="http://en.wikipedia.org/wiki/User_mode" target="new">user mode</a> level. It utilizes the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/debugging_reference.asp" target="new">Windows debugging API</a> to trace a PE file and also attaches itself to an active <a href="http://en.wikipedia.org/wiki/Computer_process" target="new">process</a>. These <a href="http://en.wikipedia.org/wiki/Application_programming_interface" target="new">API</a> functions have been provided by Microsoft teams, inside the Windows Kernel32 library, to trace a specific process, by using Microsoft tools, or perhaps, to make your own debugger! Some of those <a href="http://en.wikipedia.org/wiki/Application_programming_interface" target="new">API</a> functions inlude:</p>
<ul><tt>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp" target="new">CreateThread()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createprocess.asp" target="new">CreateProcess()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/openprocess.asp" target="new">OpenProcess()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/debugactiveprocess.asp" target="new">DebugActiveProcess()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/getthreadcontext.asp" target="new">GetThreadContext()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/setthreadcontext.asp" target="new">SetThreadContext()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/continuedebugevent.asp" target="new">ContinueDebugEvent()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/debugbreak.asp" target="new">DebugBreak()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/readprocessmemory.asp" target="new">ReadProcessMemory()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/writeprocessmemory.asp" target="new">WriteProcessMemory()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/suspendthread.asp" target="new">SuspendThread()</a> </li>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/resumethread.asp" target="new">ResumeThread()</a> </li>
<p>    </tt></ul>
<h5>3.1.1 SoftICE</h5>
<p>It was in 1987; Frank Grossman and Jim Moskun decided to establish a company called <a href="http://en.wikipedia.org/wiki/Numega" target="new">NuMega Technologies</a> in Nashua, NH, to develop some equipment to trace and test the reliability of Microsoft Windows software programs. Now, it is a part of <a href="http://en.wikipedia.org/wiki/Compuware" target="new">Compuware Corporation</a> and its product has participated to accelerate the reliability in Windows software, and additionally in Windows driver developments. Currently, everyone knows the Compuware DriverStudio that is used to establish an environment for implementing the elaboration of a kernel driver or a system file by aiding the <a href="http://www.microsoft.com/whdc/ddk/winddk.mspx" target="new">Windows Driver Development Kit (DDK)</a>. It bypasses the involvement of DDK to implement a portable executable file of kernel level for a Windows system software developer. For us, only one instrument of DriverStudio is important, <a href="http://en.wikipedia.org/wiki/SoftICE" target="new">SoftICE</a>; this debugger can be used to trace every portable executable file, a PE file for user mode level or a PE file for kernel mode level.</p>
<p><strong>Figure 1:</strong> SoftICE Window</p>
<p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody bgcolor="#000000" color="gray">
<tr>
<td><font color="#808080"><font color="#00ccff">EAX=00000000</font>EBX=7FFDD000<font color="#00ccff"> ECX=0007FFB0 EDX=7C90EB94</font> ESI=FFFFFFFF EDI=7C919738 <font color="#00ccff">EBP=0007FFF0 ESP=0007FFC4 EIP=010119E0</font> o d i s <font color="#00ccff">z </font>a <font color="#00ccff">p</font> c<br />                CS=0008 DS=0023 SS=0010 ES=0023 FS=0030 GS=0000</font> <font color="#00ccff">SS:0007FFC4=87C816D4F</font></td>
</tr>
<tr>
<td><font color="#808080">0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 &#8230;&#8230;&#8230;&#8230;&#8230;. 0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 &#8230;&#8230;&#8230;&#8230;&#8230;. 0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 &#8230;&#8230;..SciCalc. 0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 &#8230;&#8230;..backgrou 0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd&#8230;&#8230;&#8230;&#8230;..</font></td>
</tr>
<tr>
<td><font color="#808080">0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 b.| . 0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T . 0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |&#8230;&#8230;.. 0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 &#8230;. &#8230;.</font></td>
</tr>
<tr>
<td><font color="#808080"><font color="#00ccff">010119E0 PUSH EBP</font> 010119E1 MOV EBP,ESP 010119E3 PUSH -1 010119E5 PUSH 01001570 010119EA PUSH 01011D60 010119EF MOV EAX,DWORD PTR FS:[0] 010119F5 PUSH EAX 010119F6 MOV DWORD PTR FS:[0],ESP 010119FD ADD ESP,-68 01011A00 PUSH EBX 01011A01 PUSH ESI 01011A02 PUSH EDI 01011A03 MOV DWORD PTR SS:[EBP-18],ESP 01011A06 MOV DWORD PTR SS:[EBP-4],0</font></td>
</tr>
<tr>
<td><font color="#808080">:_</font><font color="#808080"></p>
<p>                </font></td>
</tr>
</tbody>
</table>
<h5>3.1.2 OllyDbg</h5>
<p>It was about four years ago that I first saw this debugger by chance. For me, it was the best choice; I was not wealthy enough to purchase SoftICE, and at that time, SoftICE only had good functions for <a href="http://en.wikipedia.org/wiki/DOS" target="new">DOS</a>, <a href="http://en.wikipedia.org/wiki/Windows_98" target="new">Windows 98</a>, and <a href="http://en.wikipedia.org/wiki/Windows_2000" target="new">Windows 2000</a>. I found that this debugger supported all kinds of Windows versions. Therefore, I started to learn it very fast, and now it is my favorite debugger for the Windows OS. It is a debugger that can be used to trace all kinds of portable executable files except a <a href="http://en.wikipedia.org/wiki/Common_Language_Infrastructure" target="new">Common Language Infrastructure (CLI)</a> file format in user mode level, by using the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/debugging_reference.asp" target="new">Windows debugging API</a>. <strong>Oleh Yuschuk</strong>, the author, is one of worthiest software developers I have seen in my life. He is a Ukrainian who now lives in Germany. I should mention here that his debugger is the best choice for hacker and cracker parties around the world! It is freeware! You can try it from the <a href="http://www.ollydbg.de/" target="new">OllyDbg Homepage</a>.</p>
<p>    <a name="more"><font color="#000000">&nbsp;</font>
<p><strong>Figure 2:</strong> OllyDbg CPU Window</p>
<p><img height="452" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=SCREENSHOT_JPG&amp;ds=20060302" width="500" alt="" /><br />    (</p>
<h5>3.1.3 Which parts are important in a debugger interface?</h5>
<p>I have introduced two debuggers without talking about how you can employ them, and also which parts you should pay attention to. Regarding using debuggers, I refer you to their instructions in help documents. However, I want to explain briefly the important parts of a debugger; of course, I am talking about low-level debuggers, or in other words, machine-language debuggers of the x86 CPU families.</p>
<p>All of low-level debuggers consist of the following subdivisions:</p>
<ol>
<li>Registers viewer.<br />
<table cellspacing="2" cellpadding="2" border="2">
<tbody>
<tr>
<td align="center"><font color="#808080">EAX</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">ECX</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">EDX</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">EBX</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">ESP</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">EBP</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">ESI</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">EDI</font></td>
</tr>
<tr>
<td align="center"><font color="#808080">EIP</font></td>
</tr>
<tr>
<td>
<p align="center"><font color="#808080">o</font><font color="#808080"> d t s z a p c</font></p>
</td>
</tr>
</tbody>
</table>
</li>
<li>Disassembler or Code viewer.<br />
<table cellspacing="2" cellpadding="2" border="2">
<tbody>
<tr>
<td>
<pre>010119E0 PUSH EBP010119E1 MOV EBP,ESP010119E3 PUSH -1010119E5 PUSH 01001570010119EA PUSH 01011D60010119EF MOV EAX,DWORD PTR FS:[0]010119F5 PUSH EAX010119F6 MOV DWORD PTR FS:[0],ESP010119FD ADD ESP,-6801011A00 PUSH EBX01011A01 PUSH ESI01011A02 PUSH EDI01011A03 MOV DWORD PTR SS:[EBP-18],ESP01011A06 MOV DWORD PTR SS:[EBP-4],0</pre>
</td>
</tr>
</tbody>
</table>
</li>
<li>Memory watcher.<br />
<table cellspacing="0" cellpadding="0" width="560" border="1">
<tbody>
<tr>
<td><font color="#808080">0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 &#8230;&#8230;&#8230;&#8230;&#8230;. 0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 &#8230;&#8230;&#8230;&#8230;&#8230;. 0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 &#8230;&#8230;..SciCalc. 0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 &#8230;&#8230;..backgrou 0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd&#8230;&#8230;&#8230;&#8230;..</font></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
</li>
<li>Stack viewer.<br />
<table cellspacing="0" cellpadding="0" width="560" border="1">
<tbody>
<tr>
<td><font color="#808080">0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 b.| . 0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T . 0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |&#8230;&#8230;.. 0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 &#8230;. &#8230;.</font></td>
</tr>
</tbody>
</table>
</li>
<li>Command line, command buttons, or shortcut keys to follow the debugging process.<br />
<table cellspacing="0" cellpadding="0" width="560" border="1">
<tbody>
<tr>
<td align="center">Command</td>
<td align="center">SoftICE</td>
<td align="center">OllyDbg</td>
</tr>
<tr>
<td align="center">Run</td>
<td align="center">F5</td>
<td align="center">F9</td>
</tr>
<tr>
<td align="center">Step Into</td>
<td align="center">F11</td>
<td align="center">F7</td>
</tr>
<tr>
<td align="center">Step Over</td>
<td align="center">F10</td>
<td align="center">F8</td>
</tr>
<tr>
<td align="center">Set Break Point</td>
<td align="center">F8</td>
<td align="center">F2</td>
</tr>
</tbody>
</table>
</li>
</ol>
<p>You can compare Figures 1 and 2 to distinguish the difference between SoftICE and OllyDbg. When you want to trace a PE file, you should mostly consider these five subdivisions. Furthermore, every debugger comprises of some other useful parts; you should discover them by yourself.</p>
<h4>3.2 Disassembler</h4>
<p>You can consider OllyDbg and SoftICE to be excellent disassemblers, but I also want to introduce another disassembler tool that is famous in the reverse engineering world.</p>
<h5>3.2.1 Proview disassembler</h5>
<p><a href="http://community.reverse-engineering.net/viewforum.php?f=50&amp;sid=a77c210bc1030dd395452bb7e1f67439" target="new">Proview</a> or <a href="http://pvdasm.reverse-engineering.net/" target="new" class="broken_link">PVDasm</a> is an admirable disassembler by the <a href="http://community.reverse-engineering.net/" target="new" class="broken_link">Reverse-Engineering-Community</a>; it is still under development and bug fixing. You can find its disassmbler source engine and employ it to create your own disassembler.</p>
<h5>3.2.2 W32Dasm</h5>
<p><a href="http://www.softpedia.com/get/Programming/Debuggers-Decompilers-Dissasemblers/WDASM.shtml" target="new">W32DASM</a> can disassemble both 16- and 32-bit executable file formats. In addition to its disassembling ability, you can employ it to analyze import, export, and resource data directories data.</p>
<h5>3.2.3 IDA Pro</h5>
<p>All reverse-engineering experts know that <a href="http://www.datarescue.com/idabase/idaproc.htm" target="new" class="broken_link">IDA Pro</a> can be used to investigate, not only x86 instructions, but that of various kinds of CPU types like AVR, PIC, and so forth. It can illustrate the assembly source of a portable executable file by using colored graphics and tables, and is very useful for any newbie in this area. Furthermore, it has the capability to trace an executable file inside the user mode level in the same way as OllyDbg.</p>
<h4>3.3 Some Useful Tools</h4>
<p>A good PE tools developer is conversant with the tools that save his time, so I recommend that you select some appropriate instruments to investigate the base information under a portable executable file.</p>
<h5>3.3.1 LordPE</h5>
<p><a href="http://www.softpedia.com/get/Programming/File-Editors/LordPE.shtml" target="new" class="broken_link">LordPE</a> by <a href="http://scifi.pages.at/yoda9k/aboutme.htm" target="new">y0da</a> is still the first choice to retrieve PE file information with the possibility to modify them.</p>
<p><img height="206" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=LORDPE_GIF&amp;ds=20060302" width="441" alt="" /></p>
<h5>3.3.2 PEiD</h5>
<p><a href="http://peid.has.it/" target="new">PE iDentifier</a> is valuable to identify the type of compilers, packers, and cryptors of PE files. As of now, it can detect more than 500 different signature types of PE files.</p>
<p><img height="166" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=PEID_GIF&amp;ds=20060302" width="296" alt="" /></p>
<h5>3.3.3 Resource Hacker</h5>
<p><a href="http://www.angusj.com/resourcehacker/" target="new">Resource Hacker </a>can be employed to modify resource directory information; icon, menu, version info, string table, and so on.</p>
<p><img height="141" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=RESOURCEHACKER_GIF&amp;ds=20060302" width="191" alt="" /></p>
<h5>3.3.4 WinHex</h5>
<p><a href="http://www.winhex.com/winhex/index-m.html" target="new">WinHex</a>, it is clear what you can do with this tool.</p>
<p><img height="230" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=WINHEX_GIF&amp;ds=20060302" width="329" alt="" /></p>
<h5>3.3.5 CFF Explorer</h5>
<p>Eventually, <a href="http://www.pmode.net/CFF.php" target="new" class="broken_link">CFF Explorer </a>by <a href="http://www.pmode.net/USERS/116/UserInfo.xml" target="new" class="broken_link">Ntoskrnl </a>is what you want to have as a PE Utility tool in your arsenal; it supports PE32/64, PE rebuild included <a href="http://en.wikipedia.org/wiki/Common_Language_Infrastructure" target="new">Common Language Infrastructure (CLI)</a> file. In other words, the <a href="http://en.wikipedia.org/wiki/Microsoft_.NET" target="new">.NET file</a>, a resource modifier, and much more facilities which can not be found in others. Just try to discover every unimaginable option by hand.</p>
<p><img height="217" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=CFFEXPLORER_GIF&amp;ds=20060302" width="301" alt="" /></p>
<h3>4 Add a New Section and Change the OEP</h3>
<p>You are ready to do the first step of making your project. I have provided a library to add a new section and rebuild the portable executable file. Before starting, I wnat you to get familiar with the headers of a PE file, by using <a href="http://www.ollydbg.de/" target="new">OllyDbg</a>. You should first open a PE file; that pops up a menu, <strong>View-&gt;Executable file</strong>. Again, you get a popup menu: <strong>Special-&gt;PE header</strong>. You will observe a scene similar to Figure 3. Now, come to the Main Menu <strong>View-&gt;Memory</strong>, and try to distinguish the sections inside the <strong>Memory map</strong> window.</p>
<h4>Figure 3</h4>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td><font color="#808080">
<pre>00000000000000020000000400000006000000080000000A0000000C0000000E00000010000000120000001400000016000000180000001A0000001C0000001D0000001E0000001F000000200000002100000022000000230000002400000025000000260000002700000028000000290000002A0000002B0000002C0000002D0000002E0000002F000000300000003100000032000000330000003400000035000000360000003700000038000000390000003A0000003B0000003C</pre>
<p>                </font></td>
<td>
<pre> 4D 5A 9000 0300 0000 0400 0000 FFFF 0000 B800 0000 0000 0000 4000 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0000000</pre>
</td>
<td>
<pre> ASCII <font color="#008000">&quot;MZ&quot;</font> DW 0090 DW 0003 DW 0000 DW 0004 DW 0000 DW FFFF DW 0000 DW 00B8 DW 0000 DW 0000 DW 0000 DW 0040 DW 0000 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DD <font color="#ff0000">000000F0</font></pre>
</td>
<td>
<pre> DOS EXE Signature DOS_PartPag = 90 (144.) DOS_PageCnt = 3 DOS_ReloCnt = 0 DOS_HdrSize = 4 DOS_MinMem = 0 DOS_MaxMem = FFFF (65535.) DOS_ReloSS = 0 DOS_ExeSP = B8 DOS_ChkSum = 0 DOS_ExeIP = 0 DOS_ReloCS = 0 DOS_TablOff = 40 DOS_Overlay = 0 Offset to PE signature</pre>
</td>
</tr>
</tbody>
</table>
<p>    <a name="more"><font color="#000000">&nbsp;</font>
<p>I want to explain how you can plainly change the Offset of Entry Point (OEP) in your sample file, <em>CALC.EXE</em> of Windows XP. First, by using a PE Tool, and also using your PE Viewer, you find OEP, <tt>0x00012475</tt>, and Image Base, <tt>0x01000000</tt>. This value of OEP is the Relative Virtual Address, so the Image Base value is used to convert it to the Virtual Address.</p>
<table cellspacing="0" cellpadding="0" width="450" border="1">
<tbody>
<tr>
<td>
<p><strong>Virtual_Address = Image_Base + Relative_Virtual_Address</strong></p>
</td>
</tr>
</tbody>
</table>
<pre>DWORD OEP_RVA = image_nt_headers-&gt;   OptionalHeader.AddressOfEntryPoint ;<span class="codeComment">// OEP_RVA = 0x00012475</span>DWORD OEP_VA = image_nt_headers-&gt;   OptionalHeader.ImageBase + OEP_RVA ;<span class="codeComment">// OEP_VA = 0x01000000 + 0x00012475 = 0x01012475</span></pre>
<h4>PE Maker: Step 1</h4>
<p>Download pemaker1.zip and test1.zip from the files at the end of this article.</p>
<p><tt>DynLoader()</tt>, in <em>loader.cpp</em>, is reserved for the data of the new section&mdash;in other words, the <strong>Loader</strong>.</p>
<h4>DynLoader Step 1</h4>
<pre><span class="codeKeyword">__stdcall</span> <span class="codeKeyword">void</span> DynLoader(){_asm{<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_MAGIC)<span class="codeComment">//----------------------------------</span>    MOV EAX,01012475h <span class="codeComment">// &lt;&lt; Original OEP</span>    JMP EAX<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_END_MAGIC)<span class="codeComment">//----------------------------------</span>}}</pre>
<p>Unfortunately, this source can only be applied for the sample test file. You should complete it by saving the value of the original OEP in the new section, and use it to reach the real OEP. I have accomplished it in Step 2 (Section 5).</p>
<h4>4.1 Retrieve and Rebuild PE file</h4>
<p>I have made a simple class library to recover PE information and to use it in a new PE file.</p>
<h4>CPELibrary Class Step 1</h4>
<pre><span class="codeComment">//----------------------------------------------------------------</span><span class="codeKeyword">class</span> CPELibrary{<span class="codeKeyword">private</span>:    <span class="codeComment">//-----------------------------------------</span>    PCHAR                   pMem;    DWORD                   dwFileSize;    <span class="codeComment">//-----------------------------------------</span><span class="codeKeyword">protected</span>:    <span class="codeComment">//-----------------------------------------</span>    PIMAGE_DOS_HEADER       image_dos_header;    PCHAR                   pDosStub;    DWORD                   dwDosStubSize, dwDosStubOffset;    PIMAGE_NT_HEADERS       image_nt_headers;    PIMAGE_SECTION_HEADER   image_section_header[MAX_SECTION_NUM];    PCHAR                   image_section[MAX_SECTION_NUM];    <span class="codeComment">//-----------------------------------------</span><span class="codeKeyword">protected</span>:    <span class="codeComment">//-----------------------------------------</span>    DWORD PEAlign(DWORD dwTarNum,DWORD dwAlignTo);    <span class="codeKeyword">void</span> AlignmentSections();    <span class="codeComment">//-----------------------------------------</span>    DWORD Offset2RVA(DWORD dwRO);    DWORD RVA2Offset(DWORD dwRVA);    <span class="codeComment">//-----------------------------------------</span>    PIMAGE_SECTION_HEADER ImageRVA2Section(DWORD dwRVA);    PIMAGE_SECTION_HEADER ImageOffset2Section(DWORD dwRO);    <span class="codeComment">//-----------------------------------------</span>    DWORD ImageOffset2SectionNum(DWORD dwRVA);    PIMAGE_SECTION_HEADER AddNewSection(<span class="codeKeyword">char</span>* szName,DWORD dwSize);    <span class="codeComment">//-----------------------------------------</span><span class="codeKeyword">public</span>:    <span class="codeComment">//-----------------------------------------</span>    CPELibrary();    ~CPELibrary();    <span class="codeComment">//-----------------------------------------</span>    <span class="codeKeyword">void</span> OpenFile(<span class="codeKeyword">char</span>* FileName);    <span class="codeKeyword">void</span> SaveFile(<span class="codeKeyword">char</span>* FileName);    <span class="codeComment">//-----------------------------------------</span>};</pre>
<p>In Table 1, the usage of <tt>image_dos_header</tt>, <tt>pDosStub</tt>, <tt>image_nt_headers</tt>, <tt>image_section_header</tt> [<tt>MAX_SECTION_NUM</tt>], and <tt>image_section</tt>[<tt>MAX_SECTION_NUM</tt>] is clear. You use <tt>OpenFile()</tt> and <tt>SaveFile()</tt> to retrieve and rebuild a PE file. Furthermore, <tt>AddNewSection()</tt> is employed to create the new section, the important step.</p>
<p>    </a><br />
<h4>4.2 Create data for the new section</h4>
<p><a name="more"><font color="#000000"> </font></a><a href="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=LINKTIP1_GIF&amp;ds=20060302" target="_blank">Full Size Image</a>)
<p>You can comprehend the difference between incremental link and no-incremental link by looking at the following picture:</p>
<p>    <img height="130" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=INCREMENTAL_LINK_GIF&amp;ds=20060302" width="415" alt="" />
<p>To acquire the virtual address of <tt>DynLoader()</tt>, you obtain the virtual address of <tt>JMP pemaker.DynLoader</tt> in the incremental link, but by no-incremental link, the real virtual address is gained by the following code:</p>
<pre>DWORD dwVA= (DWORD) DynLoader;</pre>
<p>This setting is more critical in the incremental link when you try to find the beginning and ending of the <strong>Loader</strong>, <tt>DynLoader()</tt>, by <tt>CPECryptor::ReturnToBytePtr()</tt>:</p>
<pre><span class="codeKeyword">void</span>* CPECryptor::ReturnToBytePtr(<span class="codeKeyword">void</span>* FuncName, DWORD findstr){    <span class="codeKeyword">void</span>* tmpd;    __asm   {        mov eax, FuncName        jmp dfhjg:    inc eaxdf:     mov ebx, [eax]        cmp ebx, findstr        jnz hjg        mov tmpd, eax    }    <span class="codeKeyword">return</span> tmpd;}</pre>
</p>
<p>In <em>pecrypt.cpp</em>, I have represented another class, <tt>CPECryptor</tt>, to comprise the data of the new section. Nevertheless, the data of the new section is created by <tt>DynLoader()</tt> in <em>loader.cpp</em>, DynLoader Step 1. You use the <tt>CPECryptor</tt> class to enter this data in to the new section, and also some other stuff.</p>
<h4>CPECryptor Class Step 1</h4>
<pre><span class="codeComment">//----------------------------------------------------------------</span><span class="codeKeyword">class</span> CPECryptor: <span class="codeKeyword">public</span> CPELibrary{<span class="codeKeyword">private</span>:    <span class="codeComment">//----------------------------------------</span>    PCHAR pNewSection;    <span class="codeComment">//----------------------------------------</span>    DWORD GetFunctionVA(<span class="codeKeyword">void</span>* FuncName);    <span class="codeKeyword">void</span>* ReturnToBytePtr(<span class="codeKeyword">void</span>* FuncName, DWORD findstr);    <span class="codeComment">//----------------------------------------</span><span class="codeKeyword">protected</span>:    <span class="codeComment">//----------------------------------------</span><span class="codeKeyword">public</span>:    <span class="codeComment">//----------------------------------------</span>    <span class="codeKeyword">void</span> CryptFile(<span class="codeKeyword">int</span>(__cdecl *callback) (<span class="codeKeyword">unsigned</span> <span class="codeKeyword">int</span>,                                           <span class="codeKeyword">unsigned</span> <span class="codeKeyword">int</span>));    <span class="codeComment">//----------------------------------------</span>};<span class="codeComment">//----------------------------------------------------------------</span></pre>
<h4>4.3 Some notes regarding creating a new PE file</h4>
<ul>
<li>Align the <tt>VirtualAddress</tt> and the <tt>VirtualSize</tt> of each section by <tt>SectionAlignment</tt>:
<pre>image_section_header[i]-&gt;VirtualAddress=    PEAlign(image_section_header[i]-&gt;VirtualAddress,    image_nt_headers-&gt;OptionalHeader.SectionAlignment);image_section_header[i]-&gt;Misc.VirtualSize=    PEAlign(image_section_header[i]-&gt;Misc.VirtualSize,    image_nt_headers-&gt;OptionalHeader.SectionAlignment);</pre>
</li>
<li>Align the <tt>PointerToRawData</tt> and the <tt>SizeOfRawData</tt> of each section by <tt>FileAlignment</tt>:
<pre>image_section_header[i]-&gt;PointerToRawData =    PEAlign(image_section_header[i]-&gt;PointerToRawData,            image_nt_headers-&gt;OptionalHeader.FileAlignment);image_section_header[i]-&gt;SizeOfRawData =    PEAlign(image_section_header[i]-&gt;SizeOfRawData,            image_nt_headers-&gt;OptionalHeader.FileAlignment);</pre>
</li>
<li>Correct the <tt>SizeofImage</tt> by the virtual size and the virtual address of the last section:
<pre>image_nt_headers-&gt;OptionalHeader.SizeOfImage =   image_section_header[LastSection]-&gt;VirtualAddress +   image_section_header[LastSection]-&gt;Misc.VirtualSize;</pre>
</li>
<li>Set the Bound Import Directory header to zero because this directory is not very important to execute a PE file:
<pre>image_nt_headers-&gt;   OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].  VirtualAddress = 0;image_nt_headers-&gt;   OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_                                IMPORT].Size = 0;</pre>
</li>
</ul>
<h4>4.4 Some notes regarding linking this VC Project</h4>
<ul>
<li>Set <em>Linker-&gt;General-&gt;Enable Incremental Linking</em> to <strong>No (/INCREMENTAL:NO)</strong>.</p>
<p>        <img height="125" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=LINKTIP1_GIF&amp;ds=20060302" width="500" alt="" /><br />        (</li>
</ul>
<h3>5 Store Important Data and Reach the Original OEP</h3>
<p>Right now, we save the Original OEP and also the Image Base in order to reach to the virtual address of OEP. I have reserved a free space at the end of <tt>DynLoader()</tt> to store them, DynLoader Step 2.</p>
<h4>PE Maker &#8211; Step 2</h4>
<p>Download the pemaker2.zip source files from the end of the article.</p>
<h4>DynLoader Step 2</h4>
<pre><span class="codeKeyword">__stdcall</span> <span class="codeKeyword">void</span> DynLoader(){_asm{<span class="codeComment">//------------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_MAGIC)<span class="codeComment">//------------------------------------</span>Main_0:    PUSHAD    <span class="codeComment">// get base ebp</span>    CALL Main_1Main_1:    POP EBP    SUB EBP,OFFSET Main_1    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]    PUSH EAX    RETN <span class="codeComment">// &gt;&gt; JMP to Original OEP</span><span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_DATA1)<span class="codeComment">//----------------------------------<font color="#ff0000"></font><span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_END_MAGIC)<span class="codeComment">//----------------------------------</span>}}</span>_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)</pre>
<p>The new function, <tt>CPECryptor::CopyData1()</tt>, will implement the copy of the Image Base value and the Offset of Entry Point value into 8 bytes of free space in the loader.</p>
<h4>5.1 Restore the first register&#8217;s context</h4>
<p>It is important to recover the Original Context of the thread. You have not yet done it in the DynLoader Step 2 source code. You can modify the source of <tt>DynLoader()</tt> to repossess the first Context.</p>
<pre><span class="codeKeyword">__stdcall</span> <span class="codeKeyword">void</span> DynLoader(){_asm{<span class="codeComment">//------------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_MAGIC)<span class="codeComment">//------------------------------------</span>Main_0:    <font color="#ff0000">PUSHAD<span class="codeComment">// Save the registers context in stack</span>    CALL Main_1Main_1:    POP EBP<span class="codeComment">// Get Base EBP</span>    SUB EBP,OFFSET Main_1    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]    MOV DWORD PTR [ESP+1Ch],EAX <span class="codeComment">// pStack.Eax &lt;- EAX</span>    <font color="#ff0000">POPAD <span class="codeComment">// Restore the first registers context from stack</span>    PUSH EAX    XOR  EAX, EAX    RETN <span class="codeComment">// &gt;&gt; JMP to Original OEP</span><span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_DATA1)<span class="codeComment">//----------------------------------</span>_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_END_MAGIC)<span class="codeComment">//----------------------------------</span>}}</font></font></pre>
<h4>5.2 Restore the original stack</h4>
<p>You also can recover the original stack by setting the value of the beginning stack + <tt>0x34</tt> to the Original OEP, but it is not very important. Nevertheless, in the following code, I have accomplished the loader code by a simple trick to reach the OEP in addition to redecorating the stack. You can observe the implementation by tracing using <a href="http://www.ollydbg.de/" target="new">OllyDbg</a> or SoftICE.</p>
<pre><span class="codeKeyword">__stdcall</span> <span class="codeKeyword">void</span> DynLoader(){_asm{<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_MAGIC)<span class="codeComment">//----------------------------------</span>Main_0:    PUSHAD    <span class="codeComment">// Save the registers context in stack</span>    CALL Main_1Main_1:    POP EBP    SUB EBP,OFFSET Main_1    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]    MOV DWORD PTR [ESP+54h],EAX    <span class="codeComment">// pStack.Eip &lt;- EAX</span>    POPAD    <span class="codeComment">// Restore the first registers context from stack</span>    CALL _OEP_Jump    DWORD_TYPE(0xCCCCCCCC)_OEP_Jump:    PUSH EBP    MOV EBP,ESP    MOV EAX,DWORD PTR [ESP+3Ch]    <span class="codeComment">// EAX &lt;- pStack.Eip</span>    MOV DWORD PTR [ESP+4h],EAX     <span class="codeComment">// _OEP_Jump RETURN pointer &lt;- EAX</span>    XOR EAX,EAX    LEAVE    RETN<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_DATA1)<span class="codeComment">//----------------------------------</span>_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_END_MAGIC)<span class="codeComment">//----------------------------------</span>}}</pre>
<h4>5.3 Approach OEP by structured exception handling</h4>
<p><a name="more"><font color="#000000"> </font></a><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/key_s-z_4.asp" target="new"><tt>try-except</tt> statement</a> in C++ clarifies the operation of <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/about_structured_exception_handling.asp" target="new">structured exception handling</a>. Besides the assembly code of this code, it elucidates the structured exception handler installation, the raise of an exception, and the exception handler function.</p>
<p>An exception is generated when a program falls into a fault code execution and an error happens, so in such a special condition, the program immediately jumps to a function called the exception handler from exception handler list of the Thread Information Block.</p>
<p>The next example of a </p>
<pre><span class="codeKeyword">#include</span> &quot;stdafx.h&quot;<span class="codeKeyword">#include</span> &quot;windows.h&quot;<span class="codeKeyword">void</span> RAISE_AN_EXCEPTION(){_asm{    INT 3    INT 3    INT 3    INT 3}}<span class="codeKeyword">int</span> _tmain(<span class="codeKeyword">int</span> argc, _TCHAR* argv[]){    <span class="codeKeyword">__try</span>    {        <span class="codeKeyword">__try</span>{            printf(&quot;1: Raise an Exception\n&quot;);            RAISE_AN_EXCEPTION();        }        <span class="codeKeyword">__finally</span>        {            printf(&quot;2: In Finally\n&quot;);        }    }    <span class="codeKeyword">__except</span>( printf(&quot;3: In Filter\n&quot;), EXCEPTION_EXECUTE_HANDLER )    {        printf(&quot;4: In Exception Handler\n&quot;);    }    <span class="codeKeyword">return</span> 0;}</pre>
<pre><font color="#000000"><strong>; main()</strong></font><font color="#808080">00401000: PUSH EBP00401001: MOV EBP,ESP00401003: PUSH -100401005: PUSH 00407160<font color="#000000"><strong>; <span class="codeKeyword">__try</span> {</strong></font><font color="#008000">; the structured exception handler (SEH) installation </font><font color="#0000ff">0040100A: PUSH _except_handler30040100F: MOV EAX,DWORD PTR FS:[0]00401015: PUSH EAX00401016: MOV DWORD PTR FS:[0],ESP</font>0040101D: SUB ESP,800401020: PUSH EBX00401021: PUSH ESI00401022: PUSH EDI00401023: MOV DWORD PTR SS:[EBP-18],ESP<font color="#000000"><strong>;     <span class="codeKeyword">__try</span> {</strong></font>00401026: XOR ESI,ESI00401028: MOV DWORD PTR SS:[EBP-4],ESI0040102B: MOV DWORD PTR SS:[EBP-4],100401032: PUSH OFFSET <font color="#a52a2a">&quot;1: Raise an Exception&quot;</font>00401037: CALL printf0040103C: ADD ESP,4<font color="#008000">; the raise a exception, INT 3 exception</font>; RAISE_AN_EXCEPTION()<font color="#0000ff">0040103F: INT300401040: INT300401041: INT300401042: INT3</font><font color="#000000"><strong>;     } <span class="codeKeyword">__finally</span> {</strong></font>00401043: MOV DWORD PTR SS:[EBP-4],ESI00401046: CALL 0040104D0040104B: JMP 004010800040104D: PUSH OFFSET <font color="#a52a2a">&quot;2: In Finally&quot;</font>00401052: CALL printf00401057: ADD ESP,40040105A: RETN<font color="#000000"><strong>;     }</strong></font><font color="#000000"><strong>; }</strong></font><font color="#000000"><strong>; <span class="codeKeyword">__except</span>( </strong></font>0040105B: JMP 004010800040105D: PUSH OFFSET <font color="#a52a2a">&quot;3: In Filter&quot;</font>00401062: CALL printf00401067: ADD ESP,40040106A: MOV EAX,1 ; EXCEPTION_EXECUTE_HANDLER = 10040106F: RETN<font color="#000000"><strong>;     , EXCEPTION_EXECUTE_HANDLER )</strong></font><font color="#000000"><strong>; {</strong></font><font color="#008000">; the exception handler funtion</font><font color="#0000ff">00401070: MOV ESP,DWORD PTR SS:[EBP-18]00401073: PUSH OFFSET <font color="#a52a2a">&quot;4: In Exception Handler&quot;</font>00401078: CALL printf0040107D: ADD ESP,4</font><font color="#000000"><strong>; }</strong></font>00401080: MOV DWORD PTR SS:[EBP-4],-10040108C: XOR EAX,EAX<font color="#008000">; restore previous SEH</font><font color="#0000ff">0040108E: MOV ECX,DWORD PTR SS:[EBP-10]00401091: MOV DWORD PTR FS:[0],ECX</font>00401098: POP EDI00401099: POP ESI0040109A: POP EBX0040109B: MOV ESP,EBP0040109D: POP EBP0040109E: RETN</font></pre>
<p>Make a Win32 console project, and link and run the preceding C++ code, to perceive the result:</p>
<p>
<table cellspacing="0" cellpadding="0" width="400" border="1">
<tbody bgcolor="#000000" color="gray">
<tr>
<td><font color="#ffffff"><strong>1: Raise an Exception<br />                3: In Filter<br />                2: In Finally<br />                4: In Exception Handler<br />                _</p>
<p>                </strong></font></td>
</tr>
</tbody>
</table>
<p>This program runs the exception expression, <tt>printf(&quot;3: In Filter\n&quot;);</tt>, when an exception happens&mdash;in this example, the <tt>INT 3</tt> exception. You can employ other kinds of exception too. In <a href="http://www.ollydbg.de/" target="new">OllyDbg</a>, <strong>Debugging options-&gt;Exceptions</strong>, you can see a short list of different types of exceptions.</p>
<p><img height="200" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=OLLYDBG_EXCEPTIONS_GIF&amp;ds=20060302" width="280" alt="" /></p>
<h5>5.3.1 Implement Exception Handler</h5>
<p>You want to construct a structured exception handler to reach OEP. Now, I think you have distinguished the SEH installation, the exception raise, and the exception expression filter, by foregoing the assembly code. To establish your exception handler approach, you need to comprise the following codes:</p>
<ul>
<li><strong>SEH installation</strong>:
<pre><font color="#808080">LEA EAX,[EBP+_except_handler1_OEP_Jump]PUSH EAXPUSH DWORD PTR FS:[0]MOV DWORD PTR FS:[0],ESP</font></pre>
</li>
<li><strong>An Exception Raise</strong>:
<pre><font color="#808080">INT 3</font></pre>
</li>
<li><strong>Exception handler expression filter</strong>:
<pre><font color="#808080">_except_handler1_OEP_Jump:   PUSH EBP   MOV EBP,ESP   ...   <span class="codeComment">// EXCEPTION_CONTINUE_SEARCH = 0</span>   MOV EAX, EXCEPTION_CONTINUE_SEARCH   LEAVE   RETN</font></pre>
</li>
</ul>
<p>So, you yearn to make the ensuing C++ code in assembly language to inaugurate your engine to approach the Offset of the Entry Point by SEH.</p>
<pre><span class="codeKeyword">__try</span>    <span class="codeComment">// SEH installation</span>{    __asm    {        INT 3    <span class="codeComment">// An Exception Raise</span>    }}<span class="codeKeyword">__except</span>( ..., EXCEPTION_CONTINUE_SEARCH ){}<span class="codeComment">// Exception handler expression filter</span></pre>
<p>In assembly code&#8230;</p>
<pre><font color="#808080">    <font color="#008000">; ----------------------------------------------------    ; the structured exception handler (SEH) installation    <font color="#000000"><strong>; <span class="codeKeyword">__try</span> {</strong></font></font>    LEA EAX,[EBP+_except_handler1_OEP_Jump]    PUSH EAX    PUSH DWORD PTR FS:[0]    MOV DWORD PTR FS:[0],ESP    <font color="#008000">; ----------------------------------------------------    ; the raise a INT 3 exception</font>    INT 3    INT 3    INT 3    INT 3    <font color="#000000"><strong>; }    ; <span class="codeKeyword">__except</span>( ... </strong></font>    <font color="#008000">; ----------------------------------------------------    ; exception handler expression filter</font>_except_handler1_OEP_Jump:    PUSH EBP    MOV EBP,ESP    ...    MOV EAX, EXCEPTION_CONTINUE_SEARCH ; EXCEPTION_CONTINUE_SEARCH = 0    LEAVE    RETN    <font color="#000000"><strong>; , EXCEPTION_CONTINUE_SEARCH ) { }</strong></font></font></pre>
<p>The exception value, <tt>__except(..., Value)</tt>, determines how the exception is handled. It can have three values: 1, 0, -1. To understand them, refer to the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/key_s-z_4.asp" target="new"><tt>try-except</tt> statement</a> description in the MSDN library. You set it to <tt>EXCEPTION_CONTINUE_SEARCH (0)</tt>, not to run the exception handler function; therefore, by this value, the exception is not recognized. It is simply ignored, and the thread continues its code execution.</p>
<h4>How the SEH installation is implemented</h4>
<p>As you perceived from the illustrated code, the SEH installation is done by the FS segment register. Microsoft Windows 32 bit uses the FS segment register as a pointer to the data block of the main thread. The first <font color="#0000ff">0x1C</font> bytes comprise the information of the Thread Information Block (TIB). Therefore, <tt>FS:[00h]</tt> refers to <tt>ExceptionList</tt> of the main thread, Table 3. In your code, you have pushed the pointer to <tt>_except_handler1_OEP_Jump</tt> in the stack and changed the value of <tt>ExceptionList</tt>, <tt>FS:[00h]</tt>, to the beginning of the stack, <tt>ESP</tt>.</p>
<h4>Thread Information Block (TIB)</h4>
<pre><span class="codeKeyword">typedef</span> <span class="codeKeyword">struct</span> _NT_TIB32 {   DWORD ExceptionList;   DWORD StackBase;   DWORD StackLimit;   DWORD SubSystemTib;   <span class="codeKeyword">union</span> {      DWORD FiberData;      DWORD Version;   };   DWORD ArbitraryUserPointer;   DWORD Self;} NT_TIB32, *PNT_TIB32;</pre>
<h4>Table 3: FS segment register and Thread Information Block</h4>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td align="center"><font color="#0000ff">DWORD PTR FS:[00h]</font></td>
<td align="center">ExceptionList</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">DWORD PTR FS:[04h]</font></td>
<td align="center">StackBase</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">DWORD PTR FS:[08h]</font></td>
<td align="center">StackLimit</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">DWORD PTR FS:[0Ch]</font></td>
<td align="center">SubSystemTib</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">DWORD PTR FS:[10h]</font></td>
<td align="center">FiberData / Version</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">DWORD PTR FS:[14h]</font></td>
<td align="center">ArbitraryUserPointer</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">DWORD PTR FS:[18h]</font></td>
<td align="center">Self</td>
</tr>
</tbody>
</table>
<h5>5.3.2 Attain OEP by adjusting the Thread Context</h5>
<p>In this part, you effectuate your performance by accomplishing the OEP approach. You change the Context of the thread and ignore every simple exception handling, and let the thread continue the execution, but in the original OEP!</p>
<p>    <a name="more"><font color="#000000">&nbsp;</font>
<p>When an exception happens, the context of the processor during the time of the exception is saved in the stack. Through </p>
<pre>MOV EAX, ContextRecordMOV EDI, dwOEP                   ; EAX &lt;- dwOEPMOV DWORD PTR DS:[EAX+0B8h], EDI ; pContext.Eip &lt;- EAX</pre>
<h4>Win32 Thread Context structure</h4>
<pre><span class="codeKeyword">#define</span> MAXIMUM_SUPPORTED_EXTENSION     512<span class="codeKeyword">typedef</span> <span class="codeKeyword">struct</span> _CONTEXT {    <span class="codeComment">//-----------------------------------------</span>    DWORD ContextFlags;    <span class="codeComment">//-----------------------------------------</span>    DWORD   Dr0;    DWORD   Dr1;    DWORD   Dr2;    DWORD   Dr3;    DWORD   Dr6;    DWORD   Dr7;    <span class="codeComment">//-----------------------------------------</span>    FLOATING_SAVE_AREA FloatSave;    <span class="codeComment">//-----------------------------------------</span>    DWORD   SegGs;    DWORD   SegFs;    DWORD   SegEs;    DWORD   SegDs;    <span class="codeComment">//-----------------------------------------</span>    DWORD   Edi;    DWORD   Esi;    DWORD   Ebx;    DWORD   Edx;    DWORD   Ecx;    DWORD   Eax;    <span class="codeComment">//-----------------------------------------</span>    DWORD   Ebp;    DWORD   Eip;    DWORD   SegCs;    DWORD   EFlags;    DWORD   Esp;    DWORD   SegSs;    <span class="codeComment">//-----------------------------------------</span>    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];    <span class="codeComment">//----------------------------------------</span>} CONTEXT,*LPCONTEXT;</pre>
<h4>Table 4: CONTEXT</h4>
<table cellspacing="0" cellpadding="0" width="200" border="1">
<tbody>
<tr>
<td align="center" height="35">Context Flags</td>
<td align="center" height="35"><font color="#0000ff">0&#215;00000000</font></td>
<td align="center" colspan="2" height="35"><tt>ContextFlags</tt></td>
</tr>
<tr>
<td align="center" rowspan="6">
<p>Context Debug Registers</p>
</td>
<td align="center"><font color="#0000ff">0&#215;00000004</font></td>
<td align="center" colspan="2"><tt>Dr0</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000008</font></td>
<td align="center" colspan="2"><tt>Dr1</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x0000000C</font></td>
<td align="center" colspan="2"><tt>Dr2</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000010</font></td>
<td align="center" colspan="2"><tt>Dr3</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000014</font></td>
<td align="center" colspan="2"><tt>Dr6</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000018</font></td>
<td align="center" colspan="2"><tt>Dr7</tt></td>
</tr>
<tr>
<td align="center" rowspan="9">
<p>Context Floating Point</p>
</td>
<td align="center"><font color="#0000ff">0x0000001C</font></td>
<td align="center" rowspan="9"><tt>FloatSave</tt></td>
<td align="center"><tt>StatusWord</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000020</font></td>
<td align="center"><tt>StatusWord</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000024</font></td>
<td align="center"><tt>TagWord</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000028</font></td>
<td align="center"><tt>ErrorOffset</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x0000002C</font></td>
<td align="center"><tt>ErrorSelector</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000030</font></td>
<td align="center"><tt>DataOffset</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000034</font></td>
<td align="center"><tt>DataSelector</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000038<br />                &#8230;<br />                0&#215;00000087</font></td>
<td align="center"><tt>RegisterArea</tt> [<font color="#0000ff">0x50</font>]</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000088</font></td>
<td align="center"><tt>Cr0NpxState</tt></td>
</tr>
<tr>
<td align="center" rowspan="4">Context Segments</td>
<td align="center"><font color="#0000ff">0x0000008C</font></td>
<td align="center" colspan="2"><tt>SegGs</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000090</font></td>
<td align="center" colspan="2"><tt>SegFs</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000094</font></td>
<td align="center" colspan="2"><tt>SegEs</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0&#215;00000098</font></td>
<td align="center" colspan="2"><tt>SegDs</tt></td>
</tr>
<tr>
<td align="center" rowspan="6">Context Integer</td>
<td align="center"><font color="#0000ff">0x0000009C</font></td>
<td align="center" colspan="2"><tt>Edi</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000A0</font></td>
<td align="center" colspan="2"><tt>Esi</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000A4</font></td>
<td align="center" colspan="2"><tt>Ebx</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000A8</font></td>
<td align="center" colspan="2"><tt>Edx</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000AC</font></td>
<td align="center" colspan="2"><tt>Ecx</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000B0</font></td>
<td align="center" colspan="2"><tt>Eax</tt></td>
</tr>
<tr>
<td align="center" rowspan="6">Context Control</td>
<td align="center"><font color="#0000ff">0x000000B4</font></td>
<td align="center" colspan="2"><tt>Ebp</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000B8</font></td>
<td align="center" colspan="2"><tt>Eip</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000BC</font></td>
<td align="center" colspan="2"><tt>SegCs</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000C0</font></td>
<td align="center" colspan="2"><tt>EFlags</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000C4</font></td>
<td align="center" colspan="2"><tt>Esp</tt></td>
</tr>
<tr>
<td align="center"><font color="#0000ff">0x000000C8</font></td>
<td align="center" colspan="2"><tt>SegSs</tt></td>
</tr>
<tr>
<td align="center">Context Extended Registers</td>
<td align="center">
<p align="center"><font color="#0000ff">0x000000CC<br />                &#8230;<br />                0x000002CB</font></p>
</td>
<td align="center" colspan="2"><tt>ExtendedRegisters</tt>[<font color="#0000ff">0x200</font>]</td>
</tr>
</tbody>
</table>
<p>By the following code, you have accomplished the main purpose of coming to OEP by the structured exception handler:</p>
<pre><span class="codeKeyword">__stdcall</span> <span class="codeKeyword">void</span> DynLoader(){_asm{<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_MAGIC)<span class="codeComment">//----------------------------------</span>Main_0:    PUSHAD  <span class="codeComment">// Save the registers context in stack</span>    CALL Main_1Main_1:    POP EBP    SUB EBP,OFFSET Main_1 <span class="codeComment">// Get Base EBP</span>    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]    MOV DWORD PTR [ESP+10h],EAX    <span class="codeComment">// pStack.Ebx &lt;- EAX</span>    LEA EAX,[EBP+_except_handler1_OEP_Jump]    MOV DWORD PTR [ESP+1Ch],EAX    <span class="codeComment">// pStack.Eax &lt;- EAX</span>    POPAD  <span class="codeComment">// Restore the first registers context from stack</span>    <span class="codeComment">//----------------------------------------------------</span>    <span class="codeComment">// the structured exception handler (SEH) installation</span>    PUSH EAX    XOR  EAX, EAX    PUSH DWORD PTR FS:[0]       <span class="codeComment">// NT_TIB32.ExceptionList</span>    MOV DWORD PTR FS:[0],ESP    <span class="codeComment">// NT_TIB32.ExceptionList &lt;-ESP</span>    <span class="codeComment">//----------------------------------------------------</span>    <span class="codeComment">// the raise a INT 3 exception</span>    DWORD_TYPE(0xCCCCCCCC)    <span class="codeComment">//--------------------------------------------------------</span><span class="codeComment">// -------- exception handler expression filter ----------</span>_except_handler1_OEP_Jump:    PUSH EBP    MOV EBP,ESP    <span class="codeComment">//------------------------------</span>    MOV EAX,DWORD PTR SS:[EBP+010h]   <span class="codeComment">// PCONTEXT: pContext &lt;- EAX</span>    <span class="codeComment">//==============================</span>    PUSH EDI    <span class="codeComment">// restore original SEH</span>    MOV EDI,DWORD PTR DS:[EAX+0C4h]    <span class="codeComment">// pContext.Esp</span>    PUSH DWORD PTR DS:[EDI]    POP DWORD PTR FS:[0]    ADD DWORD PTR DS:[EAX+0C4h],8    <span class="codeComment">// pContext.Esp</span>    <span class="codeComment">//------------------------------</span>    <span class="codeComment">// set the Eip to the OEP</span>    MOV EDI,DWORD PTR DS:[EAX+0A4h] <span class="codeComment">// EAX &lt;- pContext.Ebx</span>    MOV DWORD PTR DS:[EAX+0B8h],EDI <span class="codeComment">// pContext.Eip &lt;- EAX</span>    <span class="codeComment">//------------------------------</span>    POP EDI    <span class="codeComment">//==============================</span>    MOV EAX, EXCEPTION_CONTINUE_SEARCH    LEAVE    RETN<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_START_DATA1)<span class="codeComment">//----------------------------------</span>_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)<span class="codeComment">//----------------------------------</span>    DWORD_TYPE(DYN_LOADER_END_MAGIC)<span class="codeComment">//----------------------------------</span>}}</pre>
<h3>6 Build an Import Table and Reconstruct the Original Import Table</h3>
<p>There are two ways to use the Windows <a href="http://en.wikipedia.org/wiki/Microsoft_Dynamic_Link_Library" target="new">dynamic link library (DLL)</a> in Windows application programming:</p>
<ul>
<li><strong>Using Windows libraries by additional dependencies</strong>:&nbsp;<br />        <a name="more"><font color="#000000"> </font>
<p><font color="#000000"><img height="145" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=DEPENDENCIES_GIF&amp;ds=20060302" width="500" alt="" /><br />        </font>(</p>
<p>        </a><a href="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=DEPENDENCIES_GIF&amp;ds=20060302" target="_blank">Full Size Image</a>)</li>
<li><strong>Using Windows dynamic link libraries in run-time</strong>:
<pre><span class="codeComment">// DLL function signature</span><span class="codeKeyword">typedef</span> HGLOBAL (*importFunction_GlobalAlloc)(UINT, SIZE_T);...importFunction_GlobalAlloc __GlobalAlloc;<span class="codeComment">// Load DLL file</span>HINSTANCE hinstLib = LoadLibrary(&quot;Kernel32.dll&quot;);<span class="codeKeyword">if</span> (hinstLib == <span class="codeKeyword">NULL</span>){   <span class="codeComment">// Error - unable to load DLL</span>}<span class="codeComment">// Get function pointer</span>__GlobalAlloc =   (importFunction_GlobalAlloc)GetProcAddress(hinstLib,                                              &quot;GlobalAlloc&quot;);<span class="codeKeyword">if</span> (addNumbers == <span class="codeKeyword">NULL</span>){    <span class="codeComment">// Error - unable to find DLL function</span>}FreeLibrary(hinstLib);</pre>
</li>
</ul>
<p>When you make a Windows application project, the linker includes at least <em>kernel32.dll</em> in the base dependencies of your project. Without <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp" target="new"><tt>LoadLibrary()</tt></a> and <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocaddress.asp" target="new"><tt>GetProcAddress()</tt></a> of <em>Kernel32.dll</em>, you cannot load a DLL at run time. The dependencies information is stored in the import table section. By using <a href="http://www.microsoft.com/resources/documentation/Windows/XP/all/reskit/en-us/Default.asp?url=/resources/documentation/Windows/XP/all/reskit/en-us/prmb_tol_kewf.asp" target="new">Dependency Walker</a>, it is not so difficult to observe the DLL module and the functions that are imported into a PE file.</p>
<p><img height="352" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=DEPENDENCY_WALKER_GIF&amp;ds=20060302" width="480" alt="" /></p>
<p>You attempt to establish your custom import table to conduct your project. Furthermore, you have to fix up the original import table at the end to run the real code of the program.</p>
<h4>PE Maker: Step 3</h4>
<p>Download the pemaker3.zip source files from the end of the article.</p>
<h4>6.1 Construct the Client Import Table</h4>
<p>I strongly advise that you to read Section 6.4 of the <a href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx" target="new">Microsoft Portable Executable and the Common Object File Format Specification</a> document. This section contains the principal information to comprehend the import table performance. The import table data is accessible by a second data directory of the optional header from PE headers, so you can access it by using the following code:</p>
<pre>DWORD dwVirtualAddress = image_nt_headers-&gt;   OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].      VirtualAddress;DWORD dwSize = image_nt_headers-&gt;   OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].      Size;</pre>
<p>The <tt>VirtualAddress</tt> refers to structures by <tt>IMAGE_IMPORT_DESCRIPTOR</tt>. This structure contains the pointer to the imported DLL name and the relative virtual address of the first thunk.</p>
<pre><span class="codeKeyword">typedef</span> <span class="codeKeyword">struct</span> _IMAGE_IMPORT_DESCRIPTOR {    <span class="codeKeyword">union</span> {        DWORD   Characteristics;        DWORD   OriginalFirstThunk;    };    DWORD   TimeDateStamp;    DWORD   ForwarderChain;    DWORD   <font color="#ff0000">Name</font>;         <span class="codeComment">// the imported DLL name</span>    DWORD   <font color="#ff0000">FirstThunk</font>;   <span class="codeComment">// the relative virtual address of the</span>                          <span class="codeComment">// first thunk</span>} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;</pre>
<p>When a program is running, the Windows Task Manager sets the thunks by the virtual address of the function. The virtual address is found by the name of the function. At first, the thunks hold the relative virtual address of the function name, as shown in Table 5; during execution, they are fixed up by the virtual address of the functions (see Table 6).</p>
<h4>Table 5: The Import Table in a file image</h4>
<p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td rowspan="8"><tt>IMAGE_IMPORT_<br />                DESCRIPTOR[0]</tt></td>
<td><tt>OriginalFirstThunk</tt></td>
<td colspan="2" rowspan="3">&nbsp;</td>
<td colspan="2" rowspan="4">&nbsp;</td>
</tr>
<tr>
<td><tt>TimeDateStamp</tt></td>
</tr>
<tr>
<td><tt>ForwarderChain</tt></td>
</tr>
<tr>
<td><tt>Name_RVA</tt></td>
<td>&#8212;&#8212;&gt;</td>
<td><font color="#a52a2a">&quot;kernel32.dll&quot;<font color="#0000ff">,0</font></font></td>
</tr>
<tr>
<td><tt>FirstThunk_RVA</tt></td>
<td>&#8212;&#8212;&gt;</td>
<td><tt>proc_1_name_RVA</tt></td>
<td>&#8212;&#8212;&gt;</td>
<td><font color="#0000ff">0,0,</font><font color="#a52a2a">&quot;LoadLibraryA&quot;</font><font color="#0000ff">,0</font></td>
</tr>
<tr>
<td colspan="2" rowspan="3">&nbsp;</td>
<td><tt>proc_2_name_RVA</tt></td>
<td>&#8212;&#8212;&gt;</td>
<td><font color="#0000ff">0,0,</font><font color="#a52a2a">&quot;GetProcAddress&quot;</font><font color="#0000ff">,0</font></td>
</tr>
<tr>
<td><tt>proc_3_name_RVA</tt></td>
<td>&#8212;&#8212;&gt;</td>
<td><font color="#0000ff">0,0,</font><font color="#a52a2a">&quot;GetModuleHandleA&quot;</font><font color="#0000ff">,0</font></td>
</tr>
<tr>
<td>&#8230;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><tt>IMAGE_IMPORT_<br />                DESCRIPTOR[1]</tt></td>
<td colspan="5">&nbsp;</td>
</tr>
<tr>
<td><tt>...</tt></td>
<td colspan="5">&nbsp;</td>
</tr>
<tr>
<td><tt>IMAGE_IMPORT_<br />                DESCRIPTOR[n]</tt></td>
<td colspan="5">&nbsp;</td>
</tr>
</tbody>
</table>
<h4>Table 6: The Import Table in virtual memory</h4>
<p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td rowspan="8"><tt>IMAGE_IMPORT_DESCRIPTOR[0]</tt></td>
<td><tt>OriginalFirstThunk</tt></td>
<td colspan="2" rowspan="3">&nbsp;</td>
</tr>
<tr>
<td><tt>TimeDateStamp</tt></td>
</tr>
<tr>
<td><tt>ForwarderChain</tt></td>
</tr>
<tr>
<td><tt>Name_RVA</tt></td>
<td><tt>------&gt;</tt></td>
<td><font color="#a52a2a">&quot;kernel32.dll&quot;<font color="#0000ff">,0</font></font></td>
</tr>
<tr>
<td><tt>FirstThunk_RVA</tt></td>
<td><tt>------&gt;</tt></td>
<td><tt>proc_1_VA</tt></td>
</tr>
<tr>
<td colspan="2" rowspan="3">&nbsp;</td>
<td><tt>proc_2_VA</tt></td>
</tr>
<tr>
<td><tt>proc_3_VA</tt></td>
</tr>
<tr>
<td><tt>...</tt></td>
</tr>
<tr>
<td><tt>IMAGE_IMPORT_DESCRIPTOR[1]</tt></td>
<td colspan="3">&nbsp;</td>
</tr>
<tr>
<td><tt>...</tt></td>
<td colspan="3">&nbsp;</td>
</tr>
<tr>
<td><tt>IMAGE_IMPORT_DESCRIPTOR[n]</tt></td>
<td colspan="3">&nbsp;</td>
</tr>
</tbody>
</table>
<p>You want to make a simple import table to import <tt>LoadLibrary()</tt>, and <tt>GetProcAddress()</tt> from <em>Kernel32.dll</em>. You need these two essential API functions to cover other API functions in run-time. The following assembly code shows how easily you can reach your solution:</p>
<pre><font color="#808080">0101F000: <font color="#0000ff">00000000</font> ; OriginalFirstThunk0101F004: <font color="#0000ff">00000000</font> ; TimeDateStamp0101F008: <font color="#0000ff">00000000</font> ; ForwarderChain0101F00C: <font color="#0000ff">0001F034</font> ; Name;       ImageBase + 0001F034                                 -&gt; 0101F034 -&gt; &quot;Kernel32.dll&quot;,00101F010: <font color="#0000ff">0001F028</font> ; FirstThunk; ImageBase + 0001F028 -&gt; 0101F0280101F014: <font color="#0000ff">00000000</font>0101F018: <font color="#0000ff">00000000</font>0101F01C: <font color="#0000ff">00000000</font>0101F020: <font color="#0000ff">00000000</font>0101F024: <font color="#0000ff">00000000</font>0101F028: <font color="#0000ff">0001F041</font> ; ImageBase + 0001F041 -&gt; 0101F041                     -&gt; 0,0,&quot;LoadLibraryA&quot;,00101F02C: <font color="#0000ff">0001F050</font> ; ImageBase + 0001F050 -&gt; 0101F050                     -&gt; 0,0,&quot;GetProcAddress&quot;,00101F030: <font color="#0000ff">00000000</font>0101F034: <font color="#a52a2a"><span class="codeComment">'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' </span>0001F041: <font color="#0000ff">00 00</font> <font color="#a52a2a"><span class="codeComment">'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A'</span>0001F050: <font color="#0000ff">00 00</font> <font color="#a52a2a"><span class="codeComment">'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's'</span>          <span class="codeComment">'s'</span></font> <font color="#0000ff">00</font></font> <font color="#0000ff">00</font></font><font color="#0000ff">00</font></font></pre>
<p>After running&#8230;</p>
<pre><font color="#808080">0101F000: <font color="#0000ff">00000000</font> ; OriginalFirstThunk0101F004: <font color="#0000ff">00000000</font> ; TimeDateStamp0101F008: <font color="#0000ff">00000000</font> ; ForwarderChain0101F00C: <font color="#0000ff">0001F034</font> ; Name;       ImageBase + 0001F034                                 -&gt; 0101F034 -&gt; &quot;Kernel32.dll&quot;,00101F010: <font color="#0000ff">0001F028</font> ; FirstThunk; ImageBase + 0001F028 -&gt; 0101F0280101F014: <font color="#0000ff">00000000</font>0101F018: <font color="#0000ff">00000000</font>0101F01C: <font color="#0000ff">00000000</font>0101F020: <font color="#0000ff">00000000</font>0101F024: <font color="#0000ff">00000000</font>0101F028: <font color="#ff0000">7C801D77</font> ; -&gt; Kernel32.LoadLibrary()0101F02C: <font color="#ff0000">7C80AC28</font> ; -&gt; Kernel32.GetProcAddress()0101F030: <font color="#0000ff">00000000</font>0101F034: <font color="#a52a2a"><span class="codeComment">'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' </span>0001F041: <font color="#0000ff">00 00</font> <font color="#a52a2a"><span class="codeComment">'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A'</span>0001F050: <font color="#0000ff">00 00</font> <font color="#a52a2a"><span class="codeComment">'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's'</span>          <span class="codeComment">'s'</span></font> <font color="#0000ff">00</font></font> <font color="#0000ff">00</font></font><font color="#0000ff">00</font></font></pre>
<p>I have prepared a class library to make every import table by using a client string table. The <tt>CITMaker</tt> class library in <em>itmaker.h</em>; it will build an import table by <tt>sz_IT_EXE_strings</tt> and also the relative virtual address of the import table.</p>
<pre><span class="codeKeyword">static</span> <span class="codeKeyword">const</span> <span class="codeKeyword">char</span> *sz_IT_EXE_strings[]={    &quot;Kernel32.dll&quot;,    &quot;LoadLibraryA&quot;,    &quot;GetProcAddress&quot;,    0,,    0,};</pre>
<p>You subsequently employ this class library to establish an import table to support DLLs and OCXs, so this is a general library to present all possible import tables easily. The next step is clarified in the following code.</p>
<pre>CITMaker *<font color="#ff0000">ImportTableMaker</font> = <span class="codeKeyword">new</span> CITMaker( IMPORT_TABLE_EXE );...pimage_section_header=AddNewSection( &quot;.xxx&quot;, dwNewSectionSize );<span class="codeComment">// build import table by the current virtual address</span><font color="#ff0000">ImportTableMaker</font>-&gt;<font color="#008000">Build</font>( <font color="#0000ff">pimage_section_header-&gt;VirtualAddress</font> );memcpy( pNewSection, <font color="#ff0000">ImportTableMaker</font>-&gt;<font color="#008000">pMem</font>,<font color="#ff0000">ImportTableMaker</font>-&gt;<font color="#008000">dwSize</font> );...memcpy( image_section[image_nt_headers-&gt;FileHeader.NumberOfSections-1],        pNewSection,        dwNewSectionSize );...image_nt_headers-&gt;OptionalHeader.  DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress  = <font color="#0000ff">pimage_section_header-&gt;VirtualAddress</font>;image_nt_headers-&gt;OptionalHeader.  DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size  = <font color="#ff0000">ImportTableMaker</font>-&gt;<font color="#008000">dwSize</font>;...<span class="codeKeyword">delete</span> <font color="#ff0000">ImportTableMaker</font>;</pre>
<p>The import table is copied at the beginning of the new section, and the relevant data directory is adjusted to the relative virtual address of the new section and the size of the new import table.</p>
<h4>6.2 Using other API functions at run time</h4>
<p>At this time, you can load other DLLs and find the process address of other functions by using <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp" target="new"><tt>LoadLibrary()</tt></a> and <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocaddress.asp" target="new"><tt>GetProcAddress()</tt></a>:</p>
<pre><font color="#808080">lea edi, <font color="#ff0000">@</font><font color="#a52a2a">&quot;Kernel32.dll&quot;</font><span class="codeComment">//-------------------</span><font color="#0000ff">push edimov eax,offset _p_LoadLibrarycall [ebp+eax] <span class="codeComment">//LoadLibrary(lpLibFileName);</span><span class="codeComment">//-------------------</span>mov esi,eax    <span class="codeComment">// esi -&gt; hModule</span>lea edi, <font color="#ff0000">@</font><font color="#a52a2a">&quot;GetModuleHandleA&quot;</font><span class="codeComment">//-------------------</span><font color="#0000ff">push edipush esimov eax,offset _p_GetProcAddresscall [ebp+eax] <span class="codeComment">//GetModuleHandle=GetProcAddress(hModule, lpProcName);</span><span class="codeComment">//--------------------</span></font></font></font></pre>
<p>    <a name="more"><font color="#000000">&nbsp;</font></a><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp" target="new"><tt>LoadLibrary()</tt></a> and <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocaddress.asp" target="new"><tt>GetProcAddress()</tt></a> aid you in your effort to reach your intention.</p>
<p>I want to have a complete imported function table similar in performance done in a real EXE file. If you look inside a PE file, you will discover that an API call is done by an indirection jump through the virtual address of the API function:</p>
<h4>JMP DWORD PTR [XXXXXXXX]</h4>
<pre><font color="#808080">...0101F028: <font color="#ff0000">7C801D77</font>      ; Virtual Address of kernel32.LoadLibrary()...0101F120: JMP DWORD PTR [<font color="#ff0000">0101F028</font>]...0101F230: CALL <font color="#ff0000">0101F120</font> ;  JMP to kernel32.LoadLibrary...</font></pre>
<p>It makes it easy to expand the other part of your project by this performance, so you construct two data tables: the first for API virtual addresses, and the second for the <tt>JMP [XXXXXXXX]</tt>.</p>
<pre><span class="codeKeyword">#define</span> __jmp_api               byte_type(0xFF) byte_type(0x25)__asm{...<span class="codeComment">//----------------------------------------------------------------</span>_p_GetModuleHandle:             dword_type(0xCCCCCCCC)_p_VirtualProtect:              dword_type(0xCCCCCCCC)_p_GetModuleFileName:           dword_type(0xCCCCCCCC)_p_CreateFile:                  dword_type(0xCCCCCCCC)_p_GlobalAlloc:                 dword_type(0xCCCCCCCC)<span class="codeComment">//----------------------------------------------------------------</span>_jmp_GetModuleHandle:           __jmp_api   dword_type(0xCCCCCCCC)_jmp_VirtualProtect:            __jmp_api   dword_type(0xCCCCCCCC)_jmp_GetModuleFileName:         __jmp_api   dword_type(0xCCCCCCCC)_jmp_CreateFile:                __jmp_api   dword_type(0xCCCCCCCC)_jmp_GlobalAlloc:               __jmp_api   dword_type(0xCCCCCCCC)<span class="codeComment">//----------------------------------------------------------------</span>...}</pre>
<p>In the succeeding code, you have concluded your ambition to install a custom internal import table! (You cannot call it import table.)</p>
<pre><font color="#808080">    ...    lea edi,[ebp+_p_szKernel32]    lea ebx,[ebp+_p_GetModuleHandle]    lea ecx,[ebp+_jmp_GetModuleHandle]    add ecx,02h_api_get_lib_address_loop:        push ecx        <font color="#0000ff">push edi        mov eax,offset _p_LoadLibrary        call [ebp+eax]    <span class="codeComment">//LoadLibrary(lpLibFileName);</span>        pop ecx        mov esi,eax       <span class="codeComment">// esi -&gt; hModule</span>        push edi        call __strlen        add esp,04h        add edi,eax_api_get_proc_address_loop:            push ecx            <font color="#0000ff">push edi            push esi            mov eax,offset _p_GetProcAddress            <span class="codeComment">//GetModuleHandle=GetProcAddress(hModule, lpProcName);</span>            call [ebp+eax]            pop ecx</font>            <font color="#008000">mov [ebx],eax            mov [ecx],ebx    <span class="codeComment">// JMP DWORD PTR [XXXXXXXX]</span>            add ebx,04h            add ecx,06h            push edi            call __strlen            add esp,04h            add edi,eax            mov al,<span class="codeKeyword">byte</span> ptr [edi]        test al,al        jnz _api_get_proc_address_loop        inc edi        mov al,<span class="codeKeyword">byte</span> ptr [edi]    test al,al    jnz _api_get_lib_address_loop    ...</font></font></font></pre>
<h4>6.3 Fix up the Original Import Table</h4>
<p>To run the program again, you should fix up the thunks of the actual import table; otherwise, you have a corrupted target PE file. Your code must correct all of the thunks the same as Table 5 to Table 6. Once more, </p>
<pre><font color="#808080">    ...    mov ebx,[ebp+<font color="#ff0000">_p_dwImportVirtualAddress</font>]    test ebx,ebx    jz _it_fixup_end    mov esi,[ebp+<font color="#ff0000">_p_dwImageBase</font>]    add ebx,esi             <span class="codeComment">// dwImageBase + dwImportVirtualAddress</span>_it_fixup_get_lib_address_loop:        mov eax,[ebx+00Ch]  <span class="codeComment">// image_import_descriptor.Name</span>        test eax,eax        jz _it_fixup_end        mov ecx,[ebx+010h]  <span class="codeComment">// image_import_descriptor.FirstThunk</span>        add ecx,esi        mov [ebp+<font color="#ff0000">_p_dwThunk</font>],ecx    <span class="codeComment">// dwThunk</span>        mov ecx,[ebx]       <span class="codeComment">// image_import_descriptor.Characteristics</span>        test ecx,ecx        jnz _it_fixup_table            mov ecx,[ebx+010h]_it_fixup_table:        add ecx,esi        mov [ebp+<font color="#ff0000">_p_dwHintName</font>],ecx    <span class="codeComment">// dwHintName</span>        add eax,esi  <span class="codeComment">// image_import_descriptor.Name + dwImageBase = ModuleName</span>        <font color="#0000ff">push eax     <span class="codeComment">// lpLibFileName</span>        mov eax,offset _p_LoadLibrary        call [ebp+eax]               <span class="codeComment">// LoadLibrary(lpLibFileName);</span>        test eax,eax        jz _it_fixup_end        mov edi,eax_it_fixup_get_proc_address_loop:            mov ecx,[ebp+<font color="#ff0000">_p_dwHintName</font>]    <span class="codeComment">// dwHintName</span>            mov edx,[ecx]            <span class="codeComment">// image_thunk_data.Ordinal</span>            test edx,edx            jz _it_fixup_next_module            test edx,080000000h      <span class="codeComment">// .IF( import by ordinal )</span>            jz _it_fixup_by_name                and edx,07FFFFFFFh    <span class="codeComment">// get ordinal</span>                jmp _it_fixup_get_addr_it_fixup_by_name:            add edx,esi  <span class="codeComment">// image_thunk_data.Ordinal</span>                         <span class="codeComment">// + dwImageBase = OrdinalName</span>            inc edx            inc edx                  <span class="codeComment">// OrdinalName.Name</span>_it_fixup_get_addr:            <font color="#0000ff">push edx <span class="codeComment">//lpProcName</span>            push edi                 <span class="codeComment">// hModule</span>            mov eax,offset _p_GetProcAddress            call [ebp+eax]    <span class="codeComment">// GetProcAddress(hModule, lpProcName);</span>            <font color="#008000">mov ecx,[ebp+<font color="#ff0000">_p_dwThunk</font>]    <span class="codeComment">// dwThunk</span>            mov [ecx],eax  <span class="codeComment">// correction the thunk</span>            <span class="codeComment">// dwThunk =&gt; next dwThunk</span>            add dword ptr [ebp+<font color="#ff0000">_p_dwThunk</font>], <font color="#0000ff">004h</font>            <span class="codeComment">// dwHintName =&gt; next dwHintName</span>            add dword ptr [ebp+<font color="#ff0000">_p_dwHintName</font>],<font color="#0000ff">004h</font>        jmp _it_fixup_get_proc_address_loop_it_fixup_next_module:        add ebx,014h      <span class="codeComment">// sizeof(IMAGE_IMPORT_DESCRIPTOR)</span>    jmp _it_fixup_get_lib_address_loop_it_fixup_end:    ...</font></font></font></font></pre>
<pre>
<h3>7 Support DLL and OCX</h3>

Now, you intend to include the <a href="http://en.wikipedia.org/wiki/Microsoft_Dynamic_Link_Library" target="new">dynamic link library (DLL)</a> and <a href="http://en.wikipedia.org/wiki/OCX" target="new">OLE-ActiveX Control</a> in your PE builder project. Supporting them is very easy if you pay attention to the two-time arrival into the Offset of Entry Point, the relocation table implementation, and the client import table.
<h4>PE Maker: Step 4</h4>

&nbsp;

<a name="more"><font color="#000000"> </font></a><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp" target="new"><tt>LoadLibrary()</tt></a>, or an OCX is registered by using <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp" target="new"><tt>LoadLibrary()</tt></a> and <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocaddress.asp" target="new"><tt>GetProcAddress()</tt></a> through calling <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/4442206b-b2ad-47d7-8add-18002c44c5a2.asp" target="new"><tt>DllRegisterServer()</tt></a>, the first of the OEP arrival is done.

&nbsp;
<pre>hinstDLL = LoadLibrary( &quot;test1.dll&quot; );hinstOCX = LoadLibrary( &quot;test1.ocx&quot; );_DllRegisterServer = GetProcAddress( hinstOCX,                                     &quot;DllRegisterServer&quot; );_DllRegisterServer();    <span class="codeComment">// ocx register</span></pre>
</p>
<p>Download the pemaker4.zip source files from the end of the article.</p>
<h4>7.1 Twice OEP approach</h4>
<p>The Offset of Entry Point of a DLL file or an OCX file is touched by the main program atleast twice:</p>
<ul>
<li><strong>Constructor</strong>: When a DLL is loaded by </li>
<li><strong>Destructor</strong>: When the main program frees the library usage by <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/freelibrary.asp" target="new"><tt>FreeLibrary()</tt></a>, the second OEP arrival happens.
<p>&nbsp;</p>
<pre>FreeLibrary( hinstDLL );FreeLibrary( hinstOCX );</pre>
</li>
</ul>
<p>To perform this, I have employed a trick that causes in the second time again, the instruction pointer (EIP) traveling towards the original OEP by the structured exception handler.</p>
<pre><font color="#808080"><font color="#000000">_main_0:    pushad    <span class="codeComment">// save the registers context in stack</span>    call _main_1_main_1:    pop ebp    sub ebp,offset _main_1    <span class="codeComment">// get base ebp</span>    <span class="codeComment">//---------------- support dll, ocx  -----------------</span>_support_dll_0:</font>    jmp _support_dll_1        <span class="codeComment">// <font color="#ff0000">nop; nop;    // &lt;&lt; trick</font></span>                              <span class="codeComment">// in the second time OEP</span>    <font color="#000000">jmp _support_dll_2</font>_support_dll_1:    <span class="codeComment">//----------------------------------------------------</span>    ...    <span class="codeComment">//---------------- support dll, ocx  1 ---------------</span>    mov edi,[ebp+_p_dwImageBase]    add edi,[edi+03Ch]            <span class="codeComment">// edi -&gt; IMAGE_NT_HEADERS</span>    mov ax,word ptr [edi+016h]    <span class="codeComment">// edi -&gt; image_nt_headers-&gt;</span>                                  <span class="codeComment">// FileHeader.Characteristics</span>    test ax,<font color="#008000">IMAGE_FILE_DLL</font>    jz _support_dll_2        mov ax, <font color="#ff0000">9090h <span class="codeComment">// &lt;&lt; trick</span>        mov word ptr [ebp+_support_dll_0],ax</font></font><font color="#000000">_support_dll_2:    <span class="codeComment">//----------------------------------------------------</span>    ...    into OEP by SEH ...</font></pre>
<p>I hope you caught the trick in the preceding code, but this is not all of it. You have a problem in <tt>ImageBase</tt>, when the library has been loaded in different image bases by the main program. You should write some code to find the real image base and store it to use forward.</p>
<pre><font color="#808080">    mov eax,<font color="#008000">[esp+24h]</font>    <span class="codeComment">// the real imagebase</span>    mov ebx,<font color="#008000">[esp+30h]</font>    <span class="codeComment">// oep</span>    cmp eax,ebx    ja _no_dll_pe_file_0        cmp word ptr [eax],IMAGE_DOS_SIGNATURE        jne _no_dll_pe_file_0            mov [ebp+_p_dwImageBase],eax_no_dll_pe_file_0:</font></pre>
<p>This code finds the real image base by investigating the stack information. By using the real image base and the formal image base, you should correct all memory calls inside the image program!! Don't be afraid; it will be done simply by the relocating the table information.</p>
<h4>7.2 Implement relocation table</h4>
<p>To understand the relocation table better, you can take a look at Section 6.6 of the <a href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx" target="new">Microsoft Portable Executable and Common Object File Format Specification</a> document. The relocation table contains many packages to relocate the information related to the virtual address inside the virtual memory image. Each package is comprised of an 8-byte header to exhibit the base virtual address and the number of data, demonstrated by the <tt>IMAGE_BASE_RELOCATION</tt> data structure.</p>
<pre><span class="codeKeyword">typedef</span> <span class="codeKeyword">struct</span> _IMAGE_BASE_RELOCATION {   DWORD   VirtualAddress;   DWORD   SizeOfBlock;} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;</pre>
<h4>Table 7 - The Relocation Table</h4>
<p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td align="center" rowspan="7">Block[1]</td>
<td align="center" colspan="4">VirtualAddress</td>
</tr>
<tr>
<td align="center" colspan="4">SizeOfBlock</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">...</td>
<td align="center">...</td>
<td align="center">...</td>
<td align="center">...</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">00</td>
<td align="center">00</td>
</tr>
<tr>
<td align="center" rowspan="7">Block[2]</td>
<td align="center" colspan="4">VirtualAddress</td>
</tr>
<tr>
<td align="center" colspan="4">SizeOfBlock</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">...</td>
<td align="center">...</td>
<td align="center">...</td>
<td align="center">...</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">00</td>
<td align="center">00</td>
</tr>
<tr>
<td align="center">...</td>
<td align="center" colspan="4">
<p>&nbsp;</p>
<p>... </p>
<p>&nbsp;</p>
</td>
</tr>
<tr>
<td align="center" rowspan="7">Block[n]</td>
<td align="center" colspan="4">VirtualAddress</td>
</tr>
<tr>
<td align="center" colspan="4">SizeOfBlock</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">type:4</td>
<td align="center">offset:12</td>
</tr>
<tr>
<td align="center">...</td>
<td align="center">...</td>
<td align="center">...</td>
<td align="center">...</td>
</tr>
<tr>
<td align="center">type:4</td>
<td align="center">offset:12</td>
<td align="center">00</td>
<td align="center">00</td>
</tr>
</tbody>
</table>
<p>Table 7 illustrates the main idea of the relocation table. Furthermore, you can upload a DLL or an OCX file in <a href="http://www.ollydbg.de/" target="new">OllyDbg</a> to observe the relocation table, the <em>&quot;.reloc&quot;</em> section through <em>Memory map window</em>. By the way, you find the position of the relocation table by using the following code in your project:</p>
<pre>DWORD dwVirtualAddress = image_nt_headers-&gt;  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].  VirtualAddress;DWORD dwSize = image_nt_headers-&gt;  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;</pre>
<p>By OllyDbg, you have the same as the following for the <em>&quot;.reloc&quot;</em> section, by using the Long Hex viewer mode. In this example, the base virtual address is <strong>0x1000</strong> and the size of the block is <strong>0x184</strong>.</p>
<pre>008E1000 : 00001000  00000184  30163000  30403028008E1010 : 30683054  308C3080  30AC309C  30D830CC008E1020 : 30E030DC  30E830E4  30F030EC  310030F4008E1030 : 3120310D  315F3150  31A431A0  31C031A8008E1040 : 31D031CC  31F431EC  31FC31F8  32043200008E1050 : 320C3208  32143210  324C322C  32583254008E1060 : 3260325C  32683264  3270326C  32B03274</pre>
<p>It relocates the data in the subsequent virtual addresses:</p>
<pre>0x1000 + 0x0000 = 0x10000x1000 + 0x0016 = 0x10160x1000 + 0x0028 = 0x10280x1000 + 0x0040 = 0x10400x1000 + 0x0054 = 0x1054...</pre>
<p>Each package performs the relocation by using consecutive 4 bytes form its internal information. The first byte refers to the type of relocation and the next three bytes are the offset that must be used with the base virtual address and the image base to correct the image information.</p>
<p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td align="center" width="30">type</td>
<td align="center" colspan="3">offset</td>
</tr>
<tr>
<td align="center"><font color="#0000ff">03</font></td>
<td align="center"><font color="#0000ff">00</font></td>
<td align="center"><font color="#0000ff">00</font></td>
<td align="center"><font color="#0000ff">00</font></td>
</tr>
</tbody>
</table>
<h4>What is the type?</h4>
<p>The type can be one of the following values:</p>
<ul>
<li><tt>IMAGE_REL_BASED_ABSOLUTE (0)</tt>: No effect </li>
<li><tt>IMAGE_REL_BASED_HIGH (1)</tt>: Relocate by the high 16 bytes of the base virtual address and the offset </li>
<li><tt>IMAGE_REL_BASED_LOW (2)</tt>: Relocate by the low 16 bytes of the base virtual address and the offset </li>
<li><tt>IMAGE_REL_BASED_HIGHLOW (3)</tt>: Relocate by the base virtual address and the offset </li>
</ul>
<h4>What is done in the relocation?</h4>
<p>By relocation, some values inside the virtual memory are corrected according to the current image base by the <em>&quot;.reloc&quot;</em> section packages.</p>
<p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td align="center"><strong>delta_ImageBase = current_ImageBase - image_nt_headers-&gt;OptionalHeader.ImageBase</strong></td>
</tr>
</tbody>
</table>
<pre>mem[ current_ImageBase + 0x1000 ] =   mem[ current_ImageBase + 0x1000 ] + delta_ImageBase ;mem[ current_ImageBase + 0x1016 ] =   mem[ current_ImageBase + 0x1016 ] + delta_ImageBase ;mem[ current_ImageBase + 0x1028 ] =   mem[ current_ImageBase + 0x1028 ] + delta_ImageBase ;mem[ current_ImageBase + 0x1040 ] =   mem[ current_ImageBase + 0x1040 ] + delta_ImageBase ;mem[ current_ImageBase + 0x1054 ] =  mem[ current_ImageBase + 0x1054 ] + delta_ImageBase ;...</pre>
<p>I have employed the following code from Morphine packer to implement the relocation.</p>
<pre><font color="#808080">    ..._reloc_fixup:    mov eax,[ebp+_p_dwImageBase]    mov edx,eax    mov ebx,eax    add ebx,[ebx+3Ch]    <span class="codeComment">// edi -&gt; IMAGE_NT_HEADERS</span>    <span class="codeComment">// edx -&gt;image_nt_headers-&gt;OptionalHeader.ImageBase</span>    mov ebx,[ebx+034h]    <font color="#ff0000">sub edx,ebx <span class="codeComment">// edx -&gt; reloc_correction    // delta_ImageBase</span>    je _reloc_fixup_end    mov ebx,[ebp+_p_dwRelocationVirtualAddress]    test ebx,ebx    jz _reloc_fixup_end    add ebx,eax_reloc_fixup_block:    mov eax,[ebx+004h]          <span class="codeComment">//ImageBaseRelocation.SizeOfBlock</span>    test eax,eax    jz _reloc_fixup_end    lea ecx,[eax-008h]    shr ecx,001h    lea edi,[ebx+008h]_reloc_fixup_do_entry:        movzx eax,word ptr [edi]<span class="codeComment">//Entry</span>        push edx        mov edx,eax        shr eax,00Ch            <span class="codeComment">//Type = Entry &gt;&gt; 12</span>        mov esi,[ebp+_p_dwImageBase]<span class="codeComment">//ImageBase</span>        and dx,00FFFh        add esi,[ebx]        add esi,edx        pop edx_reloc_fixup_HIGH:              <span class="codeComment">// IMAGE_REL_BASED_HIGH</span>        dec eax        jnz _reloc_fixup_LOW            mov eax,edx            shr eax,010h        <span class="codeComment">//HIWORD(Delta)</span>            jmp _reloc_fixup_LOW_fixup_reloc_fixup_LOW:               <span class="codeComment">// IMAGE_REL_BASED_LOW</span>            dec eax        jnz _reloc_fixup_HIGHLOW        movzx eax,dx            <span class="codeComment">//LOWORD(Delta)</span>_reloc_fixup_LOW_fixup:            <font color="#ff0000">add word ptr [esi],ax<span class="codeComment">// mem[x] = mem[x] + delta_ImageBase</span>        jmp _reloc_fixup_next_entry_reloc_fixup_HIGHLOW:           <span class="codeComment">// IMAGE_REL_BASED_HIGHLOW</span>            dec eax        jnz _reloc_fixup_next_entry        <font color="#ff0000">add [esi],edx           <span class="codeComment">// mem[x] = mem[x] + delta_ImageBase</span>_reloc_fixup_next_entry:        inc edi        inc edi                 <span class="codeComment">//Entry++</span>        loop _reloc_fixup_do_entry_reloc_fixup_next_base:    add ebx,[ebx+004h]    jmp _reloc_fixup_block_reloc_fixup_end:    ...</font></font></font></font></pre>
<h4>7.3 Build a special import table</h4>
<p>To support the <a href="http://en.wikipedia.org/wiki/OCX" target="new">OLE-ActiveX Control</a> registration, you should present an appropriate import table to your target OCX and DLL file. Therefore, I have established an import table by the following string:</p>
<pre><span class="codeKeyword">const</span> <span class="codeKeyword">char</span> *sz_IT_OCX_strings[]={   &quot;Kernel32.dll&quot;,   &quot;LoadLibraryA&quot;,   &quot;GetProcAddress&quot;,   &quot;GetModuleHandleA&quot;,   0,   &quot;User32.dll&quot;,   &quot;GetKeyboardType&quot;,   &quot;WindowFromPoint&quot;,   0,   &quot;AdvApi32.dll&quot;,   &quot;RegQueryValueExA&quot;,   &quot;RegSetValueExA&quot;,   &quot;StartServiceA&quot;,   0,   &quot;Oleaut32.dll&quot;,   &quot;SysFreeString&quot;,   &quot;CreateErrorInfo&quot;,   &quot;SafeArrayPtrOfIndex&quot;,   0,   &quot;Gdi32.dll&quot;,   &quot;UnrealizeObject&quot;,   0,   &quot;Ole32.dll&quot;,   &quot;CreateStreamOnHGlobal&quot;,   &quot;IsEqualGUID&quot;,   0,   &quot;ComCtl32.dll&quot;,   &quot;ImageList_SetIconSize&quot;,   0,   0,};</pre>
<p>Without these API functions, the library can not be loaded, and moreover the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/4442206b-b2ad-47d7-8add-18002c44c5a2.asp" target="new"><tt>DllregisterServer()</tt></a> and <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/b71137a7-284e-4521-a3b2-9dad9c9d3c54.asp" target="new"><tt>DllUregisterServer()</tt></a> will not operate. In <tt>CPECryptor::CryptFile</tt>, I have distinguished between EXE files and DLL files in the initialization of the new import table object during creation:</p>
<pre><span class="codeKeyword">if</span>(( image_nt_headers-&gt;FileHeader.Characteristics             &amp; IMAGE_FILE_DLL ) == IMAGE_FILE_DLL ){    ImportTableMaker = <span class="codeKeyword">new</span> CITMaker( IMPORT_TABLE_OCX );}<span class="codeKeyword">else</span>{    ImportTableMaker = <span class="codeKeyword">new</span> CITMaker( IMPORT_TABLE_EXE );}</pre>
<p>&nbsp;</p>
<h3>8 Preserve the Thread Local Storage</h3>
<p>By using Thread Local Storage (TLS), a program is able to execute a multithreaded process, This performance mostly is used by <a href="http://www.borland.com/" target="new">Borland</a> linkers: <a href="http://www.borland.com/us/products/delphi/index.html" target="new">Delphi</a> and <a href="http://www.borland.com/us/products/cbuilder/index.html" target="new">C++ Builder</a>. When you pack a PE file, you should take care to keep the TLS clean; otherwise, your packer will not support Borland Delphi and C++ Builder linked EXE files. To comprehend TLS, I refer you to Section 6.7 of the <a href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx" target="new">Microsoft Portable Executable and Common Object File Format Specification</a> document. You can observe the TLS structure by <tt>IMAGE_TLS_DIRECTORY32</tt> in <em>winnt.h</em>.</p>
<pre><span class="codeKeyword">typedef</span> <span class="codeKeyword">struct</span> _IMAGE_TLS_DIRECTORY32 {   DWORD   StartAddressOfRawData;   DWORD   EndAddressOfRawData;   DWORD   AddressOfIndex;   DWORD   AddressOfCallBacks;   DWORD   SizeOfZeroFill;   DWORD   Characteristics;} IMAGE_TLS_DIRECTORY32, * PIMAGE_TLS_DIRECTORY32;</pre>
<p>    <a name="more"><font color="#000000"> </font></a><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/dialogboxreference/dialogboxfunctions/messagebox.asp" target="new"><tt>MessageBox()</tt></a> from <em>user32.dll</em>.</p>
<p>To keep the TLS directory safe, I have copied it in a special place inside the loader:</p>
<pre><font color="#808080">..._tls_dwStartAddressOfRawData:   dword_type(0xCCCCCCCC)_tls_dwEndAddressOfRawData:     dword_type(0xCCCCCCCC)_tls_dwAddressOfIndex:          dword_type(0xCCCCCCCC)_tls_dwAddressOfCallBacks:      dword_type(0xCCCCCCCC)_tls_dwSizeOfZeroFill:          dword_type(0xCCCCCCCC)_tls_dwCharacteristics:         dword_type(0xCCCCCCCC)...</font></pre>
<p>It is necessary to correct the TLS directory entry in the Optional Header:</p>
<pre><span class="codeKeyword">if</span>(image_nt_headers-&gt;   OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].   VirtualAddress!=0){   memcpy(&amp;pDataTable-&gt;image_tls_directory,          image_tls_directory,          <span class="codeKeyword">sizeof</span>(IMAGE_TLS_DIRECTORY32));   dwOffset=DWORD(pData1)-DWORD(pNewSection);   dwOffset+=<span class="codeKeyword">sizeof</span>(t_DATA_1)-<span class="codeKeyword">sizeof</span>(IMAGE_TLS_DIRECTORY32);   image_nt_headers-&gt;      OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].      VirtualAddress=dwVirtualAddress + dwOffset;}</pre>
<h3>9 Inject Your Code</h3>
<p>You are ready to place your code inside the new section. Your code is a &quot;Hello World!&quot; message by </p>
<pre><font color="#808080">...push MB_OK | MB_ICONINFORMATIONlea eax,[ebp+_p_szCaption]push eaxlea eax,[ebp+_p_szText]push eaxpush <span class="codeKeyword">NULL</span>call _jmp_MessageBox<span class="codeComment">// MessageBox(NULL, szText, szCaption, MB_OK | MB_ICONINFORMATION) ;</span>...</font></pre>
<h4>PE Maker: Step 5</h4>
<p>Download the pemaker5.zip source files from the end of the article.</p>
<p><img height="119" src="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=HELLOWORLD_GIF&amp;ds=20060302" width="146" alt="" /></p>
<h3>10 Conclusion</h3>
<p>By reading this article, you have perceived how easily you can inject code to a portable executable file. You can complete the code by using the source of other packers, create a packer in the same way as <a href="http://yodap.sourceforge.net/" target="new">Yoda's Protector</a>, and make your packer undetectable by mixing up with <a href="http://www.hxdef.org/download.php" target="new" class="broken_link">Morphine</a> source code. I hope that you have enjoyed this brief discussion of one part of the reverse engineering field. See you again in the next discussion!</p>
<p>&nbsp;</p>
</pre>
<p>    </a><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/exception_pointers_str.asp" target="new"><tt>EXCEPTION_POINTERS</tt></a>, you have access to the pointer of <tt>ContextRecord</tt>. The <tt>ContextRecord</tt> has the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/context_str.asp" target="new"><tt>CONTEXT</tt></a> data structure, as seen in Table 4. This is the thread context during the exception time. When you ignore the exception by <tt>EXCEPTION_CONTINUE_SEARCH (0)</tt>, the instruction pointer, as well as the context, will be set to <tt>ContextRecord</tt> to return to the previous condition. Therefore, if you change the <tt>Eip</tt> of the Win32 Thread Context to the Original Offset of Entry Point, it will come clearly into OEP.</a><a href="http://www.codeguru.com/dbfiles/get_image.php?id=11393&amp;lbl=SCREENSHOT_JPG&amp;ds=20060302" target="_blank">Full Size Image</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/330.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Armadillo标准壳完全扫盲</title>
		<link>http://www.donevii.com/post/329.html</link>
		<comments>http://www.donevii.com/post/329.html#comments</comments>
		<pubDate>Thu, 24 May 2007 01:31:31 +0000</pubDate>
		<dc:creator>dengwei</dc:creator>
				<category><![CDATA[doc]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=329</guid>
		<description><![CDATA[转至: http://hi.baidu.com/%CC%EC%CD%E2%C3%AB%B3%E6/blog 【前言】本人初学脱壳，以前只会用自动脱壳器，手动只脱过upx的壳，实在是菜鸟一个。日前有幸拿到一个共享软件，用peid一查，Armadillo 1.xx &#8211; 2... ]]></description>
			<content:encoded><![CDATA[<p>转至: <a href="http://hi.baidu.com/%CC%EC%CD%E2%C3%AB%B3%E6/blog">http://hi.baidu.com/%CC%EC%CD%E2%C3%AB%B3%E6/blog</a></p>
<p>【前言】<br />本人初学脱壳，以前只会用自动脱壳器，手动只脱过upx的壳，实在是菜鸟一个。日前有幸拿到一个共享软件，用peid一查，Armadillo 1.xx &#8211; 2.xx -&gt; Silicon Realms Toolworks [Overlay]，俺出生牛犊不怕虎，见壳就有脱的冲动，用od载入一看，傻了眼，这壳和upx的完全不同，入口点和一般程序差不多嘛。遂知道自己水平不济，驱猫上看雪拜读各位前辈的文章。无奈本人水平实在有限，看了大半天还是没理清楚过程。想起马gg曾经说过，实践是检验真理的唯一标准，于是操起工具对该软件大卸七块。经过2天的仔细研习，终于悟得精要，成功把壳干掉了。鉴于感觉入门门槛确实有点高，因此特写此文以帮助菜鸟们迈过刀山火海，飞向光明之巅:D</p>
<p>【术语解释】<br />为什么我要写这一段呢？因为我发现看高手们的脱文，最难逾越的一关是术语。高手们脱文中的各种说法，并不能马上就明白过来究竟是什么东西。因此，希望在这里把Armadillo脱文经常遇到的几个术语稍作解释。本人水平有限，如果解释有误请指出。</p>
<p>[OEP] 这个是Original Entry Point的缩写，中文字面意思就是程序的原入口地址。为什么叫&ldquo;原&rdquo;呢？通常加壳软件会把原来的程序编码存放，以防止静态反汇编分析，并在执行前先运行一段解码的程序。所以，加壳后的程序，其入口地址是直接指向解码部分的代码，而非原来的程序入口。我们脱壳所要做的工作，就是还原出原来的程序，并且每次执行时直接从原入口地址开始执行（而不需要再运行用于解码的&ldquo;壳&rdquo;），因此需要得知原入口地址是什么，即OEP。</p>
<p>[Armadillo] 传说中的猛壳，因为拼写太长，也有人缩写为arm壳。它使用多种加密手段以防止脱壳，比如检测debugger、修改IAT、还有高级版本的stolen byte和双线程解码。</p>
<p>[IAT] Import Address Table的缩写，也有叫输入表，引入表。它用来保存程序用到的API函数的入口地址。</p>
<p>[RVA] Relative Virtual Address，相对虚拟地址。win32系统会把进程读入到内存中执行，所以存在着内存地址和文件偏移的转换关系。PE文件头里面会有一个内存基址base，原来在文件中偏移为x的内容，在内存里面的偏移就变成base+x。为了区分这两种地址偏移，通常叫文件中的偏移为RVA</p>
<p>[magic jump]（一般破文是按10多次或者20多次F9，就来到magicjump。我根本不知道怎么去判断一个新软件的magicjump在哪里，也不知道那个次数是怎么得来的，不怕，下面我会教一种我认为比较好的方法）其实所谓magic jump，是指跳过改写IAT的代码段。Armadillo的解壳过程有一个特点，就是会改写IAT。（这里我用的是&ldquo;改写&rdquo;而不是某些文章中的&ldquo;破坏&rdquo;是有原因的。曾经我在这里也困惑过，破坏带有不可恢复的意思，事实上IAT对应的地址并没有完全破坏，只是被改写成更难辨认的形式。这里举一个具体例子）</p>
<p>00E6E0E1&nbsp;&nbsp;&nbsp;&nbsp; mov edx,[EA01B8]&nbsp;&nbsp;&nbsp;&nbsp; // ~= kernel32.dll/00D4/FindNextFileA<br />00E6E0E7&nbsp;&nbsp;&nbsp;&nbsp; add edx,64<br />00E6E0EA&nbsp;&nbsp;&nbsp;&nbsp; call edx<br />00E6E0EC&nbsp;&nbsp;&nbsp;&nbsp; mov edx,[EA0144]&nbsp;&nbsp;&nbsp;&nbsp; // ~= kernel32.dll/016F/GetModuleFileNameW<br />00E6E0F2&nbsp;&nbsp;&nbsp;&nbsp; add edx,64<br />00E6E0F5&nbsp;&nbsp;&nbsp;&nbsp; mov ecx,5</p>
<p>这个是被改写后的IAT指向的一端程序段。里面实际工作是作还原工作。先取出edx(这里对应一个假API)，然后加上64偏移才得到真正的API，再进行函数调用。FindNextFileA后面的偏移64是GetTickCount，GetModuleFileNameW后面是GetModuleHandleA，所以上面的代码相当于<br />call kernel32.GetTickCount<br />nop<br />&hellip;<br />call kernel32.GetModuleHandleA</p>
<p>这样可以使得手动脱壳过程中把IAT表弄坏（因为无法识别出正确的API），但是加壳程序却可以正常运行。是不是很狡猾？解决办法也简单，在脱壳的过程中避开执行改写IAT表的代码段，只需要修改一条指令，这条指令，正是magic jump！</p>
<p>能够坚持看到这里是否已经有点烦闷了？基本理论就这么多了。准备好工具了吗？让我们马上开始。</p>
<p>【工具】OD、LordPE、ImportREC<br />【过程】<br />【Action 1】 明察暗访OEP<br />OD载入程序，用插件隐藏OD，忽略所有异常，alt_m查看内存映射，在00401000处下内存读取断点，F9<br />程序停下来了，看到没有，熟悉的开头。没有看到？肯定你遇到异常了，shift_F9试试？<br />005E14E4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push ebp<br />005E14E5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8BEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov ebp,esp<br />005E14E7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 83C4 E4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add esp,-1C</p>
<p>我们找到OEP了，马上记下吧。Action 1目标完成：OEP=001E14E4<br />等等，是不是打错字了？不是005E14E4吗？还记得RVA吗？通常来说，windows会把程序读到从00400000开始的连续内存空间（当然也不是一成不变，只是通常碰到的情况都是这样），也就是说你看到的OEP 005E14E4是内存的地址，它的RVA是001E14E4。明白了吗？</p>
<p>【Action 2】攻下桥头堡<br />运行到OEP预示着解码阶段的完成了。所以理论上现在内存中的是已解码的程序。先不要动OD，保持在OEP入口。运行LordPE，选刚刚运行的程序的线程，full dump，Action 2完成！</p>
<p>先别对着dump出来的exe笑啊，如果现在那个是最终的脱壳结果，Armadillo就不叫猛壳了，我刚刚写的一堆理论也就白费劲。喝口水再继续吧。下面才到重点。</p>
<p>【Action 3】扫清地雷阵<br />OD没有关掉吧？恩，别动它，继续保持。运行ImportREC，选择程序进程，在下面的IAT Infos needed填入刚才拿到的OEP。AutoSearch，看到RVA框变了，那个就是IAT的地址和大小了。我这里找到的数值是001ED240<br />回到OD，d 5ed240（还记得刚刚说过的内存偏移的换算关系吗？），看到什么了？那个就是IAT呀。记下它的样子。然后分别在第一个项目和最后一个项目下硬件写入断点。（为什么用硬件捏？因为它不影响速度，而且重新运行的时候不会没掉，呵呵）<br />下面重新运行吧。F9，碰到硬件断点了。还记得IAT的样子吗？继续F9，直到第一个条目和你刚刚记下的一样。现在按page up，一直向上找GetModuleHandleA</p>
<p>00E86AB1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6A 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push 0<br />00E86AB3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FF15 D400E900&nbsp;&nbsp;&nbsp; call dword ptr ds:[E900D4]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ; kernel32.GetModuleHandleA<br />00E86AB9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3985 90C4FFFF&nbsp;&nbsp;&nbsp; cmp dword ptr ss:[ebp-3B70],eax<br />00E86ABF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 75 0F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jnz short 00E86AD0<br />00E86AC1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C785 8CC4FFFF 8&gt;mov dword ptr ss:[ebp-3B74],0E95180<br />00E86ACB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E9 C4000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jmp 00E86B94<br />00E86AD0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 83A5 68C2FFFF 0&gt;and dword ptr ss:[ebp-3D98],0<br />00E86AD7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C785 64C2FFFF C&gt;mov dword ptr ss:[ebp-3D9C],0E957C0<br />00E86AE1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EB 1C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jmp short 00E86AFF<br />00E86AE3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B85 64C2FFFF&nbsp;&nbsp;&nbsp; mov eax,dword ptr ss:[ebp-3D9C]<br />00E86AE9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 83C0 0C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add eax,0C<br />00E86AEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8985 64C2FFFF&nbsp;&nbsp;&nbsp; mov dword ptr ss:[ebp-3D9C],eax<br />00E86AF2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B85 68C2FFFF&nbsp;&nbsp;&nbsp; mov eax,dword ptr ss:[ebp-3D98]<br />00E86AF8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inc eax<br />00E86AF9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8985 68C2FFFF&nbsp;&nbsp;&nbsp; mov dword ptr ss:[ebp-3D98],eax<br />00E86AFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B85 64C2FFFF&nbsp;&nbsp;&nbsp; mov eax,dword ptr ss:[ebp-3D9C]<br />00E86B05&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8338 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmp dword ptr ds:[eax],0<br />00E86B08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0F84 86000000&nbsp;&nbsp;&nbsp; je 00E86B94<br />00E86B0E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B85 64C2FFFF&nbsp;&nbsp;&nbsp; mov eax,dword ptr ss:[ebp-3D9C]<br />00E86B14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B40 08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax,dword ptr ds:[eax+8]<br />00E86B17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 83E0 01&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and eax,1<br />00E86B1A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 85C0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test eax,eax<br />00E86B1C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 74 25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; je short 00E86B43<br />00E86B1E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A1 2800EA00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax,dword ptr ds:[EA0028]<br />00E86B23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B0D 2800EA00&nbsp;&nbsp;&nbsp; mov ecx,dword ptr ds:[EA0028]<br />00E86B29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B40 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax,dword ptr ds:[eax+20]<br />00E86B2C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3341 40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor eax,dword ptr ds:[ecx+40]<br />00E86B2F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B0D 2800EA00&nbsp;&nbsp;&nbsp; mov ecx,dword ptr ds:[EA0028]<br />00E86B35&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3341 28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor eax,dword ptr ds:[ecx+28]<br />00E86B38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 25 80000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and eax,80<br />00E86B3D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 85C0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test eax,eax<br />00E86B3F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 74 02&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; je short 00E86B43<br />00E86B41&nbsp;&nbsp;&nbsp; ^ EB A0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jmp short 00E86AE3<br />00E86B43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B85 68C2FFFF&nbsp;&nbsp;&nbsp; mov eax,dword ptr ss:[ebp-3D98]<br />00E86B49&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B0D 74B7E900&nbsp;&nbsp;&nbsp; mov ecx,dword ptr ds:[E9B774]<br />00E86B4F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B15 2800EA00&nbsp;&nbsp;&nbsp; mov edx,dword ptr ds:[EA0028]<br />00E86B55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B0481&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax,dword ptr ds:[ecx+eax*4]<br />00E86B58&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3342 24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor eax,dword ptr ds:[edx+24]<br />00E86B5B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B0D 2800EA00&nbsp;&nbsp;&nbsp; mov ecx,dword ptr ds:[EA0028]<br />00E86B61&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3341 28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor eax,dword ptr ds:[ecx+28]<br />00E86B64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B0D 2800EA00&nbsp;&nbsp;&nbsp; mov ecx,dword ptr ds:[EA0028]<br />00E86B6A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3341 44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor eax,dword ptr ds:[ecx+44]<br />00E86B6D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8B0D 2800EA00&nbsp;&nbsp;&nbsp; mov ecx,dword ptr ds:[EA0028]<br />00E86B73&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3341 6C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor eax,dword ptr ds:[ecx+6C]<br />00E86B76&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3985 90C4FFFF&nbsp;&nbsp;&nbsp; cmp dword ptr ss:[ebp-3B70],eax</p>
<p>你看到的这段可能会跟我给出的有点差异，不过很好认，会有一段mov和xor交错出现的地方，并且mov语句是完全相同的。这里是00E86B1E-00E86B76</p>
<p>向上找可以跳过这段代码的转跳语句，这里是<br />00E86B08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0F84 86000000&nbsp;&nbsp;&nbsp; je 00E86B94&nbsp;&nbsp;&nbsp;&nbsp; ;magic jump!!!!!!!!</p>
<p>我看到其他教程，这句是je short的，所以可能是Armadillo版本不同。不过道理都是一样，避开对IAT表的改写。<br />把这句改成jmp，再按F9，遇到第二个硬件断点，这时IAT转换完成。这个可是没有被做过手脚的完整IAT啊～<br />哦，这里别忘了，回到刚刚修改的jmp那里，改回je啊。不然后面的解码会出错导致程序异常终止了。（至少我脱的这个壳会这样。好像只有很少的脱文提到要恢复指令，反正恢复也没坏，多做一步吧，不然异常了可能还要重新来过）<br />再bp 005e14e4，在OEP处下断，F9，运行到OEP</p>
<p>【Action 4】长驱直入，胜利会师<br />拿出ImportREC出来吧，重新选一下进程，autosearch，步骤应该都熟悉了。这次可以点Get Imports了。如果还有unresolved pointer，就点Show Invalid，Trace Level1试试，剩下的用Cut thunk全部干掉。然后fix dump，选择Action 2 dump出来的exe，应该就多出来一个文件名后面多带一个_的exe文件。这个是脱壳后独立运行的exe啊。试试能不能运行，不行的话，调整一下ImportREC的参数再试试，有些软件不能用Add new section的。把auto search的结果填到New Import Infos，去掉Add new section再试一遍。</p>
<p>【Action 5】清除残余势力<br />脱壳出来的程序很大，因为里面包含了很多已经没用的解码程序段。为了做到完美脱壳，我们可以把没用的代码清理掉。主要过程可以参考《脱壳后软件减肥大法》http://www.pediy.com/bbshtml/BBS6/pediy6313.htm，这里就不赘述了。不过调整.idata保证VA连续的那一步我不是按它的，不需要手动调整，直接用LordPE的rebuild PE就可以了，有现成工具干吗还要造轮子了？</p>
<p>【后记】<br />当我看到脱壳出来的程序正常运行时，有一种兴奋的感觉。也许我是脱壳菜鸟，这些对高手们确实不值得一提。可是正如fly斑竹所说，我知道自己进阶了。把过程和大家共享，希望大家可以跨过入门的门槛，共同进步。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/329.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>
	</channel>
</rss>

