今天带来一个简单的COM组件的实现,非常的简单。这个组件只是简单的完成了整数的加减乘除~
首先,先罗列需要的COM接口,这里需要的接口非常简单,就是加减乘除的接口。所以定义一个ICalc类,当然这个类继承于IUnknown。
1 class ICalc : public IUnknown 2 { 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 else 22 { 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 else 80 { 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 else 14 { 15 //返回类厂对象的指针 16 HRESULT result = pCCalcFactory->QueryInterface(iid, ppv); 17 return result; 18 } 19 } 20 else 21 { 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 else 10 { 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