ASP与ActiveX控件交互实战
ActiveX控件运行在客户端。我们可以获得客户端的一些信息,如IC卡的信息,客户端的验证等等。但是ActiveX控件也有许多缺点:客户端的部署很困难,如客户端不能正确下载,下载了以后不能正确执行,下载的时候需要设置IE的安全级别等等。
更多的时候,我都在使用COM组件来扩展ASP的功能。准确地说,是服务端运行的ActivexDll组件。使用Server.CreateObject(“工程名.类名”)即可完成对组件的调用。这种方式问题很少,只要组件中以PUBLIC对外暴露方法既可。但是,有时候我们必须使用ACTIVEX控件(*.OCX)嵌入到网页中执行来获取客户端的信息。这就有了许许多多的一些问题。
这是我们需要解决的N个问题(从简单到难)
1.如何从服务端获取数据,传递到ActiveX控件中。
1)初始化时使用参数绑定
2)运行时得到数据
2.ActiveX控件得到客户端的信息,如何传递到服务端。
3.安全性
1)数字签名
2)使用IOBJSAFE接口
好了,我们开始实例学习。
这个功能演示了如何制作一个简单的控件,并嵌入网页中执行。工作环境:WINXP+VB6+IE6
我的IE安全设置为安全级别-中。所有的Activex选项设为启用。
打开vb6,新建ActiveX控件工程。
工程名:fOcx,用户控件名:UC1
为了方便,我们使用ActiveX控件接口向导…,菜单->外接程序->外接程序管理器->VB6ActiveX控件接口向导。确定即可。
打开ActiveX控件接口向导,下一步,对于可用名称和选定名称我们默认下一步,新建自定义成员,GetInfo类型:属性,下一步,共有方法中选择我们刚才添加的GetInfo,映射到控件选择TxtInfo,成员选择Text,下一步直到完成。代码窗口中会生成一些我们不需要的,删除,剩下的代码如下:
OptionExplicit
'注意!不要删除或修改下列被注释的行!
'MappingInfo=txtinfo,txtinfo,-1,Text
PublicPropertyGetGetInfo()AsString
GetInfo=txtinfo.Text
EndProperty
PublicPropertyLetGetInfo(ByValNew_GetInfoAsString)
txtinfo.Text()=New_GetInfo
PropertyChanged"GetInfo"
EndProperty
'从存贮器中加载属性值
PrivateSubUserControl_ReadProperties(PropBagAsPropertyBag)
txtinfo.Text=PropBag.ReadProperty("GetInfo","Text1")
EndSub
'将属性值写到存储器
PrivateSubUserControl_WriteProperties(PropBagAsPropertyBag)
CallPropBag.WriteProperty("GetInfo",txtinfo.Text,"Text1")
EndSub
OK,好了,我们编译成fOcx.ocx文件,然后F5直接运行,VB会打开一个测试页。如下:
E:\ProgramFiles\MicrosoftVisualStudio\VB98\UC1.html
同时,打开你的IE浏览器,看到了吧,你做的控件出现在了这个测试页中。
你可以打开测试页,可以看到ClsID,比如:890D1028-298B-45CF-9A64-6ED5A5BACBC9
因为VB编译的时候已经完成注册.所以无法模拟客户端没有安装该控件时出现的提示.我们继续
使用regsvr32F:\csdn_vb\com+_activeX\sample1\fOcx.ocx–u卸载
或者打开注册表,在HKEY_CLASSES_ROOT\CLSID下面找到890D1028-298B-45CF-9A64-6ED5A5BACBC9项,删除之,当然这种方式还有项存在而没有删除干净.
此时浏览http://yang/uc1.htm,由于IE中ActiveX设置为启动,所以,控件会显示出来。
下载后的ocx到哪里去了
打开该目录(可能有所不同)E:\WINDOWS.0\DownloadedProgramFiles,看到了吧,fOcx.UC1文件在这个目录下.
原理:客户端下载该控件后,自动注册,然后放在上述这个目录下.这时我们可以打开注册表看看CLSID,呵呵,还是以前的那个.
我们可以右键看看fOcx.UC1的属性,看看相关内容,这里显示了该OCX所依赖的所有文件.所以,你的OCX尽量减少使用高级控件或者第三方的控件,否则,下载就有些问题了.
如果IE中关于ActiveX的选项设为禁用,那么浏览器就会出现对话框”当前安全设置禁止运行该页中的ActiveX控件.因此可能无法正确显示该页”,这个就需要其他的方式来处理了。
一般用户默认的都是禁用ActiveX选项,所以让用户自己设置不太合适。
我们来看看如何从服务端获取数据,传递到ActiveX控件中。
1)初始化时使用参数绑定
2)运行时得到数据
打开vb6,新建ActiveX控件工程。
工程名:fOcx,用户控件名:UC2
为了方便,我们使用ActiveX控件接口向导…,菜单->外接程序->外接程序管理器->VB6ActiveX控件接口向导。确定即可。
打开ActiveX控件接口向导,下一步,对于可用名称和选定名称我们默认下一步,新建自定义成员,GetInfo类型:属性,下一步,共有方法中选择我们刚才添加的GetInfo,映射到控件选择TxtInfo,成员选择Text,下一步直到完成。代码窗口中会生成一些我们不需要的,删除,
'注意!不要删除或修改下列被注释的行!
'MappingInfo=txtinfo,txtinfo,-1,Text
PublicPropertyGetGetInfo()AsString
GetInfo=txtinfo.Text
EndProperty
PublicPropertyLetGetInfo(ByValNew_GetInfoAsString)
txtinfo.Text()=New_GetInfo
PropertyChanged"GetInfo"
EndProperty
PrivateSubCommand1_Click()
Label2.Caption=GetInfo()
EndSub
'从存贮器中加载属性值
PrivateSubUserControl_ReadProperties(PropBagAsPropertyBag)
txtinfo.Text=PropBag.ReadProperty("GetInfo","Text1")
EndSub
'将属性值写到存储器
PrivateSubUserControl_WriteProperties(PropBagAsPropertyBag)
CallPropBag.WriteProperty("GetInfo",txtinfo.Text,"Text1")
EndSub
编译成OCX控件.运行生成的测试页.Text中默认的是Text1如何将服务器端的数据传递给OCX呢?使用MicrosoftActiveXControlPad这个工具,可以很容易找到.直接用这个工具把测试页打开.
菜单->Edit->EditActivexControl,呵呵,打开了一个可视化的界面.
看到了吧,有一个属性框,我们可以进行设置,设置完成以后的代码如下:
<HTML>
<HEAD>
<TITLE>NewPage</TITLE>
</HEAD>
<BODY>
<OBJECTID="GetClient"WIDTH=507HEIGHT=440CLASSID="CLSID:890D1028-298B-45CF-9A64-6ED5A5BACBC9"CODEBASE="http://localhost/xml/fOcx.ocx">
<PARAMNAME="_ExtentX"VALUE="13414">
<PARAMNAME="_ExtentY"VALUE="11642">
<PARAMNAME="GetInfo"VALUE="这是ocx得到的客户端读卡器的信息">
</OBJECT>
</BODY>
</HTML>
增加了ID,ID就是我们用来访问的标志.还有我们的属性GetInfo,我们也设定初始值了好了,运行.Text中就出现了我们设定的值”这是ocx得到的客户端读卡器的信息”
我们把上边的页面改成asp的,看代码:
<HTML>
<HEAD>
<TITLE>龙卷风测试页</TITLE>
</HEAD>
<BODY>
<%
dimsValue
sValue="这是ocx得到的客户端读卡器的信息"
%>
<OBJECTID="GetClient"WIDTH=507HEIGHT=440CLASSID="CLSID:56DFCA88-F5B8-4879-853B-97FE504423FD"CODEBASE="http://localhost/xml/fOcx.ocx">
<PARAMNAME="_ExtentX"VALUE="13414">
<PARAMNAME="_ExtentY"VALUE="11642">
<PARAMNAME="GetInfo"VALUE="<%=sValue%>">
</OBJECT>
</BODY>
</HTML>
OK,运行即可
我们看看第二种情况
运行时得到数据
<HTML>
<HEAD>
<TITLE>龙卷风测试页</TITLE>
<%
dimsValue
sValue="这是ocx得到的客户端读卡器的信息"
%>
<SCRIPTID=clientEventHandlersJSLANGUAGE=javascript>
<!--
functionbutton1_onclick()
{
GetClient.GetInfo='<%=sValue%>';
}
//-->
</SCRIPT>
</HEAD>
<BODY>
<OBJECTID="GetClient"WIDTH=507HEIGHT=440CLASSID="CLSID:56DFCA88-F5B8-4879-853B-97FE504423FD"CODEBASE="http://localhost/xml/fOcx.ocx">
<PARAMNAME="_ExtentX"VALUE="13414">
<PARAMNAME="_ExtentY"VALUE="11642">
</OBJECT>
<INPUTid=button1type=buttonvalue=Buttonname=button1LANGUAGE=javascriptonclick="returnbutton1_onclick()">
</BODY>
</HTML>
运行后,点击按钮即可看到效果.
问题提出:
ActiveX控件得到客户端的信息,如何传递到服务端???一种方法就是得到值后,使用Get,Post方式提交,这可能也是最常用的.
有没有更好一些的方法呢?能不能在控件中直接向服务器发出请求而得到数据呢?
打开vb6,新建ActiveX控件工程。
工程名:fOcx,用户控件名:UC3
添加1个按钮,2个文本框
代码如下:
OptionExplicit
PrivateSubCommand1_Click()
'注意字符串和数字的写法有些区别
'使用AsyncRead通过HTTP发送你的请求
UserControl.AsyncRead"http://yang/xml/activex.asp?s1="&am ... nbsp;&"",vbAsyncTypeByteArray
UserControl.AsyncRead"http://yang/xml/activex.asp?s1="&Text1.Text,vbAsyncTypeByteArray
EndSub
'AsyncReadComplete事件用来从asp页面接受和分析。
'当容器刚完成一个异步读取请求时,发生该事件?
'AsyncProp中的数值指定了已完成的某个异步数据读取请求,
'它与前一个AsyncRead方法调用中的数据匹配。
'AsyncReadComplete事件过程中应包含错误处理代码,因为错误状态会终止下载。
'如果发生了这种情况,当访问AsyncProperty对象的Value属性时将会发生错误。
PrivateSubUserControl_AsyncReadComplete(AsyncPropAsAsyncProperty)
OnErrorGoToerrhandle
Text2.Text=ByteArrayToString(AsyncProp.Value)
errhandle:
Err.Raise601,"异步读取发生了错误",Err.Description
EndSub
'将字节数组转换成字符串
PublicFunctionByteArrayToString(bytArray()AsByte)AsString
DimsAnsAsString
sAns=StrConv(bytArray,vbUnicode)
ByteArrayToString=sAns
EndFunction
我们来看看http://yang/xml/activex.asp这个文件
<%
dimstr
str=request("s1")
ifstr="name"then
response.write("龙卷风")
elseifstr="age"then
response.write("26")
else
response.write("没有可用信息返回")
endif
%>
很简单,使用request接受参数,response返回。
这个例子可以进一步处理,将服务器名以属性的方式传递给控件。
比如:<PARAMNAME="ServerName"VALUE="192.168.0.1">
然后在程序中得到,就可以使用了,如:UserControl.AsyncRead"http://192.168.0.1/xml/activex.asp?s1=" ... t&"",vbAsyncTypeByteArray
然后在程序中得到就可以灵活处理了。