要想创建一个能够在IE中成功加载而没有“不安全”的警告或者错误提示信息的ActiveX控件,我们必须实现安全的初始化和脚本。基本上,所有要做的工作都是在DllRegisterServer 和DllUnregisterServer这两个函数中完成的。下面,我们就来一步步地将我们的ActiveX控件变成一个“安全的”控件。
1. 编辑XXX(此处为控件的工程名).cpp并添加如下的代码。其中,CLSID_SafeItem的值应该跟XXXCtrl.cpp中的IMPLEMENT_OLECREATE_EX一致,这就等同于你的ActiveX控件。同样,它也应该跟你的HTML页面中的OBJECTID标签中的CLSID一致。
以下是我工程中为实现安全的初始化和脚本添加的代码,可以与原先IDE自动生成的部分做对比查看那些部分是新增的,哪些部分是在创建ActiveX控件时自动生成的代码:
- // CCEA.cpp : CCCEAApp 和 DLL 注册的实现。
- #include "stdafx.h"
- #include "CCEA.h"
- #include "ComCat.h"
- #include "strsafe.h"
- #include "ObjSafe.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- CCCEAApp theApp;
- /*const GUID CDECL BASED_CODE _tlid =
- { 0x5E5EBDFC, 0x6D73, 0x4652, { 0x85, 0x3, 0x3F, 0xBF, 0x94, 0x7A, 0xCA, 0xD5 } };*/
- const GUID CDECL BASED_CODE _tlid =
- { 0x1f7c5839, 0x4814, 0x4f2b, { 0xbd, 0x9e, 0x81, 0xd6, 0x2b, 0x59, 0x96, 0xaf } };
- const GUID CDECL CLSID_SafeItem =
- { 0x6f82c754, 0x6c31, 0x43ea, { 0x98, 0x18, 0xe9, 0x5a, 0xd4, 0xe8, 0x72, 0xfc } };
- const WORD _wVerMajor = 1;
- const WORD _wVerMinor = 0;
- // CCCEAApp::InitInstance - DLL 初始化
- BOOL CCCEAApp::InitInstance()
- {
- BOOL bInit = COleControlModule::InitInstance();
- if (bInit)
- {
- // TODO: 在此添加您自己的模块初始化代码。
- }
- return bInit;
- }
- // CCCEAApp::ExitInstance - DLL 终止
- int CCCEAApp::ExitInstance()
- {
- // TODO: 在此添加您自己的模块终止代码。
- return COleControlModule::ExitInstance();
- }
- //创建Component Categories中的初始化安全和脚本安全项
- 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;
- // 确认HKCR\Component Categories\{..catid...}键值被注册
- CATEGORYINFO catinfo;
- catinfo.catid = catid;
- catinfo.lcid = 0x0409; // english
- //size_t len;
- // 确认描述不是太长。
- // 只复制开始的127个字符。
- // StringCchLength的第二个参数表示被读入catDescription的最大字符数。
- // 第三个参数表示字符串的长度
- //hr = StringCchLength(catDescription, STRSAFE_MAX_CCH, &len);
- int len = wcslen(catDescription);
- if (SUCCEEDED(hr))
- {
- if (len>127)
- {
- len = 127;
- }
- }
- else
- {
- // TODO: Write an error handler;
- }
- wcsncpy(catinfo.szDescription, catDescription, len);
- //hr = StringCchCopy(catinfo.szDescription, len + 1, catDescription);
- // 添加字符串结束符.
- //catinfo.szDescription[len + 1] = '\0';
- catinfo.szDescription[len] = '/0';
- hr = pcr->RegisterCategories(1, &catinfo);
- pcr->Release();
- return hr;
- }
2. 然后需要添加注册组件分类信息
同样是在XXX(此处为控件的工程名).cpp并添加如下的代码:
- //在CLSID中创建与Component Categories中初始化安全和脚本安全项中相对应的implemented Categories项
- HRESULT RegisterCLSIDInCategory(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))
- {
- CATID rgcatid[1] ;
- rgcatid[0] = catid;
- hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
- }
- if (pcr != NULL)
- pcr->Release();
- return hr;
- }
- //注销与CLSID中的相应implemented Categories项,一般用不到,因为其它程序可能也会用到这此项
- 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))
- {
- CATID rgcatid[1] ;
- rgcatid[0] = catid;
- hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
- }
- if (pcr != NULL)
- pcr->Release();
- return hr;
- }
这两个方法是全新的必须添加。
3. 需要修改DllRegisterServer函数如下,可以与原先IDE自动生成的部分做对比查看需要增加的部分:
- // 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);
- //创建脚本安全“补充”项,非CLSID中
- HRESULT hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");
- if (FAILED(hr))
- return hr;
- //创建初始化安全“补充”项,非CLSID中
- hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");
- if (FAILED(hr))
- return hr;
- //设置控件CLSID中补充项的脚本安全项,与“补充”项中的脚本安全项对应
- hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
- if (FAILED(hr))
- return hr;
- //设置控件CLSID中补充项的初始化安全项,与“补充”项中的初始化安全项对应
- hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
- if (FAILED(hr))
- return hr;
- return NOERROR;
- }
4. 最后修改修改DllUnregisterServer函数,可以与原先IDE自动生成的部分做对比查看需要增加的部分:
- // 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);
- // 删除控件初始化安全入口.
- HRESULT hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
- if (FAILED(hr))
- return hr;
- // 删除控件脚本安全入口
- hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
- if (FAILED(hr))
- return hr;
- return NOERROR;
- }
以上部分在其它控件的工程均是可以复用的,只需要注意CLSID_SafeItem的正确性,最终实现了控件安全的初始化和脚本,在XXX(此处为控件的工程名).cpp中完整的代码如下供大家参考:
- // CCEA.cpp : CCCEAApp 和 DLL 注册的实现。
- #include "stdafx.h"
- #include "CCEA.h"
- #include "ComCat.h"
- #include "strsafe.h"
- #include "ObjSafe.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- CCCEAApp theApp;
- /*const GUID CDECL BASED_CODE _tlid =
- { 0x5E5EBDFC, 0x6D73, 0x4652, { 0x85, 0x3, 0x3F, 0xBF, 0x94, 0x7A, 0xCA, 0xD5 } };*/
- const GUID CDECL BASED_CODE _tlid =
- { 0x1f7c5839, 0x4814, 0x4f2b, { 0xbd, 0x9e, 0x81, 0xd6, 0x2b, 0x59, 0x96, 0xaf } };
- const GUID CDECL CLSID_SafeItem =
- { 0x6f82c754, 0x6c31, 0x43ea, { 0x98, 0x18, 0xe9, 0x5a, 0xd4, 0xe8, 0x72, 0xfc } };
- const WORD _wVerMajor = 1;
- const WORD _wVerMinor = 0;
- // CCCEAApp::InitInstance - DLL 初始化
- BOOL CCCEAApp::InitInstance()
- {
- BOOL bInit = COleControlModule::InitInstance();
- if (bInit)
- {
- // TODO: 在此添加您自己的模块初始化代码。
- }
- return bInit;
- }
- // CCCEAApp::ExitInstance - DLL 终止
- int CCCEAApp::ExitInstance()
- {
- // TODO: 在此添加您自己的模块终止代码。
- return COleControlModule::ExitInstance();
- }
- //创建Component Categories中的初始化安全和脚本安全项
- 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;
- // 确认HKCR\Component Categories\{..catid...}键值被注册
- CATEGORYINFO catinfo;
- catinfo.catid = catid;
- catinfo.lcid = 0x0409; // english
- //size_t len;
- // 确认描述不是太长。
- // 只复制开始的127个字符。
- // StringCchLength的第二个参数表示被读入catDescription的最大字符数。
- // 第三个参数表示字符串的长度
- //hr = StringCchLength(catDescription, STRSAFE_MAX_CCH, &len);
- int len = wcslen(catDescription);
- if (SUCCEEDED(hr))
- {
- if (len>127)
- {
- len = 127;
- }
- }
- else
- {
- // TODO: Write an error handler;
- }
- wcsncpy(catinfo.szDescription, catDescription, len);
- //hr = StringCchCopy(catinfo.szDescription, len + 1, catDescription);
- // 添加字符串结束符.
- //catinfo.szDescription[len + 1] = '\0';
- catinfo.szDescription[len] = '/0';
- hr = pcr->RegisterCategories(1, &catinfo);
- pcr->Release();
- return hr;
- }
- //在CLSID中创建与Component Categories中初始化安全和脚本安全项中相对应的implemented Categories项
- HRESULT RegisterCLSIDInCategory(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))
- {
- CATID rgcatid[1] ;
- rgcatid[0] = catid;
- hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
- }
- if (pcr != NULL)
- pcr->Release();
- return hr;
- }
- //注销与CLSID中的相应implemented Categories项,一般用不到,因为其它程序可能也会用到这此项
- 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))
- {
- CATID rgcatid[1] ;
- rgcatid[0] = catid;
- hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
- }
- if (pcr != NULL)
- pcr->Release();
- return hr;
- }
- // 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);
- //创建脚本安全“补充”项,非CLSID中
- HRESULT hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");
- if (FAILED(hr))
- return hr;
- //创建初始化安全“补充”项,非CLSID中
- hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");
- if (FAILED(hr))
- return hr;
- //设置控件CLSID中补充项的脚本安全项,与“补充”项中的脚本安全项对应
- hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
- if (FAILED(hr))
- return hr;
- //设置控件CLSID中补充项的初始化安全项,与“补充”项中的初始化安全项对应
- hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
- if (FAILED(hr))
- return hr;
- 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);
- // 删除控件初始化安全入口.
- HRESULT hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
- if (FAILED(hr))
- return hr;
- // 删除控件脚本安全入口
- hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
- if (FAILED(hr))
- return hr;
- return NOERROR;
- }
这时你就能创建一个能够在IE中成功加载而没有“不安全”的警告或者错误提示信息的ActiveX控件了。
From:http://blog.csdn.net/waxgourd0/article/details/7411620