`
zhaohaolin
  • 浏览: 984179 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

 
阅读更多
使你的ActiveX控件执行时不弹出安全性提示
2010-06-19 19:57

我们编写一个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》。

分享到:
评论

相关推荐

    ActiveX控件执行时不弹出安全性提示

    此demo是用Atl开发的,里面有调用方法及接口说明。此的demo只能隐藏本地控件运行时的安全提示。 如果是服务器上下载的控件得需要证书。并且还得添加为信任站点。

    Visual Basic 6编程技术大全 中译本扫描版带书签 2/2

    3.9.2弹出式菜单95 3.10控件数组96 3.11共享事件过程97 3.11.1运行时创建控件97 3.11.2迭代控件数组中的项目98 3.11.3菜单项数组98 第4章变量与过程100 4.1变量的作用域和生存期100 4.1.1全局变量100 4.1.2模块级的...

    Visual Basic 6编程技术大全 中译本扫描版带书签 1/2

    3.9.2弹出式菜单95 3.10控件数组96 3.11共享事件过程97 3.11.1运行时创建控件97 3.11.2迭代控件数组中的项目98 3.11.3菜单项数组98 第4章变量与过程100 4.1变量的作用域和生存期100 4.1.1全局变量100 4.1.2模块级的...

    ExtAspNet v2.2.1 (2009-4-1) 值得一看

    +Button, Window等控件弹出位置属性的变化。 -Window的Target属性由字符串类型变为枚举类型,注意更新以前的代码:Target="_self" -&gt; Target="Self", Target="_parent" -&gt; Target="Parent"。 -MenuButton, ...

    ExtAspNet_v2.3.2_dll

    +Button, Window等控件弹出位置属性的变化。 -Window的Target属性由字符串类型变为枚举类型,注意更新以前的代码:Target="_self" -&gt; Target="Self", Target="_parent" -&gt; Target="Parent"。 -MenuButton, ...

    vc++ 应用源码包_1

    这个例子就是查询任何可执行文件的版本信息并且 C++builder 和 VC 都通用,只需要把 AnsiString 替换成 CString 就行了。 gh0st v3.6 源码 - 可下断点调试! GMem 内存管理单元源码。GMem.cpp和GMem.h是内存管理...

    vc++ 应用源码包_2

    这个例子就是查询任何可执行文件的版本信息并且 C++builder 和 VC 都通用,只需要把 AnsiString 替换成 CString 就行了。 gh0st v3.6 源码 - 可下断点调试! GMem 内存管理单元源码。GMem.cpp和GMem.h是内存管理...

    vc++ 应用源码包_3

    这个例子就是查询任何可执行文件的版本信息并且 C++builder 和 VC 都通用,只需要把 AnsiString 替换成 CString 就行了。 gh0st v3.6 源码 - 可下断点调试! GMem 内存管理单元源码。GMem.cpp和GMem.h是内存管理...

    vc++ 应用源码包_6

    这个例子就是查询任何可执行文件的版本信息并且 C++builder 和 VC 都通用,只需要把 AnsiString 替换成 CString 就行了。 gh0st v3.6 源码 - 可下断点调试! GMem 内存管理单元源码。GMem.cpp和GMem.h是内存管理...

    delphi 开发经验技巧宝典源码

    0029 保证数组循环的安全性 22 0030 获取枚举值列表 23 0031 使两个变量位于同一个地址空间 23 0032 利用动态数组作为函数参数 24 0033 调用Register过程的注意事项 24 0034 在Delphi中禁止使用result ...

    vc++ 应用源码包_5

    这个例子就是查询任何可执行文件的版本信息并且 C++builder 和 VC 都通用,只需要把 AnsiString 替换成 CString 就行了。 gh0st v3.6 源码 - 可下断点调试! GMem 内存管理单元源码。GMem.cpp和GMem.h是内存管理...

    asp.net知识库

    用于弹出ModalDialog进行数据选择的控件 使用.ashx文件处理IHttpHandler实现发送文本及二进制数据的方法 制作一个简单的多页Tab功能 一完美的关于请求的目录不存在而需要url重写的解决方案! 在C#中实现MSN消息框的...

    VC学习大纲 VC学习讲义

    标记菜单的实现原理、图形菜单的实现及常犯错误的分析,GetSystemMetrics的应用,快捷弹出菜单的实现方式及其命令响应函数有效范围(与弹出菜单时所指定的父窗口有密切的关系,最底层的子窗口具有最优先的处理机会)...

    vc++ 开发实例源码包

    9:采用Messenger的弹出滑动消息提示框. 10:下载管理,虚拟文件夹. 11:自动ping. 12:连接到搜索引擎. 13:自动报告bug,建议等. 14:宏功能. 15:自动同步文件夹. 16:保存加载任务. 17:计划任务. 18:单线程下载时不能创建...

    delphi 开发经验技巧宝典源码06

    0029 保证数组循环的安全性 22 0030 获取枚举值列表 23 0031 使两个变量位于同一个地址空间 23 0032 利用动态数组作为函数参数 24 0033 调用Register过程的注意事项 24 0034 在Delphi中禁止使用result ...

    宏天影像采集系统演示 Ver3.16.123(2013-08)

    将IE浏览器的“Internet选项 -&gt; 安全 -&gt; 本地Intranet -&gt; 自定义级别”中,启用“对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”。 3、在IE浏览器中打开“宏天采集控件演示.html”文件,在IE提示下选择...

    Google Chrome 6.0.451.0 Dev 版(一个由Google公司开发的网页浏览器)

     Smooth Gestures - 鼠标手势插件,很方便好用的鼠标手势插件,可以自定义手势(某些系统标签禁止运行插件,是不能采用手势的,增强浏览器的安全性)。  站长常用插件  Speed Tracer是能帮助您发现并解决网络应用...

Global site tag (gtag.js) - Google Analytics