前言
当有些网页应用出于性能、保密等考虑,需要额外开发插件,不同的浏览器支持的插件是不一样的,下面以IE的插件开发进行详细说明。
插件的IDE工具是VS2012.
创建ActiveX工程
打开VS2012,创建新工程,选择如下工程类型:
点击确定后,按照默认设置,点击完成,自动生成如下文件。
其中,UUID是插件的ID,它用于网页的调用:
在网页中调用如下代码所示:
<center>
<object ID="MFCActiveX" height=768 width=1024
CLASSID="CLSID:E976D19A-D0DA-4DFE-AC83-C155AB0EE7C9"
CODEBASE="./MFCActiveX.cab#Version=1,0,0,0">
</object>
</center>
供网页调用的外部接口
插件需要提供外部接口,供网页调用,例如登录接口。可以参考【AboutBox】接口进行添加,在【MFCActiveXControl1.idl】文件里添加接口声明:
// CMFCActiveXControl1Ctrl 的主调度接口
[
uuid(8497EC9C-262F-4A76-8B24-40244D39A63B)
]
dispinterface _DMFCActiveXControl1
{
properties:
methods:
[id(DISPID_ABOUTBOX)] void AboutBox();
// 登录
[id(1), helpstring("method Login")] void Login(BSTR swzUserName, BSTR swzUserPw, BSTR swzIP, short iLang);
};
在【MFCActiveXControl1Ctrl.cpp】文件添加接口的实现里:
// 调度映射
BEGIN_DISPATCH_MAP(CMFCActiveXControl1Ctrl, COleControl)
DISP_FUNCTION_ID(CMFCActiveXControl1Ctrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
DISP_FUNCTION_ID(CMFCActiveXControl1Ctrl, "Login", 1, Login, VT_EMPTY, VTS_BSTR VTS_BSTR VTS_BSTR VTS_I2)
END_DISPATCH_MAP()
在【MFCActiveXControl1Ctrl.h】文件里声明接口实现的函数头形式:
protected:
// 登录
void Login(LPCTSTR swzUserName, LPCTSTR swzUserPw, LPCTSTR swzIP, short iLang);
在【MFCActiveXControl1Ctrl.cpp】文件里实现登录的接口:
// 登录
void CMFCActiveXControl1Ctrl::Login(LPCTSTR swzUserName, LPCTSTR swzUserPw, LPCTSTR swzIP, short iLang)
{
// TODO: Add your dispatch handler code here
}
此外,还可以通过类视图,自动添加函数、变量和事件,但是这里添加的不是外部接口,不支持网页调用。具体添加如下:
说明:此前我接手一个ActiveX的项目,都是手工描画的页面,没有使用MFC的CDialog。维护非常不方便,感觉很奇怪。时间上ActiveX的内部页面开发跟App的UI开发没什么不一样。
网页调用的ActiveX的接口如下:
<script language="javascript" type="text/javascript" for="MFCActiveX" event="PrepareInitInfo">
var lang = "cn";
LogCount++;
if(LogCount <= 1)
{
MFCActiveX.Login(szUserName,szPass,szHostIp,"1");
document.getElementById("MFCActiveX").height=document.documentElement.clientHeight - 20;
document.getElementById("MFCActiveX").width=document.documentElement.clientWidth - 20;
}
</script>
ActiveX推送消息给网页
网页接收ActiveX的事件,在idl文件里声明:
// CMFCActiveXControl1Ctrl 的事件调度接口
[
uuid(DF467D9D-D259-4A94-8AA0-CBCE1D9F4A9F)
]
dispinterface _DMFCActiveXControl1Events
{
properties:
// 事件接口没有任何属性
methods:
// 登录返回的消息
[id(1)] void ReLogin(int iError, int iLang);
// 插件初始化消息
[id(2)] void PrepareInitInfo(void);
};
在【MFCActiveXControl1Ctrl.h】文件里实现推送给网页的消息接口:
private:
// 已经调用Relogin发送错误CODE的标志
bool m_hasEmittedReloginError;
// 事件映射
DECLARE_EVENT_MAP()// Dispatch and event IDs
public:
enum {
eventidReLogin = 1L,
eventidPrepareInitInfo,
dispidLogin = 1L
};
protected:
// 登录
void Login(LPCTSTR swzUserName, LPCTSTR swzUserPw, LPCTSTR swzIP, short iLang);
public:
// 推送登录返回消息
void FireReLogin(int iError, int iLang)
{
// 已调用过,则返回
if (m_hasEmittedReloginError)
{
return;
}
// 设置标志
m_hasEmittedReloginError = true;
FireEvent(eventidReLogin, EVENT_PARAM(VTS_I2 VTS_I2),iError,iLang);
}
// 推送初始化消息【网页应该等待插件初始化完成后,再进行登录】
void FirePrepareInitInfo(void)
{
FireEvent(eventidPrepareInitInfo, EVENT_PARAM(VTS_NONE));
}
最后贴上网页【index.asp】调用的完整示例:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Distributive Vision Control System</title>
</head>
<body>
<script language="javascript">
var LogCount = 0;
var lang = "cn";
var szUserName = new String("<%=Request.Form("UserName")%>");
var szPass = new String("<%=Request.Form("Pass1")%>");
var szHostIp = new String("<%=Request.ServerVariables("SERVER_NAME")%>");//new String("192.168.3.12");//
if((szUserName == "undefined" || szUserName == null || szUserName == "") && (szPass == "undefined" || szPass == null || szPass == ""))
{
self.location="login_cn.asp";
}
</script>
<center>
<object ID="MFCActiveX" height=768 width=1024
CLASSID="CLSID:E976D19A-D0DA-4DFE-AC83-C155AB0EE7C9"
CODEBASE="./MFCActiveX.cab#Version=1,0,0,0">
</object>
</center>
<script language="javascript">
window.onresize = function ()
{
document.getElementById("MFCActiveX").height=(document.documentElement.clientHeight-20)>768?(document.documentElement.clientHeight-20):768;
document.getElementById("MFCActiveX").width=(document.documentElement.clientWidth-20)>1024?(document.documentElement.clientWidth-20):1024;
}
</script>
<script language="javascript" type="text/javascript" for="MFCActiveX" event="PrepareInitInfo">
var lang = "cn";
LogCount++;
if(LogCount <= 1)
{
MFCActiveX.Login(szUserName,szPass,szHostIp,"1");
document.getElementById("MFCActiveX").height=document.documentElement.clientHeight - 20;
document.getElementById("MFCActiveX").width=document.documentElement.clientWidth - 20;
}
</script>
<script language="javascript" type="text/javascript" for="MFCActiveX" event="ReLogin(error,iLang)">
iLang = 1;
if(iLang == 1)
{
lang = "cn";
if(error == -1){
alert("登录超时,请检查网络连接。");
self.location="login_cn.asp?error=";
//
}
else if(error == -2){
alert("用户账户名或密码错误!");
self.location="login_cn.asp?error=";
}
else if(error == -3){
alert("登录帐户不存在!");
self.location="login_cn.asp?error=";
}
else{
self.location="login_cn.asp?error=";
window.opener=null; window.open('','_self',''); window.close();
}
}
</script>
<script>
lock = function(theEvent) {
if (theEvent != null) {
event = theEvent;
}
// 擋滑鼠右鍵選單事件
if (event.type == "contextmenu") {
return false;
// 擋滑鼠中鍵事件
} else if (event.type == "mousedown") {
// 擋滑鼠左鍵事件
if (event.button == 1) {
return false;
}
// 擋滑鼠右鍵事件
if (event.button == 2) {
return false;
}
// 擋滑鼠中鍵事件
if (event.button == 4) {
return false;
}
}
// 屏蔽按住Ctrl键或者鼠标滚动
else if (event.ctrlKey || event.type == "mousewheel") {
return false;
}
// 擋 IE 按下 F1 鈕時會觸發的 onhelp 事件
else if (event.type == "help") {
return false;
// 擋特定按鍵
} else if (event.type == "keydown") {
//alert('catch key down['+event.keyCode+']');
// 屏蔽Backspace、F5
if (event.keyCode == 8 || event.keyCode == 116) {
return false;
}
// 擋 alt、ctrl鍵
if (event.altKey || event.ctrlKey) {
return false;
}
// 擋 F3 ~ F10 功能鍵,其中此種寫法只能擋 FF 的 F1 鍵,無法擋 IE 的 F1 鍵
if (event.keyCode >= 114 && event.keyCode <= 121) {
//alert('catch Fx key['+event.keyCode+']');
try {
// IE 要將 keyCode 設為 0 才能真正擋功能鍵,
// 但 FF 會丟 Exception,所以用 try-cache 擋住
event.keyCode = 0;
} catch(e){}
return false;
}
}
}
document.onmousedown = lock;
document.onmousewheel = lock;
document.onmouseup = lock;
document.oncontextmenu = lock;
document.onkeydown = lock;
window.onhelp = lock;
</script>
</body>
</html>
示例代码请参考: