Title is No Title

not very good here!

导航

Create com step by step.1

目录:

介绍

接口

第一步:创建IDL文件

第二步:生成类型库

第三步:从IAdd继承

第四步:实现IAdd的方法

第五步:实现IUnkown

第六步:类工厂

第七步:实现IClassFactory的方法

第八步:实现DllGetClassObject

第九步:实现DllCanUnloadNow

第十步:DllRegisterServerUnregisterServer

第十一步:将IDL文件插入到工作空间中

第十二步:在Visual Basic 中使用COM刚创建的对象

 第十三步:分析我们刚创建的所有文件

第十四步:在ActiveX DLL中嵌入类型库

第十五步:从Visual C++客户方使用刚创建的COM对象

 

介绍

对于我来说,理解COM(Component Object Model)至少是不止一次的冒险旅行了。我相信,每一个希望理解COM背后基本理论的程序员,一定有过使用没有MFC/ATL的模板和宏帮助下的C++语言写了至少一个以上的简单的COM对象。在这篇文章中,我会根据COM的基本原理,介绍创建一个简单COM对象的步骤。这个创建的组件可以在VC/VB的客户端使用。

作为练习,我们会试图设计一个COM对象,实现一个假想的超级快速的加法算法。这个组件有两个长整型(long type)的参数,其返回值也是一个长整型数,是我们加法算法的结果。下面我们就开始设计这个接口。

接口

COM对象的接口,我们不会谈到实际的实现,而是要谈论使用这个COM对象并与之通信的方法签名(method signatures)。我们将会命名我们的接口为IAdd 这个接口的声明使用接口定义语言来完成(Interface Definition Language --IDL),接口定义语言是用来定义函数签名(Function Signatures)的,它使用一种独立于编程语言的格式,这有助于RPC组织从一个计算机到另一个的打包、分发和解包的参数。在我们的接口IAdd中,我们有两个方法SetFirstNumberSetSecondNumber,这两个方法用来传递加法使用的参数。然后,还有另外一个方法DoTheAddition,他用来计算实际的结果并将结果返回给客户。

第一步:创建IDL文件

创建一个新的win32 DLL工程(命名为AddObj)。接下来的所有文件将被创建到此文件夹。创建一个空文件并键入下面的内容,把它保存为IAdd.idl。接口标识符使用uuidgen.exe生成(uuidgen.exe是一个dos文件,可以在命令行直接运行它)

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;

    }

第二步 生成类型库

使用IDL编译器MIDL.EXE编译接口定义文件IAdd.idl。编译完成后,将会生成以下的文件:

IAdd.h

包含C++格式的接口声明

dlldata.c

包含代理DLL的代码。当在一个不同的处理器/计算机上调用对象时使用

IAdd.tlb

二进制文件。使用一个定义好的格式完全的描述我们的IAdd接口和它所有的方法。这个文件和COM组件分发给所有的客户。

IAdd_p.c

包含代理DLL的列集代码。当在一个不同的处理器/计算机上调用对象时使用

IAdd_i.c

包含接口IDIID

(译者注:编译方法为,如过你的机器已经安装了Visual Studio环境的话,那么你可以直接从命令行写入如下的语句,midl.exe ..\ AddObj\iadd.idl

第三步 IAdd继承

我们将在此步骤中创建一个COM对象。创建一个新文件(AddObj.h),声明一个C++类,命名这个类为CAddObj,从接口IAdd继承(在文件IAdd.h)。记住,IAdd继承自IUnknownIUnknown是一个抽象基类。因而我们不得不像IUnknown一样为抽象基类IAdd声明所有的方法。

 

///////////////////////////////////////////////////////////

//

//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的方法

 

我们将在此步骤中提供接口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

 

IUnknown方法需要被实现。在文件AddObj.cpp中,我们将实现它的三个强制的方法(AddRef,ReleaseQueryInterface)。私有成员变量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;

    }

 

/////////////////////////////////////////////////////////////////

第六步 类工厂

 

我们已经完成了Add COM对象的部分功能。作为每一个COM的准则,每个COM对象必须有一个独立的IClassFactory实现。客户将使用这个接口得到我们IAdd接口实现的实例。IClassFactory接口,像所有其他COM接口一样,继承自IUnknown。因此我们也必须提供一个IUnknown的实现,以及IClassFactory的方法(LockServer CreateInstance)。创建一个新文件(命名为AddObjFactory.h)。声明一个类CAddFactory并使之继承自IClassFactory

 

///////////////////////////////////////////////////////////

//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;

    };

/////////////////////////////////////////////////////////////////

 

posted on 2004-03-31 16:18  abraham  阅读(1167)  评论(0编辑  收藏  举报