使你的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;」前添加以下代碼:this

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

在DllUnregisterServer函數的「AFX_MANAGE_STATE(_afxModuleAddrThis);」後添加以下代碼:spa

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

 

 

方法2:實現ObjectSafe接口.net

我建立了一個MFC ActiveX ControlWizard的工程,工程爲TestAX,它的控件類是CTestAXCtrl,下面全部的代碼和操做都是在這個類的頭文件和實現文件中進行。紅色的部分是爲了實現ObjectSafe接口而增長的代碼。code

在頭文件中:orm

 

#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》。blog

 

原文連接接口

相關文章
相關標籤/搜索