摘 要 TWAIN是扫描仪厂商共同遵循的规格,是应用程序与图像设备间的标准接口。本文介绍了TWAIN的基本原理及开发应用规范,并通过一个开发实例讲解在Delphi环境下控制扫描仪进行图像传输的方法。
关键词 Delphi,TWAIN标准,扫描仪
现在使用扫描仪、数码照相机、以及其他图像获得设备的应用越来越多。因此,如何在应用程序中简单方便地将图像传输到计算机中显得非常重要。而使用TWAIN提供的函数接口,则可以很好地解决这个问题。
一、TWAIN的工作原理
TWAIN 工作组是一个致力于光栅图像输入设备通讯的组织。TWAIN就是它们提供的开发包,它提供了应用程序与图像设备间的标准接口,并且大多数的设备厂家都遵循该接口。利用这个接口就可以有效地解决系统及设备之间的不兼容问题。
TWAIN共包括四个文件,TWAIN_32.DLL、TWAIN.DLL、TWUNKER_32.EXE和 TWUNKER_16.EXE。要使用TWAIN接口,就必须保证上述四个文件安装在系统中。在WindowsXP及其后续版本的操作系统中,已经将这四个文件作为系统文件存放在系统的Windows目录下。其中前两个文件是用于32位应用程序和16位应用程序的支持文件,TWUNKET_32.EXE用于32位应用程序与32位数据源进行通讯,TWUNKET_16.EXE用于32位应用程序与16位数据源进行通讯,后两个文件运行时不可见。
TWAIN依靠三个组件( Application、Source Manager和Source)协同完成与图像设备的通讯和数据传输工作。Application就是用户编写的应用程序,Source Manager是由TWAIN提供的一个Source管理器,它不仅可以收集本地系统已经安装了的图像设备,还可以根据需要去加载设备。同时,它还是Application 与Source通讯的桥梁。(它就是前面提到的组成文件中的dll文件。)Source在这里就是扫描仪在系统中的标识。对用户来说,只要安装好扫描仪的驱动程序并将设备连接上计算机,就可以作为Source使用。
由于TWAIN的标准化,使应用程序可以做到与图像设备无关,即使更换扫描仪也不必对应用程序做任何的改动。
二、DSM_Entry()接口函数
应用程序的目标是从Source中获取数据。通常情况下,应用程序并不能和Source直接通讯。所有的请求包括数据、状态、错误信息等都要通过Source Manager来操作。TWAIN定义了大约140个操作消息,应用程序只要把这些消息通过twain_32.dll中的接口函数DSM_Entry()发送给Source Manager,就可以实现对选定的Source进行相应的操作。
TWAIN把这些操作消息称为Triplets操作,也就是每三个参数表示一组操作。这三个参数类型分别是Data Group(前缀名DG_ )、 Data Argument(前缀名DAT_ ) 和 Message ID(前缀名MSG_ )。
DSM_Entry函数的定义如下:
TW_UINT16 FAR PASCAL DSM_Entry(
pOrigin: pTW_IDENTITY, // 指向操作发起者的指针
pDest: pTW_IDENTITY, //指向目标对象的指针
DG: TW_UINT32, // Data Group参数 : DG_xxxx
DAT: TW_UINT16, // Data Argument参数: DAT_xxxx
MSG:TW_UINT16, //Message ID参数: MSG_xxxx
pData :TW_MEMREF) // 指向返回数据块的指针
其中DG、DAT、MSG参数表示一个Triplets操作。pOrigin、pDest参数会根据不同的Triplets操作而使用不同的值。如果函数成功执行返回值为TWRC_SUCCESS,失败返回TWRC_FAILURE。当然根据Triplets操作的类型不同,还会有其他的返回值,比如TWRC_XFERDONE、TWRC_CANCEL等。
上面的函数中使用了TW_UINT16、TW_UINT32等一些数据类型,在使用TWAIN过程中的所有数据结构可以访问http://www.twain.org/devfiles/twain.h获取。twain.h是C语言的头文件,在Delphi中要将其转换成Pascal语言格式。
三、TWAIN的开发规范
要通过TWAIN实现应用程序和Source的通讯,必须遵循一定的操作规范,它是有逻辑顺序的。比如在Source Manager还没有加载之前,就不可以和Source进行通讯。而这些步骤基本都是利用不同的Triplets操作来实现。下面就结合相应的Triplets操作,给大家介绍一下应用程序和Source之间传输数据的几个基本步骤。
1.加载并获取接口函数
(1)在这个步骤中,没有使用Triplets操作。首先使用LoadLibrary()函数,加载TWAIN_32.DLL文件,并使用GetProcAddress()函数,获得DSM_Entry函数指针。
Type //定义接口函数
DSMENTRYPROC = function(pOrigin: pTW_IDENTITY; pDest: pTW_IDENTITY;
DG: TW_UINT32; DAT: TW_UINT16; MSG: TW_UINT16;
pData: TW_MEMREF): TW_UINT16; stdcall;
var //定义应用程序中用到的全局变量
dsmentry: DSMENTRYPROC;
isdsmopen,isdsopen:Boolean;
hk:hbitmap;
dll:integer;
app,newds,k:ptw_identity;
(2)下面是加载Source Manager并获取DSM_Entry()入口的函数:
Function loaddsm:Boolean;//加载成功返回TRUE
Var
Path:array[0..254] of char;
twRC: TW_UINT16;
Begin
Result:= false;
GetWindowsDirectory(Path,255);
Strcat(Path,'\TWAIN_32.DLL');
if not fileexists(Path) then exit;//系统目录下没有TWAIN_32.DLL则退出
dll:=LoadLibrary(Path);
if dll<>0 then
begin
dsmentry:= GetProcAddress(dll, makeintresource(1));
if @dsmentry = nil then
begin
freelibrary(dll);
exit;
end;
result:=true;
end;
end;
2.打开Source Manager
(1)从这一步开始,所有的操作都要使用Triplets 操作来进行。这里使用的是DG_CONTROL / DAT_PARENT / MSG_OPENDSM组合,在这个操作中,应用程序要指定一个窗体作为Source的父窗体。Source Manager 将通过该窗体,实现Source和应用程序之间的消息传递。
function opendsm:boolean ;
var
twrc:tw_uint16;
begin
//初始化app指针
new(app);
app.Id :=0;
app.Version.MajorNum :=3;
app.Version.MinorNum :=5;
app.Version.Language :=13;
app.Version.Country :=1;
strcopy(app.Version.Info, '1.0');
app.SupportedGroups :=DG_IMAGE or DG_CONTROL;
//指定消息传递的父窗体
winhandle:=form1.Handle;
twrc:=dsmentry(app,NiL,DG_CONTROL,DAT_PARENT,MSG_OPENDSM,TW_MEMREF(@winhandle) );
result:=(twrc=TWRC_SUCCESS);
end;
(2)上面 dsmentry函数中的app参数必须先初始化后再调用,而且它将在下面所有的过程中作为源指针使用。
3.选择Source
Source被打开后,用户需要对其进行选择,因为有可能系统中安装有多个TWAIN设备。这时用户可以通过显示选择数据源对话框来选择或者直接选择默认数据源。这两种方式的Triplets 操作分别是:DG_CONTROL / DAT_IDENTITY / MSG_USERSELECT和DG_CONTROL / DAT_IDENTITY / MSG_GETDEFAULT。下面的代码实现的是显示对话框的方式。
function selds:boolean;
var
twrc:tw_uint16;
begin
new(newds);
newds.Id :=0;//必须为0
newds.ProductName [0]:=#0;//必须为空
twrc:=dsmentry(app, nil, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT,TW_MEMREF(newds));
result:=( twrc=twrc_success);
end;
函数执行后,newds中保存的是被选择的Source,供后续操作使用。
4.打开Source
现在,用户可以将前面选择的Source打开了。使用的Triplets 操作是DG_CONTROL / DAT_IDENTITY / MSG_OPENDS。代码如下:
function opends:boolean;
var
twrc:tw_uint16;
begin
twrc:=dsmentry(app,nil,DG_CONTROL, DAT_IDENTITY, MSG_opends, TW_MEMREF(newds));
result:=(twrc=TWRC_SUCCESS);
end;
在上面的函数中,dsmentry()的最后一个参数pData必须用前一步骤中产生的newds或者它的副本,本程序中直接使用newds。
|