﻿<?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++博客-小董's blog</title><link>http://www.cppblog.com/dm386/</link><description>win32  linux C/C==</description><language>zh-cn</language><lastBuildDate>Tue, 14 Apr 2026 23:09:06 GMT</lastBuildDate><pubDate>Tue, 14 Apr 2026 23:09:06 GMT</pubDate><ttl>60</ttl><item><title>关于asp的分词系统</title><link>http://www.cppblog.com/dm386/archive/2009/08/17/93574.html</link><dc:creator>董鸿嘉</dc:creator><author>董鸿嘉</author><pubDate>Mon, 17 Aug 2009 03:38:00 GMT</pubDate><guid>http://www.cppblog.com/dm386/archive/2009/08/17/93574.html</guid><wfw:comment>http://www.cppblog.com/dm386/comments/93574.html</wfw:comment><comments>http://www.cppblog.com/dm386/archive/2009/08/17/93574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/dm386/comments/commentRss/93574.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/dm386/services/trackbacks/93574.html</trackback:ping><description><![CDATA[最近想研究下asp的分词系统，但也没有能够研究学习的，大家给我提个意见，我该怎么找一些开源的分词呢？
<img src ="http://www.cppblog.com/dm386/aggbug/93574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/dm386/" target="_blank">董鸿嘉</a> 2009-08-17 11:38 <a href="http://www.cppblog.com/dm386/archive/2009/08/17/93574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在C++中创建COM DLL - C/C++</title><link>http://www.cppblog.com/dm386/archive/2009/08/17/93570.html</link><dc:creator>董鸿嘉</dc:creator><author>董鸿嘉</author><pubDate>Mon, 17 Aug 2009 03:27:00 GMT</pubDate><guid>http://www.cppblog.com/dm386/archive/2009/08/17/93570.html</guid><wfw:comment>http://www.cppblog.com/dm386/comments/93570.html</wfw:comment><comments>http://www.cppblog.com/dm386/archive/2009/08/17/93570.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/dm386/comments/commentRss/93570.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/dm386/services/trackbacks/93570.html</trackback:ping><description><![CDATA[<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>在本篇文章中我们将讨论如何在MSVC++中开发一个非常简单的ActiveX dll，并在Visual Basic中对它进行调用，其中的例子将用到Active Template Library（ATL）和相关的向导工具。本篇文章不会涉及COM和ATL的工作原理（尽管这是必需的），也不要求读者具有任何ATL方面的经验。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>IDL：主要的差别</strong></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>在C++与VB中开发ActiveX的最大的不同之处（除了语言和其他一些小的方面）是IDL的引入。IDL是界面定义语言（Interface Definition Language）的简写，就象其名字那样，它定义了dll的界面。客户端可以用界面将自己与对象和dll的方法绑定，但它的作用并不仅仅限于此。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>通过使用IDL，我们可以将对象的外观和代码完全独立开来，隐藏在界面之后的任何东西可以随时被改变，任何使用dll的客户端程序都无需有任何改变，因为界面并没有改变。IDL还定义了过程之间传递的数据类型和参数。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>由于IDL是完全独立于具体语言的，不仅仅局限于COM或C++，CORBA同样也可以使用IDL来定义界面。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>所有的VB AX（ActiveX）对象在编译时都使用了IDL类型库，根据对象、方法和函数在VB程序中是如何定义的，VB会在幕后完成所有的工作。在MSVC++中，创建AX dll时不会自动生成IDL，类型库并非是COM对象所必需的（DirectX COM API就是一个很好的例子。），这个工作需要C++编程人员来完成。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>MSVC++ COM ATL工程</strong></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>创建一个ATL Com AppWizard工程，并将它命名为MyAXDll。具体的方法我在这里就不啰嗦了。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>AppWizard将在工程中添加一些文件，最重要的是MyAXDll.cpp，这个文件包括了每个COM对象必须提供的dll导出函数━━DllCanUnloadNow、DllGetClassObject、DllRegisterServer和DllUnregisterServer，这些函数是dll在注册和创建时就带有的。向导代码forwards调用基本ATL CComModule类的变量_Module，该类中包含COM对象创建、注册和注销它自己所必需的所有基本函数。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>AppWizard 还会添加一个MyAXDll.idl文件，这个文件包含该工程中所有的对象、属性和方法的IDL。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>这个工程本身并没有什么有用的东西，它只是包括一些COM对象和函数的外部结构和模块，如果要使该工程具有一定的功能，就需要在其中添加一个对象。添加对象的方法相信对于大家都是一件再简单不过的事儿了，我在这里就不再详细讨论了。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>向导在该工程中添加了三个文件━━MyObject.h、MyObject.cpp和MyObject.rgs，rgs文件包含用一种注册语言编写的COM类的注册设置，其内容在编译过的dll文件中是作为一种注册源存在的，可以被Registration使用，以正确地注册dll。MyObject.h文件中包含MyObject类的定义，打开该文件并详细观察其代码就可以发现，该文件包含了一个类━━CMyObject，该类是由其他四个类继承生成的，其中的三个是模式板类，另一个是一个独立的类（ISupportErrorInfo）。此外，其中还包含一些宏定义：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>DECLARE_REGISTRY_RESOURCEID(IDR_MYOBJECT)</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>DECLARE_PROTECT_FINAL_CONSTRUCT()</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>BEGIN_COM_MAP(CMyObject) </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>COM_INTERFACE_ENTRY(IMyObject) </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>COM_INTERFACE_ENTRY(IDispatch) </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>COM_INTERFACE_ENTRY(ISupportErrorInfo)</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>END_COM_MAP()</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>DECLARE_REGISTRY_RESOURCEID宏扩展为一个静态函数，该函数在系统注册表中注册该服务器（COM对象），IDR_MYOBJECT是要注册的类的源ID。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>DECLARE_PROTECT_FINAL_CONSTRUCT()可以确保任何内部对象不会产生调用FinalConstruct()的对象，被组合的对象必须使用该宏。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>BEGIN_COM_MAP()、COM_INTERFACE_ENTRY()和END_COM_MAP()的定义是有超前性的，对它们的讨论已经超出本篇文章的范围。我们只要理解类执行的每个界面就可以了，COM_MAP中的COM_INTERFACE_ENTRY(ITheInterface)是必需的。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>MyObject.h中接下来的代码是一个函数的定义：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>这个函数的代码是在MyObject.cpp中完成的。宏STDMETHOD(FunctionName)可以扩展成如下的形式：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>virtual HRESULT STDMETHODCALLTYPE FunctionName</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>STDMETHODCALLTYPE是一个标准的__stdcall类型，因此，宏STDMETHOD可以确保该函数使用标准的调用规则，并返回一个HRESULT类型的值。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>InterfaceSupportsErrorInfo函数是ISupportErrorInfo界面中除必需的函数之外的唯一函数。通过执行这个界面，服务器可以设置出错信息对象，客户端可以使用这一出错信息对象。尽管VB中的错误与COM错误都属同一类型，但这种处理错误信息的方式与VB有很大不同。由于恰当的错误信息处理方式对于软件是极为重要的，因此很有必要对这一问题进行深入的探讨。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>COM和COM错误</strong> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>MyAXdll工程中的COM对象执行ISupportErrorInfo界面，这一界面使服务器的客户端可以查询扩展的错误信息。这种方式会使已经习惯了标准VB错误处理方式的用户感到迷惑。二者之间的差别在于对象的方法的返回值上。在VB中，我们在函数的首部定义返回值的类型，如下所示：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>Public Function DoIt() As Long...DoIt = SomeValueEnd Function</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>上面的代码将函数返回值的类型定义成Long类型数据，在VB和脚本语言中这没有什么问题。在C++中则完全不同，该函数的头部将变成如下所示的格式：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>HRESULT __stdcall DoIt( long *return_value ){...*return_value = SomeValue;return S_OK;}</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>上面的函数头部将返回值定义成S_OK，它向客户端表明，函数执行成功，真正可用的返回值被传送到一个与ByRef类似的参数中。那么为什么会是这样呢？</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>其原因就在于COM的构建方式。COM子系统有时需要通知客户端在函数调用中发生了错误，例如，如果一个客户端正在访问一个远程服务器，如果该服务器没有在网络上，此时，COM子系统就有许多返回值可供选择，而对异常的自理又对语言有较大的依赖性。因此 ，几乎所有的COM方法都返回一个HRESULT值，这个值可以表明函数的执行结果。在SDK中的 <winerror.h>文件定义了一些基本的返回类型，其中最常用的二种为：S_OK，它表明函数执行正常；E_FAIL表示函数执行异常。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>表1列出了一些常用的返回类型：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>E_NOTIMPL ：没有执行</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>E_OUTOFMEMORY：内存溢出</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>E_INVALIDARG ：一个或多个参数无效</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>E_NOINTERFACE：不支持界面</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>E_POINTER ：无效的指针</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>E_HANDLE ：无效的句柄</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>E_ABORT ：操作中止</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>上面的表列出了可以在过程之间传递的消息，一旦过程在执行中有什么不正常，COM就可以把这些消息通知客户端，在VB中这一切是如何实现的呢？</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>VB也有同样的机制。如果一个VB函数得到成功的执行，VB就加返回一个S_OK值；如果函数执行有什么异常，就会出现错误，VB会返回一个类型为HRESULT的错误对象的错误代码。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>当VB客户端程序访问COM服务器时，如果返回一个调用失败的HRESULT值，VB就会立即查询服务器看它是否支持ISupportErrorInfo界面。因为如果服务器支持这一界面，VB将向InterfaceSupportErrorInfo函数查询失败的界面是否支持扩展的错误信息。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>由于二者相同，InterfaceSupportErrorInfo会返回一个true值，这表明该界面不支持扩展错误信息，VB会询问其他界面看它们是否支持这些信息━━这一切都是由ATL在幕后完成的，因此只要COM服务器设置了相应的信息，VB是可以得到扩展错误信息的。VB使用这些信息建立相似的错误对象，然后给出一个错误类型值━━类型为HRESULT的值。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>因此，如果在VB中发现一个错误信息，真正的错误仍然只局限于COM对象的范围内，VB只是简单地返回Err.Number的值，它只用于客户端向COM对象查询扩展错误信息。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>稍后，我们将会仔细讨论如何设置错误信息。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>在对象中添加方法</strong></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>现在我们来向对象中添加方法。本例中的对象有3种方法：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>1、取二个long类型值，将二者相加，并返回结果。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>2、取一个long型数据并报告出错信息</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>3、取一个long型数据，将它转换为BSTR数据，并返回这个数据</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>在一个COM对象中添加方法需要二个步骤：1、需要在IDL文件中定义方法；2、必须由MyObject类来实现。为了说明在COM对象中添加方法的具体步骤，我们将用手工方式添加第一个方法，第二、三个方法则使用AppWizard向导来完成。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>打开MyAXDll.idl文件。文件中的IDL可以分为二部分，第一部分是MyObject对象的定义，下面是该对象所有的方法、属性。代码如下所示：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>MyObject definitions</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[ </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>object, </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>uuid(28D7C31F-1FB2-4BF8-BC98-C8A256348354), dual,</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>helpstring("IMyObject Interface"),</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>pointer_default(unique) </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>] interface IMyObject : IDispatch</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>{</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>};</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>The MyAXDll definitions: </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[ uuid(E37200F2-E3DD-4243-9248-AA6A7FE71369), </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>version(1.0), </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>helpstring("MyAXDll 1.0 Type Library")</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>]</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>library MYAXDLLLib</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>{</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>importlib("stdole32.tlb"); importlib("stdole2.tlb");</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[ </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>uuid(09374147-1B90-4D78-B5B1-6E5B97C60DF2), helpstring("MyObject Class")</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>] </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>coclass MyObject</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>{ </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[default] interface IMyObject; </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>};</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>};</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>MyAXDll把MyObject界面作为一个联合类。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>要为MyObject定义一个方法，该方法必须添加在上面代码中IMyObject : IDispatch { }中的二个括弧中间。把下列内容添加到二个括弧之间：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[id(1), helpstring("AddLongs method - adds two longs and return the result")] </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>HRESULT AddLongs([in] long FirstParam, [in] long SecondParam, [out, retval] long* rt);</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>这是在对象中添加方法的最基本IDL。 [id(1), helpstring("AddLongs method - adds two longs and return the result")]设置要添加的方法的一些属性。id(#)设置供IDispatch界面函数使用的对象的DISPID，Helpstring是一个解释这个方法作用的字符串，我们可以在VB中的对象浏览器中查看这个字符串。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>真正的函数： HRESULT AddLongs([in] long FirstParam, [in] long SecondParam, [out, retval] long* rt);除了[direction]标志外是非常简单的，这些标志用于表明如何以及谁对参数进行控制，他们同VB如何向函数传递参数有直接的关系。下面列出的一些常用的标记组合：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[in] 与VB中的ByVal相同，表明该参数是由调用者分配存储和控制的。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[out] 表明该参数由被调用函数分配存储空间。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[in, out] 与VB中的ByRef相同，表明该参数应该由调用者分配存储空间，被调用函 数可以回收该参数的存储空间，也可以重新为该参数分配空间。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[out, retval] 与VB中的As Type返回值相同，如果指针指向一个指针，则被调用函数只能为该参数分配存储空间。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>要完成这个函数，需要打开MyObject.h文件。在类的public小节中添加下面基本的函数定义：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>STDMETHOD(AddLongs)( long FirstParam, long SecondParam, long* rt);</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>这只是该对象的定义，还需要在MyObject.cpp文件中添加下面的内容： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>STDMETHODIMP CMyObject::AddLongs(long FirstParam, long SecondParam, long *rt)</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>{ </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>*rt = FirstParam + SecondParam; </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>return S_OK;</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>}</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>至此，我们就为该对象添加了一个方法。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>第二个函数通过使用向导工具可以很方便地进行定义。在工程资源管理器中选择ClassView标签，扩展CMyObject并选择IMyObject界面，右击该界面并选择&#8220;添加方法&#8221;，把该方法命名为RaiseAnError，并把下面的内容添加到参数框中：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>[in] long FirstParam, [out,retval] long * rt</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>至此，向导已经在MyAXDll.idl中添加了该方法的IDL，在MyObject.h、MyObject.cpp文件中添加了该函数的框架。打开MyObject.cpp文件，在其中的RaiseAnError函数中添加下面的内容：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>STDMETHODIMP CMyObject::RaiseAnError(long FirstParam, long *rt)</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>{</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>//该函数必须设置错误对象</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>return AtlReportError( CLSID_MyObject, "Upps an error occurred", IID_IMyObject, E_FAIL );</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>}</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>该函数使用了AtlReportError帮助函数，该函数设置错误信息，并能够让VB得到并显示这些错误信息。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>由于使用了BSTR，最后一个函数有点特殊，BSTR是一个指向OLECHAR的简单指针，分配和收回BSTR的存储空间必须通过SysAllocaXX字符串函数实现，否则就可能扰乱COM系统，从而可能使你遇到一些奇怪的问题。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>The function takes one long value, convert it to a BSTR and returns it. Define it like this, using the AppWizard mentioned above:</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>该函数取得一个long型数据，转换为BSTR数据并将转换的结果返回给调用者。用AppWizard定义如下：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>名字： ConvertToString</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>参数： [in] long FirstParam, [out, retval] BSTR* ConvertedValue</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>生成的代码非常简单，如下所示：</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>STDMETHODIMP CMyObject::ConvertToString(long FirstParam, BSTR* ConvertedValue )</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>{</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>TCHAR tzConverted[20];\</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>//清零</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>memset( tzConverted, 0, 20 ); </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>//用C运行库函数进行转换</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>_itoa( FirstParam, tzConverted, 10 ); //转换为BSTR </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>USES_CONVERSION; </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>if ( ::SysReAllocString( ConvertedValue, A2OLE( tzConverted ) ) ) </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>return S_OK;</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>return E_OUTOFMEMORY;</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>}</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>这里比较重要的一点是，返回值的存储空间的分配是由SysReAllocString()完成的，由于BSTR是由客户端程序创建的，使用SysAllocString()函数可以保证它不被覆盖。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>That is it. Compile the project and fix any errors that have sneaked into the typing of the code. </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>所有的3个方法都添加后，编译该工程并修正其中出现的错误。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>客户端软件</strong></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>客户端软件是一个VB程序，我们可以使用本篇文章附加的程序（需要首先编译dll）也可以自己创建一个VB程序。在工程符号库中为MyAXdll.dll类型库建立一个符号。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>结论</strong></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>本篇文章没有详细讨论COM和ATL的有关知识，但它从一个VB编程人员的角度出发，简要地介绍了如何使用ATL和COM对VB进行扩展的基本技巧。</td>
        </tr>
    </tbody>
</table>
</span>
<img src ="http://www.cppblog.com/dm386/aggbug/93570.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/dm386/" target="_blank">董鸿嘉</a> 2009-08-17 11:27 <a href="http://www.cppblog.com/dm386/archive/2009/08/17/93570.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>