• 使你的ActiveX控件执行时不弹出安全性提示(转载)


    我们编写一个ActiveX控件在IE中运行,一般会弹出一个安全提示,如何避免这种情况?下面是我在参考前人的文章后,总结出“在浏览器中执行时不弹出警告的ActiveX控件”的两种编写方法,予以备忘。注意,这里不会弹出警告是说在执行时不会弹出,也就是说已经安装了这个ActiveX控件。如果要下载安装这个ActiveX控件时不会弹出安全警告,恐怕就得去买数字证书了。不过即使有数字证书,还是得用户同意后才会下载安装。
    以下两种方法在WINXP-SP2+VC6下通过。

    方法1:修改注册表 可能你在看完下面的过程后会发现,程序没有一个地方对注册表操作过。其实不然,这里所谓的修改注册表的方法就是使用组件类型管理器(Component Categories Manager)创建一个正确的入口到系统注册表。IE通过检测注册表判断一个控件是否可以安全地初始化和脚本操作。IE会通过调用 ICatInformation::IsClassOfCategories 方法确定控件是否支持给出的安全性分组。其中对注册表的操作都已经封装起来,隐藏在底层了,所以看不到。

    必须包括两个头文件

    #include <comcat.h>
    #include <Objsafe.h>
    
    
    const GUID CDECL CLSID_SafeItem = 
    {0xD321B11E, 0x8E79, 0x4829, 0xAB, 0x80, 0x9E, 0x59, 0x92, 0x06, 0xAB, 0xB7};//用你的控件类GUID替换
    // 注册组件种类为安全
    HRESULT AddCategorySafty(CATID catid, TCHAR* 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;
    
        CATEGORYINFO catinfo;
        catinfo.catid = catid;
        catinfo.lcid = 0x0409 ; // 英语语言
    
        // 最长只拷贝127个字符。
        int len = lstrlen(catDescription);
    if (len > 127)
    {
       len = 127;
    }
        lstrcpyn((TCHAR*)(catinfo.szDescription), catDescription, len+1);
    
        hr = pcr->RegisterCategories(1, &catinfo);
    pcr->Release();
    
        return hr;
    }
    
    //移除已经注册为安全的组件种类
    HRESULT RemoveCategorySafty(CATID catid)
    {
        ICatRegister* pcr = NULL ;
        HRESULT hr = S_OK ;
    
        hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
       NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
        if (FAILED(hr))
            return hr;
    
        hr = pcr->UnRegisterCategories(1, &catid);
    pcr->Release();
    
        return hr;
    }
    
    // 把你的控件注册到已经注册为安全的组件种类
    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;
    }
    // 把你的控件从安全组件种类移除
    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;
    }
    
    //使你的控件不弹出警告地执行
    HRESULT MakeActiveXSafty(REFCLSID clsid)
    {
    HRESULT hr;
    
        hr = AddCategorySafty(CATID_SafeForInitializing, 
       _T("Controls safely initializable!"));
        if (FAILED(hr))
            return hr;
        hr = RegisterCLSIDInCategory(clsid, CATID_SafeForInitializing);
        if (FAILED(hr))
            return hr;
    
        hr = AddCategorySafty(CATID_SafeForScripting, _T("Controls safely scriptable!"));
        if (FAILED(hr))
            return hr;
        hr = RegisterCLSIDInCategory(clsid, CATID_SafeForScripting);
    
    return hr;
    }
    
    //去除控件的安全执行性
    HRESULT UnMakeActiveXSafty(REFCLSID clsid)
    {
    HRESULT hr;
        hr = UnRegisterCLSIDInCategory(clsid, CATID_SafeForInitializing);
        if (FAILED(hr))
            return hr;
        hr = UnRegisterCLSIDInCategory(clsid, CATID_SafeForScripting);
        if (FAILED(hr))
            return hr;
    
    //下面的代码是把安全组件种类去掉。去掉的话,如果有其他的控件注册为这两个种类
    //那么其他的控件执行时就会弹出警告。需不需要下面的代码就见仁见智,看实际情况了
        hr = RemoveCategorySafty(CATID_SafeForInitializing);
        if (FAILED(hr))
            return hr;
        hr = RemoveCategorySafty(CATID_SafeForScripting);
    
    return hr;
    }

    然后在DllRegisterServer函数的“return NOERROR;”前添加如下代码:

    HRESULT hr = MakeActiveXSafty(CLSID_SafeItem);
    if (FAILED(hr))
            return hr;

    在DllUnregisterServer函数的“AFX_MANAGE_STATE(_afxModuleAddrThis);”后添加如下代码:

    HRESULT hr = UnMakeActiveXSafty(CLSID_SafeItem);
    if (FAILED(hr))
            OutputDebugString(_T("去除控件的安全执行性时出错!"));

    方法2:实现ObjectSafe接口

    我创建了一个MFC ActiveX ControlWizard的工程,工程为TestAX,它的控件类是CTestAXCtrl,下面所有的代码和操作都是在这个类的头文件和实现文件中进行。红色的部分是为了实现ObjectSafe接口而增加的代码。

    在头文件中:

    #if !defined(AFX_TESTAXCTL_H__C2084528_F93E_42D8_A13D_7E38775A0481__INCLUDED_)
    #define AFX_TESTAXCTL_H__C2084528_F93E_42D8_A13D_7E38775A0481__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    // #include <ComCat.h>
    #include <ObjSafe.h>//增加这个头文件
    
    // TestAXCtl.h : Declaration of the CTestAXCtrl ActiveX Control class.
    
    /////////////////////////////////////////////////////////////////////////////
    // CTestAXCtrl : See TestAXCtl.cpp for implementation.
    
    class CTestAXCtrl : public COleControl
    {
    DECLARE_DYNCREATE(CTestAXCtrl)
    
    // Constructor
    public:
    CTestAXCtrl();
    
    //增加如下代码:
    DECLARE_INTERFACE_MAP()
      
    BEGIN_INTERFACE_PART(MyObjSafe, IObjectSafety)
    STDMETHOD_(HRESULT, GetInterfaceSafetyOptions) ( 
       REFIID riid,
       DWORD __RPC_FAR *pdwSupportedOptions,
       DWORD __RPC_FAR *pdwEnabledOptions
       );
    
    STDMETHOD_(HRESULT, SetInterfaceSafetyOptions) ( 
       REFIID riid,
       DWORD dwOptionSetMask,
       DWORD dwEnabledOptions
       );
    END_INTERFACE_PART(MyObjSafe);
    
    。。。。。。
    
    在实现文件中:
    
    // TestAXCtl.cpp : Implementation of the CTestAXCtrl ActiveX Control class.
    
    #include "stdafx.h"
    #include "testAX.h"
    #include "TestAXCtl.h"
    #include "TestAXPpg.h"
    
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    
    IMPLEMENT_DYNCREATE(CTestAXCtrl, COleControl)
    
    //接口映射
    BEGIN_INTERFACE_MAP(CTestAXCtrl, COleControl )
    INTERFACE_PART(CTestAXCtrl, IID_IObjectSafety, MyObjSafe)
    END_INTERFACE_MAP()
    
    。。。。。。(其他代码省略)
    
    //接口的函数实现
    ULONG FAR EXPORT CTestAXCtrl::XMyObjSafe::AddRef()
    {
    METHOD_PROLOGUE(CTestAXCtrl, MyObjSafe)
    return pThis->ExternalAddRef();
    }
    
    ULONG FAR EXPORT CTestAXCtrl::XMyObjSafe::Release()
    {
    METHOD_PROLOGUE(CTestAXCtrl, MyObjSafe)
    return pThis->ExternalRelease();
    }
    
    HRESULT FAR EXPORT CTestAXCtrl::XMyObjSafe::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
    {
    METHOD_PROLOGUE(CTestAXCtrl, MyObjSafe)
    return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
    }
    
    //调用方法与数据是否可信任,设置这两个标志位就可以了
    const DWORD g_dwSupportedBits = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
    const DWORD g_dwNotSupportedBits = ~g_dwSupportedBits;
    
    HRESULT FAR EXPORT CTestAXCtrl::XMyObjSafe::GetInterfaceSafetyOptions(REFIID riid,
                       DWORD __RPC_FAR *pdwSupportedOptions,
                       DWORD __RPC_FAR *pdwEnabledOptions)
    {
    METHOD_PROLOGUE(CTestAXCtrl, MyObjSafe)
    *pdwSupportedOptions = *pdwEnabledOptions = g_dwSupportedBits;
    return S_OK;
    }
    
    HRESULT FAR EXPORT CTestAXCtrl::XMyObjSafe::SetInterfaceSafetyOptions(REFIID riid,
                       DWORD dwOptionSetMask,
                       DWORD dwEnabledOptions)
    {
    METHOD_PROLOGUE(CTestAXCtrl, MyObjSafe)
    
    //如果有任何一个不支持的设置位,则返回不支持错误。
    if (dwOptionSetMask & g_dwNotSupportedBits) 
    { 
       return CO_E_NOT_SUPPORTED;
    }
    //不需要做其他的事情
    return S_OK;
    }

    详细的接口实现步骤请参考MSDN的《TN038: MFC/OLE IUnknown Implementation》。

    原文链接

  • 相关阅读:
    一道打印的面试题
    Quartz使用总结
    子类和父类之间的静态代码块、静态方法、非静态代码块、构造函数之间的执行关系
    springboot使用 @EnableScheduling、@Scheduled开启定时任务
    springboot的Interceptor、Filter、Listener及注册
    ConcurrentHashMap 的工作原理及代码实现
    为什么Hashtable ConcurrentHashmap不支持key或者value为null
    Android 通过Java代码生成创建界面。动态生成View,动态设置View属性。addRules详解
    Android 自定义title 之Action Bar
    Android常用控件之GridView与ExpandableListView的用法
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/7771020.html
Copyright © 2020-2023  润新知