ActiveX控件实现安全的初始化和脚本

时间:2022-06-12 21:01:23

要想创建一个能够在IE中成功加载而没有“不安全”的警告或者错误提示信息的ActiveX控件,我们必须实现安全的初始化和脚本。基本上,所有要做的工作都是在DllRegisterServer 和DllUnregisterServer这两个函数中完成的。下面,我们就来一步步地将我们的ActiveX控件变成一个“安全的”控件。

       1. 编辑XXX(此处为控件的工程名).cpp并添加如下的代码。其中,CLSID_SafeItem的值应该跟XXXCtrl.cpp中的IMPLEMENT_OLECREATE_EX一致,这就等同于你的ActiveX控件。同样,它也应该跟你的HTML页面中的OBJECTID标签中的CLSID一致。

       以下是我工程中为实现安全的初始化和脚本添加的代码,可以与原先IDE自动生成的部分做对比查看那些部分是新增的,哪些部分是在创建ActiveX控件时自动生成的代码:

[cpp]  view plain  copy  print ?
  1. // CCEA.cpp : CCCEAApp 和 DLL 注册的实现。  
  2.   
  3. #include "stdafx.h"  
  4. #include "CCEA.h"  
  5. #include "ComCat.h"  
  6. #include "strsafe.h"  
  7. #include "ObjSafe.h"  
  8.   
  9. #ifdef _DEBUG  
  10. #define new DEBUG_NEW  
  11. #endif  
  12.   
  13.   
  14. CCCEAApp theApp;  
  15.   
  16. /*const GUID CDECL BASED_CODE _tlid = 
  17.         { 0x5E5EBDFC, 0x6D73, 0x4652, { 0x85, 0x3, 0x3F, 0xBF, 0x94, 0x7A, 0xCA, 0xD5 } };*/  
  18. const GUID CDECL BASED_CODE _tlid =  
  19.         { 0x1f7c5839, 0x4814, 0x4f2b, { 0xbd, 0x9e, 0x81, 0xd6, 0x2b, 0x59, 0x96, 0xaf } };  
  20. const GUID CDECL CLSID_SafeItem =  
  21.         { 0x6f82c754, 0x6c31, 0x43ea, { 0x98, 0x18, 0xe9, 0x5a, 0xd4, 0xe8, 0x72, 0xfc } };  
  22. const WORD _wVerMajor = 1;  
  23. const WORD _wVerMinor = 0;  
  24.   
  25.   
  26.   
  27. // CCCEAApp::InitInstance - DLL 初始化  
  28.   
  29. BOOL CCCEAApp::InitInstance()  
  30. {  
  31.     BOOL bInit = COleControlModule::InitInstance();  
  32.   
  33.     if (bInit)  
  34.     {  
  35.         // TODO: 在此添加您自己的模块初始化代码。  
  36.     }  
  37.   
  38.     return bInit;  
  39. }  
  40.   
  41.   
  42.   
  43. // CCCEAApp::ExitInstance - DLL 终止  
  44.   
  45. int CCCEAApp::ExitInstance()  
  46. {  
  47.     // TODO: 在此添加您自己的模块终止代码。  
  48.   
  49.     return COleControlModule::ExitInstance();  
  50. }  
  51.   
  52. //创建Component Categories中的初始化安全和脚本安全项  
  53. HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)  
  54. {  
  55.     ICatRegister *pcr = NULL ;  
  56.     HRESULT hr = S_OK ;  
  57.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,   
  58.             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
  59.     if (FAILED(hr))  
  60.         return hr;  
  61.   
  62.     // 确认HKCR\Component Categories\{..catid...}键值被注册  
  63.     CATEGORYINFO catinfo;  
  64.     catinfo.catid = catid;  
  65.     catinfo.lcid = 0x0409; // english  
  66.     //size_t len;  
  67.     // 确认描述不是太长。  
  68.     // 只复制开始的127个字符。  
  69.     // StringCchLength的第二个参数表示被读入catDescription的最大字符数。  
  70.     // 第三个参数表示字符串的长度  
  71.     //hr = StringCchLength(catDescription, STRSAFE_MAX_CCH, &len);  
  72.     int len = wcslen(catDescription);  
  73.     if (SUCCEEDED(hr))  
  74.     {  
  75.         if (len>127)  
  76.         {  
  77.             len = 127;  
  78.         }  
  79.     }     
  80.     else  
  81.     {  
  82.         // TODO: Write an error handler;  
  83.     }  
  84.   
  85.     wcsncpy(catinfo.szDescription, catDescription, len);  
  86.     //hr = StringCchCopy(catinfo.szDescription, len + 1, catDescription);  
  87.     // 添加字符串结束符.  
  88.     //catinfo.szDescription[len + 1] = '\0';  
  89.     catinfo.szDescription[len] = '/0';  
  90.   
  91.     hr = pcr->RegisterCategories(1, &catinfo);  
  92.     pcr->Release();  
  93.     return hr;  
  94. }  


       2. 然后需要添加注册组件分类信息

       同样是在XXX(此处为控件的工程名).cpp并添加如下的代码:

[cpp]  view plain  copy  print ?
  1. //在CLSID中创建与Component Categories中初始化安全和脚本安全项中相对应的implemented Categories项  
  2. HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)  
  3. {  
  4.     // 注册组件分类信息  
  5.     ICatRegister *pcr = NULL ;  
  6.     HRESULT hr = S_OK ;  
  7.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,   
  8.                 NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
  9.   
  10.     if (SUCCEEDED(hr))  
  11.     {  
  12.        CATID rgcatid[1] ;  
  13.        rgcatid[0] = catid;  
  14.        hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);  
  15.     }  
  16.   
  17.     if (pcr != NULL)  
  18.         pcr->Release();  
  19.               
  20.     return hr;  
  21.   
  22. }  
  23.   
  24. //注销与CLSID中的相应implemented Categories项,一般用不到,因为其它程序可能也会用到这此项  
  25. HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)  
  26. {  
  27.     ICatRegister *pcr = NULL ;  
  28.     HRESULT hr = S_OK ;  
  29.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,   
  30.             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
  31.   
  32.     if (SUCCEEDED(hr))  
  33.     {  
  34.        CATID rgcatid[1] ;  
  35.        rgcatid[0] = catid;  
  36.        hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);  
  37.     }  
  38.   
  39.     if (pcr != NULL)  
  40.         pcr->Release();  
  41.     return hr;  
  42. }  


       这两个方法是全新的必须添加。

       3. 需要修改DllRegisterServer函数如下,可以与原先IDE自动生成的部分做对比查看需要增加的部分:

[cpp]  view plain  copy  print ?
  1. // DllRegisterServer - 将项添加到系统注册表  
  2.   
  3. STDAPI DllRegisterServer(void)  
  4. {  
  5.     AFX_MANAGE_STATE(_afxModuleAddrThis);  
  6.   
  7.     if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))  
  8.         return ResultFromScode(SELFREG_E_TYPELIB);  
  9.   
  10.     if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))  
  11.         return ResultFromScode(SELFREG_E_CLASS);  
  12.   
  13.     //创建脚本安全“补充”项,非CLSID中  
  14.     HRESULT hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");  
  15.     if (FAILED(hr))  
  16.         return hr;  
  17.   
  18.     //创建初始化安全“补充”项,非CLSID中  
  19.     hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");  
  20.     if (FAILED(hr))  
  21.         return hr;  
  22.   
  23.     //设置控件CLSID中补充项的脚本安全项,与“补充”项中的脚本安全项对应  
  24.     hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);  
  25.     if (FAILED(hr))  
  26.         return hr;  
  27.   
  28.     //设置控件CLSID中补充项的初始化安全项,与“补充”项中的初始化安全项对应  
  29.     hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);  
  30.     if (FAILED(hr))  
  31.         return hr;  
  32.   
  33.     return NOERROR;  
  34. }  


       4. 最后修改修改DllUnregisterServer函数,可以与原先IDE自动生成的部分做对比查看需要增加的部分:

[cpp]  view plain  copy  print ?
  1. // DllUnregisterServer - 将项从系统注册表中移除  
  2.   
  3. STDAPI DllUnregisterServer(void)  
  4. {  
  5.     AFX_MANAGE_STATE(_afxModuleAddrThis);  
  6.     if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))  
  7.         return ResultFromScode(SELFREG_E_TYPELIB);  
  8.   
  9.     if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))  
  10.         return ResultFromScode(SELFREG_E_CLASS);  
  11.   
  12.     // 删除控件初始化安全入口.  
  13.     HRESULT hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);  
  14.     if (FAILED(hr))  
  15.         return hr;  
  16.   
  17.     // 删除控件脚本安全入口  
  18.     hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);  
  19.     if (FAILED(hr))  
  20.         return hr;  
  21.   
  22.     return NOERROR;  
  23. }  


       以上部分在其它控件的工程均是可以复用的,只需要注意CLSID_SafeItem的正确性,最终实现了控件全的初始和脚本,在XXX(此处为控件的工程名).cpp中完整的代码如下供大家参考:

[cpp]  view plain  copy  print ?
  1. // CCEA.cpp : CCCEAApp 和 DLL 注册的实现。  
  2.   
  3. #include "stdafx.h"  
  4. #include "CCEA.h"  
  5. #include "ComCat.h"  
  6. #include "strsafe.h"  
  7. #include "ObjSafe.h"  
  8.   
  9. #ifdef _DEBUG  
  10. #define new DEBUG_NEW  
  11. #endif  
  12.   
  13.   
  14. CCCEAApp theApp;  
  15.   
  16. /*const GUID CDECL BASED_CODE _tlid = 
  17.         { 0x5E5EBDFC, 0x6D73, 0x4652, { 0x85, 0x3, 0x3F, 0xBF, 0x94, 0x7A, 0xCA, 0xD5 } };*/  
  18. const GUID CDECL BASED_CODE _tlid =  
  19.         { 0x1f7c5839, 0x4814, 0x4f2b, { 0xbd, 0x9e, 0x81, 0xd6, 0x2b, 0x59, 0x96, 0xaf } };  
  20. const GUID CDECL CLSID_SafeItem =  
  21.         { 0x6f82c754, 0x6c31, 0x43ea, { 0x98, 0x18, 0xe9, 0x5a, 0xd4, 0xe8, 0x72, 0xfc } };  
  22. const WORD _wVerMajor = 1;  
  23. const WORD _wVerMinor = 0;  
  24.   
  25.   
  26.   
  27. // CCCEAApp::InitInstance - DLL 初始化  
  28.   
  29. BOOL CCCEAApp::InitInstance()  
  30. {  
  31.     BOOL bInit = COleControlModule::InitInstance();  
  32.   
  33.     if (bInit)  
  34.     {  
  35.         // TODO: 在此添加您自己的模块初始化代码。  
  36.     }  
  37.   
  38.     return bInit;  
  39. }  
  40.   
  41.   
  42.   
  43. // CCCEAApp::ExitInstance - DLL 终止  
  44.   
  45. int CCCEAApp::ExitInstance()  
  46. {  
  47.     // TODO: 在此添加您自己的模块终止代码。  
  48.   
  49.     return COleControlModule::ExitInstance();  
  50. }  
  51.   
  52. //创建Component Categories中的初始化安全和脚本安全项  
  53. HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)  
  54. {  
  55.     ICatRegister *pcr = NULL ;  
  56.     HRESULT hr = S_OK ;  
  57.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,   
  58.             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
  59.     if (FAILED(hr))  
  60.         return hr;  
  61.   
  62.     // 确认HKCR\Component Categories\{..catid...}键值被注册  
  63.     CATEGORYINFO catinfo;  
  64.     catinfo.catid = catid;  
  65.     catinfo.lcid = 0x0409; // english  
  66.     //size_t len;  
  67.     // 确认描述不是太长。  
  68.     // 只复制开始的127个字符。  
  69.     // StringCchLength的第二个参数表示被读入catDescription的最大字符数。  
  70.     // 第三个参数表示字符串的长度  
  71.     //hr = StringCchLength(catDescription, STRSAFE_MAX_CCH, &len);  
  72.     int len = wcslen(catDescription);  
  73.     if (SUCCEEDED(hr))  
  74.     {  
  75.         if (len>127)  
  76.         {  
  77.             len = 127;  
  78.         }  
  79.     }     
  80.     else  
  81.     {  
  82.         // TODO: Write an error handler;  
  83.     }  
  84.   
  85.     wcsncpy(catinfo.szDescription, catDescription, len);  
  86.     //hr = StringCchCopy(catinfo.szDescription, len + 1, catDescription);  
  87.     // 添加字符串结束符.  
  88.     //catinfo.szDescription[len + 1] = '\0';  
  89.     catinfo.szDescription[len] = '/0';  
  90.   
  91.     hr = pcr->RegisterCategories(1, &catinfo);  
  92.     pcr->Release();  
  93.     return hr;  
  94. }  
  95.   
  96. //在CLSID中创建与Component Categories中初始化安全和脚本安全项中相对应的implemented Categories项  
  97. HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)  
  98. {  
  99.     // 注册组件分类信息  
  100.     ICatRegister *pcr = NULL ;  
  101.     HRESULT hr = S_OK ;  
  102.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,   
  103.                 NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
  104.   
  105.     if (SUCCEEDED(hr))  
  106.     {  
  107.        CATID rgcatid[1] ;  
  108.        rgcatid[0] = catid;  
  109.        hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);  
  110.     }  
  111.   
  112.     if (pcr != NULL)  
  113.         pcr->Release();  
  114.               
  115.     return hr;  
  116.   
  117. }  
  118.   
  119. //注销与CLSID中的相应implemented Categories项,一般用不到,因为其它程序可能也会用到这此项  
  120. HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)  
  121. {  
  122.     ICatRegister *pcr = NULL ;  
  123.     HRESULT hr = S_OK ;  
  124.     hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,   
  125.             NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);  
  126.   
  127.     if (SUCCEEDED(hr))  
  128.     {  
  129.        CATID rgcatid[1] ;  
  130.        rgcatid[0] = catid;  
  131.        hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);  
  132.     }  
  133.   
  134.     if (pcr != NULL)  
  135.         pcr->Release();  
  136.     return hr;  
  137. }  
  138.   
  139.   
  140. // DllRegisterServer - 将项添加到系统注册表  
  141.   
  142. STDAPI DllRegisterServer(void)  
  143. {  
  144.     AFX_MANAGE_STATE(_afxModuleAddrThis);  
  145.   
  146.     if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))  
  147.         return ResultFromScode(SELFREG_E_TYPELIB);  
  148.   
  149.     if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))  
  150.         return ResultFromScode(SELFREG_E_CLASS);  
  151.   
  152.     //创建脚本安全“补充”项,非CLSID中  
  153.     HRESULT hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");  
  154.     if (FAILED(hr))  
  155.         return hr;  
  156.   
  157.     //创建初始化安全“补充”项,非CLSID中  
  158.     hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");  
  159.     if (FAILED(hr))  
  160.         return hr;  
  161.   
  162.     //设置控件CLSID中补充项的脚本安全项,与“补充”项中的脚本安全项对应  
  163.     hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);  
  164.     if (FAILED(hr))  
  165.         return hr;  
  166.   
  167.     //设置控件CLSID中补充项的初始化安全项,与“补充”项中的初始化安全项对应  
  168.     hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);  
  169.     if (FAILED(hr))  
  170.         return hr;  
  171.   
  172.     return NOERROR;  
  173. }  
  174.   
  175.   
  176. // DllUnregisterServer - 将项从系统注册表中移除  
  177.   
  178. STDAPI DllUnregisterServer(void)  
  179. {  
  180.     AFX_MANAGE_STATE(_afxModuleAddrThis);  
  181.     if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))  
  182.         return ResultFromScode(SELFREG_E_TYPELIB);  
  183.   
  184.     if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))  
  185.         return ResultFromScode(SELFREG_E_CLASS);  
  186.   
  187.     // 删除控件初始化安全入口.  
  188.     HRESULT hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);  
  189.     if (FAILED(hr))  
  190.         return hr;  
  191.   
  192.     // 删除控件脚本安全入口  
  193.     hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);  
  194.     if (FAILED(hr))  
  195.         return hr;  
  196.   
  197.     return NOERROR;  
  198. }  


       这时你就能创建一个能够在IE中成功加载而没有“不安全”的警告或者错误提示信息的ActiveX控件了。


From:http://blog.csdn.net/waxgourd0/article/details/7411620