ATL开发技术精要Word格式文档下载.docx
《ATL开发技术精要Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《ATL开发技术精要Word格式文档下载.docx(15页珍藏版)》请在冰点文库上搜索。
3、ATL技术
ATL(ActiveTemplateLibrary)是微软的活动模板库,是一个产生C++/COM代码的框架,专门用于开发COM组件。
ATL提供了小巧、高效、灵活的类,这些类为创建可互操作的COM组件提供了基本的设施。
ATL完全面向COM组件,其结构完全针对COM中的诸多规范。
是编写COM组件的快捷工具。
三、实现
1、项目
打开VisualStudio.Net2005,建立一个解决方案或项目DeanUSBKey。
在项目类型中选择VisualC++下的ATL选项,在模板中选择”ATL Project”,项目名为DeanUSBKey。
点击确定,系统就在指定的目录下建立了DeanUSBKey项目和解决方案。
点击确定后,会出现建立ATL项目向导对话框,引导用户快捷方便的建立ATL项目。
点击下一步,进入项目属性设置对话框,如图1所示。
可以通过该对话框选择是否属性化和发布方式等。
图1项目属性设置对话框
具体选项说明如下:
Attributed即属性化,支持属性化编程,是未来的发展方向,是IDL方案的一种替代方案。
Dynamic-linklibrary(DLL)即动态链接库,表示建立一个DLL的组件程序。
Executable(EXE)即可执行文件,表示建立一个EXE的组件程序。
Service(EXE)即服务,表示建立一个系统服务组件程序,系统启动后就会加载并执行的程序。
Allowmergingofproxy/stubcode即允许合并代理/存根代码,选择该项表示把“代理/存根”代码合并到组件程序中,否则需要单独编译,单独注册代理存根程序。
SupportMFC即支持MFC,建议不要选择,除非有特殊的原因,比如我们原来的程序是基于MFC的,我们的组件必须要MFC的支持。
一般在写ATL程序,不选择该项。
但是很多VC程序员对于MFC的数据集合类和字符串类依赖很大,建议采用STL中的相关类进行替代。
具体替换方案:
1、std:
:
string代替MFC中的CString;
2、std:
vector代替MFC的数组类如CArray,CPtrArray等;
3、std:
list替换MFC中的CList等列表类;
4、对于BSTR建议采用CComBSTR类,或_bstr_t类,本例子中就会用到该类;
SupportCOM+1.0支持事务处理的COM+功能。
我们选择如图1所示的选项,点击完成。
ATLProject项目就生成好了,系统会在指定目录下生成一系列文件,ReadMe.txt里有各文件的文件说明。
尤其要注意接口定义语言文件(DeanUSBKey.idl),它描述了对象的接口细节。
2、组件
在COM模型中,客户请求服务时,是通过接口和组件进行交互的。
现在还是一个空的ATL项目,还没有任何组件。
添加组件,也就是添加ATL对象类。
在DeanUSBKey项目上点击右键,添加类,弹出对话框。
在类别中选择ATL。
在模板中选择“ATLSimpleObject”即ATL简单对象。
点击确定,出现建立组件向导。
如图2所示,在ShortName输入组件名称USBKey,其它内容系统会自动填写。
注意组件名称不能和项目名称重名。
点击下一步进入组件选项设置界面。
如图3所示
图2ATL简单对象组件名字对话框
图3ATL简单对象组件选项对话框
Threadingmodel即线程模型,COM中的线程,这是一个复杂的部分。
我们选"
单元"
(Apartment),它代表当在线程中调用组件函数的时候,这些调用会排队进行。
如果想了解详细细节可以参看《COM技术内幕》一书。
Interface即接口,双重(Dual),双重接口表示在一个接口中,同时支持自定义接口和IDispatch接口。
这个非常重要,为了能够使组件能够在脚本中使用,必须选择双重接口选项。
因为脚本语言的解释器只认识IDispatch接口。
自定义接口(Custom),直接实现的是IUnknown接口。
Aggregation即聚合,写的组件,将来是否允许被其他人以聚合方式(有聚合和包容两种方式)使用。
Only(只能创建为聚合),有点类似C++或Java中的不能直接创建实例的虚类,如果不是处于设计目的,一般这个选项不用。
大多数情况下支持“聚合”,所以我们选择“Yes”。
ISupportErrorInfo是否支持丰富信息的错误处理接口。
Connectionpoints即连接点,是否支持连接点接口(事件、回调)。
IObjectWithSite是否支持IE的调用。
我们选择如图3所示的选项,点击完成。
USBKey的组件建立完成。
在生成的USBKey.cpp里将是接口IUSBKey的实现。
3、接口方法
在类视图中,IUSBKey接口上点击鼠标右键。
在添加项里有添加方法和属性,选择添加方法。
打开图4所示的添加接口方法对话框。
添加接口方法GetContent,并添加接口方法的参数。
[in]表示参数方向是输入;
[out]表示参数方向是输出;
[out,retval]表示参数方向是输出,同时可以作为函数运算结果的返回值。
一个函数中,可以有多个[in]、[out],但[retval]只能有一个,并且要和[out]组合后在最后一个位置。
详细的定义说明可以参考IDL的语法说明。
图4添加接口方法对话框
在USBKey.cpp文件里添加函数GetContent的具体实现过程。
核心代码如下:
STDMETHODIMPCUSBKey:
GetContent(LONGlFlags,BSTR*pUSBContent)
{
EPAS_STATUSretval;
//状态
EPAS_HANDLEepsHandle;
//EPAS句柄
//创建设备句柄
retval=epas_CreateContext(&
epsHandle,0,EPAS_API_VERSION);
//调用EPAS的API函数访问USBKey硬件
if(FT_SUCCESS!
=retval)
{returnReturnError(retval);
}//返回相应的错误
//打开设备
retval=epas_OpenDevice(epsHandle,lFlags,(void*)szAppID);
=retval)
}
//得到序列号
unsignedlongsn[2]={0};
retval=epas_GetProperty(epsHandle,EPAS_PROP_SERNUM,NULL,sn,sizeof(sn));
}
charm_sn[8*1024+17]={0};
sprintf_s(m_sn,"
%08X%08X"
sn[1],sn[0]);
//以16进制打印到字符串m_sn中
//得到加密字符串
//1、登录
chars[80]="
1234"
;
//登录密码
retval=epas_Verify(epsHandle,EPAS_VERIFY_USER_PIN,(unsignedchar*)s,4);
=retval){returnReturnError(retval);
//2、打开文件
EPAS_FILEINFOepsFileInfo={0};
unsignedlongepsFileID=0x1234;
//文件编号
retval=epas_OpenFile(epsHandle,0,epsFileID,&
epsFileInfo,sizeof(epsFileInfo));
}
//3、读取文件内容
unsignedlongrLen=0;
unsignedcharrBuff[8*1024]={0};
ZeroMemory(rBuff,8*1024);
retval=epas_Read(epsHandle,0,0,rBuff,epsFileInfo.ulFileSize,&
rLen);
//4、关闭文件
retval=epas_CloseFile(epsHandle);
//关闭设备,删除Context
retval=epas_CloseDevice(epsHandle);
retval=epas_DeleteContext(epsHandle);
strcat_s(m_sn,(char*)rBuff);
*pUSBContent=_com_util:
ConvertStringToBSTR((char*)r_sn);
returnS_OK;
为了能在函数中使用USBKey厂家提供的访问函数和使用BSTR类,需在stdafx.h头文件里面引入相应的.h和.lib文件。
如下:
#include"
FT_ND_API.h"
//ePass1000ND的接口头文件
comutil.h"
#pragmacomment(lib,"
FT_ND_API.lib"
)
comsuppw.lib"
如果编译通过,VS.NetIDE会打开窗口选择执行控件的外部文件。
选择regsvr32。
编译成功后,组件会自动注册。
可以在系统组件服务里面查看刚注册的组件DeanUSBKey。
4、错误处理
COM方法通过返回HRESULT来报告错误,其他信息异常可以通过IErrorInfo接口提供给客户端,这里主要讲述HRESULT返回COM方法错误。
HRESULT由一个32位代码组成。
分为四部分,如下:
Field
Severity
Reserved
Facility
Code
Bit(s)
31
29-30
16-28
0-15
各字段说明:
Severity字段是其中最重要的一个。
当一个方法返回时若该字段被设置了值,就说明发生了一个错误。
该字段使所有的COM错误代码显示为负的十进制整数。
Reserved字段目前是预留字段。
Facility字段为错误类别代码,总共表示8192种错误,由一个集中的机构负责分配这些种类。
Code字段提供了一个可容纳65536个代码的空间。
具体的错误代码就在该字段里面体现。
在读取USBKey信息时,捕获的错误做处理,以COM错误的形式抛出。
即把前16位改为0x80FF,代码如下:
LONGCUSBKey:
ReturnError(LONGretval)
return0x80FF0000+retval;
5、实现IObjectSafety接口
ActiveX控件的编写到此就可以结束了,但我们在浏览器使用改控件的过程中,经常都会弹出现在运行的脚本不安全的提示。
如果给客户使用,将会带来极大不便。
怎么解决呢,可以通过实现IObjectSafety接口来解决。
ATL在类IObjectSafetyImpl中提供了此接口的实现。
如果浏览器发现你的控件支持IObjectSafety,就在导入控件之前调用IObjectSafety:
SetInterfaceSafetyOptions方法来确保安全性脚本操作。
就不会弹出提示对话框。
在USBKey.h文件里继承类列表的末尾(classATL_NO_VTABLECUSBKey)加入如下语句:
publicIObjectSafetyImpl<
CUSBKey,INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA>
并在COM映射里添加一下行(黑体部分):
BEGIN_COM_MAP(CUSBKey)
COM_INTERFACE_ENTRY(IObjectSafety)
END_COM_MAP()
四、测试
在网页里通过脚本语言调用ActiveX控件DeanUSBKey。
可以通过VBScript和JAVAScript来调用。
为了能在脚本语言里使用控件接口,需知道接口的classid,可以查看接口的注册表脚本文件USBKey.rgs找到classid值。
调用代码为:
<
objectclassid="
clsid:
4F3320E4-4B66-4C85-8538-6E17699AAB46"
id="
Dean"
name="
>
/object>
formid="
form1"
name="
method="
post"
action="
"
>
<
ahref="
#"
onclick="
returnCallUSB();
js调用ActiveX测试<
/a>
inputid="
Write"
type="
button"
value="
vb调用ActiveX测试"
/>
/form>
SCRIPTLANGUAGE="
JavaScript"
!
—
//JavaScript调用Demo
functionCallUSB()
{
try{
varUSBContent=Dean.GetContent(0);
alert(USBContent);
}catch(e){
alert("
错误号:
"
+e.number);
returnfalse;
}
//-->
/SCRIPT>
scriptlanguage="
VBScript"
type="
text/vbscript"
‘VBScript调用Demo
SubWrite_OnClick
OnErrorResumeNext
USBContent=Dean.GetContent(0)
MsgBox
USBContent
MsgBox(err.numberand&
hff)
EndSub
/script>
五、部署
Internet软件分发单位是“软件包”,它由包含.INF文件或软件分发.OSD文件(或两者都包括)的.CAB文件所组成。
一个分发单位也可以包含软件组件,如ActiveX控件,DLL文件等。
1、Inf文件编写
INF文件是一个文本文件,指定运行控件所需要下载或者呈交的文件(比如.DLL或者其它.OCX)。
一个.INF文件就捆绑了.CAB压缩文件所有的必须文件。
缺省情况下,与现有硬盘中文件版本号相同的文件不被下载。
INF文件如下:
[version]
signature="
$CHICAGO$"
AdvancedINF=2.0
[Add.Code]
FT_ND_API.dll=FT_ND_API.dll
DeanUSBKey.dll=DeanUSBKey.dll
[FT_ND_API.dll]
file-win32-x86=thiscab
DestDir=11
FileVersion=1,0,6,413
[DeanUSBKey.dll]
file-win32-x86=thiscab
RegisterServer=yes
clsid={4F3320E4-4B66-4C85-8538-6E17699AAB46}
DestDir=11
FileVersion=1,0,0,1
[RegisterFiles]
%11%\DeanUSBKey.dll
说明:
thiscab"
是一个关键字,指包含该INF的CAB文件。
也可以从网上下载所需要的DLL文件,只要指定一个HTTP网址即可,如:
file-win32-x86=
关键字"
file-win32-x86"
指定平台是x86。
FileVersion"
文件版本号。
DestDir"
指的是装载目录或者文件的地址:
11指系统目录WINDOWS/SYSTEM32;
10指Windows目录。
2、Cab打包
Windows在系统目录中自带了CAB制作工具IExpress(\WINDOWS\system32\目录下)。
打开IExpress:
1)选择“CreatenewSelfExtractionDirectivefile”,点击下一步。
2)选择“Createcompressedfilesonly(ActiveXInstalls)”,点击下一步。
3)点击Add,把文件添加(ft_nd_api.dll,DeanUSBKey.dll,duk_usbkey.inf)添加进去,点击下一步。
4)点击Browse,输入.CAB文件的存放地址(包含所取文件名),这里取TestCAB.CAB,并且要选中“StorefilesusingLongFileNameinsidePackage”。
点击下一步。
5)选择“Don’tsave”,一直点击下一步,直到完成。
3、自动安装
用浏览器调用ActiveX组件或者发布组件打包文件都需要用OBJECT元素。
发布.CAB文件,需要在OBJECT元素的CODEBASE特性引用包含.INF文件的.CAB文件。
当访问该页面时,InternetExplorer将自动把.CAB文件作为软件分发单位下载并安装,每次访问时还会自动检测版本并进行更新。
注意,浏览器出于安全性考虑,会拦截未经数字认证的控件。
修改浏览器设置,在Internet选项-〉安全-〉受信任的站点-〉站点中添加服务器地址,不要选复选框“对该区域中的所有站点要求服务器验证”。
解决浏览器拦截问题,而不用更改浏览器的安全级别。
六、结束语
程序在WindowsServer2003+MicrosoftVisualStudio.NET2005(C++)英文版环境下调试通过。
组件技术得到越来越广泛的应用,而VC提供的活动模板库为我们创建功能强大的COM组件提供了很好的框架。
通过ActiveX网页控件使网页也可以访问客户端的硬件资源。
丰富B/S结构系统的功能。