﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-行百里者半九十-随笔分类-编码点滴</title><link>http://www.cppblog.com/gracelee/category/4816.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 13 May 2009 15:16:21 GMT</lastBuildDate><pubDate>Wed, 13 May 2009 15:16:21 GMT</pubDate><ttl>60</ttl><item><title>用C实现的一个基本COM接口IFoo（来自COM Programmer's Cookbook）——C实现COM接口系列2</title><link>http://www.cppblog.com/gracelee/archive/2009/05/11/82582.html</link><dc:creator>小葱蘸酱</dc:creator><author>小葱蘸酱</author><pubDate>Mon, 11 May 2009 08:28:00 GMT</pubDate><guid>http://www.cppblog.com/gracelee/archive/2009/05/11/82582.html</guid><wfw:comment>http://www.cppblog.com/gracelee/comments/82582.html</wfw:comment><comments>http://www.cppblog.com/gracelee/archive/2009/05/11/82582.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gracelee/comments/commentRss/82582.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gracelee/services/trackbacks/82582.html</trackback:ping><description><![CDATA[<p>在<a href="http://www.cppblog.com/gracelee/archive/2009/04/29/81414.html">C实现COM接口系列1</a>中实现的com接口IFoo与使用它的客户耦合在一起，没有实现在各自分离的模块，因此不符合模块化编程思想。本期添加类厂支持，以使接口的实现与接口的使用相分离。</p>
<p>---------------------------------------------------<br>类厂的作用到底是什么？<br>将接口的实现与客户使用分离开来吗？</p>
<p>不尽然。使用CoCreateInstance，客户可以完全不必知道类厂的存在，而创建组件，获取组件实现的接口并使用。</p>
<p>即COM库可以完全抛开类厂的概念，而是提供一个这样的函数原型：<br>CoCreateObject(REFID rclsid,...,REFID riid,void **ppItf);<br>用户在调用的时候可以对riid提供IID_Unknown或者特定于该对象的一个接口，直接获取该对象的IUnknown或特定的接口指针。</p>
<p>可以看到，这正是CoCreateInstance所作的事情。</p>
<p>1 类厂提供了间接创建类对象的方式：用户可以先获取并持有类厂接口指针，通过该指针所指向的类厂接口创建类对象。适用于需要创建多个（或重复创建）类对象的地方，减少了每次都要定位对象库并把对象库装入内存的开销。<br>2 类厂提供了保证组件库留在内存不被卸载出去的另一种方法：类厂接口函数LockServer。组件库维护一个库范围计数器，只有该计数器为0时，组件库才允许自己被卸载出内存。（与此相对，引用计数是类对象范围的，通过该类实现的各个接口来维护。如果一个类对象的引用计数达到0，那么该对象占有的内存就被释放，该对象上的接口指针也不再有效。）<br>除了调用LockServer锁定组件库以外，当创建的组件个数大于0时，组件库也不能被卸载。也可以说，调用一次LockServer()的作用相当于创建了一个组件。</p>
<p>-----------------------------------------------------------------------<br>客户一侧：<br>1 使用一个接口需要知道哪些信息？<br>备选：<br>接口IID<br>类对象（类厂）CLSID（或ProgID）<br>接口函数原型（参数个数，类型，返回值）<br>实现接口组件的线程模型（进程内、进程外、远程）？<br>类型库typelib信息？</p>
<p>服务一侧：<br>2 实现一个组件和接口以供客户调用，需要提供哪些东西？<br>备选：<br>所有客户使用组件和接口所需的内容<br>额外的还有：</p>
<p><br>--------------------------------------------------------------------<br>为dll添加.def文件与直接在需要导出的函数定义处指定_declspec( dllexport )有区别吗？如果有是什么区别？</p>
<p>我发现在outdll.c中这样指定：<br>__declspec( dllexport ) HRESULT DllGetClassObject (REFCLSID rclsid, REFIID riid, void **ppv)<br>会产生编译错误：<br>1&gt;------ Build started: Project: outside, Configuration: Debug Win32 ------<br>1&gt;Compiling...<br>1&gt;outdll.c<br>1&gt;d:\outside-cf\outside\outdll.c(19) : error C2375: 'DllGetClassObject' : redefinition; different linkage<br>1&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c:\program files\microsoft visual studio 8\vc\platformsdk\include\objbase.h(833) : see declaration of 'DllGetClassObject'<br>1&gt;Build log was saved at "<a href="file:///d:/outside-cf/outside/Debug/BuildLog.htm">file://d:\outside-cf\outside\Debug\BuildLog.htm</a>"<br>1&gt;outside - 1 error(s), 0 warning(s)<br>========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========</p>
<p>c2375的解释意思是出错的函数使用的链接指示符与之前声明的不同。<br>Compiler Error C2375<br>'function' : redefinition; different linkage</p>
<p>The function is already declared with a different linkage specifier.</p>
<p>objbase.h中声明了DllGetClassObject()函数：<br>STDAPI&nbsp; DllGetClassObject(IN REFCLSID rclsid, IN REFIID riid, OUT LPVOID FAR* ppv);</p>
<p>而使用.def文件就没有问题。</p>
<p>-----------------------------------------------------------------------------<br>初次执行结果：</p>
<p>问题就是总有一个分配的内存没有释放：</p>
<p><img style="WIDTH: 655px; HEIGHT: 437px" height=437 src="http://www.cppblog.com/images/cppblog_com/gracelee/10441/o_outside-cf-mleak.JPG" width=655 border=0></p>
<p>&nbsp;</p>
<p><br>根据打印出来的内存地址可以判断，应该是先创建的类厂对象的内存没有释放。<br>检查代码，main()中并没有忘记调用Release(pCF)释放类厂对象。打印Release(pCF)的返回值，发现是1，即在类厂接口指针上少调用了一次Release，那么，究竟是哪里少的呢？</p>
<p>main()函数中有关类厂对象引用计数的地方就是CoGetClassObject和Release（CreateInstance跟类厂自己的引用计数无关），这是一对增加引用计数和减少引用计数的对应操作，所以,main()中应该没有问题。</p>
<p>那么，就只有创建类厂对象的时候了。下面看一下类厂对象是如何创建的。<br>首先，main调用CoGetClassObject，该函数就调用dll中的DllGetClassObject。由于是第一次调用（不考虑其他客户使用该dll的情况），程序执行到CreateClassFactory(...),该函数执行完后，类厂对象的引用计数是1。</p>
<p>由于创建成功，因此继续向下执行到QueryInterface,此时，类厂对象的引用计数变成了2。然后，DllGetClassObject返回，com库函数CoGetClassObject也应该返回。注意，此时的类厂对象引用计数已经是2了！</p>
<p>因此，问题就出在这里。main调用一次CoGetClassObject后，类厂对象的引用计数是2，而不是我想向中的1。于是，后面调用一次Release也就当然无法释放掉类场对象了。</p>
<p>&nbsp;</p>
<p>&nbsp;</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: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">HRESULT&nbsp;DllGetClassObject&nbsp;(REFCLSID&nbsp;rclsid,&nbsp;REFIID&nbsp;riid,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">ppv)<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ppv&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(IsEqualCLSID&nbsp;(rclsid,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">CLSID_Outside))<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">vpcfOutside)<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateClassFactory&nbsp;(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">CLSID_Outside,&nbsp;CreateOutside,<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">IID_IClassFactory,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">vpcfOutside);<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&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">&nbsp;(hr&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;NOERROR)<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;hr;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;QueryInterface&nbsp;(vpcfOutside,&nbsp;riid,&nbsp;ppv);<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;E_FAIL;<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br>找到了原因，改正就很容易了。这里我觉得需要把DllGetClassObject作如下修改：<br></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: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">HRESULT&nbsp;DllGetClassObject&nbsp;(REFCLSID&nbsp;rclsid,&nbsp;REFIID&nbsp;riid,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">ppv)<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ppv&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(IsEqualCLSID&nbsp;(rclsid,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">CLSID_Outside))<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">vpcfOutside)<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateClassFactory&nbsp;(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">CLSID_Outside,&nbsp;CreateOutside,<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">IID_IClassFactory,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">vpcfOutside);<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&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">&nbsp;(hr&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;NOERROR)<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;hr;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(IsEqualIID(riid,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">IID_IClassFactory))<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ppv&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;vpcfOutside;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Set&nbsp;*ppv&nbsp;to&nbsp;vpcfOutside&nbsp;directly&nbsp;instead&nbsp;of&nbsp;QueryInterface&nbsp;if&nbsp;first&nbsp;time&nbsp;creation</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;NOERROR;<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Release(vpcfOutside);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Any&nbsp;interface&nbsp;requested&nbsp;(riid)&nbsp;other&nbsp;than&nbsp;IID_ClassFactory&nbsp;and&nbsp;IID_Unknown&nbsp;not&nbsp;support&nbsp;by&nbsp;class&nbsp;factory,<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;call&nbsp;Release&nbsp;to&nbsp;free&nbsp;the&nbsp;memory.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;E_FAIL;<br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;QueryInterface&nbsp;(vpcfOutside,&nbsp;riid,&nbsp;ppv);<br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;E_FAIL;<br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>&nbsp;</p>
<p>修改后在执行，内存都正常释放了。</p>
<p><img src="http://www.cppblog.com/images/cppblog_com/gracelee/10441/r_outside-cf-mleak-solve.JPG" border=0></p>
<p>-------------------------------------------------------------------------------------------<br>CreateClassFactory代码说明<br></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: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">HRESULT&nbsp;CreateClassFactory&nbsp;(REFCLSID&nbsp;rclsid,<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pfnCreate)(IUnknown&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">,&nbsp;REFIID,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">),&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;REFIID&nbsp;riid,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">ppv)<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;ClassFactory&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;hr;<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ppv&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Alloc&nbsp;(</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">&nbsp;(ClassFactory),&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">))<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;hr;<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">icf.lpVtbl&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">vtblClassFactory;<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">cRef&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;After&nbsp;this&nbsp;call,&nbsp;cRef==1</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">pfnCreate&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pfnCreate;<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;QueryInterface&nbsp;(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">icf,&nbsp;riid,&nbsp;ppv);&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;After&nbsp;this&nbsp;call,&nbsp;cRef==2</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Release&nbsp;(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">icf);&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Corresponds&nbsp;to&nbsp;"this-&gt;cRef&nbsp;=&nbsp;1",&nbsp;ater&nbsp;this&nbsp;call,&nbsp;cRef==1</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;hr;<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>&nbsp;</p>
<p>可以看到，两行代码的效果是对引用计数增1及减1，这两行代码执行后，对引用计数的影响互相抵消，等于没有改变引用计数。那么，把这两行同时注释掉，是不是可以呢？<br>我的回答是：在本例中可以。因为这两行代码之间的QueryInterface总是可以执行成功的（因为是用IDD_ClassFactory来调用该函数的）。所以，即便把这两行代码同时注释掉，CreateClassFactory执行结束后，类厂对象的引用计数也增了1，以后调用Release就可以释放掉类厂对象占用的内存。<br>但是，如果CFQueryInterface的代码编写中除了错误，比如，像这样写：<br></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: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;HRESULT&nbsp;CFQueryInterface&nbsp;(IClassFactory&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pcf,&nbsp;REFIID&nbsp;riid,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">ppv)<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;ClassFactory&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;IMPL&nbsp;(ClassFactory,&nbsp;icf,&nbsp;pcf);<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(IsEqualIID&nbsp;(riid,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">IID_IUnknown)&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsEqualIID&nbsp;(riid,&nbsp;&amp;IID_IClassFactory))&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Comment&nbsp;out&nbsp;this&nbsp;condition&nbsp;to&nbsp;create&nbsp;an&nbsp;error</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ppv&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">icf;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ppv&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;E_NOINTERFACE;<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;AddRef&nbsp;((IClassFactory&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ppv);<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;NOERROR;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p><br>那么，这两行代码之间的QueryInterface就会执行出错，那么类厂对象占用的内存就永远没有机会释放了。<br>也就是说，AddRef和Release虽然在作用上对引用计数来说相互抵消，但Release函数提供了释放对象内存的机会（当引用计数为0时），如果不成对的调用他们，也就失去了管理对象内存（释放对象占用的内存）的机会。</p>
<p>---------------------------------------------------------------------------<br>组件库outside文件说明：<br>&nbsp;IFoo.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IFoo接口声明<br>&nbsp;outside.c&nbsp;&nbsp; 组件对象、IFoo接口实现<br>&nbsp;cf.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类厂对象、IClassFactory接口实现<br>&nbsp;outdll.c&nbsp;&nbsp;&nbsp; 组件库导出函数实现<br>&nbsp;outside.def 组件库模块定义文件，导出函数声明<br>&nbsp;outside.reg 组件库注册文件</p>
----------------------------------------------------------------------------<br>源码： <a title=outside-cf href="http://www.cppblog.com/Files/gracelee/outside-cf.zip">outside-cf</a>
<img src ="http://www.cppblog.com/gracelee/aggbug/82582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gracelee/" target="_blank">小葱蘸酱</a> 2009-05-11 16:28 <a href="http://www.cppblog.com/gracelee/archive/2009/05/11/82582.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C实现的一个基本COM接口IFoo（来自COM Programmer's Cookbook）——C实现COM接口系列1</title><link>http://www.cppblog.com/gracelee/archive/2009/04/29/81414.html</link><dc:creator>小葱蘸酱</dc:creator><author>小葱蘸酱</author><pubDate>Wed, 29 Apr 2009 04:08:00 GMT</pubDate><guid>http://www.cppblog.com/gracelee/archive/2009/04/29/81414.html</guid><wfw:comment>http://www.cppblog.com/gracelee/comments/81414.html</wfw:comment><comments>http://www.cppblog.com/gracelee/archive/2009/04/29/81414.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/gracelee/comments/commentRss/81414.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gracelee/services/trackbacks/81414.html</trackback:ping><description><![CDATA[<p>用C实现的一个基本COM接口IFoo（来自COM Programmer's Cookbook）</p>
<p><br>把该文中实现的代码整理汇总到一个项目中。目前只是实现到一个中间阶段，重点在说明COM接口的实现原理，还没有包含类厂的部分。以后还需陆续添加类厂等高级功能。</p>
<p>文件组成：<br>ifoo.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COM接口IFoo,接口ID IID_IFoo 声明文件。<br>outside.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COM接口实现。这里实现IFoo的是一个结构体COutside.<br>util.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一些宏定义、全局函数、变量声明文件。<br>main.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 笔者为实现项目添加的文件。提供main函数、内存管理函数Alloc,Free的实现（封装C运行库函数malloc和free.）、接口ID定义。</p>
<p>COM接口到底是什么？<br>COM接口是一个指向虚函数表的指针。通过这个指针可以访问内存中某处的各个功能块，执行预定义的功能，完成用户的任务。这些功能块以函数的形式存在（想不出还有其他形式:)）并被调用。它们有一个共同点：都包含一个指针参数，指向这些功能要操作的数据地址。在C++中，这个地址就是对象的首地址，也就是类成员函数中隐含的this指针。在C函数中并没有这种现成的便利，因此代码实现中在接口定义时仍使用了接口指针（HRESULT (__stdcall * QueryInterface)&nbsp;&nbsp; (IFoo * This,&nbsp; const IID * const, void **)），而在接口函数实现时根据结构体布局结构，从这个接口指针推算得到对象实例指针。</p>
<p>typedef struct IFoo <br>{<br>&nbsp;struct IFooVtbl * lpVtbl;<br>} IFoo;<br>typedef struct IFooVtbl IFooVtbl;<br>struct IFooVtbl<br>{<br>&nbsp;<br>&nbsp;HRESULT (__stdcall * QueryInterface)&nbsp;&nbsp; (IFoo * This,&nbsp; const IID * const, void **) ;<br>&nbsp;ULONG (__stdcall * AddRef)&nbsp;&nbsp;&nbsp; (IFoo * This) ;<br>&nbsp;ULONG (__stdcall * Release)&nbsp;&nbsp; (IFoo * This) ;</p>
<p>&nbsp;HRESULT (__stdcall * SetValue)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (IFoo * This,&nbsp; int) ;<br>&nbsp;HRESULT (__stdcall * GetValue)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (IFoo * This,&nbsp; int *) ;<br>};</p>
<p>COM接口的要求：</p>
<p>每一个COM接口（指向的虚函数表）的头三个函数必须是IUnknown接口的函数：QueryInterface,AddRef和Release。在C++中，称为从IUnknown接口继承。<br>对于调用QueryInterface响应查询IID_IUnknwon得到的接口指针值，同一个对象实现的所有接口必须相同。这是判断两个COM对象是否是同一个对象的标准。</p>
<p>&nbsp;</p>
<p>宏定义&#8220;#define IUNK_VTABLE_OF(x) ((IUnknownVtbl *)((x)-&gt;lpVtbl))&#8220;说明</p>
<p>在预处理输出文件main.i中可以找到IUnknownVtbl和IFooVtbl的声明：<br>&nbsp;&nbsp;&nbsp; typedef struct IUnknownVtbl<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HRESULT ( __stdcall *QueryInterface )( <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IUnknown * This,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const IID * const riid,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void **ppvObject);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG ( __stdcall *AddRef )( <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IUnknown * This);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG ( __stdcall *Release )( <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IUnknown * This);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; } IUnknownVtbl;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; struct IUnknown<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct IUnknownVtbl *lpVtbl;<br>&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; </p>
<p>struct IFooVtbl<br>{<br>&nbsp;<br>&nbsp;HRESULT (__stdcall * QueryInterface)&nbsp;&nbsp; (IFoo * This,&nbsp; const IID * const, void **) ;<br>&nbsp;ULONG (__stdcall * AddRef)&nbsp;&nbsp;&nbsp; (IFoo * This) ;<br>&nbsp;ULONG (__stdcall * Release)&nbsp;&nbsp; (IFoo * This) ;</p>
<p>&nbsp;HRESULT (__stdcall * SetValue)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (IFoo * This,&nbsp; int) ;<br>&nbsp;HRESULT (__stdcall * GetValue)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (IFoo * This,&nbsp; int *) ;<br>};</p>
<p>该宏定义的作用就是把IFoo接口中的IFooVtbl类型的指针拿出来（(x)-&gt;lpVtbl)），并强制转换（(IUnknownVtbl *)）成IUnknownVtbl。<br>&#8220;强制转换&#8221;的结果是什么呢？是怎么做到的呢？<br>很明显，结果就是得到的指针不再是IFooVtbl *类型，而是变成了IUnknownVtbl *类型。至于做法，系统应该记录每一个变量、表达式的类型。当进行强制类型转换时，就（临时地）修改其类型为转换到的类型。<br>同理，QueryInterface, AddRef, Release宏定义中的(IUnknown *)也是这种用法。</p>
<p>可以看到，宏&#8220;IUNK_VTABLE_OF&#8220;的作用是供宏QueryInterface,宏AddRef，宏Release引用，把IFooVtbl *类型转换为IUnknownVtbl *类型，最终达到调用IUnknownVtbl中定义的三个QueryInterface,AddRef,Release函数。</p>
<p>那么，这种大费周章的目的是什么呢？为什么不以IFooVtbl中三个函数的定义形式（不通过强制转换来转换成必须的类型），直接调用IFooVtbl中定义的函数呢？虽然强制转换在参数值上并不会造成改变，最终调用的也是IFooVtbl定义的函数（FooQueryInterface,FooAddRef,FooRelease）。</p>
<p>为什么一定要通过IUnknown接口指针调用这三个函数呢？修改QueryInterface宏定义如下：<br>#define QueryInterface(pif, iid, pintf) \<br>&nbsp;(((pif)-&gt;lpVtbl)-&gt;QueryInterface(pif, iid, (void **)(pintf)))<br>即通过IFoo接口指针来调用由IUnknown引入的函数，有什么不对的地方吗？</p>
<p>试验表明，将QueryInterface宏定义如下也可以编译通过，执行起来也没有出现任何异常。<br>#define QueryInterface(pif, iid, pintf) \<br>&nbsp;(((pif)-&gt;lpVtbl)-&gt;QueryInterface(pif, iid, (void **)(pintf)))</p>
<p>&nbsp;</p>
<p>对于IUnknown接口的三个函数，调用时传递的参数是IUnknown *类型（见QueryInterface, AddRef, Release宏定义），而函数定义中（FooQueryInterface, FooAddRef, FooRelease）声明的参数是IFoo *类型，这种不一致的情况是怎么出现的？这种不一致不会有问题吗？</p>
<p>这种不一致的产生是由于从不同的角度看待引起的。如果从IUnknown接口来看，那么接口函数中的第一个参数类型就是IUnknown *;如果从IFoo来看，那么第一个参数的类型就是IFoo *。</p>
<p>这种不一致性只是针对于编译器对于类型的编译要求有意义的，在接口实现及使用时，传递给lpVtbl-&gt;QueryInterface, lpVtbl-&gt;AddRef,lpVtbl-&gt;Release的第一个参数在值上都是相同的，都是实现该接口的内存地址（在本例中是COutside对象的首地址）。</p>
<p>&nbsp;</p>
<p>一些语法现象回顾</p>
<p>函数指针变量定义、赋值及调用。<br>HRESULT (__stdcall * pQI)&nbsp;&nbsp; (IFoo * This,&nbsp; const IID * const, void **) ;<br>定义一个函数指针变量pQI,该变量指向&#8220;返回HRESULT,取3个参数分别为类型IFoo *,const IID * const, void **&#8221;的函数。</p>
<p>typedef HRESULT (__stdcall * QIType)&nbsp;&nbsp; (IFoo * This,&nbsp; const IID * const, void **) ;<br>定义一个函数指针类型，该类型的指针指向&#8220;返回HRESULT,取3个参数分别为类型IFoo *,const IID * const, void **&#8221;的函数。</p>
<p>HRESULT __stdcall QueryInterface(IFoo * This,&nbsp; const IID * const, void **) ;//函数声明示例<br>pQI = 0;&nbsp;&nbsp; // 函数指针赋值，0表示不指向任何函数。<br>pQI = QueryInterface;&nbsp; // 函数指针赋值，pQI指向QueryInterface。<br>pQI = &amp;QueryInterface; // 与上面等价。</p>
<p>QueryInterface(&amp;this-&gt;ifoo, riid, ppv);&nbsp; // 使用函数名直接调用<br>pQI(&amp;this-&gt;ifoo, riid, ppv);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 函数指针调用<br>(*pQI)(&amp;this-&gt;ifoo, riid, ppv);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 第二种函数指针调用方式</p>
<p><br>宏定义、展开规则<br>对于宏，一直有一种雾里看花的感觉，似乎很随意，怎么来都行，比如：<br>#define AddRef(pif) \<br>&nbsp;(IUNK_VTABLE_OF(pif)-&gt;AddRef((IUnknown *)(pif)))</p>
<p>宏定义应该是可以嵌套的，即宏定义的&#8220;内容&#8220;中还可以包含（嵌套）宏，如本例，&#8220;IUNK_VTABLE_OF&#8221;就是嵌套宏。在展开的时候，将嵌套的宏也一并展开（替换成定义的内容），直到不再有宏为止。<br>那么就有两个疑问：<br>1。如果被嵌套的宏包含（直接或间接）定义的宏，那么展开就没完没了，死循环了。<br>2。如果定义的内容中有跟定义的宏同名的字符串（比如上面的例子IUNK_VTABLE_OF），那么怎么区分这同名的东东是嵌套的宏（需要展开），还是一般的字符串（不需要展开）？</p>
<p><br>函数调用规范约定、main函数调用规范。</p>
<p>一开始把几个文件汇总到项目里时，编译通不过，错误提示大致意思是，不能把一种调用规范的函数指针转换成另一种调用规范的函数指针。后来把调用规范改为&nbsp;&nbsp; /Gz(__stdcall),编译为（Compile As）改为/TC(Compile As C Code)就好了。</p>
<p>想来是对于.c文件，编译器缺省使用的是__cdecl，而IFoo中的接口宏定义在win32下展开成了__stdcall，所以出现了矛盾。而使用/Gz强制未声明调用规范的函数使用__stdcall，实现就与声明一致了。</p>
<p><br>(size_t)&amp;(((s *)0)-&gt;m)</p>
<p>c++程序员也许都知道，访问地址&#8220;0&#8221;处的成员是一大忌，会造成GP。然而，取地址&#8220;0&#8221;处的成员的地址，却是个合法的操作。虽然地址&#8220;0&#8221;处并没有什么内容，但是，如果在地址0处存放一个内容，那么该内容中的成员也是有地址的。本例中正是巧妙地利用这种方法，从接口地址计算得出实现该接口的实例地址，进而访问实例的内部变量。<br><br>------------------------------------------------------------------------------------<br>2009年5月6日<br>附上源码：<a href="http://www.cppblog.com/Files/gracelee/outside.zip">/Files/gracelee/outside.zip</a><br><br>代码执行结果：<br><img src="http://www.cppblog.com/images/cppblog_com/gracelee/10441/o_outside.JPG" border=0><br></p>
<img src ="http://www.cppblog.com/gracelee/aggbug/81414.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gracelee/" target="_blank">小葱蘸酱</a> 2009-04-29 12:08 <a href="http://www.cppblog.com/gracelee/archive/2009/04/29/81414.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自动类型转换——操作符重载</title><link>http://www.cppblog.com/gracelee/archive/2009/01/16/72176.html</link><dc:creator>小葱蘸酱</dc:creator><author>小葱蘸酱</author><pubDate>Fri, 16 Jan 2009 07:51:00 GMT</pubDate><guid>http://www.cppblog.com/gracelee/archive/2009/01/16/72176.html</guid><wfw:comment>http://www.cppblog.com/gracelee/comments/72176.html</wfw:comment><comments>http://www.cppblog.com/gracelee/archive/2009/01/16/72176.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gracelee/comments/commentRss/72176.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gracelee/services/trackbacks/72176.html</trackback:ping><description><![CDATA[用户自定义类(class)类型可以当作系统内建类型(build-in type)来处理，对这一点我一直很惊奇，也很迷惑，特别是在类定义、继承关系很复杂的时候，要找到来龙去脉真的很抓头。最近工作中碰到这一块的东西，顺便借这个机会澄清一些概念。<br><br>看下面代码：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;CBase&nbsp;{<br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;CBase()<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">CBase&nbsp;constructor()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">~</span><span style="color: #000000;">CBase()<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">CBase&nbsp;destructor()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">()<br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">CBase::operator&nbsp;long()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&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></span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">()<br></span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">CBase::operator&nbsp;char()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;">&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;">'</span><span style="color: #000000;">a</span><span style="color: #000000;">'</span><span style="color: #000000;">;<br></span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;">}<br></span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;">;<br></span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;CDerived:</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;CBase<br></span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br></span><span style="color: #008080;">28</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;CDerived()<br></span><span style="color: #008080;">29</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">30</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">CDerived&nbsp;constructor()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">31</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">32</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">33</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">~</span><span style="color: #000000;">CDerived()<br></span><span style="color: #008080;">34</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">35</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">CDerived&nbsp;destructor()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">36</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">37</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">38</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">()<br></span><span style="color: #008080;">39</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="color: #008080;">40</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">CDerived::operator&nbsp;long()</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">41</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;CBase::</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return *((CBase *)this);//change the above code to this looks better<br></span><span style="color: #008080;">42</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008080;">43</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">44</span>&nbsp;<span style="color: #000000;">};<br></span><span style="color: #008080;">45</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">46</span>&nbsp;<span style="color: #000000;"></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main()<br></span><span style="color: #008080;">47</span>&nbsp;<span style="color: #000000;">{<br></span><span style="color: #008080;">48</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;CDerived&nbsp;d;<br></span><span style="color: #008080;">49</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">&nbsp;lTmp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d;<br></span><span style="color: #008080;">50</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">lTmp=</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;lTmp&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">51</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;cTmp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;d;<br></span><span style="color: #008080;">52</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">cTmp=</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;cTmp&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;endl;<br></span><span style="color: #008080;">53</span>&nbsp;<span style="color: #000000;"><br></span><span style="color: #008080;">54</span>&nbsp;<span style="color: #000000;">}</span></div>
<p><br>由于定义了操作符重载CDerived::operator long() 和CBase::operator long()，49行得以编译通过。同理，定义了CBase::operator char()，51行可以编译。<br><br>执行结果为：<br><strong>CBase constructor()<br>CDerived constructor()<br>CDerived::operator long()<br>CBase::operator long()<br>lTmp=0<br>CBase::operator char()<br>cTmp=a<br>CDerived destructor()<br>CBase destructor()<br><br></strong></p>
<p>这里涉及到的概念主要有：<br>1 类成员操作符重载（使得用户定义类型转换为内建类型成为可能。对于用户定义类型之间的转换，还可以通过构造函数的方式进行）<br>2 自动类型转换。自动类型转换发生的情况有以下几种：<br>函数调用时传递的实参类型与函数声明中指定的参数类型不匹配<br>函数返回的对象类型与函数声明中指定的返回类型不匹配<br>表达式中操作数的类型不一致（这正是上面例子中的情况）<br><br></p>
有意思的是，即使不定义CBase::operator char()，上面的51行仍能通过，真得感叹编译器的聪明才智了，或许只是编译器source中多了一些的if{}else{}呢？<img src ="http://www.cppblog.com/gracelee/aggbug/72176.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gracelee/" target="_blank">小葱蘸酱</a> 2009-01-16 15:51 <a href="http://www.cppblog.com/gracelee/archive/2009/01/16/72176.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VBScript写的计算异或的一个小工具</title><link>http://www.cppblog.com/gracelee/archive/2007/08/03/29278.html</link><dc:creator>小葱蘸酱</dc:creator><author>小葱蘸酱</author><pubDate>Fri, 03 Aug 2007 05:05:00 GMT</pubDate><guid>http://www.cppblog.com/gracelee/archive/2007/08/03/29278.html</guid><wfw:comment>http://www.cppblog.com/gracelee/comments/29278.html</wfw:comment><comments>http://www.cppblog.com/gracelee/archive/2007/08/03/29278.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gracelee/comments/commentRss/29278.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gracelee/services/trackbacks/29278.html</trackback:ping><description><![CDATA[工作中经常会需要计算一大串字节的异或，用计算器手工一个一个的输入太累人了，碰巧这两天在关注VBScript，于是就想到写了这个工具。这是我第一次用VB，代码很简单，希望能对你有用。<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008000;">'</span><span style="color: #008000;">==========================================================================</span><span style="color: #008000;"><br>'<br>'<br>'</span><span style="color: #008000;">&nbsp;NAME:&nbsp;calc_xor.vbs</span><span style="color: #008000;"><br>'<br>'</span><span style="color: #008000;">&nbsp;COMMENT:&nbsp;Calculates&nbsp;the&nbsp;result&nbsp;of&nbsp;'xor'&nbsp;all&nbsp;elements&nbsp;in&nbsp;the&nbsp;input</span><span style="color: #008000;"><br>'<br>'</span><span style="color: #008000;">==========================================================================</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">Option</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Explicit</span><span style="color: #000000;"><br><br></span><span style="color: #0000ff;">Dim</span><span style="color: #000000;">&nbsp;strInput<br><br></span><span style="color: #008000;">'</span><span style="color: #008000;">Promt&nbsp;for&nbsp;string&nbsp;to&nbsp;search&nbsp;for&nbsp;in&nbsp;log&nbsp;files</span><span style="color: #008000;"><br></span><span style="color: #000000;">strInput&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">InputBox</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">Enter&nbsp;data&nbsp;to&nbsp;calc&nbsp;on.</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">calc&nbsp;xor</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">""</span><span style="color: #000000;">)<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;strInput&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">""</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">then</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;wscript.quit<br></span><span style="color: #0000ff;">end</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">If</span><span style="color: #000000;"><br><br></span><span style="color: #008000;">'</span><span style="color: #008000;">MsgBox(Len(strInput))</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">Dim</span><span style="color: #000000;">&nbsp;arrayBytes()<br></span><span style="color: #0000ff;">ReDim</span><span style="color: #000000;">&nbsp;arrayBytes(</span><span style="color: #0000ff;">Len</span><span style="color: #000000;">(strInput)</span><span style="color: #000000;">/</span><span style="color: #000000;">2</span><span style="color: #000000;">)<br><br></span><span style="color: #0000ff;">Dim</span><span style="color: #000000;">&nbsp;i,nBytes<br></span><span style="color: #0000ff;">Dim</span><span style="color: #000000;">&nbsp;chHalf1,chHalf2,chWhole<br>i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br>nBytes&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br><br></span><span style="color: #0000ff;">Do</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">While</span><span style="color: #000000;">&nbsp;(i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Len</span><span style="color: #000000;">(strInput))<br></span><span style="color: #008000;">'</span><span style="color: #008000;">Skip&nbsp;spaces&nbsp;between&nbsp;elements</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">Do</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">While</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Asc</span><span style="color: #000000;">(</span><span style="color: #0000ff;">Mid</span><span style="color: #000000;">(strInput,i,</span><span style="color: #000000;">1</span><span style="color: #000000;">))&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">32</span><span style="color: #000000;">&nbsp;</span><span style="color: #008000;">'</span><span style="color: #008000;">space</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">Loop</span><span style="color: #000000;">&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Asc</span><span style="color: #000000;">(</span><span style="color: #0000ff;">Mid</span><span style="color: #000000;">(strInput,i,</span><span style="color: #000000;">1</span><span style="color: #000000;">))<br>&nbsp;&nbsp;&nbsp;&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Asc</span><span style="color: #000000;">(</span><span style="color: #0000ff;">Mid</span><span style="color: #000000;">(strInput,i</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">1</span><span style="color: #000000;">))<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">'</span><span style="color: #008000;">Check&nbsp;and&nbsp;convert&nbsp;first&nbsp;half</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">If</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">48</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">And</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">57</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Then</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">48</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">ElseIf</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">65</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">And</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">70</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Then</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">65</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">ElseIf</span><span style="color: #000000;">&nbsp;chhalf1&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">97</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">And</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">104</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Then</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">97</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">Else</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">MsgBox</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">invalid&nbsp;character</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wscript.quit<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">End</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">If</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">'</span><span style="color: #008000;">&nbsp;Check&nbsp;and&nbsp;convert&nbsp;the&nbsp;second&nbsp;half</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">If</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">48</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">And</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">57</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Then</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">48</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">ElseIf</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">65</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">And</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">70</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Then</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">65</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">ElseIf</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">97</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">And</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">104</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Then</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chHalf2&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">97</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">Else</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">MsgBox</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">invalid&nbsp;character</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wscript.quit<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">End</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">If</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">'</span><span style="color: #008000;">&nbsp;Combine&nbsp;the&nbsp;first&nbsp;and&nbsp;second&nbsp;halves&nbsp;together&nbsp;to&nbsp;form&nbsp;a&nbsp;whole&nbsp;byte</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;chWhole&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chHalf1&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">16</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;chHalf2<br>&nbsp;&nbsp;&nbsp;&nbsp;arrayBytes(nBytes)&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;chWhole<br>&nbsp;&nbsp;&nbsp;&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;nBytes&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;nBytes&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">Loop</span><span style="color: #000000;"><br><br></span><span style="color: #008000;">'</span><span style="color: #008000;">MsgBox(CStr(nBytes)&nbsp;+&nbsp;"&nbsp;bytes&nbsp;all&nbsp;together")</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">Dim</span><span style="color: #000000;">&nbsp;WshSHell<br></span><span style="color: #0000ff;">set</span><span style="color: #000000;">&nbsp;WshShell&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">CreateObject</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">WScript.Shell</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br>WshShell.Run(</span><span style="color: #000000;">"</span><span style="color: #000000;">calc</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br>WScript.Sleep(</span><span style="color: #000000;">100</span><span style="color: #000000;">)<br>WshShell.AppActivate(</span><span style="color: #000000;">"</span><span style="color: #000000;">Calculator</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br>WScript.Sleep(</span><span style="color: #000000;">100</span><span style="color: #000000;">)<br><br>WshShell.SendKeys(</span><span style="color: #000000;">"</span><span style="color: #000000;">{F6}</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #008000;">'</span><span style="color: #008000;">Change&nbsp;to&nbsp;Decimal</span><span style="color: #008000;"><br>'</span><span style="color: #008000;">WshShell.SendKeys("{F4}")&nbsp;'Change&nbsp;to&nbsp;single&nbsp;byte</span><span style="color: #008000;"><br></span><span style="color: #000000;">WScript.Sleep(</span><span style="color: #000000;">100</span><span style="color: #000000;">)<br>WshShell.SendKeys(</span><span style="color: #000000;">"</span><span style="color: #000000;">0</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br></span><span style="color: #0000ff;">For</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">to</span><span style="color: #000000;">&nbsp;nBytes<br>&nbsp;&nbsp;&nbsp;&nbsp;WshShell.SendKeys(</span><span style="color: #000000;">"</span><span style="color: #000000;">{^}</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;WScript.Sleep(</span><span style="color: #000000;">100</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;WshShell.SendKeys(arrayBytes(i</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">))<br>&nbsp;&nbsp;&nbsp;&nbsp;WScript.Sleep(</span><span style="color: #000000;">100</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;WshShell.SendKeys(</span><span style="color: #000000;">"</span><span style="color: #000000;">{=}</span><span style="color: #000000;">"</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;WScript.Sleep(</span><span style="color: #000000;">100</span><span style="color: #000000;">)<br></span><span style="color: #0000ff;">Next</span><span style="color: #000000;"><br><br>WshShell.SendKeys(</span><span style="color: #000000;">"</span><span style="color: #000000;">{F5}</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #008000;">'</span><span style="color: #008000;">Change&nbsp;to&nbsp;Hex&nbsp;for&nbsp;easy&nbsp;recognition</span></div>
<br><br><br><img src ="http://www.cppblog.com/gracelee/aggbug/29278.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gracelee/" target="_blank">小葱蘸酱</a> 2007-08-03 13:05 <a href="http://www.cppblog.com/gracelee/archive/2007/08/03/29278.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用sprintf格式化字符串</title><link>http://www.cppblog.com/gracelee/archive/2007/07/31/29085.html</link><dc:creator>小葱蘸酱</dc:creator><author>小葱蘸酱</author><pubDate>Tue, 31 Jul 2007 08:43:00 GMT</pubDate><guid>http://www.cppblog.com/gracelee/archive/2007/07/31/29085.html</guid><wfw:comment>http://www.cppblog.com/gracelee/comments/29085.html</wfw:comment><comments>http://www.cppblog.com/gracelee/archive/2007/07/31/29085.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/gracelee/comments/commentRss/29085.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gracelee/services/trackbacks/29085.html</trackback:ping><description><![CDATA[写代码时经常会用到用sprintf格式化某个字符串，比如：<br>sprintf(mess,"This is field 1,Field 2,Field 3\n");<br><br>当这样的域很多的时候，一行放不下，为了便于阅读，需要把它们分成几行：<br>sprintf(mess,"This is filed 1,\<br>&nbsp;&nbsp;&nbsp; Field 2,\<br>&nbsp;&nbsp;&nbsp; Field 3,\<br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp;&nbsp;&nbsp; Field n\n");<br><br>但是，这样带来个问题，就是格式化后的mess的各个域之间就产生了不想要的字符（如空格等，使用UE可以清楚的看到），原因是由于使用了续行符"\"（line-continuation character），而不用续行符又无法通过编译（C2001）。<br><br>这时可以用双引号来把各个域分隔开，这样就既解决了可读性的问题，又解决了编译问题：<br>sprintf(mess,"This is filed 1,"<br>&nbsp;&nbsp;&nbsp; "Field 2,"<br>
&nbsp;&nbsp;&nbsp; "Field 3,"<br>
&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; "Field n\n");<br>
<br><br> <img src ="http://www.cppblog.com/gracelee/aggbug/29085.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gracelee/" target="_blank">小葱蘸酱</a> 2007-07-31 16:43 <a href="http://www.cppblog.com/gracelee/archive/2007/07/31/29085.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>