首页 > 代码库 > 《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组件的实现
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。