如何将 MFC ActiveX 控件标记为可安全执行脚本和初始化


摘要


默认情况下,MFC ActiveX 控件不会标记为脚本安全和初始化安全。 在将安全级别设置为 "中" 或 "高" 的情况下,在 Internet Explorer 中运行控件时,这会很明显。 在这两种模式中,可能会显示警告:控件的数据不安全,或者控件可能不安全,以便脚本能够使用。控件可以使用两种方法来消除这些错误。 第一个涉及实现 IObjectSafety 接口的控件,对于想要更改其行为的控件很有用,如果在 Internet 浏览器的上下文中运行,则会变成 "安全的"。 第二个涉及修改控件的 DllRegisterServer 函数以将注册表中的控件标记为 "safe"。 本文介绍这些方法中的第二种。 第一种方法(实现 IObjectSafety 接口)将在 Internet 客户端 SDK 中介绍。请记住,如果控件实际上是安全的,应将其标记为安全。 有关此操作的说明,请参阅互联网客户端 SDK 文档。 请参阅 "组件开发" 部分下的 "ActiveX 控件的安全初始化和脚本编写"。注意 本文不介绍如何将控件标记为可安全下载。 有关代码下载和代码签名的详细信息,请参阅 Internet 客户端 SDK。

更多信息


请按照以下步骤将 MFC ActiveX 控件标记为可安全执行脚本和初始化的安全:
  1. 通过将以下 cathelp 和 cathelp 文件添加到你的项目来实现 CreateComponentCategory 和 RegisterCLSIDInCategory helper 函数。

    Cathelp.h

          #include "comcat.h"      // 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);

    Cathelp.cpp

          #include "comcat.h"      // Helper function to create a component category and associated      // description      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;      }      // Helper function to register a CLSID as belonging to a component      // category      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;      }
  2. 修改 DllRegisterServer 以将控件标记为安全。 在项目中的 .cpp 文件中找到 DllRegisterServer 的实现。 您需要将多项信息添加到此 .cpp 文件。 包括实现 CreateComponentCategory 和 RegisterCLSIDInCategory 的文件:
          #include "CatHelp.h"
    定义与安全组件类别关联的 GUID:
          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}};
    定义与你的控件关联的 GUID。 为简单起见,你可以从控件的主 .cpp 文件中的 IMPLEMENT_OLECREATE_EX 宏借用 GUID。 稍微调整格式,使其看起来如下所示:
          const GUID CDECL BASED_CODE _ctlid =      { 0x43bd9e45, 0x328f, 0x11d0,              { 0xa6, 0xb9, 0x0, 0xaa, 0x0, 0xa7, 0xf, 0xc2 } };
    若要将控件标记为可安全执行脚本和初始化,请修改 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);          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(                  _ctlid, CATID_SafeForScripting) ))                return ResultFromScode(SELFREG_E_CLASS);          if (FAILED( RegisterCLSIDInCategory(                  _ctlid, CATID_SafeForInitializing) ))                return ResultFromScode(SELFREG_E_CLASS);          return NOERROR;      }
由于以下两个原因,通常不会修改 DllUnregisterServer 函数:
  • 您不希望删除组件类别,因为其他控件可能会使用它。
  • 尽管定义了 UnRegisterCLSIDInCategory 函数,但默认情况下,DllUnregisterServer 从注册表中完全删除控件的条目。 因此,从控件的注册中删除类别几乎很少使用。
编译和注册控件后,应在注册表中找到以下条目:
   HKEY_CLASSES_ROOT\Component   Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}   HKEY_CLASSES_ROOT\Component   Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}   HKEY_CLASSES_ROOT\CLSID\{"your controls GUID"}\Implemented   Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}   HKEY_CLASSES_ROOT\CLSID\{"your controls GUID"}\Implemented   Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4} 

参考


Internet 客户端 SDK-针对 ActiveX 控件的组件开发安全初始化和脚本编写