﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-为了遗忘的记录-随笔分类-C++</title><link>http://www.cnitblog.com/Raistlin/category/1568.html</link><description>Think!</description><language>zh-cn</language><lastBuildDate>Thu, 29 Sep 2011 04:29:27 GMT</lastBuildDate><pubDate>Thu, 29 Sep 2011 04:29:27 GMT</pubDate><ttl>60</ttl><item><title>还是关于异常</title><link>http://www.cnitblog.com/Raistlin/archive/2006/05/31/11300.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Wed, 31 May 2006 03:40:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2006/05/31/11300.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/11300.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2006/05/31/11300.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/11300.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/11300.html</trackback:ping><description><![CDATA[早上看到一篇别人的blog,上有如下代码:<br />try{<br />   ...<br />   throw "teststring";//1<br />}<br />catch(string &amp; rs){//2<br />   ...<br />}<br />想要用//2处的语句来捕获//1处的异常,当然是不对的.<br />正确的应该是:<br />catch(char * ps){ 或 catch(const char * ps){<br /><br />其实因为"teststring"是保存在代码段中的,所以应该抛出const指针<br />try{<br />   ...<br />   throw static_cast&lt;const char *&gt;("teststring");<br />}<br />catch(char * ps){//错,改为=&gt; catch(const char * ps){<br />   ...<br />}<br />天下太平,但如果钻牛角尖:<br />try{<br />   ...<br />   throw static_cast&lt;const char *&gt;("teststring");//3<br />}<br />catch(const char * const&amp; rps){//4<br />   ...<br />}<br />可以吗?编译正常,但//4无法捕获//3的异常.<br />但为什么<br />try{<br />   ...<br />   throw static_cast&lt;const string&gt;string("teststring");//5<br />}<br />catch(const string &amp; rs){//6<br />   ...<br />}<br />//6处就可以捕获到//5处的异常呢<br />因为//5处抛出的异常类型根本就不是const的.只是string的类型<br />而//3处的异常的类型的确是cosnt char *<br />嘿嘿...<br /><br />简单的说异常的处理需要引入一个全局的对象.<br />throw x;的时候用x来给这个全局对象y赋值,当捕获的时候在catch( type z)处,用y给z赋值.<br />如果x的类型不是指针(比如string),不管它有没有常量性,y的类型都是string,而z的类型不管是string 还是const string都能捕获x.<br /><br />但是,当x的类型是指针的时候,y的类型的常量性和x是一致的,z的类型也只有和x一致才能捕获x的异常.<br /><br />但//4处就是不能捕获//3的异常.<br />也许是VC++的问题?<br />不知道别的编译器如何.<br />还好用引用来捕获指针...普通人应该都不会这么做-_-<br />但尽量用const类型来catch,应该是个好习惯.<br /><br /><br /><img src ="http://www.cnitblog.com/Raistlin/aggbug/11300.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2006-05-31 11:40 <a href="http://www.cnitblog.com/Raistlin/archive/2006/05/31/11300.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么叫Link...什么叫Symbol</title><link>http://www.cnitblog.com/Raistlin/archive/2006/05/25/11029.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Thu, 25 May 2006 03:09:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2006/05/25/11029.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/11029.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2006/05/25/11029.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/11029.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/11029.html</trackback:ping><description><![CDATA[
		<p>以下代码在VC6.0中并不会抛出异常</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">try</span>
				<span style="COLOR: #000000">{<br />  </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000"> p </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000">[</span>
				<span style="COLOR: #008000">/*</span>
				<span style="COLOR: #008000">0xFFFFFFE0</span>
				<span style="COLOR: #008000">*/</span>
				<span style="COLOR: #000000">numeric_limits</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">::max()];<br /> }<br /> </span>
				<span style="COLOR: #0000ff">catch</span>
				<span style="COLOR: #000000">(bad_alloc x){<br />  cerr</span>
				<span style="COLOR: #000000">&lt;&lt;</span>
				<span style="COLOR: #000000">x.what();<br /> }</span>
		</div>
		<p>和标准C++描述的不一样.<br />new会被链接到一个debug版本的库,然后跳出一个assert.<br />就算参数符合assert条件,若分配失败,只是返回0,并不抛出bac_alloc异常.<br />在网上找了两篇文章,对VC甚不耐烦<br /><br />(据说出自CSDN,谁写的无心情去考究了):<br /><strong>在VC6.0中如何让new操作失败后抛出异常？</strong><br /><br />标准C++规定new一个对象时如果分配内存失败就应抛出一个std::bad_alloc异常，如果不希望抛出异常而仅仅传回一个NULL指针，可以用new的无异常版本：new(nothrow)。</p>
		<p>VC6.0在&lt;new&gt;头文件中声明了这两种operator new操作符：</p>
		<p>void *__cdecl operator new(size_t) _THROW1(std::bad_alloc)；</p>
		<p>void *__cdecl operator new(size_t, const std::nothrow_t&amp;) _THROW0()；</p>
		<p>并分别定义在newop.cpp和newop2.cpp中。而_THROW0和_THROW1则是两个宏，在Include目录的xstddef文件中定义:</p>
		<p>#define _THROW0() throw ()</p>
		<p>#define _THROW1(x) throw (x)</p>
		<p>newop.cpp和newop2.cpp对应的目标模块被打包进标准C++库中。标准C++库有若干个版本: libcp.lib(单线程静态版)、libcpd.lib(单线程静态调试版)、libcpmt.lib(多线程静态版)、libcpmtd.lib(多线程静态调试版)、msvcprt.lib(多线程动态版的导入库)，msvcprtd.lib(多线程动态调试版的导入库)，这些库与相应版本的C标准库一起使用，比如libcp.lib与libc.lib搭配。另外，VC6.0在new.cpp还定义了一个operator new，原型如下 :</p>
		<p>void * operator new( unsigned int cb )</p>
		<p>而new.cpp对应的目标模块却是被打包进C标准库中的(是不是有点奇怪?)。</p>
		<p>一般来说，程序员不会显式指定链接C++标准库，可是当程序中确实使用了标准C++库时链接器却能聪明地把相应的C++标准库文件加进输入文件列表，这是为什么？其实任何一个C++标准头文件都会直接或间接地包含use_ansi.h文件，打开它一看便什么都清楚了(源码之前，了无秘密) :</p>
		<p>/***</p>
		<p>*use_ansi.h - pragmas for ANSI Standard C++ libraries</p>
		<p>*</p>
		<p>* Copyright (c) 1996-1997, Microsoft Corporation. All rights reserved.</p>
		<p>*</p>
		<p>*Purpose:</p>
		<p>* This header is intended to force the use of the appropriate ANSI</p>
		<p>* Standard C++ libraries whenever it is included.</p>
		<p>*</p>
		<p>* [Public]</p>
		<p>*</p>
		<p>****/</p>
		<p>#if _MSC_VER &gt; 1000</p>
		<p>#pragma once</p>
		<p>#endif</p>
		<p>#ifndef _USE_ANSI_CPP</p>
		<p>#define _USE_ANSI_CPP</p>
		<p>#ifdef _MT</p>
		<p>#ifdef _DLL</p>
		<p>#ifdef _DEBUG</p>
		<p>#pragma comment(lib,"msvcprtd")</p>
		<p>#else// _DEBUG</p>
		<p>#pragma comment(lib,"msvcprt")</p>
		<p>#endif// _DEBUG</p>
		<p>#else// _DLL</p>
		<p>#ifdef _DEBUG</p>
		<p>#pragma comment(lib,"libcpmtd")</p>
		<p>#else// _DEBUG</p>
		<p>#pragma comment(lib,"libcpmt")</p>
		<p>#endif// _DEBUG</p>
		<p>#endif// _DLL</p>
		<p>#else// _MT</p>
		<p>#ifdef _DEBUG</p>
		<p>#pragma comment(lib,"libcpd")</p>
		<p>#else// _DEBUG</p>
		<p>#pragma comment(lib,"libcp")</p>
		<p>#endif// _DEBUG</p>
		<p>#endif</p>
		<p>#endif// _USE_ANSI_CPP</p>
		<p>现在我们用实际代码来测试一下new会不会抛出异常，建一个test.cpp源文件：</p>
		<p>// test.cpp</p>
		<p>#include &lt;new&gt;</p>
		<p>#include &lt;iostream&gt;</p>
		<p>using namespace std;</p>
		<p>class BigClass </p>
		<p>{</p>
		<p>public:</p>
		<p>BigClass() {}</p>
		<p>~BigClass(){}</p>
		<p>char BigArray[0x7FFFFFFF];</p>
		<p>};</p>
		<p>int main()</p>
		<p>{</p>
		<p>try </p>
		<p>{</p>
		<p>BigClass *p = new BigClass;</p>
		<p>}</p>
		<p>catch( bad_alloc &amp;a) </p>
		<p>{</p>
		<p>cout &lt;&lt; "new BigClass, threw a bad_alloc exception" &lt;&lt; endl;</p>
		<p>}</p>
		<p>BigClass *q = new(nothrow) BigClass;</p>
		<p>if ( q == NULL )</p>
		<p>cout &lt;&lt; "new(nothrow) BigClass, returned a NULL pointer" &lt;&lt; endl;</p>
		<p>try </p>
		<p>{</p>
		<p>BigClass *r = new BigClass[1];</p>
		<p>}</p>
		<p>catch( bad_alloc &amp;a) </p>
		<p>{</p>
		<p>cout &lt;&lt; "new BigClass[1], threw a bad_alloc exception" &lt;&lt; endl;</p>
		<p>}</p>
		<p>return 0;</p>
		<p>} </p>
		<p>根据VC6.0编译器与链接器的做法(请参考《为什么会出现LNK2005"符号已定义"的链接错误？》)，链接器会首先在C++标准库中解析符号，然后才是C标准库，所以如果开发者没有自定义operator new的话最后程序链接的应该是C++标准库中newop.obj和newop2.obj模块里的代码。可是程序运行的结果却是:</p>
		<p>new(nothrow) BigClass, returned a NULL pointer</p>
		<p>显然程序始终未抛出bad_alloc异常。单步跟踪观察，发现第1个和第3个new实际上调用了new.cpp里的operator new，而第二个new(nothrow)则正确地调用了newop2.cpp定义的版本。很难理解是吧？但是当你用</p>
		<p>dumpbin /SYMBOLS libcp.lib</p>
		<p>dump出libcp.lib所有的符号信息时，你会发现其中的newop.obj模块没有定义任何符号(其它版本也一样)。不可思议！newop.cpp的实现代码明明写在那儿，怎么会....？让我们再仔细看看newop.cpp，咦，operator new的定义被包裹在一个#if...#endif块中:</p>
		<p>#if !defined(_MSC_EXTENSIONS)</p>
		<p>...</p>
		<p>...</p>
		<p>void *__cdecl operator new(size_t size) _THROW1(_STD bad_alloc)</p>
		<p>{</p>
		<p>...</p>
		<p>...</p>
		<p>}</p>
		<p>#endif</p>
		<p>哦，原来需要_MSC_EXTENSIONS宏未定义，实现代码才是有效的啊。那么这个宏是什么意思？其实Visual C++在语言层面上对ANSI C标准做了一些特殊的扩展，定义_MSC_EXTENSIONS意味着编译器支持这样的扩展，没有定义它编译器就会严格按照ANSI C标准来编译程序。实际上如果指定了编译选项/Ze编译器就会自动定义这个宏，指定/Za则不会，而且/Ze是缺省选项。作者猜想Visual Studio的开发人员在build标准C++库时很可能没有指定/Za，导致newop.cpp中的operator new定义被无情抛弃。是他们的疏漏吗？我看未必，大家可以试试用/Za选项去编译那些标准库文件，看看有多少编译不通过。VC标准库的实现用了很多微软扩展的语言特性，不指定/Za是情有可原的，我不明白的是newop.cpp的作者(好象是P.J. Plauger老人家)为什么会加上一个如此愚蠢的"#if !defined(_MSC_EXTENSIONS)"，因为实在看不出这个operator new定义与_MSC_EXTENSIONS有什么冲突的地方。</p>
		<p>既然标准C++库里的newop.obj是个空壳，那我们就只好自己动手丰衣足食了。把newop.cpp和dbgint.h(都在VC98\crt\src目录下)拷贝到test.cpp所在的目录，并将newop.cpp中的</p>
		<p>#include &lt;dbgint.h&gt;</p>
		<p>改成</p>
		<p>#include "dbgint.h"</p>
		<p>然后用</p>
		<p>cl /c /Za /D_CRTBLD newop.cpp</p>
		<p>编译它。/D_CRTBLD定义了_CRTBLD宏，为什么这么做呢？因为dbgint.h属于内部头文件，VC不希望应用程序用到它，便在文件中埋伏了这么一段:</p>
		<p>#ifndef _CRTBLD</p>
		<p>/*</p>
		<p>* This is an internal C runtime header file. It is used when building</p>
		<p>* the C runtimes only. It is not to be used as a public header file.</p>
		<p>*/</p>
		<p>#error ERROR: Use of C runtime library internal header file.</p>
		<p>#endif /* _CRTBLD */</p>
		<p>可我们确确实实是想build标准库(的一部分)，所以只好强行突破这个限制了。然后编译test.cpp:</p>
		<p>cl /c /GX test.cpp</p>
		<p>最后进行链接:</p>
		<p>link test.obj newop.obj</p>
		<p>这时再运行test.exe输出的结果就是</p>
		<p>new BigClass, threw a bad_alloc exception</p>
		<p>new(nothrow) BigClass, returned a NULL pointer</p>
		<p>new BigClass[1], threw a bad_alloc exception</p>
		<p>值得庆幸的是虽然VC6.0如此弱智，但VC7.1却表现良好，原因是VC7.1的newop.cpp和newaop.cpp(数组版)取消了那个愚的"#if !defined(_MSC_EXTENSIONS)"，于是标准C++库中的newop.obj和newaop.obj模块都实实在在地有了相应代码。另外，nothrow版的定义也分别转移到了newopnt.cpp和newaopnt.cpp中。</p>
		<p>后记: 作者在2001年便碰到过这个问题，百思不得其解，于是在CSDN论坛上发问，也不见答复。从此便搁置一旁，直到最近因探究LNK2005链接错误而彻底弄清楚VC链接器解析符号的规则后，才意识到二者或有联系。于是重拾旧疑，顺藤而上，果然问题就迎刃而解。此题虽小，功夫却做足，最后总算水落石出，解除了4年的积惑。<br /></p>
		<p>
				<br />另一篇文章(网上被大量转载,来源不可知,我觉得这篇文章有些内容不一定正确):<br /><strong>为什么会出现LNK2005"符号已定义"的链接错误?<br /></strong>  许多Visual C++的使用者都碰到过LNK2005:symbol already defined和LNK1169:one or more multiply defined symbols found这样的链接错误，而且通常是在使用第三方库时遇到的。对于这个问题，有的朋友可能不知其然，而有的朋友可能知其然却不知其所以然，那么本文就试图为大家彻底解开关于它的种种疑惑。</p>
		<p>    大家都知道，从C/C++源程序到可执行文件要经历两个阶段:(1)编译器将源文件编译成汇编代码，然后由汇编器(assembler)翻译成机器指令(再加上其它相关信息)后输出到一个个目标文件(object file,VC的编译器编译出的目标文件默认的后缀名是.obj)中；(2)链接器(linker)将一个个的目标文件(或许还会有若干程序库)链接在一起生成一个完整的可执行文件。</p>
		<p>    编译器编译源文件时会把源文件的全局符号(global symbol)分成强(strong)和弱(weak)两类传给汇编器，而随后汇编器则将强弱信息编码并保存在目标文件的符号表中。那么何谓强弱呢？编译器认为函数与初始化了的全局变量都是强符号，而未初始化的全局变量则成了弱符号。比如有这么个源文件:</p>
		<p>extern int errorno;<br />int buf[2] = {1,2};<br />int *p;</p>
		<p>int main()<br />{<br />   return 0;<br />}</p>
		<p>其中main、buf是强符号，p是弱符号，而errorno则非强非弱，因为它只是个外部变量的使用声明。</p>
		<p>    有了强弱符号的概念，我们就可以看看链接器是如何处理与选择被多次定义过的全局符号:</p>
		<p>规则1: 不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号)；</p>
		<p>
				<br />规则2: 如果一个符号在某个目标文件中是强符号，在其它文件中都是弱符号，那么选择强符号；</p>
		<p>
				<br />规则3: 如果一个符号在所有目标文件中都是弱符号，那么选择其中任意一个；</p>
		<p>    由上可知多个目标文件不能重复定义同名的函数与初始化了的全局变量，否则必然导致LNK2005和LNK1169两种链接错误。可是，有的时候我们并没有在自己的程序中发现这样的重定义现象，却也遇到了此种链接错误，这又是何解？嗯，问题稍微有点儿复杂，容我慢慢道来。</p>
		<p>
				<br />    众所周知，ANSI C/C++ 定义了相当多的标准函数，而它们又分布在许多不同的目标文件中，如果直接以目标文件的形式提供给程序员使用的话，就需要他们确切地知道哪个函数存在于哪个目标文件中，并且在链接时显式地指定目标文件名才能成功地生成可执行文件，显然这是一个巨大的负担。所以C语言提供了一种将多个目标文件打包成一个文件的机制，这就是静态程序库(static library)。开发者在链接时只需指定程序库的文件名，链接器就会自动到程序库中寻找那些应用程序确实用到的目标模块，并把(且只把)它们从库中拷贝出来参与构建可执行文件。几乎所有的C/C++开发系统都会把标准函数打包成标准库提供给开发者使用(有不这么做的吗？)。</p>
		<p>    程序库为开发者带来了方便，但同时也是某些混乱的根源。我们来看看链接器是如何解析(resolve)对程序库的引用的。<br />    <br />    在符号解析(symbol resolution)阶段，链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们，在此期间它要维护若干个集合:(1)集合E是将被合并到一起组成可执行文件的所有目标文件集合；(2)集合U是未解析符号(unresolved symbols，比如已经被引用但是还未被定义的符号)的集合；(3)集合D是所有之前已被加入到E的目标文件定义的符号集合。一开始，E、U、D都是空的。</p>
		<p>(1): 对命令行中的每一个输入文件f，链接器确定它是目标文件还是库文件，如果它是目标文件，就把f加入到E，并把f中未解析的符号和已定义的符号分别加入到U、D集合中，然后处理下一个输入文件。</p>
		<p>(2): 如果f是一个库文件，链接器会尝试把U中的所有未解析符号与f中各目标模块定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号，那么就把m加入到E中，并把m中未解析的符号和已定义的符号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过程直至到达一个不动点(fixed point)，此时U和D不再变化。而那些未加入到E中的f里的目标模块就被简单地丢弃，链接器继续处理下一输入文件。</p>
		<p>(3): 如果处理过程中往D加入一个已存在的符号，或者当扫描完所有输入文件时U非空，链接器报错并停止动作。否则，它把E中的所有目标文件合并在一起生成可执行文件。</p>
		<p>    VC带的编译器名字叫cl.exe，它有这么几个与标准程序库有关的选项: /ML、/MLd、/MT、/MTd、/MD、/MDd。这些选项告诉编译器应用程序想使用什么版本的C标准程序库。/ML(缺省选项)对应单线程静态版的标准程序库(libc.lib)；/MT对应多线程静态版标准库(libcmt.lib)，此时编译器会自动定义_MT宏；/MD对应多线程DLL版(导入库msvcrt.lib，DLL是msvcrt.dll)，编译器自动定义_MT和_DLL两个宏。后面加d的选项都会让编译器自动多定义一个_DEBUG宏，表示要使用对应标准库的调试版，因此/MLd对应调试版单线程静态标准库(libcd.lib)，/MTd对应调试版多线程静态标准库(libcmtd.lib)，/MDd对应调试版多线程DLL标准库(导入库msvcrtd.lib，DLL是msvcrtd.dll)。虽然我们的确在编译时明白无误地告诉了编译器应用程序希望使用什么版本的标准库，可是当编译器干完了活，轮到链接器开工时它又如何得知一个个目标文件到底在思念谁？为了传递相思，我们的编译器就干了点秘密的勾当。在cl编译出的目标文件中会有一个专门的区域(关心这个区域到底在文件中什么地方的朋友可以参考COFF和PE文件格式)存放一些指导链接器如何工作的信息，其中有一种就叫缺省库(default library)，这些信息指定了一个或多个库文件名，告诉链接器在扫描的时候也把它们加入到输入文件列表中(当然顺序位于在命令行中被指定的输入文件之后)。说到这里，我们先来做个小实验。写个顶顶简单的程序，然后保存为main.c :</p>
		<p>/* main.c */<br />int main() { return 0; }</p>
		<p>用下面这个命令编译main.c(什么？你从不用命令行来编译程序？这个......) :</p>
		<p>cl /c main.c</p>
		<p>/c是告诉cl只编译源文件，不用链接。因为/ML是缺省选项，所以上述命令也相当于: cl /c /ML main.c 。如果没什么问题的话(要出了问题才是活见鬼！当然除非你的环境变量没有设置好，这时你应该去VC的bin目录下找到vcvars32.bat文件然后运行它。)，当前目录下会出现一个main.obj文件，这就是我们可爱的目标文件。随便用一个文本编辑器打开它(是的，文本编辑器，大胆地去做别害怕)，搜索"defaultlib"字符串，通常你就会看到这样的东西: "-defaultlib:LIBC -defaultlib:OLDNAMES"。啊哈，没错，这就<br />是保存在目标文件中的缺省库信息。我们的目标文件显然指定了两个缺省库，一个是单线程静态版标准库libc.lib(这与/ML选项相符)，另外一个是oldnames.lib(它是为了兼容微软以前的C/C++开发系统)。</p>
		<p>    VC的链接器是link.exe，因为main.obj保存了缺省库信息，所以可以用</p>
		<p>link main.obj libc.lib</p>
		<p>或者</p>
		<p>link main.obj</p>
		<p>来生成可执行文件main.exe，这两个命令是等价的。但是如果你用</p>
		<p>link main.obj libcd.lib</p>
		<p>的话，链接器会给出一个警告: "warning LNK4098: defaultlib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library"，因为你显式指定的标准库版本与目标文件的缺省值不一致。通常来说，应该保证链接器合并的所有目标文件指定的缺省标准库版本一致，否则编译器一定会给出上面的警告，而LNK2005和LNK1169链接错误则有时会出现有时不会。那么这个有时到底是什么时候？呵呵，别着急，下面的一切正是为喜欢追根究底的你准备的。</p>
		<p>    建一个源文件，就叫mylib.c，内容如下:</p>
		<p>/* mylib.c */<br />#include &lt;stdio.h&gt;</p>
		<p>void foo()<br />{<br />   printf("%s","I am from mylib!\n");<br />}</p>
		<p>用</p>
		<p>cl /c /MLd mylib.c</p>
		<p>命令编译，注意/MLd选项是指定libcd.lib为默认标准库。lib.exe是VC自带的用于将目标文件打包成程序库的命令，所以我们可以用</p>
		<p>lib /OUT:my.lib mylib.obj</p>
		<p>将mylib.obj打包成库，输出的库文件名是my.lib。接下来把main.c改成:</p>
		<p>/* main.c */<br />void foo();</p>
		<p>int main()<br />{<br />   foo();<br />   return 0;<br />}</p>
		<p>用</p>
		<p>cl /c main.c</p>
		<p>编译，然后用</p>
		<p>link main.obj my.lib</p>
		<p>进行链接。这个命令能够成功地生成main.exe而不会产生LNK2005和LNK1169链接错误，你仅仅是得到了一条警告信息:"warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library"。我们根据前文所述的扫描规则来分析一下链接器此时做了些啥。</p>
		<p>    一开始E、U、D都是空集，链接器首先扫描到main.obj，把它加入E集合，同时把未解析的foo加入U，把main加入D，而且因为main.obj的默认标准库是libc.lib，所以它被加入到当前输入文件列表的末尾。接着扫描my.lib，因为这是个库，所以会拿当前U中的所有符号(当然现在就一个foo)与my.lib中的所有目标模块(当然也只有一个mylib.obj)依次匹配，看是否有模块定义了U中的符号。结果mylib.obj确实定义了foo，于是它被加入到E，foo从U转移到D，mylib.obj引用的printf加入到U，同样地，mylib.obj指定的默认标准库是libcd.lib，它也被加到当前输入文件列表的末尾(在libc.lib的后面)。不断地在my.lib库的各模块上进行迭代以匹配U中的符号，直到U、D都不再变化。很明显，现在就已经到达了这么一个不动点，所以接着扫描下一个输入文件，就是libc.lib。链接器发现libc.lib里的printf.obj里定义有printf，于是printf从U移到D，而printf.obj被加入到E，它定义的所有符号加入到D，它里头的未解析符号加入到U。链接器还会把每个程序都要用到的一些初始化操作所在的目标模块(比如crt0.obj等)及它们所引用的模块(比如malloc.obj、free.obj等)自动加入到E中，并更新U和D以反应这个变化。事实上，标准库各目标模块里的未解析符号都可以在库内其它模块中找到定义，因此当链接器处理完libc.lib时，U一定是空的。最后处理libcd.lib，因为此时U已经为空，所以链接器会抛弃它里面的所有目标模块从而结束扫描，然后合并E中的目标模块并输出可执行文件。</p>
		<p>    上文描述了虽然各目标模块指定了不同版本的缺省标准库但仍然链接成功的例子，接下来你将目睹因为这种不严谨而导致的悲惨失败。</p>
		<p>    修改mylib.c成这个样子:</p>
		<p>#include &lt;crtdbg.h&gt;</p>
		<p>void foo()<br />{<br />   // just a test , don't care memory leak<br />   _malloc_dbg( 1, _NORMAL_BLOCK, __FILE__, __LINE__ );<br />}</p>
		<p>其中_malloc_dbg不是ANSI C的标准库函数，它是VC标准库提供的malloc的调试版，与相关函数配套能帮助开发者抓各种内存错误。使用它一定要定义_DEBUG宏，否则预处理器会把它自动转为malloc。继续用</p>
		<p>cl /c /MLd mylib.c<br />lib /OUT:my.lib mylib.obj</p>
		<p>编译打包。当再次用</p>
		<p>link main.obj my.lib</p>
		<p>进行链接时，我们看到了什么？天哪，一堆的LNK2005加上个贵为"fatal error"的LNK1169垫底，当然还少不了那个LNK4098。链接器是不是疯了？不，你冤枉可怜的链接器了，我拍胸脯保证它可是一直在尽心尽责地照章办事。</p>
		<p>    一开始E、U、D为空，链接器扫描main.obj，把它加入E，把foo加入U，把main加入D，把libc.lib加入到当前输入文件列表的末尾。接着扫描my.lib，foo从U转移到D，_malloc_dbg加入到U，libcd.lib加到当前输入文件列表的尾部。然后扫描libc.lib，这时会发现libc.lib里任何一个目标模块都没有定义_malloc_dbg(它只在调试版的标准库中存在)，所以不会有任何一个模块因为_malloc_dbg而加入E，但是每个程序都要用到的初始化模块(如crt0.obj等)及它们所引用的模块(比如malloc.obj、free.obj等)还是会自动加入到E中，同时U和D被更新以反应这个变化。当链接器处理完libc.lib时，U只剩_malloc_dbg这一个符号。最后处理libcd.lib，发现dbgheap.obj定义了_malloc_dbg，于是dbgheap.obj加入到E，它里头的未解析符号加入U，它定义的所有其它符号也加入D，这时灾难便来了。之前malloc等符号已经在D中(随着libc.lib里的malloc.obj加入E而加入的)，而dbgheap.obj又定义了包括malloc在内的许多同名符号，这引发了重定义冲突，链接器只好中断工作并报告错误。</p>
		<p>    现在我们该知道，链接器完全没有责任，责任在我们自己的身上。是我们粗心地把缺省标准库版本不一致的目标文件(main.obj)与程序库(my.lib)链接起来，导致了大灾难。解决办法很简单，要么用/MLd选项来重编译main.c；要么用/ML选项重编译mylib.c。</p>
		<p>    在上述例子中，我们拥有库my.lib的源代码(mylib.c)，所以可以用不同的选项重新编译这些源代码并再次打包。可如果使用的是第三方的库，它并没有提供源代码，那么我们就只有改变自己程序的编译选项来适应这些库了。但是如何知道库中目标模块指定的默认库呢？其实VC提供的一个小工具便可以完成任务，这就是dumpbin.exe。运行下面这个命令</p>
		<p>dumpbin /DIRECTIVES my.lib</p>
		<p>然后在输出中找那些"Linker Directives"引导的信息，你一定会发现每一处这样的信息都会包含若干个类似"-defaultlib:XXXX"这样的字符串，其中XXXX便代表目标模块指定的缺省库名。</p>
		<p>    知道了第三方库指定的默认标准库，再用合适的选项编译我们的应用程序，就可以避免LNK2005和LNK1169链接错误。喜欢IDE的朋友，你一样可以到 "Project属性" -&gt; "C/C++" -&gt; "代码生成(code generation)" -&gt; "运行时库(run-time library)" 项下设置应用程序的默认标准库版本，这与命令行选项的效果是一样的。<br /><br /><br /><br /><br />好文章还不是一般的多:<br />Under The Hood, July 1997<br /><a href="http://comcamp.diy.myrice.com/techarticles/vc/0010.htm">http://comcamp.diy.myrice.com/techarticles/vc/0010.htm</a><br /><br />为什么全局变量没有初始化?<br /><a href="http://comcamp.diy.myrice.com/techarticles/vc/0011.htm">http://comcamp.diy.myrice.com/techarticles/vc/0011.htm</a><br /><br /><br />链接一个静态LIB,不在客户端代码中使用它的任何变量和代码,但要让这个LIB的全局变量被初始化的方法是:<br />这个链接库头文件应该这么写:<br />extern CMyClass *g_pObject ;<br />static void *__dummy = (void*)g_pObject ;</p>
		<p>// lib.cpp<br />CMyClass *g_pObject = CMyClass::Instance() ; // Singleton<br /><br />__dummy会出现在任何包含这个头文件的CPP文件的OBJ中,所以LINKER会把静态库中的g_pObject链接到Exe中,包括它的构造和析构<br /><br /><br />&lt;iostream&gt;很有意思,其中有一行<br />static ios_base::Init _Ios_init;<br />ios_base::Init是个类,在类的构造中判断构造是否第一次被调用,如果是,则初始化cout,cin,cerr等<br />在类的析构中判断这是不是最后一次构造,如果是,则调用cout.flush() .... (basic_ostream等的析构并没有调用flush)<br />具体怎么判断是否第一次调用构造,是否最后一次调用析构,那是用一个int的静态类成员来计算...<br /><br />其实这样会增加exe文件的尺寸,降低程序启动速度....<br /></p>
<img src ="http://www.cnitblog.com/Raistlin/aggbug/11029.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2006-05-25 11:09 <a href="http://www.cnitblog.com/Raistlin/archive/2006/05/25/11029.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在动态链接库中包含资源；在静态链接库中包含资源？</title><link>http://www.cnitblog.com/Raistlin/archive/2006/05/08/10205.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Mon, 08 May 2006 08:32:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2006/05/08/10205.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/10205.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2006/05/08/10205.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/10205.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/10205.html</trackback:ping><description><![CDATA[
		<p>
				<strong>资源DLL是怎么回事？<br /></strong>其实也就是建一个包含资源的DLL，加载该DLL并从该DLL读取相关资源。API如下： <br />HINSTANCE LoadLibrary(<br />  LPCTSTR lpLibFileName   // address of filename of executable module<br />);</p>
		<p>HGLOBAL LoadResource(<br />  HMODULE hModule, // resource-module handle<br />  HRSRC hResInfo   // resource handle<br />);</p>
		<p>HRSRC FindResource(<br />  HMODULE hModule, // module handle<br />  LPCTSTR lpName,  // pointer to resource name<br />  LPCTSTR lpType   // pointer to resource type<br />);</p>
		<p>void AfxSetResourceHandle( HINSTANCE hInstResource );]<br />HINSTANCE AfxGetResourceHandle( );<br />CString::LoadString(UINT nID) calls:<br />   int AFXAPI AfxLoadString(UINT nIDS, LPTSTR lpszBuf, UINT nMaxBuf = 256);</p>
		<p>
				<strong>MFC怎么在应用程序框架中自动加入资源(mfc的光标对话框等)</strong>
				<br />MFC的文件保存在如下位置：<br />X:\Microsoft Visual Studio\VC98\MFC\Include<br />X:\Microsoft Visual Studio\VC98\MFC\Lib<br />X:\Microsoft Visual Studio\VC98\MFC\SRC<br />其中include文件包含了资源的头文件.h和定义文件.rc</p>
		<p>
				<strong>MFC的这些资源怎么被神不知鬼不觉的编译链接到MFC程序中？<br /></strong>见下图:</p>
		<p>  <img height="189" alt="resource1.jpg" src="http://www.cnitblog.com/images/cnitblog_com/raistlin/resource1.jpg" width="320" border="0" /><br /><br /><img height="405" alt="resource2.jpg" src="http://www.cnitblog.com/images/cnitblog_com/raistlin/resource2.jpg" width="439" border="0" /><br /><br /><img height="463" alt="resource3.jpg" src="http://www.cnitblog.com/images/cnitblog_com/raistlin/resource3.jpg" width="467" border="0" /><br /><br /><img height="382" alt="resource4.jpg" src="http://www.cnitblog.com/images/cnitblog_com/raistlin/resource4.jpg" width="551" border="0" /><br /><br /><img height="296" alt="resource5.jpg" src="http://www.cnitblog.com/images/cnitblog_com/raistlin/resource5.jpg" width="536" border="0" /><br /><br /><strong>程序源代码文件的物理位置规划</strong></p>
		<p>虽然不能直接把资源放到静态链接库中，但只要稍做变通，就能弄出一个可以到处使用的对话框静态链接库了。</p>
		<p>
				<strong>但还有个问题是如何避免资源ID的冲突</strong>
		</p>
		<p>// Next default values for new objects<br />// <br />#ifdef APSTUDIO_INVOKED<br />#ifndef APSTUDIO_READONLY_SYMBOLS<br />#define _APS_3D_CONTROLS                     1<br />#define _APS_NEXT_RESOURCE_VALUE        227<br />#define _APS_NEXT_COMMAND_VALUE         32831<br />#define _APS_NEXT_CONTROL_VALUE         1274<br />#define _APS_NEXT_SYMED_VALUE           104<br />#endif<br />#endif<br /></p>
<img src ="http://www.cnitblog.com/Raistlin/aggbug/10205.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2006-05-08 16:32 <a href="http://www.cnitblog.com/Raistlin/archive/2006/05/08/10205.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++拷贝构造函数深入分析以及重写operator =</title><link>http://www.cnitblog.com/Raistlin/archive/2006/03/30/8278.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Thu, 30 Mar 2006 02:34:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2006/03/30/8278.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/8278.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2006/03/30/8278.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/8278.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/8278.html</trackback:ping><description><![CDATA[
		<p> </p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img id="Codehighlighter1_24_609_Open_Image" onclick="this.style.display='none'; Codehighlighter1_24_609_Open_Text.style.display='none'; Codehighlighter1_24_609_Closed_Image.style.display='inline'; Codehighlighter1_24_609_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_24_609_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_24_609_Closed_Text.style.display='none'; Codehighlighter1_24_609_Open_Image.style.display='inline'; Codehighlighter1_24_609_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> CTestCopyConstruct</span>
				<span id="Codehighlighter1_24_609_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cnitblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_24_609_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000">:<br /><img id="Codehighlighter1_55_147_Open_Image" onclick="this.style.display='none'; Codehighlighter1_55_147_Open_Text.style.display='none'; Codehighlighter1_55_147_Closed_Image.style.display='inline'; Codehighlighter1_55_147_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_55_147_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_55_147_Closed_Text.style.display='none'; Codehighlighter1_55_147_Open_Image.style.display='inline'; Codehighlighter1_55_147_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    CTestCopyConstruct()</span>
						<span id="Codehighlighter1_55_147_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cnitblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_55_147_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        TRACE(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">Enter CTestCopyConstruct();this is %d\n</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #0000ff">this</span>
								<span style="COLOR: #000000">);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        strTest </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">not ok</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        i </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img id="Codehighlighter1_199_342_Open_Image" onclick="this.style.display='none'; Codehighlighter1_199_342_Open_Text.style.display='none'; Codehighlighter1_199_342_Closed_Image.style.display='inline'; Codehighlighter1_199_342_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_199_342_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_199_342_Closed_Text.style.display='none'; Codehighlighter1_199_342_Open_Image.style.display='inline'; Codehighlighter1_199_342_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    CTestCopyConstruct(</span>
						<span style="COLOR: #0000ff">const</span>
						<span style="COLOR: #000000"> CTestCopyConstruct </span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000">src)</span>
						<span id="Codehighlighter1_199_342_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cnitblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_199_342_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        TRACE(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">Enter CTestCopyConstruct(const CTestCopyConstruct &amp;src);this is %d;src is %d\n</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #0000ff">this</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #000000">&amp;</span>
								<span style="COLOR: #000000">src);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        strTest </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> src.strTest;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        i </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> src.i;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img id="Codehighlighter1_408_581_Open_Image" onclick="this.style.display='none'; Codehighlighter1_408_581_Open_Text.style.display='none'; Codehighlighter1_408_581_Closed_Image.style.display='inline'; Codehighlighter1_408_581_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_408_581_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_408_581_Closed_Text.style.display='none'; Codehighlighter1_408_581_Open_Image.style.display='inline'; Codehighlighter1_408_581_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    CTestCopyConstruct </span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> operator </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000">(</span>
						<span style="COLOR: #0000ff">const</span>
						<span style="COLOR: #000000"> CTestCopyConstruct </span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000"> src)</span>
						<span id="Codehighlighter1_408_581_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cnitblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_408_581_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        TRACE(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">Enter CTestCopyConstruct &amp; operator =(const CTestCopyConstruct &amp; src);this is %d;src is %d\n</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #0000ff">this</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #000000">&amp;</span>
								<span style="COLOR: #000000">src);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        strTest </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> src.strTest;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        i </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> src.i;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">*</span>
								<span style="COLOR: #0000ff">this</span>
								<span style="COLOR: #000000">;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    CString strTest;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> i;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_641_773_Open_Image" onclick="this.style.display='none'; Codehighlighter1_641_773_Open_Text.style.display='none'; Codehighlighter1_641_773_Closed_Image.style.display='inline'; Codehighlighter1_641_773_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_641_773_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_641_773_Closed_Text.style.display='none'; Codehighlighter1_641_773_Open_Image.style.display='inline'; Codehighlighter1_641_773_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />CTestCopyConstruct GetTest()</span>
				<span id="Codehighlighter1_641_773_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cnitblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_641_773_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    CTestCopyConstruct ret1;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    ret1.strTest </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">ok</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    ret1.i </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    CTestCopyConstruct ret2;</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> ret1;</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> CTestDlg::OnOK() <br /><img id="Codehighlighter1_799_1206_Open_Image" onclick="this.style.display='none'; Codehighlighter1_799_1206_Open_Text.style.display='none'; Codehighlighter1_799_1206_Closed_Image.style.display='inline'; Codehighlighter1_799_1206_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_799_1206_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_799_1206_Closed_Text.style.display='none'; Codehighlighter1_799_1206_Open_Image.style.display='inline'; Codehighlighter1_799_1206_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_799_1206_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cnitblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_799_1206_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    CTestCopyConstruct var1;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    CTestCopyConstruct var2 </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> GetTest();<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">\nresult 1:\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">var1 is %d\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000">var1);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">var2 is %d var2.str is %s\n\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000">var2,var2.strTest);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    CTestCopyConstruct var3 </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> var2;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    CTestCopyConstruct var4;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    var4 </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> var2;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">\nresult 2:\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">var3 is %d var3.str is %s\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000">var3,var3.strTest);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">var4 is %d var2.str is %s\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000">var4,var4.strTest);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>
				<br />
				<br />代码如上，调试窗口输出如下：<br />Enter CTestCopyConstruct();this is 1242980<br />Enter CTestCopyConstruct();this is 1242848<br />Enter CTestCopyConstruct();this is 1242840<br />Enter CTestCopyConstruct(const CTestCopyConstruct &amp;src);this is 1242972;src is 1242848</p>
		<p>result 1:<br />var1 is 1242980<br />var2 is 1242972 var2.str is ok</p>
		<p>Enter CTestCopyConstruct(const CTestCopyConstruct &amp;src);this is 1242964;src is 1242972<br />Enter CTestCopyConstruct();this is 1242956<br />Enter CTestCopyConstruct &amp; operator =(const CTestCopyConstruct &amp; src);this is 1242956;src is 1242972</p>
		<p>result 2:<br />var3 is 1242964 var3.str is ok<br />var4 is 1242956 var2.str is ok<br /><br />分析：<br />CTestCopyConstruct var1;\\1<br />CTestCopyConstruct var2 = GetTest();\\2<br />代码的执行如下：<br />当前堆栈指针(sp) = 1242980<br />sp -= 8//在堆栈中为var1分配空间<br />在var1上(1242980 - 1242973)调用构造函数<br />sp -= 8//在堆栈中为var2分配空间<br />sp -= n//保护当前环境<br />进入了GetTest函数<br />当前sp = 1242848<br />sp -= 8//为ret1分配空间<br />构建ret1<br />sp -= 8//为ret2分配空间<br />构建ret2<br />......<br />对var2(1242972处的堆栈段)调用拷贝构造函数，以test1(1242848处)为参数<br />//析构test1 test2等...<br />sp += n//恢复运行环境<br />......<br /><br />另：<br />operater = () 和默认构造函数不一样，只重写=运算符而不提供拷贝构造函数，调用的仍然是默认的构造函数。<br />默认构造函数和赋值运算符处理的情况不一样，一个是在已分配的空间上调用，一个是在已构造的对象上调用。<br /><br />默认拷贝构造函数会调用类中各成员的拷贝构造函数。CString 由于提供了拷贝构造函数，所以上面例子中即使去掉拷贝构造函数，var2 仍然会得到正确的值。<br /><br />调试的环境是vc6.0 debug 默认选项。编译没有优化。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">CTestCopyConstruct(</span>
				<span style="COLOR: #0000ff">const</span>
				<span style="COLOR: #000000"> CTestCopyConstruct </span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000">src)<br /><img id="Codehighlighter1_52_195_Open_Image" onclick="this.style.display='none'; Codehighlighter1_52_195_Open_Text.style.display='none'; Codehighlighter1_52_195_Closed_Image.style.display='inline'; Codehighlighter1_52_195_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_52_195_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_52_195_Closed_Text.style.display='none'; Codehighlighter1_52_195_Open_Image.style.display='inline'; Codehighlighter1_52_195_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />        </span>
				<span id="Codehighlighter1_52_195_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cnitblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_52_195_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Enter CTestCopyConstruct(const CTestCopyConstruct &amp;src);this is %d;src is %d\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #0000ff">this</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000">src);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        strTest </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> src.strTest;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        i </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> src.i;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />    }</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" />与<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align="top" />CTestCopyConstruct(</span>
				<span style="COLOR: #0000ff">const</span>
				<span style="COLOR: #000000"> CTestCopyConstruct </span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000">src)<br /><img id="Codehighlighter1_275_393_Open_Image" onclick="this.style.display='none'; Codehighlighter1_275_393_Open_Text.style.display='none'; Codehighlighter1_275_393_Closed_Image.style.display='inline'; Codehighlighter1_275_393_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_275_393_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_275_393_Closed_Text.style.display='none'; Codehighlighter1_275_393_Open_Image.style.display='inline'; Codehighlighter1_275_393_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />        :strTest (src.strTest)</span>
				<span id="Codehighlighter1_275_393_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cnitblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_275_393_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        TRACE(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Enter CTestCopyConstruct(const CTestCopyConstruct &amp;src);this is %d;src is %d\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #0000ff">this</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">&amp;</span>
						<span style="COLOR: #000000">src);<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        i </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> src.i;<br /><img src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />    }</span>
				</span>
		</div>
		<br />前者先调用了CString::CString()再调用CString::operator =<br />后者直接调用了CString::CString(CString &amp; src);<br /><br /><br />默认的赋值运算的行为：首先调用父类的赋值运算。<br />然后会为自己独有的各成员寻找赋值运算。如果成员的赋值运算符被重写，则调用这个重写的赋值运算符函数，如果这个重写的运算符函数是private，编译将无法通过。<br />默认的拷贝构造函数的行为：首先调用父类的拷贝构造函数。<br />然后为自己独有的各成员寻找拷贝构造函数。如果这个成员提供拷贝构造函数，则调用之，如果成员的类提供的拷贝构造函数是private，编译将无法通过。<br />(子类完全可以把父类当成自己的一个成员?)<br /><br /><br />可以说默认的赋值运算和默认的拷贝构造函数是类最常被用到的两个函数了...内部却不是一般的复杂。<img src ="http://www.cnitblog.com/Raistlin/aggbug/8278.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2006-03-30 10:34 <a href="http://www.cnitblog.com/Raistlin/archive/2006/03/30/8278.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自由地生成补丁程序</title><link>http://www.cnitblog.com/Raistlin/archive/2006/02/10/6540.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Fri, 10 Feb 2006 04:08:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2006/02/10/6540.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/6540.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2006/02/10/6540.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/6540.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/6540.html</trackback:ping><description><![CDATA[<P>啥时候也轮到俺写补丁程序了。虽然网络如此发达的今天，实在应该使用在线升级比较好。但微软不是还提供补丁程序下载吗...<BR>nsis的脚本不熟,installshield是庞然大物而且似乎产生的垃圾比实际安装的要多..-_-!<BR>所以自己弄个可以自己定制生成补丁的程序<BR>其实没那么玄，用微软的cabsdk和vc自身的编译功能就可以了<BR><BR>功能:<BR>&nbsp;压缩源文件<BR>&nbsp;解压文件<BR>&nbsp;替换文件或新建文件或删除文件<BR>&nbsp;若失败恢复原系统文件<BR>&nbsp;登记/判断补丁信息<BR><BR>方法:<BR>1、使用cabsdk来生成cab文件 cabsdk可从微软网站上下载<BR>2、建立工程A，功能如下：<BR>&nbsp;(a)设置补丁程序信息<BR>&nbsp;(b)指定补丁源文件和将被替换(或添加)的文件路径<BR>&nbsp;(c)生成配置信息文件patch.ini<BR>&nbsp;(d)调用cabsdk中CABARC.EXE压缩补丁文件和配置信息文件到cab文件<BR>&nbsp;(e)修改工程B的rc文件，把cab文件作为工程B的资源，设置生成的exe文件的描述信息<BR>&nbsp;(f)调用vc编译器NMAKE.exe编译链接工程B<BR>3、建立工程B，功能如下：<BR>&nbsp;(a)调用cabsdk中fdi解压资源中的cab文件到临时文件夹<BR>&nbsp;(b)读取cab文件中的patch.ini<BR>&nbsp;(c)判断补丁是否有效<BR>&nbsp;(d)根据patch.ini信息循环: 备份目标文件，更新文件<BR>&nbsp;(e)失败:恢复原有文件<BR>&nbsp;(f)成功:注册补丁信息，如写入注册表<BR>&nbsp;(g)删除临时文件<BR><BR>即将添加新功能:修改注册表...<BR>未完待修改...<BR><BR>-------------------------------------------传说中的分割线-------------------------------------------<BR>您肯定被上面的搞晕了吧。。没关系，因为还有更好的方式可以实现这个目的，即不需要调用外部的程序直接生成补丁程序。<BR>这就需要：<BR>&nbsp;&nbsp;&nbsp;1直接压缩文件。通过调用FCI的函数可以实现<BR>&nbsp;&nbsp;&nbsp;2直接修改补丁程序的资源。这个难了点，不过俺有秘密武器:)。<BR><BR>不管如何实现的，补丁的数据格式需要预先定义。<BR>补丁的信息和内容保存在补丁程序的资源中。文件名为Patch.cab<BR>Patch.cab<BR>&nbsp; -Patch.ini<BR>&nbsp; -source files<BR><BR>Patch.ini内容如下<BR>patchName=xxx<BR>disusedPatchs=xxx;xxx;xxx<BR>appTitle=xxxx<BR>appDescription=xxx<BR>appComments=xxx<BR>pathVars=path1,path2,path3,path4<BR>path1.type=FIXED<BR>path1.value=xxx<BR>path2.type=ENVIRONMENT<BR>path2.value=%systemenvirement%<BR>path2.alterValue=xxx<BR>path3.type=REGISTER<BR>path3.value=HKEY_LOCALMACHINE|regpath<BR>path3.alterValue=xxx<BR>path4.type=USERINPUT<BR>path4.value=*path3*<BR>filesUpdate=ufile1;ufile2;ufile3...<BR>ufile1.src=....<BR>ufile1.dest=*path1*\relativepath<BR>ufile2.src=...<BR>ufile2=absolutepath<BR>ufile3.src=...<BR>ufile3=...<BR>filesAdd=afile1;afile2..<BR>afile1.src=...<BR>afile1.dest=dest path..<BR>afile2.src=...<BR>afile2.dest=...<BR>filesDelete=dfile1;dfile2..<BR>dfile1=path..<BR>dfile2=path..<BR>regUpdate=ureg1;ureg2...<BR>ureg1.type=BINARY/DWORD/SZ<BR>ureg1.parent=HKEK_LOCAL_MACHINE/HKEY_CURRENT_USER<BR>ureg1.keyname=...<BR>ureg1.keyvalue=...<BR>regAdd=areg1;areg2..<BR>areg1.type=BINARY/DWORD/SZ<BR>areg1.parent=HKEK_LOCAL_MACHINE/HKEY_CURRENT_USER<BR>areg1.keyname=...<BR>areg1.keyvalue=...<BR>regDelete=dreg1;dreg2...<BR>dreg1.parent=HKEK_LOCAL_MACHINE/HKEY_CURRENT_USER<BR>dreg1.keyname=...</P>
<P>-------------------------------------------暗淡的分割线-------------------------------------------<BR>发现要能生成适合各种情况的能订制的补丁要考虑的东西太多太多了...自己要定义一套东西...<BR>相当于制作安装程序要考虑的内容...<BR>那何必呢...直接研究NSIS不就可以了...<BR>NSIS帮助文档的翻译:<A href="http://foobar.nease.net/nsis/index.html">http://foobar.nease.net/nsis/index.html</A>,和英文的没啥差别,差别就是语言不同.哈<BR>稍微看了一下，又倒了胃口...<BR>本来安装程序这东西就很复杂,提供定制更麻烦,InstallShield不就有无数个变量吗...<BR><BR>-------------------------------------------最后的分割线-------------------------------------------<BR>最终还是用NSIS来做了...<BR>其实NSIS晦涩的地方在于:<BR>1，没有丰富的中文资料，Document上那点内容看了不会让人放心，说实在还是得去他们论坛查，够麻烦<BR>2，很多语法类似于汇编语言<BR>3, contrib目录下有很多库，每个库有各自的文档，而且是不怎么详细的文档<BR><BR>不过便利的地方也很多:<BR>写个.ini文件就可以订制对话框<BR>可以调用外部DLL<BR>支持回调函数(CALLBACK)<BR>可以编写NSIS自己的DLL，直接访问安装程序内部数据<BR><BR>下图是是调用了外部DLL执行mssql的.sql文件，并由外部DLL回调内部方法输出SQL语句的例子。<BR><IMG height=1071 alt=nsispatch.jpg src="http://www.cnitblog.com/images/cnitblog_com/raistlin/nsispatch.jpg" width=505 border=0></P><img src ="http://www.cnitblog.com/Raistlin/aggbug/6540.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2006-02-10 12:08 <a href="http://www.cnitblog.com/Raistlin/archive/2006/02/10/6540.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Activex和ie 浏览器的互动</title><link>http://www.cnitblog.com/Raistlin/archive/2005/12/30/5924.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Fri, 30 Dec 2005 09:51:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2005/12/30/5924.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/5924.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2005/12/30/5924.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/5924.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/5924.html</trackback:ping><description><![CDATA[<P>今天中午看到一个电子签名的软件。一看，惊艳！<BR>activex控件直接读取html元素的值，比如&lt;input type="text"&gt;&lt;/input&gt;<BR><BR>实在是牛啊！俺一开始以为是用javascript来做的.查看了例子的源代码后发现不是.<BR><BR>那么这个acitvex控件至少应该可以获得ie 浏览器的接口IWebBrowser2,但它是怎么做的呢?<BR><BR>一开始我的思路是:ie浏览器作为一个容器,它是否同时实现了IOleContainer和IWebBrowser2?试验发现不对...经过多方google,找到CSDN中shanhe的专栏<A href="http://blog.csdn.net/shanhe/category/15859.aspx?PageNumber=2">http://blog.csdn.net/shanhe/category/15859.aspx?PageNumber=2</A><BR>找到可行的代码如下:</P>
<P>IOleContainer* pContainer;<BR>HRESULT hr = m_pClientSite-&gt;GetContainer(&amp;pContainer);<BR>if (FAILED(hr))<BR>&nbsp;&nbsp;&nbsp; return hr;</P>
<P>IServiceProvider* pServiceProvider;<BR>hr = pContainer-&gt;QueryInterface(IID_IServiceProvider,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void**)&amp;pServiceProvider);<BR>pContainer-&gt;Release();<BR>if (FAILED(hr))<BR>&nbsp;&nbsp;&nbsp; return hr;</P>
<P>IWebBrowser2* pWebBrowser;<BR>hr = pServiceProvider-&gt;QueryService(SID_SWebBrowserApp,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IID_IWebBrowser2,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void**)&amp;pWebBrowser);<BR>pServiceProvider-&gt;Release();<BR>if (FAILED(hr))<BR>&nbsp;&nbsp;&nbsp; return hr;<BR><BR>可以获取了IWebBrowser2接口,但如何读取html元素的值呢?IWebBrowser2接口似乎没有这个功能?<BR><BR>又是千山万水的google:<BR>vckbase:<BR><A href="http://vckbase.net/document/viewdoc/?id=1446">http://vckbase.net/document/viewdoc/?id=1446</A><BR>codeguru:<BR><A href="http://www.codeguru.com/Cpp/COM-Tech/atl/misc/article.php/c3619/">http://www.codeguru.com/Cpp/COM-Tech/atl/misc/article.php/c3619/</A><A href="http://tech.163.com/05/0420/13/1HPMEUVJ00091589.html http://vckbase.net/document/viewdoc/?id=1446http://www.codeguru.com/Cpp/COM-Tech/atl/misc/article.php/c3619/"><BR></A></P><A href="/Raistlin/images/cnitblog_com/raistlin/iehtmlelement.jpg"></A>
<P><A href="/images/cnitblog_com/raistlin/iehtmlelement.jpg" target=_blank><IMG height=193 alt=iehtmlelement.jpg src="http://www.cnitblog.com/images/cnitblog_com/raistlin/iehtmlelement.jpg" width=400 border=0>&nbsp;</A><BR><BR><BR>msdn 2003 :<BR>MSHTML ReferenceHOWTO: Get the WebBrowser Object Model of an HTML Frame<BR>HOWTO: Retrieve the URL of a Web Page from an ActiveX Control</P>
<P>msdn关于MSHTML的参考也够烂，列出一堆接口方法就不管了。究竟结构如何要自己去研究。总之很是不爽。</P><img src ="http://www.cnitblog.com/Raistlin/aggbug/5924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2005-12-30 17:51 <a href="http://www.cnitblog.com/Raistlin/archive/2005/12/30/5924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于键盘输入和输入法的记录</title><link>http://www.cnitblog.com/Raistlin/archive/2005/12/19/5592.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Mon, 19 Dec 2005 07:10:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2005/12/19/5592.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/5592.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2005/12/19/5592.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/5592.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/5592.html</trackback:ping><description><![CDATA[<STRONG>关于光标的一些函数<BR></STRONG>BOOL CreateCaret(HWND hWnd,HBITMAP hBitmap,int nWidth,int nHeight);为窗口创建光标<BR>BOOL DestroyCaret();销毁光标<BR>UINT GetCaretBlinkTime();光标闪烁间隔时间<BR>BOOL GetCaretPos(LPPOINT lpPoint);光标在当前窗口的client位置<BR>BOOL HideCaret(HWND hWnd);隐藏<BR>BOOL SetCaretBlinkTime(UINT uMSeconds);光标闪烁间隔时间<BR>BOOL SetCaretPos(int X,int Y);位置<BR>BOOL ShowCaret(HWND hWnd);显示<BR><BR>CWnd::CreateCaret<BR>CWnd::CreateSolidCaret<BR>CWnd::CreateGrayCaret<BR>CWnd::GetCaretPos<BR>CWnd::SetCaretPos<BR>CWnd::HideCaret<BR>CWnd::ShowCaret<BR><BR><STRONG>为其它进程模拟输入字符：</STRONG><BR>摘自<A href="http://www.pcbookcn.com/article/1113.htm">http://www.pcbookcn.com/article/1113.htm</A><BR>　　首先要知道在Windows系统中与键盘按键相关的消息有：WM_KEYDOWN、WM_KEYUP、 WM_SYSKEYDOWN、WM_SYSKEYUP、WM_CHAR等。其中，WM_KEYDOWN为键按下，WM_KEYUP为键弹起，WM_SYSKEYDOWN为系统键按下，WM_SYSKEYUP为系统键弹起，WM_CHAR为按键对应的字符。<BR>　　要模拟键盘产生键盘消息，我们就发送一条键盘消息给指定窗口。比如要模拟一个字母键“A”，可以这样:PostMessage(hWnd, WM_CHAR, 'A', 0); 模拟按一个回车：PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0)。这里的关键问题是要确定窗口句柄（hWnd），使用GetFocus()函数可以得到键盘光标所在窗口句柄，但该函数只能得到当前进程内的窗口句柄。<BR>　　如果要得到其他应用程序的键盘光标所在窗口句柄，需要调用 AttachThreadInput()函数。该函数的作用就是将其他窗口线程的输入附加到本窗口线程的输入操作中，这样就可以调用GetFocus()函数得到其他窗口的句柄了。<BR><BR>AttachThreadInput()函数的原形如下: <BR>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">BOOL&nbsp;AttachThreadInput(&nbsp;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top>DWORD&nbsp;idAttach,&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;需要附加的线程ID&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">DWORD&nbsp;idAttachTo,&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;附加到的线程ID&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">BOOL&nbsp;fAttach&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;true&nbsp;附加&nbsp;false&nbsp;取消&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">);&nbsp;</SPAN></DIV>函数使用的过程大致如下: <BR>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">HWND&nbsp;hWnd;&nbsp;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top>hWnd&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;GetForegroundWindow();&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;得到当前窗口&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">&nbsp;(hWnd&nbsp;</SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000">&nbsp;Form1</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">Handle)&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;排除程序本身的窗口&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">DWORD&nbsp;FormThreadID&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;GetCurrentThreadId();&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;本程序的线程ID&nbsp;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;当前窗口的线程ID&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">DWORD&nbsp;CWndThreadID&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;GetWindowThreadProcessId(hWnd,&nbsp;NULL);&nbsp;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;附加输入线程&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">AttachThreadInput(CWndThreadID,&nbsp;FormThreadID,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">);&nbsp;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;得到当前键盘光标所在的窗口&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">hWnd&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;GetFocus();&nbsp;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;取消附加的输入线程&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">AttachThreadInput(CWndThreadID,&nbsp;FormThreadID,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">);&nbsp;<BR></SPAN></DIV>hWnd就是当前键盘光标所在的窗口句柄。另外，经过测试发现，在Windows2000系统下发送字符消息（WM_CHAR）时，如果字符是一个汉字，则该字符对应的虚拟键盘码高位不为0，这样得到的字符就不正确。解决办法是做一个“与”运算: ch &amp; 0xFF就可以了。 <BR><BR><BR><STRONG>输入法的切换:</STRONG><BR>WM_INPUTLANGCHANGE<BR>platform sdk=&gt;User Interface Servic=&gt;windowing=&gt;windows=&gt;window reference =&gt;Messages<BR><BR><STRONG>关于输入法:</STRONG><BR>platform sdk=&gt;Windows Base Services=&gt;International Features=&gt;Input Method Editor<BR><BR><BR><STRONG>自己处理键盘输入要做的事：<BR></STRONG>如果你要自己处理键盘和输入法的输入而不用Eidt或richedit等控件的话，至少需要做以下处理以下消息WM_IME_STARTCOMPOSITION;WM_IME_ENDCOMPOSITION;WM_IME_COMPOSITION;<BR>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">LRESULT&nbsp;CCaretStudyView::OnImeStartComposition(WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam)<BR><IMG id=Codehighlighter1_77_492_Open_Image onclick="this.style.display='none'; Codehighlighter1_77_492_Open_Text.style.display='none'; Codehighlighter1_77_492_Closed_Image.style.display='inline'; Codehighlighter1_77_492_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_77_492_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_77_492_Closed_Text.style.display='none'; Codehighlighter1_77_492_Open_Image.style.display='inline'; Codehighlighter1_77_492_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN id=Codehighlighter1_77_492_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.cnitblog.com/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_77_492_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HIMC&nbsp;hIMC&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;::ImmGetContext(m_hWnd);<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;COMPOSITIONFORM&nbsp;CompForm;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CompForm.dwStyle&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;CFS_POINT;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CompForm.ptCurrentPos.x&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">10</SPAN><SPAN style="COLOR: #000000">;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">用实际的值代替</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CompForm.ptCurrentPos.y&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">10</SPAN><SPAN style="COLOR: #000000">;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">用实际的值代替</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;::ImmSetCompositionWindow(hIMC,&nbsp;</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">CompForm);<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">DropCaret();可在此处隐藏光标，在OnImeEndComposition消息处理中再显示光标</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;::ImmReleaseContext(m_hWnd,&nbsp;hIMC);<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;::DefWindowProc(m_hWnd,&nbsp;WM_IME_STARTCOMPOSITION,&nbsp;wParam,&nbsp;lParam);<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top><BR><IMG id=Codehighlighter1_542_602_Open_Image onclick="this.style.display='none'; Codehighlighter1_542_602_Open_Text.style.display='none'; Codehighlighter1_542_602_Closed_Image.style.display='inline'; Codehighlighter1_542_602_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_542_602_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_542_602_Closed_Text.style.display='none'; Codehighlighter1_542_602_Open_Image.style.display='inline'; Codehighlighter1_542_602_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align=top>LRESULT&nbsp;CCaretStudyView::OnImeEndComposition()&nbsp;</SPAN><SPAN id=Codehighlighter1_542_602_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.cnitblog.com/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_542_602_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">ShowCaretAtCurrentPosition();</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;Default();<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/None.gif" align=top>LRESULT&nbsp;CCaretStudyView::OnImeComposition(WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam)<BR><IMG id=Codehighlighter1_677_1288_Open_Image onclick="this.style.display='none'; Codehighlighter1_677_1288_Open_Text.style.display='none'; Codehighlighter1_677_1288_Closed_Image.style.display='inline'; Codehighlighter1_677_1288_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_677_1288_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_677_1288_Closed_Text.style.display='none'; Codehighlighter1_677_1288_Open_Image.style.display='inline'; Codehighlighter1_677_1288_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN id=Codehighlighter1_677_1288_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.cnitblog.com/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_677_1288_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG id=Codehighlighter1_708_1267_Open_Image onclick="this.style.display='none'; Codehighlighter1_708_1267_Open_Text.style.display='none'; Codehighlighter1_708_1267_Closed_Image.style.display='inline'; Codehighlighter1_708_1267_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_708_1267_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_708_1267_Closed_Text.style.display='none'; Codehighlighter1_708_1267_Open_Image.style.display='inline'; Codehighlighter1_708_1267_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">&nbsp;(lParam&nbsp;</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">&nbsp;GCS_RESULTSTR)&nbsp;</SPAN><SPAN id=Codehighlighter1_708_1267_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.cnitblog.com/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_708_1267_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">get&nbsp;result&nbsp;text</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HIMC&nbsp;hIMC&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;::ImmGetContext(m_hWnd);<BR><IMG id=Codehighlighter1_781_1252_Open_Image onclick="this.style.display='none'; Codehighlighter1_781_1252_Open_Text.style.display='none'; Codehighlighter1_781_1252_Closed_Image.style.display='inline'; Codehighlighter1_781_1252_Closed_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_781_1252_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_781_1252_Closed_Text.style.display='none'; Codehighlighter1_781_1252_Open_Image.style.display='inline'; Codehighlighter1_781_1252_Open_Text.style.display='inline';" src="http://www.cnitblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">&nbsp;(hIMC)&nbsp;</SPAN><SPAN id=Codehighlighter1_781_1252_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.cnitblog.com/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_781_1252_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">const</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;maxLenInputIME&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">200</SPAN><SPAN style="COLOR: #000000">;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wchar_t&nbsp;wcs[maxLenInputIME];<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LONG&nbsp;bytes&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;::ImmGetCompositionStringW(hIMC,<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GCS_RESULTSTR,&nbsp;wcs,&nbsp;(maxLenInputIME</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">2</SPAN><SPAN style="COLOR: #000000">);<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000"><IMG src="http://www.cnitblog.com/images/dot.gif"><IMG src="http://www.cnitblog.com/images/dot.gif"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;Set&nbsp;new&nbsp;position&nbsp;after&nbsp;converted</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPoint&nbsp;pos&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;GetCurrentPos();<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;COMPOSITIONFORM&nbsp;CompForm;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CompForm.dwStyle&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;CFS_POINT;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CompForm.ptCurrentPos.x&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;pos.x;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CompForm.ptCurrentPos.y&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;pos.y;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;::ImmSetCompositionWindow(hIMC,&nbsp;</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">CompForm);<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;::ImmReleaseContext(m_hWnd,&nbsp;hIMC);<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;Default();<BR><IMG src="http://www.cnitblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>以上三个消息是不做处理也可以，只不过不会支持如微软拼音输入法的跟随功能。<BR><BR>并WM_IME_CHAR和WM_CHAR添加字符。在WM_KEYDOWN中处理特殊字符，如VK_BACK VK_DELTE<img src ="http://www.cnitblog.com/Raistlin/aggbug/5592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2005-12-19 15:10 <a href="http://www.cnitblog.com/Raistlin/archive/2005/12/19/5592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC程序使用chm帮助文件</title><link>http://www.cnitblog.com/Raistlin/archive/2005/12/19/5579.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Mon, 19 Dec 2005 01:30:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2005/12/19/5579.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/5579.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2005/12/19/5579.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/5579.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/5579.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; 最近在做一个安装程序。想要弄一个上下文相关帮助。<BR>&nbsp;&nbsp;&nbsp; 一开始想用vc6自带的上下文相关帮助。在建立工程的时候选择context-sensitive help即可。嗯，vc帮我创建了AfxDlg.rtf、setup.cnt、setup.hm、setup.hpj、setup.ph等文件，以为省事了，用word打开AfxDlg.rtf一看，完全不会编辑。看了《inside visual c++》里面的文章，还是一头雾水。<BR>&nbsp;&nbsp;&nbsp; winhelp这老掉牙的东西，在win98年代就被htmlhelp淘汰了，俺还用它干嘛？决定弃暗投明，使用html help workshop来做帮助。html help workshop是一款制作chm文件的工具，微软免费提供，到处有的下。使用起来也方便，比编辑rtf格式要方便多得多，基本方法是把制作好的网页往里面塞，不浪费口舌了。 
<DIV><BR>&nbsp;&nbsp;&nbsp; 用html help workshop制作chm是方便，关键是怎么让它可以"上下文相关"。程序里调用chm帮组文件的api是<BR>&nbsp;&nbsp;&nbsp; HWND HtmlHelp(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD dwData);&nbsp;<BR>&nbsp;&nbsp;&nbsp; 更改App类的WinHelp()方法如下：<BR>&nbsp;void CSetupApp::WinHelp(DWORD dwData, UINT nCmd) <BR>&nbsp;{<BR>&nbsp; ::HtmlHelp(NULL, "E:\\workshop\\setup\\hlp\\chmtest.chm", HH_HELP_CONTEXT, dwData);<BR>&nbsp;}<BR>&nbsp;&nbsp;&nbsp; 具体文件在哪需要具体分析。这里要说的是这个dwData可是很有来头的，设个断点就可以看个清楚了：<BR>&nbsp;ID_HELP命令的消息路径是：<BR>&nbsp;CWnd::OnWndMsg()<BR>&nbsp;CDialog::OnCommandHelp()</DIV>
<DIV>&nbsp;LRESULT CDialog::OnCommandHelp(WPARAM, LPARAM lParam)<BR>&nbsp;{<BR>&nbsp; if (lParam == 0 &amp;&amp; m_nIDHelp != 0)<BR>&nbsp;&nbsp; lParam = HID_BASE_RESOURCE + m_nIDHelp;//m_nIDHelp就是你的对话框的id哦<BR>&nbsp; if (lParam != 0)<BR>&nbsp; {<BR>&nbsp;&nbsp; CWinApp* pApp = AfxGetApp();<BR>&nbsp;&nbsp; if (pApp != NULL)<BR>&nbsp;&nbsp;&nbsp; pApp-&gt;WinHelp(lParam);//</DIV>
<DIV>&nbsp;&nbsp; return TRUE;<BR>&nbsp; }<BR>&nbsp; return FALSE;<BR>&nbsp;}</DIV>
<DIV>&nbsp;</DIV>
<DIV>如何写CHM:<BR>&nbsp;&nbsp;&nbsp; 现在要做的就是把dwData和想要显示的东西关联起来。</DIV>
<DIV>&nbsp;具体方法是：<BR>&nbsp;1、使用记事本建立一个文本文件，文件名为Map.h。在该文件中输入下面的内容： <BR>&nbsp;#define TOPIC1 100 <BR>&nbsp;#define TOPIC2 200 <BR>&nbsp;这里TOPIC1、TOPIC2是一些常量，100、200是你在API调用时指定的ContextID。 <BR>&nbsp;2、在HTMLHelp Workshop中选择Project标签，点击HtmlHelp API information按钮，在对话框的Map标签中选择Header File按钮，然后选择你前面建立的Map.h文件。 <BR>&nbsp;3、还是在HtmlHelp API information对话框中选择Alias标签，点击Add按钮，在对话框中的Whenever This Constant or number is passed to the HTMLHelp API下输入常量，如TOPIC1。 <BR>&nbsp;4、在Use it to Refer to This HTML File中选择HTML文件，如Topic1.html。 <BR>&nbsp;5、重复3、4两步指定所有文件。 <BR>&nbsp;6、编译文件就可以了。 <BR>&nbsp;（转自<A href="http://www.china-askpro.com/msg44/qa78.shtml">http://www.china-askpro.com/msg44/qa78.shtml</A>）<BR>&nbsp;具体的ContextID不是100，200啊，是HID_BASE_RESOURCE+对话框ID。<BR>&nbsp;查找一下发现：#define HID_BASE_RESOURCE 0x00020000UL ，如果你的对话框ID值是0x0102那就该<BR>&nbsp;#define MYDLGID 0x20102了。</DIV>
<DIV>注：// Help ID bases（afxpriv.h）<BR>#define HID_BASE_COMMAND&nbsp;&nbsp;&nbsp; 0x00010000UL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ID and IDM <BR>#define HID_BASE_RESOURCE&nbsp;&nbsp; 0x00020000UL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // IDR and IDD<BR>#define HID_BASE_PROMPT&nbsp;&nbsp;&nbsp;&nbsp; 0x00030000UL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // IDP<BR>#define HID_BASE_NCAREAS&nbsp;&nbsp;&nbsp; 0x00040000UL<BR>#define HID_BASE_CONTROL&nbsp;&nbsp;&nbsp; 0x00050000UL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // IDC<BR>#define HID_BASE_DISPATCH&nbsp;&nbsp; 0x00060000UL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // IDispatch help codes</DIV>
<DIV>&nbsp;</DIV>
<DIV>如何调用HtmlHelp:<BR>&nbsp;&nbsp;&nbsp;微软在提供html help workshop的时候提供了调用方法，就是在html help workshop的安装目录下提供了个头文件和静态库，这个库的作用是装载hhctrl.ocx(system32目录下)，调用其中真正的htmlhelp方法。具体见：<BR>&nbsp;<A href="http://www.yesky.com/SoftChannel/72342376173010944/20010409/165483.shtml"><FONT color=#003399>http://www.yesky.com/SoftChannel/72342376173010944/20010409/165483.shtml</FONT></A></DIV><img src ="http://www.cnitblog.com/Raistlin/aggbug/5579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2005-12-19 09:30 <a href="http://www.cnitblog.com/Raistlin/archive/2005/12/19/5579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>你也许还没用过的vc++的调试的功能</title><link>http://www.cnitblog.com/Raistlin/archive/2005/12/14/5380.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Wed, 14 Dec 2005 08:41:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2005/12/14/5380.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/5380.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2005/12/14/5380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/5380.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/5380.html</trackback:ping><description><![CDATA[<P>刚刚在IT博客网闲逛的时候看到了<A href="/wangk/">孤独的夜</A>的一片文章《<A href="/wangk/archive/2005/12/14/5369.html">如何调试MFC中的内存泄漏</A>》，讲道用设置{,,msvcrtd.dll}_crtBreakAlloc<FONT style="BACKGROUND-COLOR: #ffffff"><STRONG>这个变量</STRONG></FONT>来调试内存泄露的问题。<BR><BR>在<A href="http://support.microsoft.com/kb/q151585/">How to use _crtBreakAlloc to debug a memory allocation</A>你可以找到英文的更完整的版本，静态链接和动态连接到C运行库的名称是不一样的<BR>静态:_crtBreakAlloc<BR>动态:{,,msvcr40d.dll}*__p__crtBreakAlloc()&nbsp; (vc++4.0 和4.1版本，估计没人在用吧)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{,,msvcrtd.dll}*__p__crtBreakAlloc()&nbsp; (Visual C++ 4.2 or later)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{,,msvcrtd.dll}_crtBreakAlloc (好像这样也是可以的)<BR><BR><BR>{,,msvcrtd.dll}__p__crtBreakAlloc()是个什么东西呢？<BR><BR>查看msdn索引“Advanced Breakpoint”and you will find out...<BR><BR>语法如下：<BR>{[function],[source],[exe] } location<BR>{[function],[source],[exe] } variable_name<BR>{[function],[source],[exe] } expression</P><img src ="http://www.cnitblog.com/Raistlin/aggbug/5380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2005-12-14 16:41 <a href="http://www.cnitblog.com/Raistlin/archive/2005/12/14/5380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于cout在winows上的实现的讨论?</title><link>http://www.cnitblog.com/Raistlin/archive/2005/11/14/4469.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Mon, 14 Nov 2005 09:16:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2005/11/14/4469.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/4469.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2005/11/14/4469.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/4469.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/4469.html</trackback:ping><description><![CDATA[<P>看了一篇关于C++中标准输出cout的文章，因为最近正搞一个console程序，对于cout如何被实现产生了兴趣。</P>
<P>我能找到的关于cout的内容就只是一个声明： <BR>extern _CRTIMP ostream cout; </P>
<P>具体这个cout是怎么被定义的一无所知，可能不同平台有不同的定义<BR></P>
<P>在vc++6.0实验如下<BR>#include &lt;fstream&gt; <BR>int main(int argc, char* argv[]) <BR>{&nbsp;<BR>&nbsp;&nbsp;&nbsp;std::filebuf myfile(&amp;_iob[1]);&nbsp;<BR>&nbsp;&nbsp;&nbsp;std::ostream mycout(&amp;myfile);&nbsp;<BR>&nbsp;&nbsp;&nbsp;mycout&lt;&lt;"test.";&nbsp;<BR>&nbsp;&nbsp;&nbsp;return 0; <BR>} <BR>效果和cout&lt;&lt;"test."完全相同。<BR><BR>cout其实就是输出到标准输出。而标准输出是可以被重定向的，标准输出被重定向后，cout将输出到被重定向后的目标。</P>
<P>vc++6.0中_iob的声明为<BR>_CRTIMP extern FILE _iob[];<BR>_iob[0]为标准输入，_iob[1]为标准输出，_iob[2]为标准错误输出<BR>用VC的debug观察得出_iob的值是固定的。<BR>_iob[0]._file==0<BR>_iob[1]._file==1<BR>_iob[2]._file==2</P>
<P>调用windows API也可以写到标准输出:<BR>DWORD dwByteWrited=0;<BR>WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"Test StdHandle",13,&amp;dwByteWrited,NULL);<BR><BR>如果标准输出没有被重定向GetStdHandle返回的值似乎固定为7。<BR>标准输出被重定向后GetStdHandle返回的值是其它的不固定值。</P>
<P>这好像涉及到语言在具体平台上的实现了...unix的cout和windows的cout的内部实现应该是不同的...没用过unix，猜测而已</P><img src ="http://www.cnitblog.com/Raistlin/aggbug/4469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2005-11-14 17:16 <a href="http://www.cnitblog.com/Raistlin/archive/2005/11/14/4469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NT下判断用户是否有管理员权限</title><link>http://www.cnitblog.com/Raistlin/archive/2005/07/25/1122.html</link><dc:creator>Raistlin</dc:creator><author>Raistlin</author><pubDate>Mon, 25 Jul 2005 01:11:00 GMT</pubDate><guid>http://www.cnitblog.com/Raistlin/archive/2005/07/25/1122.html</guid><wfw:comment>http://www.cnitblog.com/Raistlin/comments/1122.html</wfw:comment><comments>http://www.cnitblog.com/Raistlin/archive/2005/07/25/1122.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/Raistlin/comments/commentRss/1122.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/Raistlin/services/trackbacks/1122.html</trackback:ping><description><![CDATA[<P>用VC来操纵NT权限的东西真是头大...只想实现判断用户是否为管理员，被RID(relative identifier )搞死了，从头到尾我都没明白它是怎么回事。MSDN含糊其词，网上找的东西不是太高深，就是太表面，要不是黑客大侠们写的用来超越管理员权限的代码，就是大学课堂里面表面的解释。看得头晕脑涨，呜乎哀哉。<BR>一开始只会用LookupAccountName获得用户的SID，GetSidIdentifierAuthority获得SID_IDENTIFIER_AUTHORITY值，再和SECURITY_NT_AUTHORITY比较，相同则认为具备管理员权限，不同则不具备，代码写得战战兢兢。后来去csdn求助，完善代码如下，希望不至于出大乱子..</P>
<DIV style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
<DIV><SPAN style="COLOR: #000000">BOOL&nbsp;CRSysInfo::IsUserAdminPrivilege(</SPAN><SPAN style="COLOR: #0000ff">const</SPAN><SPAN style="COLOR: #000000">&nbsp;CString&nbsp;</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">&nbsp;strUserName,BOOL&nbsp;</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">&nbsp;bAdminPrivilege)<BR>{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bAdminPrivilege&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;FALSE;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PSIDpSid&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;NULL;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORDcbSid&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPTSTRbufDomain&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;NULL;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORDcbDomain&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SID_NAME_USEtype;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LookupAccountName(NULL,strUserName,pSid,</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">cbSid,bufDomain,</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">cbDomain,</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">type);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(cbSid)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pSid&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">[cbSid];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bufDomain&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;TCHAR[cbDomain];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(LookupAccountName(NULL,strUserName,pSid,</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">cbSid,bufDomain,</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">cbDomain,</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">type))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PSID_IDENTIFIER_AUTHORITY&nbsp;pAutho&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;GetSidIdentifierAuthority(pSid);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwErr&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;GetLastError();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">!</SPAN><SPAN style="COLOR: #000000">dwErr)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SID_IDENTIFIER_AUTHORITY&nbsp;AdminAuth&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;SECURITY_NT_AUTHORITY;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bAdminPrivilege&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">!</SPAN><SPAN style="COLOR: #000000">memcmp(pAutho,</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">AdminAuth,</SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(SID_IDENTIFIER_AUTHORITY));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete[]pSid;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete[]bufDomain;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(bAdminPrivilege)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;returnTRUE;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;rc;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USER_INFO_1&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">info;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rc&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;NetUserGetInfo(NULL,_bstr_t(strUserName),</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">,(</SPAN><SPAN style="COLOR: #0000ff">byte</SPAN><SPAN style="COLOR: #000000">**</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">info);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(rc&nbsp;</SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000">&nbsp;NERR_Success)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bAdminPrivilege&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;info</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">usri1_priv&nbsp;</SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000">&nbsp;USER_PRIV_ADMIN;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NetApiBufferFree(info);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;returnrc&nbsp;</SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000">&nbsp;NERR_Success;<BR>}<BR></SPAN></DIV></DIV><img src ="http://www.cnitblog.com/Raistlin/aggbug/1122.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/Raistlin/" target="_blank">Raistlin</a> 2005-07-25 09:11 <a href="http://www.cnitblog.com/Raistlin/archive/2005/07/25/1122.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>