作者:
杜春辉
以下的代码是将一个COM注册、反注册到某一个COM组:
下载源代码
一、关于普通DLL插件的实现VC知识库里已有文章介绍,但在很多大型的软件中(如ArcGis、Office)中都不是采用这种方法,基于COM的插件在当今的大型软件中应用的更广泛。
二、实现插件离不开三个要素
- 插件管理器(即:要使用这些插件的主程)
- 插件基本接口(即:插件与管理器都认可的接口标准),在DLL插件中这个要素通常是一个标准的C++头文件,在COM插件中我们常用一个包含基类的接口COM,在这个COM中它只定义接口,不作任何实现。
- 插件COM,在这些COM中,它们只实现基类COM库的接口,没有自己的接口。
本文的例子中TestSvr是第一个要素,是插件管理器,plugin目录下的两个工程是第三个要素是插件COM,Interface code目录下的工程是提供基本类的COM,是我们上面提到的第二个要素。
三、在DLL插件中我们搜索插件的方法是将插件存放在与主程序相对固定的目录下,主程序通过搜索目录文件而搜索插件,在COM插件里我们不能用这种方法搜索插件,这里我们采用的方法是每个COM插件都注到一下固定的COM分组中,主程序在COM分组中搜索出插件 。以下的代码是将一个COM注册、反注册到某一个COM组:
void SpecialReg(GUID ID_SubItem,BOOL bRegister) { ICatRegister* pICatRegister = NULL ; HRESULT hr = ::CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_ALL, IID_ICatRegister, (void**)&pICatRegister) ; if (FAILED(hr)) { ErrorMessage("Could not create the ComCat component.", hr); return ; } CATEGORYINFO CatInfo ; CatInfo.catid = CATID_MyCategory ; CatInfo.lcid = LOCALE_SYSTEM_DEFAULT ; wcscpy(CatInfo.szDescription,sCateGoryName) ; if (bRegister) { hr = pICatRegister->RegisterCategories(1, &CatInfo) ; hr = pICatRegister->RegisterClassImplCategories(ID_SubItem, 1, &CATID_MyCategory) ; } else { hr = pICatRegister->UnRegisterClassImplCategories(ID_SubItem, 1, &CATID_MyCategory); ICatInformation* pICatInformation = NULL ; hr = pICatRegister->QueryInterface(IID_ICatInformation, (void**)&pICatInformation) ; IEnumCLSID* pIEnumCLSID = NULL ; hr = pICatInformation->EnumClassesOfCategories(1, &CATID_MyCategory, 0, NULL, &pIEnumCLSID) ; CLSID clsid ; hr = pIEnumCLSID->Next(1, &clsid, NULL) ; if (hr == S_FALSE) { hr = pICatRegister->UnRegisterCategories(1, &CATID_MyCategory) ; } pIEnumCLSID->Release() ; pICatInformation->Release() ; } if (pICatRegister) { pICatRegister->Release() ; } }以下的代码是从COM组中列举各个COM组件
ICatInformationPtr pICatInformation(CLSID_StdComponentCategoriesMgr); IEnumCLSID* pIEnumCLSID = NULL ; HRESULT hr = pICatInformation->EnumClassesOfCategories(1, &CATID_RdExcelExportCategory, 0, NULL, &pIEnumCLSID) ; ASSERT(SUCCEEDED(hr)) ; long nComandID = _BASE_COMMAND_ID_; CLSID clsid ; while ((hr = pIEnumCLSID->Next(1, &clsid, NULL)) == S_OK) { RDINTERFACELib::ICommandPtr pCommand(clsid); }