在 VC 知識庫中關於普通 DLL 插件的實現已有多篇文章,但在 ArcGIS、Office 等大型商業軟件中,基於 COM 的插件架構才是主流選擇。本文將系統剖析 COM 插件模型的核心要素、註冊發現機制,並提供關鍵代碼實現,幫助開發者掌握企業級插件系統的構建方法。
無論何種插件架構,都離不開以下三個角色:
TestSvr。Interface code 目錄下的專案),不包含任何實現。plugin 目錄下的兩個專案)。DLL 插件通常通過掃描固定目錄發現插件,但 COM 插件採用更靈活的方式:每個插件註冊到固定的 COM 分類(Category)中,宿主程序通過枚舉該分類下的類別來發現插件。這得益於 Windows 提供的 ICatRegister 和 ICatInformation 接口。
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();
}
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);
// 此處可進一步調用插件接口方法
}
COM 插件模型通過「契約接口 + 組件類別註冊」實現了宿主與插件的完全解耦,支持版本演進、跨語言調用、進程外激活等高級特性,是大型軟件擴展架構的首選。實戰中應注意:
IPlugin2)。RegFree COM 或 Side-by-Side 組件可避免註冊表汙染。完整範例代碼已打包,歡迎下載研究。