1. 创建ActiveX控件

以管理员身份运行VS2010(这里注意,一定要确保当前处于管理员运行状态,否则后续注册控件的时候会有问题),新建MFC  ActiveX项目

下一步,“运行时许可证”不用勾选,下一步,勾选“在插入对话框中可用”

点击完成。

修改输出环境为release 32位

修改项目属性:选择菜单栏项目——ActiveXDemo属性——配置属性——常规

修改两处地方   “MFC的使用”和“字符集”,如下图所示

修改完点击确认即可

插入对话框,修改属性  visible改为true,style改为child

为新建的对话框新建类CActiveXDlg

在CActiveXDemoCtrl类的头文件中引用刚才的类

#include "ActiveXDlg.h"

在public中定义该对话框的一个对象

CActiveXDlg m_MyDlg;

接下来为CActiveXDemoCtrl类添加WM_CREATE消息响应OnCreate函数,添加代码如下

int CActiveXDemoCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (COleControl::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码
	m_MyDlg.Create(IDD_DIALOG1,this);  //初始化对话框
	return 0;
}

上述步骤主要将新建的对话框对象绑定到控件上,接下来需要在控件上显示该对话框。编辑CActiveXDemoCtrl类的OnDraw函数,注释掉两行绘图代码,改成下面的形式:

void CActiveXDemoCtrl::OnDraw(
			CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
	if (!pdc)
		return;

	// TODO: 用您自己的绘图代码替换下面的代码。
	//pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
	//pdc->Ellipse(rcBounds);

	m_MyDlg.MoveWindow(rcBounds,true);
}

然后我们在刚开始间建的对话框上建立一个测试函数,具体步骤:删除确定和取消按钮,添加一个新按钮,修改caption为测试,如下图

双击添加测试按钮的响应函数如下

void CActiveXDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	MessageBox("我的第一个网页ActiveX测试");
}

最后生成解决方案,生成过程中可能会出现如下错误

这个主要是因为没有管理员权限,无法完成控件注册造成的。

解决办法(1)退出当前VS,重新以管理员身份打开再运行即可。

                 (2)还有一种办法,通过cmd命令窗口手工进行注册(注意,cmd命令窗口同样需要以管理员身份运行)

D:\code\ActiveXDemo\Release>regsvr32 ActiveXDemo.ocx

注册成功后会弹出下面的提示

同理,如果需要手工卸载某个控件用如下cmd命令即可

D:\code\ActiveXDemo\Release>regsvr32 /u ActiveXDemo.ocx

2.创建html页面并导入ActiveX控件

页面代码如下

<HTML>
<HEAD>
    <TITLE>基于MFC的ActiveX控件全程实录</TITLE>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK" />

</HEAD>
<BODY>
    <OBJECT ID="Test_js" WIDTH=200 HEIGHT=300
            CLASSID="CLSID:B852A7D3-3356-400E-A2BF-A15F7D0F99CB">
        <PARAM NAME="_Version" VALUE="65536">
        <PARAM NAME="_ExtentX" VALUE="2646">
        <PARAM NAME="_ExtentY" VALUE="1323">
        <PARAM NAME="_StockProps" VALUE="0">
    </OBJECT>

</BODY>
</HTML>

这里唯一需要注意的地方就是对应的CLASSID号

我们找到刚才建的ActiveX,在源文件中找到ActiveXDemo.idl,双击打开即可找到该ID号

这里主要,会有好几个uuid号,我们需要的是注释  “//  CActiveXDemoCtrl的类信息”  下面的uuid号。把这个uuid号复制到html文件中指定的位置即可。

用IE浏览器打开刚才的html页面

一般情况下,由于IE保护机制,打开网页后会出现下图所示对话框

这里我们先不管,点击是。然后会出现我们的activex控件,点击测试按钮,出现下图

另外,有些人的机器每次加载时还会提示是否允许加载activeX控件的提示,老是显示这个就比较讨厌。解决方法如下:

IE浏览器——internet选项——高级,勾选“允许活动内容在我的电脑的文件中运行”

3. 修改控件的信息安全

为了避免每次打开网页都弹出下面的对话框,我们需要对控件进行信息安全认证

具体步骤如下

(1)在ActiveXDemoCtrl.h文件中引入文件

#include <objsafe.h>

然后在CActiveXDemoCtrl类的protected部分添加下面的代码

	//去掉安全警告 BEGIN
	DECLARE_INTERFACE_MAP()
	BEGIN_INTERFACE_PART(ObjectSafety, IObjectSafety)
		STDMETHOD(GetInterfaceSafetyOptions)(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions);
		STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions);
	END_INTERFACE_PART(ObjectSafety)
	//去掉安全警告 END

最后在ActiveXDemoCtrl.cpp文件的  “IMPLEMENT_DYNCREATE(CActiveXDemoCtrl, COleControl)”  下面添加下述代码

//去掉安全警告 BEGIN
	BEGIN_INTERFACE_MAP(CActiveXDemoCtrl, COleControl)
		INTERFACE_PART(CActiveXDemoCtrl, IID_IObjectSafety, ObjectSafety)
	END_INTERFACE_MAP()
	// Implementation of IObjectSafety
	STDMETHODIMP CActiveXDemoCtrl::XObjectSafety::GetInterfaceSafetyOptions(
		REFIID riid,
		DWORD __RPC_FAR *pdwSupportedOptions,
		DWORD __RPC_FAR *pdwEnabledOptions)
	{
		METHOD_PROLOGUE_EX(CActiveXDemoCtrl, ObjectSafety)
			if (!pdwSupportedOptions || !pdwEnabledOptions)
			{
				return E_POINTER;
			}
			*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER 
				| INTERFACESAFE_FOR_UNTRUSTED_DATA;
			*pdwEnabledOptions = 0;
			if (NULL == pThis->GetInterface(&riid))
			{
				TRACE("Requested interface is not supported.\n");
				return E_NOINTERFACE;
			}
			// What interface is being checked out anyhow?
			OLECHAR szGUID[39];
			int i = StringFromGUID2(riid, szGUID, 39);
			if (riid == IID_IDispatch)
			{
				// Client wants to know if object is safe for scripting
				*pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
				return S_OK;
			}
			else if (riid == IID_IPersistPropertyBag
				|| riid == IID_IPersistStreamInit
				|| riid == IID_IPersistStorage
				|| riid == IID_IPersistMemory)
			{
				// Those are the persistence interfaces COleControl derived controls support
				// as indicated in AFXCTL.H
				// Client wants to know if object is safe for initializing from persistent data
				*pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
				return S_OK;
			}
			else
			{
				// Find out what interface this is, and decide what options to enable
				TRACE("");
				return E_NOINTERFACE;
			}
	}
	STDMETHODIMP CActiveXDemoCtrl::XObjectSafety::SetInterfaceSafetyOptions(
		REFIID riid,
		DWORD dwOptionSetMask,
		DWORD dwEnabledOptions)
	{
		METHOD_PROLOGUE_EX(CActiveXDemoCtrl, ObjectSafety)
			OLECHAR szGUID[39];
		// What is this interface anyway?
		// We can do a quick lookup in the registry under HKEY_CLASSES_ROOT\Interface
		int i = StringFromGUID2(riid, szGUID, 39);
		if (0 == dwOptionSetMask && 0 == dwEnabledOptions)
		{
			// the control certainly supports NO requests through the specified interface
			// so it"s safe to return S_OK even if the interface isn"t supported.
			return S_OK;
		}
		// Do we support the specified interface?
		if (NULL == pThis->GetInterface(&riid))
		{
			TRACE1("%s is not support.\n", szGUID);
			return E_FAIL;
		}
		if (riid == IID_IDispatch)
		{
			TRACE("");
			TRACE("In other words, is the control safe for scripting?\n");
			if (INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwOptionSetMask 
				&& INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwEnabledOptions)
			{
				return S_OK;
			}
			else
			{
				return E_FAIL;
			}
		}
		else if (riid == IID_IPersistPropertyBag
			|| riid == IID_IPersistStreamInit
			|| riid == IID_IPersistStorage
			|| riid == IID_IPersistMemory)
		{
			TRACE("");
			TRACE("In other words, is the control safe for initializing from persistent data?\n");
			if (INTERFACESAFE_FOR_UNTRUSTED_DATA == dwOptionSetMask 
				&& INTERFACESAFE_FOR_UNTRUSTED_DATA == dwEnabledOptions)
			{
				return NOERROR;
			}
			else
			{
				return E_FAIL;
			}
		}
		else
		{
			TRACE1("", szGUID);
			return E_FAIL;
		}
	}
	STDMETHODIMP_(ULONG) CActiveXDemoCtrl::XObjectSafety::AddRef()
	{
		METHOD_PROLOGUE_EX_(CActiveXDemoCtrl, ObjectSafety)
			return (ULONG)pThis->ExternalAddRef();
	}
	STDMETHODIMP_(ULONG) CActiveXDemoCtrl::XObjectSafety::Release()
	{
		METHOD_PROLOGUE_EX_(CActiveXDemoCtrl, ObjectSafety)
			return (ULONG)pThis->ExternalRelease();
	}
	STDMETHODIMP CActiveXDemoCtrl::XObjectSafety::QueryInterface(
		REFIID iid, LPVOID* ppvObj)
	{
		METHOD_PROLOGUE_EX_(CActiveXDemoCtrl, ObjectSafety)
			return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
	}
	//去掉安全警告 END

重新生成解决方案即可

最后给出代码链接     https://download.csdn.net/download/qianbin3200896/10585896      还不明白的朋友可以参照该代码(vs2010)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐