首页 > 代码库 > 《COM原理与应用》学习笔记——一个简单的COM组件的实现

《COM原理与应用》学习笔记——一个简单的COM组件的实现

  今天带来一个简单的COM组件的实现,非常的简单。这个组件只是简单的完成了整数的加减乘除~

首先,先罗列需要的COM接口,这里需要的接口非常简单,就是加减乘除的接口。所以定义一个ICalc类,当然这个类继承于IUnknown。

1 class ICalc : public IUnknown2 {3 public:4     virtual long __stdcall add(long a, long b) = 0;5     virtual long __stdcall minus(long a, long b) = 0;6     virtual long __stdcall times(long a, long b) = 0;7     virtual long __stdcall devide(long a, long b) = 0;8 };

这只是定义了一个接口,接着我们要定义COM对象类,COM对象类理所当然的要继承自ICalc类。其中override是C++11提供的新关键字,表示明确的覆盖父类的某个函数。

 1 class CCalc : public ICalc 2 { 3 public: 4     CCalc(); 5     ~CCalc() = default; 6  7 public: 8     //IUnknown interface: 9     virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv) override;10     virtual ULONG __stdcall AddRef() override;11     virtual ULONG __stdcall Release() override;12 13     //ICalc interface:14     virtual long __stdcall add(long a, long b) override;15     virtual long __stdcall minus(long a, long b) override;16     virtual long __stdcall times(long a, long b) override;17     virtual long __stdcall devide(long a, long b) override;18 19 private:20     long m_lRef;//用于计数的变量21 };

接着是类厂的定义,定义如下:

class CCalcFactory : public IClassFactory{public:    CCalcFactory();    ~CCalcFactory() = default;public:    //STDMETHODCALLTYPE = __stdcall    //IUnknown interface:    virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID &iid, void **ppv) override;    virtual ULONG STDMETHODCALLTYPE AddRef() override;    virtual ULONG STDMETHODCALLTYPE Release() override;    //IClassFactory interface:    virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, const IID &iid, void **ppv) override;    virtual HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) override;protected:    long m_lRef;};

 接下来讲解以上各个类的具体实现:

首先是Ccalc的实现,那几个加减乘除的接口我就不写了。

HRESULT CCalc::QueryInterface(const IID &iid, void **ppv){    if (iid == IID_Calc)    {        *ppv = (ICalc *) this;        ((ICalc *)(*ppv))->AddRef();    }     else if (iid == IID_IUnknown)    {        *ppv = (ICalc *) this;        ((ICalc *)(*ppv))->AddRef();    }    else    {        *ppv = NULL;        return E_NOINTERFACE;    }    return S_OK;}ULONG CCalc::AddRef(){    ++m_lRef;    return (ULONG)m_lRef;}ULONG CCalc::Release(){    --m_lRef;    //当引用计数变为0的时候就将COM对象删除,并将COM对象的引用减一以便COM库知道能否释放资源    if (m_lRef == 0)    {        --g_ulCalcNumber;        delete this;        return 0;    }    return (ULONG)m_lRef;}

接下来是类厂的实现:

 1 extern ULONG g_ulCalcNumber; 2 extern ULONG g_ulLockNumber; 3  4 CCalcFactory::CCalcFactory() 5 { 6     m_lRef = 0; 7 } 8  9 HRESULT CCalcFactory::QueryInterface(const IID &iid, void **ppv)10 { 11     if (iid == IID_IUnknown)12     {//返回自己的IUnknown指针13         *ppv = (IUnknown *)this;14         ((IUnknown *)(*ppv))->AddRef();15     }16     else if (iid == IID_IClassFactory)17     {//如果IID是类厂的IID就返回自己的接口指针以便客户程序能够用该指针创建COM对象18         *ppv = (IClassFactory *)this;19         ((IClassFactory *)(*ppv))->AddRef();20     }21     else22     {23         *ppv = NULL;24         return E_NOINTERFACE;25     }26 27     return S_OK;28 }29 30 ULONG CCalcFactory::AddRef()31 {32     ++m_lRef;33     return (ULONG)m_lRef;34 }35 36 ULONG CCalcFactory::Release()37 {38     --m_lRef;39     if (m_lRef == 0)40     {41         delete this;42         return 0;43     }44     return (ULONG)m_lRef;45 }46 47 HRESULT CCalcFactory::CreateInstance(IUnknown *pUnkOuter, const IID &iid, void **ppv)48 {49     CCalc *pObj;50     HRESULT result;51     52     if (NULL != pUnkOuter)53     {54         return CLASS_E_NOAGGREGATION;55     }56 57     pObj = new (std::nothrow) CCalc;58     if (pObj == NULL)59     {60         return E_OUTOFMEMORY;61     }62 63     result = pObj->QueryInterface(iid, ppv);64     if (result != S_OK)65     {66         --g_ulCalcNumber;67         delete pObj;68     }69 70     return result;71 }72 73 HRESULT CCalcFactory::LockServer(BOOL fLock)74 {75     if (fLock)76     {77         ++g_ulLockNumber;78     } 79     else80     {81         --g_ulLockNumber;82     }83     return NOERROR;84 }

其他重要函数的实现:

 1 //这个导出函数是COM库用来创建类厂对象的函数,函数原型必须这样写。 2 extern "C" HRESULT __stdcall DllGetClassObject(const CLSID &clsid, const IID &iid, LPVOID *ppv) 3 { 4     if (clsid == CLSID_CCalc) 5     { 6         //创建类厂对象 7         CCalcFactory *pCCalcFactory = new (std::nothrow)CCalcFactory; 8  9         if (pCCalcFactory == NULL)10         {11             return E_OUTOFMEMORY;12         }13         else14         {15             //返回类厂对象的指针16             HRESULT result = pCCalcFactory->QueryInterface(iid, ppv);17             return result;18         }19     } 20     else21     {22         return CLASS_E_CLASSNOTAVAILABLE;23     }24 }25     
 1 //COM库用来查看是否可以卸载COM对象的函数 2 extern "C" HRESULT __stdcall DllCanUnloadNow() 3 { 4     //当COM对象的引用计数为0,类厂没有被锁,那么就可以卸载 5     if (g_ulCalcNumber == 0 && g_ulLockNumber == 0) 6     { 7         return S_OK; 8     }  9     else10     {11         return S_FALSE;12     }13 }
 1 //注册函数,将COM插件注册到注册表中 2 extern "C" HRESULT __stdcall DllRegisterServer() 3 { 4     char szModule[1024]; 5     DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, (LPWSTR)szModule, 1024); 6     if (dwResult == 0) 7         return SELFREG_E_CLASS; 8     return RegisterServer(CLSID_CCalc, 9         szModule,10         "Calc.Object",11         "Calc Component",12         NULL);13 }
1 //反注册函数,也可以说是注销函数吧。2 extern "C" HRESULT __stdcall DllUnregisterServer()3 {4     return UnregisterServer(CLSID_CCalc,5         "Calc.Object", NULL);6 }

里面的具体注册过程什么的我也是拷贝的其他人的代码。具体请参见附件中的代码。

不太会用博客园的文件系统,先发个百度网盘的链接吧:http://pan.baidu.com/s/1sjPmLKp

《COM原理与应用》学习笔记——一个简单的COM组件的实现