VS2005 C++ 开发ActiveX控件
simpleboy 2013/8/20整理 simpleboy2008@163.com
ActiveX在网页开发中经常得到应用,基本的开发步骤为:
第一步:开发ActiveX控件
第二步:在网页中通过JavaScript调用ActiveX控件
第三步:通过浏览器使用ActiveX控件
下面给出具体的例子
一、开发ActiveX控件
在VS2005中,使用编程向导,选择MFC ActiveX控件,如下图所示。
缺省完成即可。
然后类视图中的TaxLib类中添加控件的处理函数,添加的函数返回类型是LONG,一个输入参数num的类型是LONG,添加过程以及添加效果如下图所示。
其中的AddOne是刚才添加的控件处理方法,AboutBox方法是缺省条件下开发工具自动生成的。后面的使用就可以使用这两个方法来实验了。
双击AddOne函数就可以看到函数定义了,代码如下(对应的文件名为Tax.idl):
// Tax.idl : ActiveX 控件项目的类型库源。
// 此文件将由MIDL 编译器工具处理以
// 产生类型库(Tax.tlb),该类型库将成为
// Tax.ocx 中的资源。
#include <olectl.h>
#include <idispids.h>
[ uuid(DC2A37EC-649B-42E9-8243-4EA232ED1C77), version(1.0),
helpfile("Tax.hlp"),
helpstring("Tax ActiveX 控件模块"),
control ]
library TaxLib
{
importlib(STDOLE_TLB);
// CTaxCtrl 的主调度接口
[ uuid(CC389683-C147-490B-88DA-BF57022A615D),
helpstring("Tax Control 的调度接口")]
dispinterface _DTax
{
properties:
methods:
[id(DISPID_ABOUTBOX)] void AboutBox();
[id(1), helpstring("方法AddOne")] LONG AddOne(LONG num);
};
// CTaxCtrl 的事件调度接口
[ uuid(10F7C381-1316-439D-BAE6-8C3D2221185D),
helpstring("Tax Control 的事件接口") ]
dispinterface _DTaxEvents
{
properties:
// 事件接口没有任何属性
methods:
};
// CTaxCtrl 的类信息
[ uuid(D3C5CECF-26AA-46FD-945A-1D73C1DA06CC),
helpstring("Tax Control"), control ]
coclass Tax
{
[default] dispinterface _DTax;
[default, source] dispinterface _DTaxEvents;
};
};
这里要特别提醒一下,在控件使用的时候,需要一个控件编号,在TaxLib属性中看到的uuid号码对应的是Tax.idl文件中出现的第一个号码“DC2A37EC-649B-42E9-8243-4EA232ED1C77”,很多时候大家会使用这个号码作为控件编号,这是不对的,对的号码是类信息中的号码,即最后一个号码“D3C5CECF-26AA-46FD-945A-1D73C1DA06CC”。
控件处理函数在TaxCtrl.cpp文件中实现,代码如下:
// TaxCtrl.cpp : CTaxCtrl ActiveX 控件类的实现。
#include "stdafx.h"
#include "Tax.h"
#include "TaxCtrl.h"
#include "TaxPropPage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNCREATE(CTaxCtrl, COleControl)
// 消息映射
BEGIN_MESSAGE_MAP(CTaxCtrl, COleControl)
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
// 调度映射
BEGIN_DISPATCH_MAP(CTaxCtrl, COleControl)
DISP_FUNCTION_ID(CTaxCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(CTaxCtrl, "AddOne", dispidAddOne, AddOne, VT_I4, VTS_I4)
END_DISPATCH_MAP()
// 事件映射
BEGIN_EVENT_MAP(CTaxCtrl, COleControl)
END_EVENT_MAP()
// 属性页
// TODO: 按需要添加更多属性页。请记住增加计数!
BEGIN_PROPPAGEIDS(CTaxCtrl, 1)
PROPPAGEID(CTaxPropPage::guid)
END_PROPPAGEIDS(CTaxCtrl)
// 初始化类工厂和guid
IMPLEMENT_OLECREATE_EX(CTaxCtrl, "TAX.TaxCtrl.1",
0xd3c5cecf, 0x26aa, 0x46fd, 0x94, 0x5a, 0x1d, 0x73, 0xc1, 0xda, 0x6, 0xcc)
// 键入库ID 和版本
IMPLEMENT_OLETYPELIB(CTaxCtrl, _tlid, _wVerMajor, _wVerMinor)
// 接口ID
const IID BASED_CODE IID_DTax =
{ 0xCC389683, 0xC147, 0x490B, { 0x88, 0xDA, 0xBF, 0x57, 0x2, 0x2A, 0x61, 0x5D } };
const IID BASED_CODE IID_DTaxEvents =
{ 0x10F7C381, 0x1316, 0x439D, { 0xBA, 0xE6, 0x8C, 0x3D, 0x22, 0x21, 0x18, 0x5D } };
// 控件类型信息
static const DWORD BASED_CODE _dwTaxOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;
IMPLEMENT_OLECTLTYPE(CTaxCtrl, IDS_TAX, _dwTaxOleMisc)
// CTaxCtrl::CTaxCtrlFactory::UpdateRegistry -
// 添加或移除CTaxCtrl 的系统注册表项
BOOL CTaxCtrl::CTaxCtrlFactory::UpdateRegistry(BOOL bRegister)
{
// TODO: 验证您的控件是否符合单元模型线程处理规则。
// 有关更多信息,请参考MFC 技术说明64。
// 如果您的控件不符合单元模型规则,则
// 必须修改如下代码,将第六个参数从
// afxRegApartmentThreading 改为0。
if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_TAX,
IDB_TAX,
afxRegApartmentThreading,
_dwTaxOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}
// CTaxCtrl::CTaxCtrl - 构造函数
CTaxCtrl::CTaxCtrl()
{
InitializeIIDs(&IID_DTax, &IID_DTaxEvents);
// TODO: 在此初始化控件的实例数据。
}
// CTaxCtrl::~CTaxCtrl - 析构函数
CTaxCtrl::~CTaxCtrl()
{
// TODO: 在此清理控件的实例数据。
}
// CTaxCtrl::OnDraw - 绘图函数
void CTaxCtrl::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);
}
// CTaxCtrl::DoPropExchange - 持久性支持
void CTaxCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
// TODO: 为每个持久的自定义属性调用PX_ 函数。
}
// CTaxCtrl::OnResetState - 将控件重置为默认状态
void CTaxCtrl::OnResetState()
{
COleControl::OnResetState(); // 重置DoPropExchange 中找到的默认值
// TODO: 在此重置任意其他控件状态。
}
// CTaxCtrl::AboutBox - 向用户显示“关于”框
void CTaxCtrl::AboutBox()
{
CDialog dlgAbout(IDD_ABOUTBOX_TAX);
dlgAbout.DoModal();
}
// CTaxCtrl 消息处理程序
LONG CTaxCtrl::AddOne(LONG num)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加调度处理程序代码
return num+1;
}
从代码中可以看出AboutBox函数会弹出一个关于的对话框,而AddOne则返回输入整数加1,代码编译后,如果没有出错,则可以得到控件Tax.ocx了,如下图所示。
可以使用VS2005自带的工具测试控件的功能,如下图所示。
在测试容器中插入新控件,选择刚才编译好的控件(注意:编译好的控件自动会添加到测试容器中,开发人员不需要添加),如下图所示。
出现一个椭圆形,表示控件已经装载,可以进行测试了。我们这里只是测试控件的方法是否可以正常调用。如下图所示。
在方法名下拉列表中,就是控件的两个调用方法,先调用AboutBox方法,这个方法不需要输入参数,直接点调用即可,效果如下图所示。
AddOne方法调用需要输入参数num,在参数位置输入整数3并点设置值,然后点调用,可以看到返回值是整数4,即函数执行成功,输入参数以及执行效果如下图所示。
通过控件容器测试,说明控件没有任何问题,下面就是控件的使用问题。
二、使用JavaScript调用ActiveX控件
有很多方法可以调用ActiveX控件,这里选择在JavaScript中调用ActiveX控件。
编辑一个HTML文档,名字为t.html,编辑内容如下:
<html>
<head>
<title>ActiveX控件Demo</title>
<OBJECT id="L" classid="CLSID:D3C5CECF-26AA-46FD-945A-1D73C1DA06CC"></OBJECT>
</head>
<body>
<input id="Button1" type="button" value="执行函数" οnclick="javascript:RunFunc();" />
<input id="Button3" type="button" value="关于" οnclick="javascript:About();" />
<hr color="blue">
</body>
</html>
<script language="javascript">
<!--
function RunFunc()
{
var lNum = L.AddOne(9);
alert("9+1 = "+lNum);
}
function About()
{
L.AboutBox();
}
// -->
</script>
这里特别提醒一下,classid号码要输入对,否则调用会因为找不到控件而失败。其他的含义比较简单,这里就不啰嗦了。
这里是在本地调用ActiveX控件,其他形式的调用,还需要对控件进行安全方面的一些处理,否则浏览器会禁止执行。
三、浏览器使用ActiveX控件
双击刚才编辑的x.html文档,缺省情况下,启动IE浏览器打开页面,会有一个报警,效果如下图所示。
允许启动控件,则可以点击“执行函数”和“关于”按钮了。
点击“执行函数”按钮,效果如下图所示。
点击“关于”按钮,效果如下图所示。