分享

基于MFC的Activex 安全

 昵称597197 2011-02-25

刚接触用MFC编写ActiveX,遇到的麻烦还真不少。想将MFC界面放到控件里面去,最后终于搞定,
【1】,编写控件
对话框界面类 CTestDlg
控件类 CMFCOcxCtrl
int CMFCOcxCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (COleControl::OnCreate(lpCreateStruct) == -1)
  return -1;

       m_pTestDlg = new CTestDlg;
 m_pTestDlg ->Create( IDD_TEST_DIALOG, this );
 int iScreenX = GetSystemMetrics( SM_CXSCREEN );
 int iScreenY = GetSystemMetrics( SM_CYSCREEN );
 int iStandardX = 824;
 int iStandardY = 618;

 CRect rect;
 rect.left = 0;
 rect.top = 0;
 rect.right = iStandardX;
 rect.bottom = iStandardY;
 m_pTestDlg ->MoveWindow( &rect );
 m_pTestDlg ->ShowWindow( SW_SHOW );

 return 0;
}
终于在网页中出现了对话框。这个网页是在本地的html文件
【2】设置控件安全初始化和脚本安全初始化
 我是采用的实现 IObjectSafety 接口:以下
---------------------------------------
MFCOcxCtrl.h
  #include <ObjSafe.h>
  class CMFCOcxCtrl : public COleControl
 {
     DECLARE_DYNCREATE(CMFCOcxCtrl)

 DECLARE_INTERFACE_MAP()
 BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)
  STDMETHOD_(HRESULT, GetInterfaceSafetyOptions) (
  /* [in] */ REFIID riid,
  /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
  /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions
  );

  STDMETHOD_(HRESULT, SetInterfaceSafetyOptions) (
   /* [in] */ REFIID riid,
   /* [in] */ DWORD dwOptionSetMask,
   /* [in] */ DWORD dwEnabledOptions
   );
 END_INTERFACE_PART(ObjSafe);
    //.............
 }
MFCOcxCtrl.cpp
 // Interface map for IObjectSafety
      BEGIN_INTERFACE_MAP( CMonitorClientOcxCtrl, COleControl )
             INTERFACE_PART(CMonitorClientOcxCtrl, IID_IObjectSafety, ObjSafe)
      END_INTERFACE_MAP()
      /////////////////////////////////////////////////////////////////////////////
// IObjectSafety member functions

// Delegate AddRef, Release, QueryInterface

ULONG FAR EXPORT CMFCOcxCtrl::XObjSafe::AddRef()
{
 METHOD_PROLOGUE(CMFCOcxCtrl, ObjSafe)
  return pThis->ExternalAddRef();
}

ULONG FAR EXPORT CMFCOcxCtrl::XObjSafe::Release()
{
 METHOD_PROLOGUE(CMFCOcxCtrl, ObjSafe)
  return pThis->ExternalRelease();
}

HRESULT FAR EXPORT CMFCOcxCtrl::XObjSafe::QueryInterface(
 REFIID iid, void FAR* FAR* ppvObj)
{
 METHOD_PROLOGUE(CMFCOcxCtrl, ObjSafe)
  return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

const DWORD dwSupportedBits =
INTERFACESAFE_FOR_UNTRUSTED_CALLER |
INTERFACESAFE_FOR_UNTRUSTED_DATA;
const DWORD dwNotSupportedBits = ~ dwSupportedBits;

/*
-------------------------------------------------------------
CPlayerCtrl::XObjSafe::GetInterfaceSafetyOptions
Allows container to query what interfaces are safe for what. We're
optimizing significantly by ignoring which interface the caller is
asking for.
----------------------------------------------------------------
*/
HRESULT STDMETHODCALLTYPE
CMFCOcxCtrl::XObjSafe::GetInterfaceSafetyOptions(
 /* [in] */ REFIID riid,
 /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
 /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions)
{
 METHOD_PROLOGUE(CMFCOcxCtrl, ObjSafe)

  HRESULT retval = ResultFromScode(S_OK);

 // does interface exist?
 IUnknown FAR* punkInterface;
 retval = pThis->ExternalQueryInterface(&riid,
  (void * *)&punkInterface);
 if (retval != E_NOINTERFACE) { // interface exists
  punkInterface->Release(); // release it--just checking!
 }

 /*
 we support both kinds of safety and have always both set,
 regardless of interface
 */
 *pdwSupportedOptions = *pdwEnabledOptions = dwSupportedBits;

 return retval; // E_NOINTERFACE if QI failed
}

/*
----------------------------------------------------------------------
CPlayerCtrl::XObjSafe::SetInterfaceSafetyOptions
Since we're always safe, this is a no-brainer--but we do check to make
sure the interface requested exists and that the options we're asked to
set exist and are set on (we don't support unsafe mode).
---------------------------------------------------------------------
*/
HRESULT STDMETHODCALLTYPE
CMFCOcxCtrl::XObjSafe::SetInterfaceSafetyOptions(
 /* [in] */ REFIID riid,
 /* [in] */ DWORD dwOptionSetMask,
 /* [in] */ DWORD dwEnabledOptions)
{
 METHOD_PROLOGUE(CMFCOcxCtrl, ObjSafe)

  // does interface exist?
  IUnknown FAR* punkInterface;
 pThis->ExternalQueryInterface(&riid, (void * *)&punkInterface);
 if (punkInterface) { // interface exists
  punkInterface->Release(); // release it--just checking!
 }
 else { // interface doesn't exist
  return ResultFromScode(E_NOINTERFACE);
 }

 // can't set bits we don't support
 if (dwOptionSetMask & dwNotSupportedBits) {
  return ResultFromScode(E_FAIL);
 }

 // can't set bits we do support to zero
 dwEnabledOptions &= dwSupportedBits;
 // (we already know there are no extra bits in mask )
 if ((dwOptionSetMask & dwEnabledOptions) !=
  dwOptionSetMask) {
   return ResultFromScode(E_FAIL);
 }

 // don't need to change anything since we're always safe
 return ResultFromScode(S_OK);
}
------------------------------------------------------------------
完毕。


 以下据说也可以:(转载)
 请按照下列步骤来 MFC ActiveX 控件标记为对于脚本安全和对初始化安全: 1. 通过向项目添加下列 cathelp.h 和 cathelp.cpp 文件实现 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。 为简单起见, 您可借用 GUID 从 IMPLEMENT_OLECREATE_EX 宏对控件主 .cpp 文件中。 略微调整格式: 它类似下面这样       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 函数: 因此两 • 您不希望删除组件类别, 因为它可能使用其他控件。 
• DllUnregisterServer 虽然有是 UnRegisterCLSIDInCategory 函数定义, 默认从注册表删除控件的项完全。 因此, 从控件注册删除类别是很少使用。 
应编译和注册控件, 后, 在注册表中找到以下项:    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}


【3】,控件与网页交互
如果想在网页中调用该控件,需要添加对外的接口,然后直接用html或者脚本语言调用即可。
如果想让控件通知网页,就需要为控件添加事件,然后在需要通知的地方激发一下事件即可,当然网页中也要检测事件,这里用JavaScript做个例子:
在控件中有事件:
void onCloseWindow(void)
{
 FireEvent(eventidonCloseWindow, EVENT_PARAM(VTS_NONE));
}
在网页中有:
<script for="MFCOCX" EVENT="onCloseWindow()" language="javascript">
    alert("Event Fire");
</script>

【4】,发布控件
(1),打包
用到的工具CABARC.EXE,MAKECAB.EXE
需要配置inf文件,例如:
[Version]
Signature="$Chicago$"
AdvancedINF=2.5

[DefaultInstall]
CopyFiles=MFCOcx,config
RegisterOCXs=RegisterOCXSection

[RegisterOCXSection]
%11%\MFCOcx.ocx

[SourceDisksNames]
1="MFCOcx Files","MFCOcx.cab",1

[SourceDisksFiles]
MFCOcx.ocx=1

[MFCOcx]
MFCOcx.ocx,,,33
relate.dll,,,33

[config]
setting.ini,,,33

[DestinationDirs]
MFCOcx.ocx=11
config=11,MFCTestOcx\default

打成CAB包cabarc.exe n MFCOcx.cab MFCOcx.ocx MFCOcx.inf  relate.dll setting.ini

(2)数字签名,工具:makecert.exe signcode.exe cert2spc.exe EXTRACT.EXE

做成一个简单的批处理:
echo "make cab..."
cabarc.exe n MFCOcx.cab MFCOcx.ocx MFCOcx.inf  relate.dll setting.ini
makecert.exe -n CN=mycom -sv test.pvk -r test.cer
cert2spc.exe test.cer test.spc
signcode.exe -spc  test.spc -v  test.pvk -t http://timestamp./scripts/timstamp.dll MFCOcx.cab

echo "make MFCOcx.cab finished."

然后将制作的cab文件和网页放到服务器上即可。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多