最近接到一个任务,要求实现在B/S的架构中调用客户端本地资源,这个问题在B/S的架构中是比较难以实现的,原因不必说了吧,想必大家都很清楚,而用来实现这个需求就要用上比较老的技术啦,ActiveX控件.
ActiveX控件,在.Net之前是非常风光的技术呀,它是属于COM架构的一部分,可以使用诸如VC,Delphi,VB等来创建,由于本人只懂VB,所以只好拿出封存已久的VB来啦.
最近接到一个任务,要求实现在B/S的架构中调用客户端本地资源,这个问题在B/S的架构中是比较难以实现的,原因不必说了吧,想必大家都很清楚,而用来实现这个需求就要用上比较老的技术啦,ActiveX控件.
ActiveX控件,在.Net之前是非常风光的技术呀,它是属于COM架构的一部分,可以使用诸如VC,Delphi,VB等来创建,由于本人只懂VB,所以只好拿出封存已久的VB来啦.
费话不说了,先上个Demo的最终的效果图:
Demo是非常简单的,实现的功能大致描述一下:用户在文本框中输入逻辑盘符,然后点击查看磁盘信息,JS调用OCX控件提供的方法,OCX调用系统的API函数获取磁盘信息,JS获取结果发送到服务器,服务器处理后再显示出来最终的结果,其中显示最终结果的过程是无刷新的,应用的是JS的异步Http请求技术.(友情提示:大家看到图片的背景色是不是感觉很不爽?呵呵,不过这个颜色对眼睛很好的,如果谁的眼睛经常看了一天显示器后发干发涩,那就Google一下"苹果绿",然后按照步骤设置一下吧,本人深有感触,真的很好^^)
废话不说,开始Demo的制做
1.打开VB6,创建ActiveX控件工程,命名为ActiveXControl,将自动添加的UserControl1改名为MyControl,新增一个模块,命名为mdlGlobal.
2.在模块中编写下面的代码:
Code
Public Declare Function GetDiskFreeSpaceEx Lib "kernel32" _
Alias "GetDiskFreeSpaceExA" _
(ByVal lpRootPathName As String, _
lpFreeBytesAvailableToCaller As Currency, _
lpTotalNumberOfBytes As Currency, _
lpTotalNumberOfFreeBytes As Currency) As Long
3.在MyControl里编写如下代码:
Code
Option Explicit
Public Function GetDriveInfo(driveNo As String) As String
Dim BytesFreeToCalller As Currency
Dim TotalBytes As Currency
Dim TotalFreeBytes As Currency
Dim TotalBytesUsed As Currency
Dim RootPathName As String
RootPathName = driveNo
Call GetDiskFreeSpaceEx(RootPathName, _
BytesFreeToCalller, _
TotalBytes, _
TotalFreeBytes)
Dim strResult As String
strResult = driveNo & "@" & _
Format$(TotalBytes * 10000, "###,###,###,##0") & "@" & _
Format$(TotalFreeBytes * 10000, "###,###,###,##0") & "@" & _
Format$(BytesFreeToCalller * 10000, "###,###,###,##0") & "@" & _
Format$((TotalBytes - TotalFreeBytes) * 10000, "###,###,###,##0")
GetDriveInfo = strResult
End Function
控件中只提供了一个方法,参数是磁盘驱动器的编号,这里面会调用API函数得到结果,然后拼接成字符串返回给调用者.
4.编写测试程序
在当前的工程中添加一个"标准Exe工程",然后在自动添加的窗体里新增OCX控件,添加一个按钮,在它的单击事件中编写下面的代码
Code
MsgBox Me.MyControl1.GetDriveInfo("C:\")
将后添加的测试工程设置为启动项目,然后运行项目,点击按钮出现对话框:
5.生成OCX控件
VB6和.Net不一样,它可以支持临时编译,所以在控件的项目文件夹中不会看到类似于Bin这样的目录,我们需要手工的生成它.回到控件工程,点击"文件->生成ActiveXControl.ocx",然后选择一下路径就可以了.
6.打包成cab
我们在打开包含有ActiveX控件的网页时,IE会给我一个提进,是否安装某个ActiveX控件,如果选是则会安装它.我们也可以实现同样的效果,这就需要将ocx控件连同它的运行环境都打包到cab中,这个打包工具是VS6自带的,VB6提供一个图形化的安装工具,点击"开始->程序->Microsoft Vistual Basic 6.0->Microsoft Vistual Basic 6.0工具->Package & Deployment",打开如下界面:
点击浏览找到保存过的工程文件,然后点击"打包"按钮,出现下面对话框:
选择Internet软件包,连续点击两次"下一步".出现下图对话框
将左面列表框中的每个文件都设置成"包含在此压缩文件中",以保证在IE中安装时一次下载就将环境全部安装,避免从其它站点下载时需到问题.设置完成后,点击下一步,将安全性都设为安全,最后保存脚本.
在执行完以上的步骤后,在项目的目录下会创建一个"包"文件夹,里面包含了CAB文件和一个网页,网页中包含了调用控件的代码:
Code
<OBJECT ID="MyControl"
CLASSID="CLSID:3F3C90B6-6B90-4A9B-A29B-42667701E45F"
CODEBASE="ActiveXControl.CAB#version=1,0,0,0">
</OBJECT>
ClassID标识了这个控件的GUID,这是ActiveX所必需要有的,注册了以后这个控件的信息会存储在注册表中(非著名的Dll hell问题),CodeBase指名了控件的安装包下载地址和版本,用来使IE自动根据版本号进行安装,现在,在你的本机上就可以调用这个控件啦,将生成的文件ActiveXControl.htm修改为如下所示:
Code
<head>
<title>
无标题页
</title>
<script type="text/javascript">
function InvokeOcx()
{
var driveNo=document.getElementById('txtDrive').value;
driveNo+=':\\';
var control=document.getElementById('MyControl');
var result=control.GetDriveInfo(driveNo);
var info=document.getElementById('lblInfo');
info.innerText=result;
}
</script>
</head>
<body>
<form name="form1" id="form1">
<object id="MyControl" classid="CLSID:3F3C90B6-6B90-4A9B-A29B-42667701E45F" codebase="ActiveXControl.CAB#version=1,0,0,0" height="0" width="0">
</object>
<input name="txtDrive" type="text" id="txtDrive" /><br />
<br />
磁盘信息为:<span id="lblInfo"></span>
<br />
<br />
<input type="button" name="btnInvoke" value="查看磁盘信息" onclick="InvokeOcx();" id="btnInvoke" /></div>
</form>
</body>
</html>
用IE打开后就可以看到效果啦.
大家是不是以为大功告成啦?其实还差的远呢,将这个文件放在站点下面,去其它机器试验一下就会发现IE是不会安装它的,要解决这个问题就需要对控件进行数字签名或者安装发行这个签名的证书,这个留在第二篇再讨论.
一点说明:为什么在标题中要嵌入英文?原因是为了能够让国外的网友能查询到这篇文章。平常在Google上查资料的时候,经常参考国外网友的博客,帮助我解决了很多问题,所以我也想让他们能够参考我写的内容。当然文中我不可能全部译为英文,所以我尽量把代码粘全,靠代码说话吧。