由於項目需求,需要用到OCX控件。而在IE瀏覽器中加載OCX控件會有如下提示:
這是因為OCX控件有一個ID,而這個ID注冊后IE不認為該OCX控件是安全的。所以,必須把這個控件注冊為安全控件。
假設已經創建好OCX控件工程了。操作步驟如下:
第一步:在xxxApp類頭文件(.h)添加如下函數聲明。
// 去掉IE提示“此控件不安全的”提示框; // Helper function to create a component category and associated // description HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription); // Helper function to register a CLSID as belonging to a component // category HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid); // Helper function to unregister a CLSID as belonging to a component // category HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid);
注意:這些函數聲明不是xxxApp類成員函數聲明,而是全局函數聲明。
第二步:在xxxApp類的實現文件(.cpp)添加如下函數實現。
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription) { ICatRegister* pcr = NULL; HRESULT hr = S_OK; hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); if (FAILED(hr)) return hr; // Make sure the HKCR/Component Categories/{..catid...} // key is registered CATEGORYINFO catinfo; catinfo.catid = catid; catinfo.lcid = 0x0409; // english // Make sure the provided description is not too long. // Only copy the first 127 characters if it is int len = wcslen(catDescription); if (len > 127) len = 127; wcsncpy(catinfo.szDescription, catDescription, len); // Make sure the description is null terminated catinfo.szDescription[len] = '/0'; hr = pcr->RegisterCategories(1, &catinfo); pcr->Release(); return hr; } HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid) { // Register your component categories information. ICatRegister* pcr = NULL; HRESULT hr = S_OK; hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); if (SUCCEEDED(hr)) { // Register this category as being "implemented" by // the class. CATID rgcatid[1]; rgcatid[0] = catid; hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid); } if (pcr != NULL) pcr->Release(); return hr; } HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid) { ICatRegister *pcr = NULL; HRESULT hr = S_OK; hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); if (SUCCEEDED(hr)) { // Unregister this category as being "implemented" by the class. CATID rgcatid[1]; rgcatid[0] = catid; hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid); } if (pcr != NULL) pcr->Release(); return hr; }
第三步:在xxxApp類的實現文件(xxx.cpp)定義兩個GUID用來注冊控件的安全性,同時需要定義要注冊為安全的CLSID。
const CATID CATID_SafeForScripting = { 0x7dd95801, 0x9882, 0x11cf, { 0x9f, 0xa9, 0x00, 0xaa, 0x00, 0x6c, 0x42, 0xc4 } }; const CATID CATID_SafeForInitializing = { 0x7dd95802, 0x9882, 0x11cf, { 0x9f, 0xa9, 0x00, 0xaa, 0x00, 0x6c, 0x42, 0xc4 } }; const CATID CLSID_SafeItem = { 0xedb3ce, 0xe6b9, 0x4883, { 0x83, 0xc0, 0x3f, 0xbb, 0x40, 0xf7, 0x58, 0x5f } };
兩個GUID為CATID_SafeForScripting 、CATID_SafeForInitializing;安全的CLSID為CLSID_SafeItem。
在OCX控件注冊完成后,在注冊表的如下地方可以看到上面的兩個GUID。
1)32位版本位置:
HKEY_CLASSES_ROOT\Wow6432Node\CLSID\[xxxCtrl類的uuid]\Implemented Categories,下面有這兩個GUID。
2)64位版本位置:
HKEY_CLASSES_ROOT\CLSID\[xxxCtrl類的uuid]\Implemented Categories,下面有這兩個GUID。
注意:[xxxCtrl類的uuid]是xxx.idl文件中xxxCtrl的類信息的uuid。
CLSID_SafeItem的值是根據在xxxCtrl類實現文件(xxxCtrl.cpp)中IMPLEMENT_OLECREATE_EX的定義而來的(實際上就是ActiveX的CLASSID)。IMPLEMENT_OLECREATE_EX值如下:
第四步:修改OCX控件的注冊、反注冊代碼。
// DllRegisterServer - 將項添加到系統注冊表 STDAPI DllRegisterServer(void) { //AFX_MANAGE_STATE(_afxModuleAddrThis); //if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid)) // return ResultFromScode(SELFREG_E_TYPELIB); //if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE)) // return ResultFromScode(SELFREG_E_CLASS); //return NOERROR; //新注冊代碼 AFX_MANAGE_STATE(_afxModuleAddrThis); if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid)) return ResultFromScode(SELFREG_E_TYPELIB); if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE)) return ResultFromScode(SELFREG_E_CLASS); if (FAILED(CreateComponentCategory( CATID_SafeForScripting, L"Controls that are safely scriptable"))) return ResultFromScode(SELFREG_E_CLASS); if (FAILED(CreateComponentCategory( CATID_SafeForInitializing, L"Controls safely initializable from persistent data"))) return ResultFromScode(SELFREG_E_CLASS); if (FAILED(RegisterCLSIDInCategory( CLSID_SafeItem, CATID_SafeForScripting))) return ResultFromScode(SELFREG_E_CLASS); if (FAILED(RegisterCLSIDInCategory( CLSID_SafeItem, CATID_SafeForInitializing))) return ResultFromScode(SELFREG_E_CLASS); return NOERROR; } // DllUnregisterServer - 將項從系統注冊表中移除 STDAPI DllUnregisterServer(void) { //AFX_MANAGE_STATE(_afxModuleAddrThis); //if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor)) // return ResultFromScode(SELFREG_E_TYPELIB); //if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE)) // return ResultFromScode(SELFREG_E_CLASS); //return NOERROR; //新反注冊代碼 HRESULT hr; AFX_MANAGE_STATE(_afxModuleAddrThis); // Remove entries from the registry. hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing); if (FAILED(hr)) return hr; hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting); if (FAILED(hr)) return hr; if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor)) return ResultFromScode(SELFREG_E_TYPELIB); if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE)) return ResultFromScode(SELFREG_E_CLASS); return NOERROR; }
至此完成了注冊安全性的OCX控件。