Programming 版 (精华区)

发信人: quest (1234), 信区: Programming
标  题: 循循渐进COM指南
发信站: 哈工大紫丁香 (2001年07月26日09:07:57 星期四), 转信

循循渐进COM指南

刘峰

介绍

    我认为每一个希望能理解COM背后的基本原理程序员,都必须至少用一般的C++语言写
一个简单的COM对象,也就是在没有MFC/ATL等模板和宏的帮助下完成一个COM对象。在这
篇文章里,我将介绍一个从最初的原理来建立一个COM对象的指导方针。该组件能被
VC/VB客户程序使用。

作为一个练习,我们将设计一个COM组件,它实现了假定的非常快的加法运算。该组件接
收两个LONG类型的参数,给用户返回一个LONG类型的值,该值就是加法运算的结果。

接口

    COM对象的接口不讨论实际的实现,但是该方法名将被另外的与该组件通讯的客户使
用。我们将我们的接口命名为Iadd。使用接口定义语言(IDL)声明该接口。在我们的接
口Iadd里,有两个被用做传递参数的方法SetFirstNumber和SetSecondNumber,而方法
DoTheAddition是实际完成加法运算和返回结果的。

第一步:

    建立一个新的Win32 DLL项目(AddObjSay),新建一个空文件并键入下面的内容,将
其存为Iadd.idl。接口的标识符guid由工具guidgen.exe产生。

import "unknwn.idl";
[
object,
uuid(1221db62-f3d8-11d4-825d-00104b3646c0),
helpstring("interface  IAdd is used for implementing a super-fast addition 
Algorithm")
]

interface IAdd : IUnknown
    {
    HRESULT     SetFirstNumber(long nX1);
    HRESULT     SetSecondNumber(long nX2);
    HRESULT     DoTheAddition([out,retval] long *pBuffer);
    };
[
uuid(3ff1aab8-f3d8-11d4-825d-00104b3646c0),
helpstring("Interfaces for Code Guru algorithm implementations .")
]
library CodeGuruMathLib
    {
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    interface IAdd;
}
第二步:

    使用命令行编译工具MIDL.EXE编译文件Iadd.idl,将生成下列文件:
Iadd.H        包含C++风格的接口描述
Dlldata.c      包含代理DLL的代码,在离程组件中使用
Iadd.tlb       二进制文件,定义了IADD接口和它所有方法的格式。
Iadd_p.c      包含了代理DLL的汇集代码,在不同的进程/计算机间通讯时使用。
Iadd_i.h      包含了接口的IIDs.
第三步:

    开始建立COM组件。建立一个新文件Addobj.H,声明一个从接口Iadd(Iadd.H)派生的
C++类,命名为CAddObj。切记,IAdd从IUnknown派生,同样也是一个抽象基类。因此,我
们必须为抽象类Iadd和Iunknown声明所有的方法。

///////////////////////////////////////////////////////////
//
//AddObj.h
//Contains the C++ class declarations for implementing the IAdd
//interfaces
//
#include    "IAdd.h"
extern long g_nComObjsInUse;
class CAddObj : 
        public IAdd
    {
    public:

    //IUnknown interface 
    HRESULT __stdcall QueryInterface(
                                REFIID riid , 
                                void **ppObj);
    ULONG   __stdcall AddRef();
    ULONG   __stdcall Release();

    //IAdd interface
    HRESULT __stdcall SetFirstNumber( long nX1);
    HRESULT __stdcall SetSecondNumber( long nX2);
    HRESULT __stdcall DoTheAddition( long *pBuffer);

    private:

    long m_nX1 , m_nX2; //operands for addition
    long m_nRefCount;   //for managing the reference count
    };

///////////////////////////////////////////////////////////
第四步:

    提供接口Iadd所有的方法的具体实现。建立一个新文件(AddObj.CPP),并加入实现
代码:

///////////////////////////////////////////////////////////
//
//AddObj.cpp
//Contains the method  implementations of the IAdd interface
//interfaces
//

#include    <objbase.h>

#include    "AddObj.h"
#include    "IAdd_i.c"

HRESULT __stdcall CAddObj::SetFirstNumber( long nX1)
    {
    m_nX1=nX1;
    if (m_bIsLogEnabled) WriteToLog("Junk");
    return S_OK;
    }

HRESULT __stdcall CAddObj::SetSecondNumber( long nX2)
    {
    m_nX2=nX2;
    return S_OK;
    }

HRESULT __stdcall CAddObj::DoTheAddition( long *pBuffer)
    {
    *pBuffer =m_nX1 + m_nX2;

    return S_OK;
}
第五步:

    Iunknown接口的方法也需要实现。我们将在同一个文件中实现三个方法(AddRef,
Release,QueryInterface)。私有成员变量m_nRefCount用来维护对象的生命周期,
m_nRefCount不能直接增加和减少,应用一个线程安全的方法,可以使用API函数
InterlockedIncrement 和InterlockedDecrement:

HRESULT __stdcall CAddObj::QueryInterface(
                                    REFIID riid , 
                                    void **ppObj)
    {
    if (riid == IID_IUnknown)
        {
        *ppObj = static_cast(this) ; 
        AddRef() ;
        return S_OK;
        }

    if (riid == IID_IAdd)
        {
        *ppObj = static_cast(this) ;
        AddRef() ;
        return S_OK;
        }

    //
    //if control reaches here then , let the client know that
    //we do not satisfy the required interface
    //

    *ppObj = NULL ;
    return E_NOINTERFACE ;
    }//QueryInterface method



ULONG   __stdcall CAddObj::AddRef()
    {
    return InterlockedIncrement(&m_nRefCount) ;
    }

    
    
ULONG   __stdcall CAddObj::Release()
    {     
    long nRefCount=0;
    nRefCount=InterlockedDecrement(&m_nRefCount) ;
    if (nRefCount == 0) delete this;
    return nRefCount;
}

第六步:

    我们已经完成了该COM组件的功能部分。作为一个COM组件,每个COM对象还必须实现
一个特殊的接口IclassFactory。客户程序通过该接口得到一个组件对象的实例。类厂接
口IclassFactory和其他接口一样,也必须从Iunkonwn接口派生。建立一个新文件(
Addobjfactory.cpp),声明一个从接口IclassFactory派生的类CaddFactory:

///////////////////////////////////////////////////////////
//
//AddObjFactory.h
//Contains the C++ class declarations for the IClassFactory implementations
//

class CAddFactory : public IClassFactory
    {

    public:


    //interface IUnknown methods 
    HRESULT __stdcall QueryInterface(
                                REFIID riid , 
                                void **ppObj);
    ULONG   __stdcall AddRef();
    ULONG   __stdcall Release();


    //interface IClassFactory methods 
    HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
                                             const IID& iid,
                                             void** ppv) ;
    HRESULT __stdcall LockServer(BOOL bLock) ; 

    private:
    long m_nRefCount;
};

第七步:

    实现CaddFactory中的方法,建立一个新文件(Addobjfactory.cpp),实现
IclassFactory和Iunknown中的所有方法,其中AddRef,Release,QueryInterface的实现
类似CaddObj。方法CreateInstanc是用来实例化CaddObj和返回接口指针的。而方法
LoakServer在此没有给出具体的实现。

HRESULT __stdcall CAddFactory::CreateInstance(IUnknown* pUnknownOuter,
                                           const IID& iid,
                                           void** ppv) 
    {
    //
    //This method lets the client manufacture components en masse
    //The class factory provides a mechanism to control the way
    //the component is created. Within the class factory the 
    //author of the component may decide to selectivey enable
    //or disable creation as per license agreements 
    //
    //

    // Cannot aggregate.
    if (pUnknownOuter != NULL)
        {
        return CLASS_E_NOAGGREGATION ;
        }

    //
    // Create an instance of the component.
    //
    CAddObj* pObject = new CAddObj ;
    if (pObject == NULL)
        {
        return E_OUTOFMEMORY ;
        }

    //
    // Get the requested interface.
    //
    return pObject->QueryInterface(iid, ppv) ;
    }


HRESULT __stdcall CAddFactory::LockServer(BOOL bLock) 
    {
    return E_NOTIMPL;
    }
第八步:

    一个在程COM组件仅仅是一个简单的WIN32 DLL。每个COM DLL必须有一个输出函数
DllGetClassObject。客户程序调用该函数得到一个类厂的实例(Iunknow或
IClassFactory)。建立一个新文件(Exports.Cpp)实现该函数。

STDAPI DllGetClassObject(const CLSID& clsid,
                         const IID& iid,
                         void** ppv)
    {
    //
    //Check if the requested COM object is implemented in this DLL
    //There can be more than 1 COM object implemented in a DLL
    //
    if (clsid == CLSID_AddObject)
        {
        //
        //iid specifies the requested interface for the factory object
        //The client can request for IUnknown, IClassFactory,
        //IClassFactory2
        //
        CAddFactory *pAddFact = new CAddFactory;
        if (pAddFact == NULL)
            return E_OUTOFMEMORY;
        else
            {
            return pAddFact->QueryInterface(iid , ppv);
            }
        }
    //
    //if control reaches here then that implies that the object
    //specified by the user is not implemented in this DLL
    //
    return CLASS_E_CLASSNOTAVAILABLE;
}

第九步:

    当COM DLL从内存卸载时,客户程序应该知道。一个在程组件可以通过调用API函数
LoadLibrary显示将DLL加载到客户进程空间,可以调用FreeLibrary卸载DLL。

    COM DLL安全卸载时客户程序必须知道。客户程序必须确认没有该组件对象的实例存
在。我们将在COM DLL中加入一个全局变量g_nComObjsInUse,并在CaddObj和
CaddFactory的构造函数中对该变量执行增量操作,同样,在他们对应的析构函数中进行
减量操作。

    我们需要输出另一个特殊函数DllCanUnloadNow,具体实现如下:

STDAPI DllCanUnloadNow()
    {
    //
    //A DLL is no longer in use when it is not managing any existing objects
    // (the reference count on all of its objects is 0). 
    //We will examine the value of g_nComObjsInUse 
    //
    if (g_nComObjsInUse == 0)
        {
        return S_OK;
        }
    else
        {
        return S_FALSE;
        }
    }
第十步:

    一个COM对象的位置信息必须加入注册表中。这可以通过建立一个外部的.REG文件或
创建一个DLL输出函数DllRegisterServer来实现。为了从注册表中删除该信息,我们需要
一个输出函数DllUnregisterServer。这两个函数的实现在文件Registry.Cpp中,工具
Regsve32.exe可以用来加载DLL并执行DllRegisterServer和DllUnregisterServer。

为了输出上述4个函数,我们需要建立.DEF文件如下:
;contains the list of functions that are being exported from this DLL
DESCRIPTION     "Simple COM object"
EXPORTS
                DllGetClassObject       PRIVATE
                DllCanUnloadNow         PRIVATE
                DllRegisterServer       PRIVATE
                DllUnregisterServer     PRIVATE
第十一步:

将文件Iadd.idl加入项目的工作区中:



为该项目建立定制选项:



为了在每次建立后执行Regsvr32.exe在”Post-build step”对话框中加入一个命令行:




建立该DLL。

第十二步:

    从VB中使用该COM组件,建立一个简单的EXE项目,执行下面几行代码即可。

    Dim iAdd As CodeGuruMathLib.iAdd
    Set iAdd = CreateObject("CodeGuru.FastAddition")
    iAdd.SetFirstNumber 100
    iAdd.SetSecondNumber 200
    MsgBox "total = " & iAdd.DoTheAddition()
第十三步:

    我们所用到的文件如下:
IAdd.idl  接口声明 
AddObj.h  CaddObj类的声明  
AddObjFactory.h  CaddFactory类的声明  
AddObj.cpp  CaddObj的具体实现
AddObj.cpp  CaddFactory的具体实现  
Exports.cpp  DllGetClassObject,DllCanUnloadNow 和 DllMain的实现  
Registry.cpp  DllRegisterServer,DllUnregisterServer的实现  
AddObjGuid.h  AddObj COM对象的GUID
第十四步:

    类型库随同Addobj.Dll一起发布。简单的处理是,将类型库Iadd.tbl作为一个二进制
资源加入到AddObj.Dll中。这样,我们只需要将DLL发布给客户即可。





第十五步:

    一个Visual C++用户可以通过下列几步使用该组件:
1、#import “iadd.lib”
2、#include “iadd.h”
3、编写客户程序。
//
///Client.cpp
//
//Demo of client using the COM object from AddObj.dll 
//

#include    <objbase.h>
#include    <stdio.h>
#import     "AddObj.dll"
//
//Here we do a #import on the DLL ,you can also do a #import on the .TLB 
//The #import directive generates two files (.tlh/.tli) in the output 
folders.
//

void main()
    {

    long n1 =100, n2=200;        
    long nOutPut = 0;

    CoInitialize(NULL);
    CodeGuruMathLib::IAddPtr pFastAddAlgorithm;
    //
    //IAddPtr is not the actual interface IAdd, but a template C++ class 
(_com_ptr_t)
    //that contains an embedded instance of the raw IAdd pointer
    //While destructing , the destructor makes sure to invoke Release() on the
 internal
    //raw interface pointer. Further, the operator -> has been overloaded to 
direct all
    //method invocations to the internal raw interface pointer.
    //
    pFastAddAlgorithm.CreateInstance("CodeGuru.FastAddition");

    pFastAddAlgorithm->SetFirstNumber(n1);//"->" overloading in action
    pFastAddAlgorithm->SetSecondNumber(n2);
    nOutPut = pFastAddAlgorithm->DoTheAddition();

    printf("\nOutput after adding %d & %d is %d\n",n1,n2,nOutPut);
}

循循渐进COM指南

刘峰

介绍

    我认为每一个希望能理解COM背后的基本原理程序员,都必须至少用一般的C++语言写
一个简单的COM对象,也就是在没有MFC/ATL等模板和宏的帮助下完成一个COM对象。在这
篇文章里,我将介绍一个从最初的原理来建立一个COM对象的指导方针。该组件能被
VC/VB客户程序使用。

作为一个练习,我们将设计一个COM组件,它实现了假定的非常快的加法运算。该组件接
收两个LONG类型的参数,给用户返回一个LONG类型的值,该值就是加法运算的结果。

接口

    COM对象的接口不讨论实际的实现,但是该方法名将被另外的与该组件通讯的客户使
用。我们将我们的接口命名为Iadd。使用接口定义语言(IDL)声明该接口。在我们的接
口Iadd里,有两个被用做传递参数的方法SetFirstNumber和SetSecondNumber,而方法
DoTheAddition是实际完成加法运算和返回结果的。

第一步:

    建立一个新的Win32 DLL项目(AddObjSay),新建一个空文件并键入下面的内容,将
其存为Iadd.idl。接口的标识符guid由工具guidgen.exe产生。

import "unknwn.idl";
[
object,
uuid(1221db62-f3d8-11d4-825d-00104b3646c0),
helpstring("interface  IAdd is used for implementing a super-fast addition 
Algorithm")
]

interface IAdd : IUnknown
    {
    HRESULT     SetFirstNumber(long nX1);
    HRESULT     SetSecondNumber(long nX2);
    HRESULT     DoTheAddition([out,retval] long *pBuffer);
    };
[
uuid(3ff1aab8-f3d8-11d4-825d-00104b3646c0),
helpstring("Interfaces for Code Guru algorithm implementations .")
]
library CodeGuruMathLib
    {
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    interface IAdd;
}
第二步:

    使用命令行编译工具MIDL.EXE编译文件Iadd.idl,将生成下列文件:
Iadd.H        包含C++风格的接口描述
Dlldata.c      包含代理DLL的代码,在离程组件中使用
Iadd.tlb       二进制文件,定义了IADD接口和它所有方法的格式。
Iadd_p.c      包含了代理DLL的汇集代码,在不同的进程/计算机间通讯时使用。
Iadd_i.h      包含了接口的IIDs.
第三步:

    开始建立COM组件。建立一个新文件Addobj.H,声明一个从接口Iadd(Iadd.H)派生的
C++类,命名为CAddObj。切记,IAdd从IUnknown派生,同样也是一个抽象基类。因此,我
们必须为抽象类Iadd和Iunknown声明所有的方法。

///////////////////////////////////////////////////////////
//
//AddObj.h
//Contains the C++ class declarations for implementing the IAdd
//interfaces
//
#include    "IAdd.h"
extern long g_nComObjsInUse;
class CAddObj : 
        public IAdd
    {
    public:

    //IUnknown interface 
    HRESULT __stdcall QueryInterface(
                                REFIID riid , 
                                void **ppObj);
    ULONG   __stdcall AddRef();
    ULONG   __stdcall Release();

    //IAdd interface
    HRESULT __stdcall SetFirstNumber( long nX1);
    HRESULT __stdcall SetSecondNumber( long nX2);
    HRESULT __stdcall DoTheAddition( long *pBuffer);

    private:

    long m_nX1 , m_nX2; //operands for addition
    long m_nRefCount;   //for managing the reference count
    };

///////////////////////////////////////////////////////////
第四步:

    提供接口Iadd所有的方法的具体实现。建立一个新文件(AddObj.CPP),并加入实现
代码:

///////////////////////////////////////////////////////////
//
//AddObj.cpp
//Contains the method  implementations of the IAdd interface
//interfaces
//

#include    <objbase.h>

#include    "AddObj.h"
#include    "IAdd_i.c"

HRESULT __stdcall CAddObj::SetFirstNumber( long nX1)
    {
    m_nX1=nX1;
    if (m_bIsLogEnabled) WriteToLog("Junk");
    return S_OK;
    }

HRESULT __stdcall CAddObj::SetSecondNumber( long nX2)
    {
    m_nX2=nX2;
    return S_OK;
    }

HRESULT __stdcall CAddObj::DoTheAddition( long *pBuffer)
    {
    *pBuffer =m_nX1 + m_nX2;

    return S_OK;
}
第五步:

    Iunknown接口的方法也需要实现。我们将在同一个文件中实现三个方法(AddRef,
Release,QueryInterface)。私有成员变量m_nRefCount用来维护对象的生命周期,
m_nRefCount不能直接增加和减少,应用一个线程安全的方法,可以使用API函数
InterlockedIncrement 和InterlockedDecrement:

HRESULT __stdcall CAddObj::QueryInterface(
                                    REFIID riid , 
                                    void **ppObj)
    {
    if (riid == IID_IUnknown)
        {
        *ppObj = static_cast(this) ; 
        AddRef() ;
        return S_OK;
        }

    if (riid == IID_IAdd)
        {
        *ppObj = static_cast(this) ;
        AddRef() ;
        return S_OK;
        }

    //
    //if control reaches here then , let the client know that
    //we do not satisfy the required interface
    //

    *ppObj = NULL ;
    return E_NOINTERFACE ;
    }//QueryInterface method



ULONG   __stdcall CAddObj::AddRef()
    {
    return InterlockedIncrement(&m_nRefCount) ;
    }

    
    
ULONG   __stdcall CAddObj::Release()
    {     
    long nRefCount=0;
    nRefCount=InterlockedDecrement(&m_nRefCount) ;
    if (nRefCount == 0) delete this;
    return nRefCount;
}

第六步:

    我们已经完成了该COM组件的功能部分。作为一个COM组件,每个COM对象还必须实现
一个特殊的接口IclassFactory。客户程序通过该接口得到一个组件对象的实例。类厂接
口IclassFactory和其他接口一样,也必须从Iunkonwn接口派生。建立一个新文件(
Addobjfactory.cpp),声明一个从接口IclassFactory派生的类CaddFactory:

///////////////////////////////////////////////////////////
//
//AddObjFactory.h
//Contains the C++ class declarations for the IClassFactory implementations
//

class CAddFactory : public IClassFactory
    {

    public:


    //interface IUnknown methods 
    HRESULT __stdcall QueryInterface(
                                REFIID riid , 
                                void **ppObj);
    ULONG   __stdcall AddRef();
    ULONG   __stdcall Release();


    //interface IClassFactory methods 
    HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
                                             const IID& iid,
                                             void** ppv) ;
    HRESULT __stdcall LockServer(BOOL bLock) ; 

    private:
    long m_nRefCount;
};

第七步:

    实现CaddFactory中的方法,建立一个新文件(Addobjfactory.cpp),实现
IclassFactory和Iunknown中的所有方法,其中AddRef,Release,QueryInterface的实现
类似CaddObj。方法CreateInstanc是用来实例化CaddObj和返回接口指针的。而方法
LoakServer在此没有给出具体的实现。

HRESULT __stdcall CAddFactory::CreateInstance(IUnknown* pUnknownOuter,
                                           const IID& iid,
                                           void** ppv) 
    {
    //
    //This method lets the client manufacture components en masse
    //The class factory provides a mechanism to control the way
    //the component is created. Within the class factory the 
    //author of the component may decide to selectivey enable
    //or disable creation as per license agreements 
    //
    //

    // Cannot aggregate.
    if (pUnknownOuter != NULL)
        {
        return CLASS_E_NOAGGREGATION ;
        }

    //
    // Create an instance of the component.
    //
    CAddObj* pObject = new CAddObj ;
    if (pObject == NULL)
        {
        return E_OUTOFMEMORY ;
        }

    //
    // Get the requested interface.
    //
    return pObject->QueryInterface(iid, ppv) ;
    }


HRESULT __stdcall CAddFactory::LockServer(BOOL bLock) 
    {
    return E_NOTIMPL;
    }
第八步:

    一个在程COM组件仅仅是一个简单的WIN32 DLL。每个COM DLL必须有一个输出函数
DllGetClassObject。客户程序调用该函数得到一个类厂的实例(Iunknow或
IClassFactory)。建立一个新文件(Exports.Cpp)实现该函数。

STDAPI DllGetClassObject(const CLSID& clsid,
                         const IID& iid,
                         void** ppv)
    {
    //
    //Check if the requested COM object is implemented in this DLL
    //There can be more than 1 COM object implemented in a DLL
    //
    if (clsid == CLSID_AddObject)
        {
        //
        //iid specifies the requested interface for the factory object
        //The client can request for IUnknown, IClassFactory,
        //IClassFactory2
        //
        CAddFactory *pAddFact = new CAddFactory;
        if (pAddFact == NULL)
            return E_OUTOFMEMORY;
        else
            {
            return pAddFact->QueryInterface(iid , ppv);
            }
        }
    //
    //if control reaches here then that implies that the object
    //specified by the user is not implemented in this DLL
    //
    return CLASS_E_CLASSNOTAVAILABLE;
}

第九步:

    当COM DLL从内存卸载时,客户程序应该知道。一个在程组件可以通过调用API函数
LoadLibrary显示将DLL加载到客户进程空间,可以调用FreeLibrary卸载DLL。

    COM DLL安全卸载时客户程序必须知道。客户程序必须确认没有该组件对象的实例存
在。我们将在COM DLL中加入一个全局变量g_nComObjsInUse,并在CaddObj和
CaddFactory的构造函数中对该变量执行增量操作,同样,在他们对应的析构函数中进行
减量操作。

    我们需要输出另一个特殊函数DllCanUnloadNow,具体实现如下:

STDAPI DllCanUnloadNow()
    {
    //
    //A DLL is no longer in use when it is not managing any existing objects
    // (the reference count on all of its objects is 0). 
    //We will examine the value of g_nComObjsInUse 
    //
    if (g_nComObjsInUse == 0)
        {
        return S_OK;
        }
    else
        {
        return S_FALSE;
        }
    }
第十步:

    一个COM对象的位置信息必须加入注册表中。这可以通过建立一个外部的.REG文件或
创建一个DLL输出函数DllRegisterServer来实现。为了从注册表中删除该信息,我们需要
一个输出函数DllUnregisterServer。这两个函数的实现在文件Registry.Cpp中,工具
Regsve32.exe可以用来加载DLL并执行DllRegisterServer和DllUnregisterServer。

为了输出上述4个函数,我们需要建立.DEF文件如下:
;contains the list of functions that are being exported from this DLL
DESCRIPTION     "Simple COM object"
EXPORTS
                DllGetClassObject       PRIVATE
                DllCanUnloadNow         PRIVATE
                DllRegisterServer       PRIVATE
                DllUnregisterServer     PRIVATE
第十一步:

将文件Iadd.idl加入项目的工作区中:



为该项目建立定制选项:



为了在每次建立后执行Regsvr32.exe在”Post-build step”对话框中加入一个命令行:




建立该DLL。

第十二步:

    从VB中使用该COM组件,建立一个简单的EXE项目,执行下面几行代码即可。

    Dim iAdd As CodeGuruMathLib.iAdd
    Set iAdd = CreateObject("CodeGuru.FastAddition")
    iAdd.SetFirstNumber 100
    iAdd.SetSecondNumber 200
    MsgBox "total = " & iAdd.DoTheAddition()
第十三步:

    我们所用到的文件如下:
IAdd.idl  接口声明 
AddObj.h  CaddObj类的声明  
AddObjFactory.h  CaddFactory类的声明  
AddObj.cpp  CaddObj的具体实现
AddObj.cpp  CaddFactory的具体实现  
Exports.cpp  DllGetClassObject,DllCanUnloadNow 和 DllMain的实现  
Registry.cpp  DllRegisterServer,DllUnregisterServer的实现  
AddObjGuid.h  AddObj COM对象的GUID
第十四步:

    类型库随同Addobj.Dll一起发布。简单的处理是,将类型库Iadd.tbl作为一个二进制
资源加入到AddObj.Dll中。这样,我们只需要将DLL发布给客户即可。





第十五步:

    一个Visual C++用户可以通过下列几步使用该组件:
1、#import “iadd.lib”
2、#include “iadd.h”
3、编写客户程序。
//
///Client.cpp
//
//Demo of client using the COM object from AddObj.dll 
//

#include    <objbase.h>
#include    <stdio.h>
#import     "AddObj.dll"
//
//Here we do a #import on the DLL ,you can also do a #import on the .TLB 
//The #import directive generates two files (.tlh/.tli) in the output 
folders.
//

void main()
    {

    long n1 =100, n2=200;        
    long nOutPut = 0;

    CoInitialize(NULL);
    CodeGuruMathLib::IAddPtr pFastAddAlgorithm;
    //
    //IAddPtr is not the actual interface IAdd, but a template C++ class 
(_com_ptr_t)
    //that contains an embedded instance of the raw IAdd pointer
    //While destructing , the destructor makes sure to invoke Release() on the
 internal
    //raw interface pointer. Further, the operator -> has been overloaded to 
direct all
    //method invocations to the internal raw interface pointer.
    //
    pFastAddAlgorithm.CreateInstance("CodeGuru.FastAddition");

    pFastAddAlgorithm->SetFirstNumber(n1);//"->" overloading in action
    pFastAddAlgorithm->SetSecondNumber(n2);
    nOutPut = pFastAddAlgorithm->DoTheAddition();

    printf("\nOutput after adding %d & %d is %d\n",n1,n2,nOutPut);
}


--
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: wpc.hit.edu.cn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:214.164毫秒