扫描程序设计说明文档
一、TWAIN的文件组成
TWAIN共包括4个二进制文件。如果要使用该接口,就必须要保证他们被成功地安装在本地计算机上。
文 件 名
说 明
TWAIN_32.DLL
32位应用程序的支持文件,32位程序使用TWAIN通讯必须使用该文件。
TWAIN.DLL
16位应用程序的支持文件,16位程序使用TWAIN通讯必须使用该文件。
TWUNKER_32.EXE
实现32位应用程序与32位数据源进行通讯,它运行时不可见。
TWUNKER_16.EXE
实现32位应用程序与16位数据源进行通讯,它运行时不可见。
注意:在Windows NT 环境下16位数据源不能够正常工作。
在Windows 操作系统中,Microsoft已经把这些文件作为系统文件随同操作系统一起发布了。可以在Windows安装目录中查找到这些文件。通过TWAIN提供的头文件,可以实现扫描功能。
二、TWAIN的结构
TWAIN依靠三个组件协同完成与图像设备的通讯和数据传输工作,这三个组件就是 Application、Source Manager和Source。
组件
说明
Application
就是你要编写的应用程序。
Source Manager
是由TWAIN提供的一个Source的管理器,它不仅可以收集本地系统已经安装了的图像设备,还可以根据需要去加载设备。同时,它最重要的功能是担任Application 与Source通讯的桥梁。(其实,它就是我们前面提到的组成文件中的dll文件。)
Source
在这里可以看作是图像设备。事实上它是由设备厂家提供的一个dll文件。这个dll文件是支持twain接口的。
它们的层次结构图如下:
从上图可以看到,Application要从Source获得图像数据,必须通过Source Manager传递来实现。Application与Source Manager 间的通讯是靠调用TWAIN提供的OpenDSM( )函数实现。而Application不能直接与Source 通讯,Source Manager与Source 间的通讯是靠调用TWAIN提供的OpenDS()函数实现。
三、消息定义
TWAIN把它定义的操作称为Triplets操作,就是每个操作用三个定义的参数来表示。这个三个参数用不同前缀名来区分。这三个参数类型分别是Data Group、 Data Argument和 Message ID。每个Triplets操作都是唯一的,不会有歧意,它们代表一个特定的操作行为。
四、TWAIN的接口函数
要编写应用程序实现与支持TWAIN标准的图像设备通讯,只需要了解上面提到的OpenDSM( )接口函数。TWAIN定义了大约140个操作消息。只要把这些消息通过OpenDSM( )函数发给Source Manager,就可以实现对选定的Source进行相应的操作。Source Manager会分辨那些消息属于自己,那些消息是该转发给Source。
在使用OpenDSM( )前,必须要加载TWAIN_32.DLL文件以获得OpenDSM( )函数指针。 TWAIN所有的操作都是通过OpenDSM( )函数来实现的。
五、TWAIN的操作流程
Application、 Source Manager 和 Source要实现数据传输,必须遵循一个操作流程。你要进行的操作应该在这个流程规定的动作队列中按逻辑去执行。比如,在没有加载Source Manager前,Application是不能要求Source传输数据的。为了更好的去描述这个流程,TWAIN为该流程定义了7个状态(1-7)。
状态位 1, 2, 3
这几个状态是用于描述Source Manager的,它们是Source Manager专有的状态位,所以Source Manager 的标志位是不会大于3的.
状态位4, 5, 6, 7
这几个状态是Source专有的。如果Source打开了,Source 的标志位就不会小于4;如果Source关闭了,Source就没有了标志位。
应用程序可以使用了多个Source,每个与Source的连接都是一个单独的会话,对于打开的每个Source,他们的标志位都是相互独立的,不互相关联。
流程标志位说明
状态 1 – 准备会话
在Application和Source Manager建立会话前,Source Manager的标志位是1。
在这个时候,Source Manager还没有被加载到内存中。如果Source Manager 被加载到内存中,则状态位是2或者3。
状态2 –加载Source Manager
Source Manager现在已经被成功地加载到了程序中,但是没有打开Source Manager。
在这个时候, Source Manager开始准备去接受Application的Triplets操作。
状态3 – 打开Source Manager
Source Manager已经打开并且准备去管理Source。Source Manager现在准备向Source发送打开操作,去打开指定的Source,并等待所有针对Source的操作结束后,去关闭打开的Source。Source Manager在会话关闭前,状态位将保持为3。 当Application打开的Source没有关闭时,Source Manager 会拒绝关闭。
状态 4 – 打开Source
在响应Application的一个指定的Triplets操作后,Source被加载到系统中,并且被Source manager 打开。Source在加载前将检测是否有足够的系统资源让自己运行(内存、设备是否可用等等…)。 Application不仅可以查询Source的性能参数(当前解析度、是否支持彩色或黑白图像、自动文档传送是否可用), Application还可以去设置的Source的性能参数。比如Application可以要求Source按指定的分辨率传输黑白图像。
注意: 可以在Source的状态位是4, 5, 6, 或 7时,去查询Source的性能参数。但是要想设置Source的性能参数必须在状态位是4的时候设置,除非Application和Source有特殊的约定,否则在标志位为其他数的时候都不可以进行性能参数设置。
状态 5 – Source可用
现在可以让Source工作了,此时Source开始为数据传输做准备。在该状态下,可以执行一个Triplets操作,用以选择是否让Source显示它自己的用户界面(Source提供的软件界面)。当Source准备好给Application传输数据时,标志位就从5变为6了。
状态 6 –准备数据传输
该状态下,Source已经准备好了为Application传输数据。在传输工作开始前,Application应该查询将要被传输的图像的相关信息(分辨率,图像大小…)。
状态 7 –传输开始
Source开始进行数据传输,它把获得的数据传输给你的应用程序。 传输工作要么成功完成,要么提前中止。在传输工作完成后, Source将会发送一个返回代码去表示传输工作的最终结果。
八、TWAIN的应用实现
1. 初始化TWAIN
void CLcTwain::InitializeTwain(HWND hMainWnd)
{
appID.Id = 0; appID.Version.MajorNum = 1;
appID.Version.MinorNum = 703;
appID.Version.Language = TWLG_USA;
appID.Version.Country = TWCY_USA;
#ifdef WIN32
lstrcpy (appID.Version.Info, "TWAIN_32 Twacker 1.7.0.3 01/18/1999");
lstrcpy (appID.ProductName, "TWACKER_32");
#else
lstrcpy (appID.Version.Info, "TWAIN Twacker 1.7.0.3 01/18/1999");
lstrcpy (appID.ProductName, "TWACKER_16");
#endif
appID.ProtocolMajor = 1;//TWON_PROTOCOLMAJOR;
appID.ProtocolMinor = 7;//TWON_PROTOCOLMINOR;
appID.SupportedGroups = DG_IMAGE | DG_CONTROL;
lstrcpy (appID.Manufacturer, "TWAIN Working Group");
lstrcpy (appID.ProductFamily, "TWAIN Toolkit");
// pass app particulars to glue code
ASSERT(&appID);
ASSERT(hMainWnd);
hWnd = hMainWnd; // get copy of app window handle
OpenDSM();
return;
}
2. 选择默认的扫描仪
BOOL CLcTwain::TWSelectDefaultDS()
{
TW_UINT16 twRC = TWRC_FAILURE;
TW_IDENTITY NewDSIdentity;
memset(&NewDSIdentity, 0, sizeof(TW_IDENTITY));
if (TWDSOpen)
{
twRC = TWRC_FAILURE;
}
else
{
twRC = CallDSMEntry(&appID,
NULL,
DG_CONTROL,
DAT_IDENTITY,
MSG_GETDEFAULT,
(TW_MEMREF)&NewDSIdentity);
dsID = NewDSIdentity;
}
return (twRC);
}
3. 打开Source Manager
BOOL CLcTwain::OpenDSM()
{
TW_UINT16 twRC = TWRC_FAILURE;
OFSTRUCT OpenFiles;
#define WINDIRPATHSIZE 160
char WinDir[WINDIRPATHSIZE];
TW_STR32 DSMName;
memset(&OpenFiles, 0, sizeof(OFSTRUCT));
memset(WinDir, 0, sizeof(char[WINDIRPATHSIZE]));
memset(DSMName, 0, sizeof(TW_STR32));
if (TWDSMOpen!=TRUE)
{
GetWindowsDirectory (WinDir, WINDIRPATHSIZE);
strcpy(DSMName,"TWAIN_32.DLL");
if ((hDSMDLL = LoadLibrary(DSMName)) != NULL &&
(hDSMDLL >= (HANDLE)VALID_HANDLE) &&
(lpDSM_Entry = (DSMENTRYPROC)GetProcAddress(hDSMDLL, MAKEINTRESOURCE (1))) != NULL)
{
twRC = CallDSMEntry(&appID,
NULL,
DG_CONTROL,
DAT_PARENT,
MSG_OPENDSM,
(TW_MEMREF)&hWnd);
switch (twRC)
{
case TWRC_SUCCESS:
TWDSMOpen = TRUE;
break;
case TWRC_FAILURE:
default:
// Trouble opening the SM, inform. the user
TWDSMOpen = FALSE;
break;
}
}
else
return -1;
}
// Let the caller know what happened
return (TWDSMOpen);
}
4. 打开Source
BOOL CLcTwain::OpenDS()
{
TW_UINT16 twRC = TWRC_FAILURE;
if (TWDSMOpen==FALSE)
{
OpenDSM();
}
else
{
if (TWDSOpen==TRUE)
{
}
else
{
twRC = CallDSMEntry(&appID,
NULL,
DG_CONTROL,
DAT_IDENTITY,
MSG_OPENDS,
&dsID);
switch (twRC)
{
case TWRC_SUCCESS:
// do not change flag unless we successfully open
TWDSOpen = TRUE;
break;
case TWRC_FAILURE:
break;
default:
break;
}
}
}
return TWDSOpen;
}
5. 处理Source的事件
BOOL CLcTwain::ProcessTWMessage(LPMSG lpMsg, HWND hWnd)
{
TW_UINT16 twRC = TWRC_NOTDSEVENT;
TW_EVENT twEvent;
memset(&twEvent, 0, sizeof(TW_EVENT));
ASSERT(lpMsg);
ASSERT(hWnd);
if ((IsDSMOpen()) && (TWIsDSOpen()))
{
twEvent.pEvent = (TW_MEMREF)lpMsg;
if(((lpMsg->wParam != 0) && (lpMsg->lParam == 0)) ||((lpMsg->wParam == 0) && (lpMsg->lParam != 0)))
{
twRC = CallDSMEntry(&appID,
&dsID,
DG_CONTROL,
DAT_EVENT,
MSG_PROCESSEVENT,
(TW_MEMREF)&twEvent);
switch (twEvent.TWMessage)
{
case MSG_XFERREADY:
//If AcqFlag >0 then we are in state 5
if (AcqFlag)
{
TWTransferImage(hWnd);
}
break;
case MSG_CLOSEDSREQ:
case MSG_CLOSEDSOK:
if (TWDisableDS())
{
// if (CloseDS())
{
// CloseDSM(NULL);
}
}
break;
case MSG_NULL:
default:
break;
}
}
}
// tell the caller what happened
return (twRC==TWRC_DSEVENT); // returns TRUE or FALSE
}
6. 使用本地模式传输数据
void CLcTwain::DoNativeTransfer(HWND hWnd)
{
TW_PENDINGXFERS twPendingXfer;
TW_UINT16 twRC = TWRC_FAILURE;
TW_UINT16 twRC2 = TWRC_FAILURE;
TW_UINT32 hBitMap = NULL;
HANDLE hbm_acq = NULL; char buffer[2048];
CString Weishu1, strTemp, test;
static CString str;
LPBITMAPINFOHEADER lpdib = NULL;
BOOL g_bSpecialMenu = FALSE;
memset(&twPendingXfer, 0, sizeof(TW_PENDINGXFERS));
memset(buffer, 0, sizeof(char[2048]));
ASSERT(hWnd);
twPendingXfer.Count = 0;
do
{
twRC = CallDSMEntry(&appID,
&dsID,
DG_IMAGE,
DAT_IMAGENATIVEXFER,
MSG_GET,
(TW_MEMREF)&hBitMap);
CFileFind finder;
test.Format("%s//%s//*.%s",Folder,pici,FileFormat);
BOOL bWorking = finder.FindFile(test);
int j = 0;
int k = 1;
while (bWorking)
{
bWorking = finder.FindNextFile();
if(finder.GetFileName() !='.' && finder.GetFileName() != ".." && finder.GetFileName()!="Thumbs.db")
{
++k;
strTemp.Format("%d",k);
j = strlen(strTemp);
if(j == 0 || j==1)
j =0;
strTemp.Format("%d",j);
}
test = finder.GetFileName();
str.Format("%s//%s//%s",Folder,pici,test);
}
if(i == 0)
{
int n = atoi(Weishu);
int m = n -j;
switch(m)
{
case 0: Weishu1 = "";break;
case 1: Weishu1 = "";break;
case 2: Weishu1 = "0";break;
case 3: Weishu1 = "00";break;
case 4: Weishu1 = "000";break;
case 5: Weishu1 = "0000";break;
case 6: Weishu1 = "00000";break;
case 7: Weishu1 = "000000";break;
case 8: Weishu1 = "0000000";break;
case 9: Weishu1 = "00000000";break;
}
str.Format("%s//%s//%s%s%d.%s",Folder,pici,FileName,Weishu1,k,FileFormat);
int type = FindType(FileFormat);
CxImage* ima = new CxImage();
ima->CreateFromHANDLE((HBITMAP)hBitMap);
ima->Save(str, type);
if(Single == "0")
{
i++;
}
}
else
{
//单页tiff
{
FILE* fdest=fopen(str, "r+b");
CxImageTIF* ima2app = new CxImageTIF;
ima2app->CreateFromHANDLE((HBITMAP)hBitMap);
ima2app->SetFrame(i);
ima2app->Encode(fdest, true);
delete ima2app;
fclose(fdest);
}
}
//////////////////////////////////////////////////////////////////
switch (twRC)
{
case TWRC_XFERDONE:
hbm_acq = (HBITMAP)hBitMap;
g_bSpecialMenu = FALSE;
twRC2 = CallDSMEntry(&appID,
&dsID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_ENDXFER,
(TW_MEMREF)&twPendingXfer);
if (twRC2 != TWRC_SUCCESS)
{
}
wsprintf(buffer,"Pending Xfers = %d/r/n",twPendingXfer.Count);
if (twPendingXfer.Count == 0)
{
if (hbm_acq&&(lpdib = (LPBITMAPINFOHEADER)GlobalLock(hbm_acq))!=NULL)
{
if(!g_bSpecialMenu)
{
CloseConnection(NULL);
}
GlobalUnlock(hbm_acq);
}
}
if (hbm_acq >= (HANDLE)VALID_HANDLE)
{
SendMessage(hWnd, PM_XFERDONE, (WPARAM)hbm_acq, 0); }
else
{
SendMessage(hWnd, PM_XFERDONE, NULL, 0);
}
break;
case TWRC_CANCEL:
twRC2 = CallDSMEntry(&appID,
&dsID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_ENDXFER,
(TW_MEMREF)&twPendingXfer);
if (twRC2 != TWRC_SUCCESS)
{
}
if (twPendingXfer.Count == 0)
{
if(!g_bSpecialMenu)
{
CloseConnection(NULL);
}
}
SendMessage(hWnd, PM_XFERDONE, NULL, 0);
break;
case TWRC_FAILURE:
twRC2 = CallDSMEntry(&appID,
&dsID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_ENDXFER,
(TW_MEMREF)&twPendingXfer);
if (twRC2 != TWRC_SUCCESS)
{
}
if (twPendingXfer.Count == 0)
{
if(!g_bSpecialMenu)
{
CloseConnection(NULL);
}
}
SendMessage(hWnd, PM_XFERDONE, NULL, 0);
break;
default:
twRC2 = CallDSMEntry(&appID,
&dsID,
DG_CONTROL,
DAT_PENDINGXFERS,
MSG_ENDXFER,
(TW_MEMREF)&twPendingXfer);
if (twRC2 != TWRC_SUCCESS)
{
}
if (twPendingXfer.Count == 0)
{
if(!g_bSpecialMenu)
{
CloseConnection(NULL);
}
}
SendMessage(hWnd, PM_XFERDONE, NULL, 0);
break;
}
}while(twPendingXfer.Count != 0);
AcqFlag = 0;
}