求扫描仪的接口原码!好象有一个通用的动态链接库什么的!(200分)

  • 主题发起人 主题发起人 梅游刃
  • 开始时间 开始时间

梅游刃

Unregistered / Unconfirmed
GUEST, unregistred user!
求扫描仪的接口原码!好象有一个通用的动态链接库什么的!
送上200分。
 
TWAIN32.DLL
除了厂家,好象没有谁去写这东东吧
而且有现成的ActiveX,调用就行,何必要原码?
不同的扫描仪有不同的TWAIN32.DLL,反正ActiveX通用,要来原码干嘛?
 
同意楼上
www.playicq.com查一下,看有没有操作数据库的源码
 
unit Scanners;

interface

uses
SysUtils, Windows, Messages, Graphics,Twain;

resourcestring // Errorstrings:
SErrDSMEntryNotFound = 'DSMEntry not found in Twain DLL';
SErrTwainNotLoaded = 'Twain DLL couldn''t be loaded';
SErrDSMCallFailed = 'DSM Call failed in %s';
SErrDSMUnknownError = 'DSM Call failed in %s: Code %.04x';
SErrDSOpen = 'Cannot Close Source Manager: A Source is Currently Open';
SErrCantGetStatus = 'Can''t get Status';
STWErrGeneralDSM = 'DSM Error at %s:'#13'%s';
STWErrGeneralDS = 'DS Error at %s:'#13'%s';

type
// Exceptions:
ETwainError = class(Exception);

{*******************************************************************
LoadTwain
Tries to load the Twain-DLL.
Result is True if the lib was loaded successfully.

Function is called automatically if needed.

ToDo:
Does this already mean a Scanner is available?
*******************************************************************}
function LoadTwain: Boolean;

{*******************************************************************
UnloadTwain
Removes the (previous) loaded Twain-DLL from Memory
*******************************************************************}
procedure UnloadTwain;

{*******************************************************************
unsorted functions
(Some should move to a DS class?!)
*******************************************************************}
procedure TWOpenDSM(hWnd: HWND);
procedure TWCloseDSM;
function TWIsDSMOpen: Boolean;
procedure TWOpenDS;
procedure TWCloseDS;
procedure TWEnableDS(show: Boolean);
procedure TWEnableDSUIOnly;
procedure TWDisableDS;
function TWIsDSOpen: Boolean;
function TWIsDSEnabled: Boolean;
procedure TWSelectDS;
function ProcessSourceMessage(var Msg: TMsg): Boolean;
procedure TWAcquire(hWnd: HWND; aBmp: TBitmap; show: Boolean);
function TWNativeTransfer: Boolean;

type
TTWTransfer = (ttNative, ttMemory, ttFile);

implementation

const
TWAIN_DLL_Name = 'c:/TWAIN_32.DLL';
DSM_Entry_Name = 'DSM_Entry';//

(*******************************************************************
Some (unsorted) global variables
*******************************************************************)
var
bmp: TBitmap; // the actual bmp used for scanning, must be removed
HDSMDLL: HMODULE = 0; // the library handle: will stay global
appId: TW_IDENTITY; // our (Application) ID. (may stay global)
dsId: TW_IDENTITY; // Data Source ID (will become member of DS class)
hMainWnd: HWND; // maybe will be removed, use application.handle instead

TWDSMOpen: Boolean = False; // flag, may stay global
TWDSOpen: Boolean = False; // will become member of DS class
TWDSEnabled: Boolean = False; // will become member of DS class

(*******************************************************************
Load and unload twain dll
is this conform to twain? (I don't check if 'fileExist', but
LoadLibrary also does this and will fail if the DLL is not
found?!)
This code is currently used for applications, so no DS_Entry
is used, and so that entry is not searched.
*******************************************************************)
function LoadTwain: Boolean;
begin
if HDSMDLL =0 then
begin
HDSMDLL := LoadLibrary(TWAIN_DLL_Name);
DSM_Entry := GetProcAddress(HDSMDLL, DSM_Entry_Name);

if @DSM_Entry = nil then
raise ETwainError.Create(SErrDSMEntryNotFound);
end;

Result := (HDSMDLL <> 0);
end;

procedure UnloadTwain;
begin
if HDSMDLL <> 0 then
begin
DSM_Entry := nil;
FreeLibrary(HDSMDLL);
HDSMDLL := 0;
end;
end;

(******************************************************************
Some helping functions for error handling

ToDo:
check texts, change to resourcestrings and move to
something like a ScannersConst.pas unit
*******************************************************************)
function Condition2String(ConditionCode: TW_UINT16): string;
begin
// Texts copied from PDF Documentation: Rework needed
case ConditionCode of
TWCC_BADCAP:
Result :=
'Capability not supported by Source or operation (get,'#13+
'set) is not supported on capability, or capability had'#13+
'dependencies on other capabilities and cannot be'#13+
'operated upon at this time';
TWCC_BADDEST:
Result := 'Unknown destination in DSM_Entry.';
TWCC_BADPROTOCOL:
Result := 'Unrecognized operation triplet.';
TWCC_BADVALUE:
Result := 'Data parameter out of supported range.';
TWCC_BUMMER:
Result := 'General failure. Unload Source immediately.';
TWCC_CAPUNSUPPORTED:
Result := 'Capability not supported by Source.';
TWCC_CAPBADOPERATION:
Result := 'Operation not supported on capability.';
TWCC_CAPSEQERROR:
Result :=
'Capability has dependencies on other capabilities and '#13+
'cannot be operated upon at this time.';
TWCC_DENIED:
Result := 'File System operation is denied (file is protected).';
TWCC_PAPERDOUBLEFEED:
Result := 'Transfer failed because of a feeder error';
TWCC_FILEEXISTS:
Result := 'Operation failed because file already exists.';
TWCC_FILENOTFOUND:
Result := 'File not found.';
TWCC_LOWMEMORY:
Result := 'Not enough memory to complete operation.';
TWCC_MAXCONNECTIONS:
Result :=
'Source is connected to maximum supported number of applications.';
TWCC_NODS:
Result := 'Source Manager unable to find the specified Source.';
TWCC_NOTEMPTY:
Result := 'Operation failed because directory is not empty.';
TWCC_OPERATIONERROR:
Result :=
'Source or Source Manager reported an error to the'#13+
'user and handled the error; no application action required.';
TWCC_PAPERJAM:
Result := 'Transfer failed because of a feeder error';
TWCC_SEQERROR:
Result := 'Illegal operation for current Source Manager'#13+
'Source state.';
TWCC_SUCCESS:
Result := 'Operation worked.';
else
Result := Format('Unknown Condition %.04x', [ConditionCode]);
end;
end;

(*******************************************************************
RaiseLastDSMCondition (idea: like RaiseLastWin32Error)
Tries to get the status from the DSM and raises an exception
with it.
*******************************************************************)
procedure RaiseLastDSMCondition(at: string);
var
status: TW_STATUS;
begin
Assert(@DSM_Entry <> nil);
if DSM_Entry(@appId, nil, DG_CONTROL, DAT_STATUS, MSG_GET,
@status) <> TWRC_SUCCESS then
raise ETwainError.Create(SErrCantGetStatus)
else
raise ETwainError.CreateFmt(STWErrGeneralDSM, [at,
Condition2String(status.ConditionCode)]);
end;

(*******************************************************************
RaiseLastDSCondition
same again, but for the actual DS
(should be a method of DS)
*******************************************************************)
procedure RaiseLastDSCondition(at: string);
var
status: TW_STATUS;
begin
Assert(@DSM_Entry <> nil);
if DSM_Entry(@appId, @dsID, DG_CONTROL, DAT_STATUS, MSG_GET, @status) <>
TWRC_SUCCESS then
raise ETwainError.Create(SErrCantGetStatus)
else
raise ETwainError.CreateFmt(STWErrGeneralDS, [at,
Condition2String(status.ConditionCode)]);
end;

(*******************************************************************
TwainCheckDSM (idea: like Win32Check or GDICheck in Graphics.pas)
*******************************************************************)
procedure TwainCheckDSM(res: TW_UINT16; at: string);
begin
if res <> TWRC_SUCCESS then
begin
if res = TWRC_FAILURE then
RaiseLastDSMCondition(at)
else
raise ETwainError.CreateFmt(SErrDSMUnknownError, [at, res]);
end;
end;

(*******************************************************************
TwainCheckDS
same again, but for the actual DS
(should be a method of DS)
*******************************************************************)
procedure TwainCheckDS(res: TW_UINT16; at: string);
begin
if res <> TWRC_SUCCESS then
begin
if res = TWRC_FAILURE then
RaiseLastDSCondition(at)
else
raise ETwainError.CreateFmt(SErrDSMUnknownError, [at, res]);
end;
end;

(*******************************************************************
CallDSMEntry:
Short form for DSM Calls: appId is not neaded as parameter
*******************************************************************)
function CallDSMEntry(pDest: pTW_IDENTITY; DG: TW_UINT32; DAT: TW_UINT16;
MSG: TW_UINT16; pData: TW_MEMREF): TW_UINT16;
begin
Assert(@DSM_Entry <> nil);

Result := DSM_Entry(@appID, pDest, DG, DAT, MSG, pData);
if (Result <> TWRC_SUCCESS) and (DAT <> DAT_EVENT) then
begin
end;
end;

(*******************************************************************
Short form for (actual) DS Calls. appId and dsID is not needed
(this should be a DS class method)
*******************************************************************)
function DSCall(DG: TW_UINT32; DAT: TW_UINT16; MSG: TW_UINT16;
pData: TW_MEMREF): TW_UINT16;
begin
Assert(@DSM_Entry <> nil);
Result := DSM_Entry(@appID, @dsID, DG, DAT, MSG, pData);
end;

(*******************************************************************
A lot of the following code is a conversion from the
twain example program
(and some comments are copied, too)

(The error handling is done differently)

Most functions should be moved to a DSM or DS class
*******************************************************************)

(*******************************************************************
Functions from DCA_GLUE.C
*******************************************************************)
procedure TWOpenDSM(hWnd: HWND);
begin
if not TWDSMOpen then
begin
Assert(hWnd <> 0);

if not LoadTwain then
raise ETwainError.Create(SErrTwainNotLoaded);

appId.Id := 0; // init to 0, but Source Manager will assign real value

appId.Version.MajorNum := 1;
appId.Version.MinorNum := 0;
appId.Version.Language := TWLG_USA;
appId.Version.Country := TWCY_USA;
appId.Version.Info := 'Delphi Twain Test';

appId.ProtocolMajor := 1; // TWON_PROTOCOLMAJOR;
appId.ProtocolMinor := 7; //TWON_PROTOCOLMINOR;
appId.SupportedGroups := DG_IMAGE or DG_CONTROL;

appID.ProductName := 'TwainTest';
appId.ProductFamily := 'Delphi Twain Framework';
appId.Manufacturer := 'TeSoft';

hMainWnd := hWnd;

TwainCheckDSM(CallDSMEntry(nil, DG_CONTROL, DAT_PARENT, MSG_OPENDSM,
@hMainWnd), 'TWOpenDSM');

TWDSMOpen := True;
end;
end;

procedure TWCloseDSM;
begin
if TWDSOpen then
raise ETwainError.Create(SErrDSOpen);

if TWDSMOpen then
begin
// This call performs one important function:
// - tells the SM which application, appID.id, is requesting SM to close
// - be sure to test return code, failure indicates SM did not close !!

TwainCheckDSM(CallDSMEntry(nil, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM,
@hMainWnd), 'TWCloseDSM');

TWDSMOpen := False;

UnloadTwain;
end;
end;

function TWIsDSMOpen: Boolean;
begin
Result := TWDSMOpen;
end;

procedure TWOpenDS;
begin
Assert(TWDSMOpen, 'DSM must be open');

if not TWDSOpen then
begin
TwainCheckDSM(CallDSMEntry(nil, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, @dsID),
'TWOpenDS');
TWDSOpen := True;
end;
end;

procedure TWCloseDS;
begin
Assert(TWDSMOpen, 'DSM must be open');
if TWDSOpen then
begin
TwainCheckDSM(CallDSMEntry(nil, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, @dsID),
'TWCloseDS');
TWDSOpen := False;
end;
end;

procedure TWEnableDS(show: Boolean);
var
twUI: TW_USERINTERFACE;
begin
Assert(TWDSOpen, 'DS must be open');

if not TWDSEnabled then
begin
FillChar(twUI, SizeOf(twUI), #0);

twUI.hParent := hMainWnd;
twUI.ShowUI := show;

TwainCheckDSM(CallDSMEntry(@dsID, DG_CONTROL, DAT_USERINTERFACE,
MSG_ENABLEDS, @twUI), 'TWEnableDS');

TWDSEnabled := True;
end;
end;

procedure TWEnableDSUIOnly;
var
twUI: TW_USERINTERFACE;
begin
Assert(TWDSOpen, 'DS must be open');

if not TWDSEnabled then
begin
FillChar(twUI, SizeOf(twUI), #0);

twUI.hParent := hMainWnd;
twUI.ShowUI := True;

TwainCheckDSM(CallDSMEntry(@dsID, DG_CONTROL, DAT_USERINTERFACE,
MSG_ENABLEDSUIONLY, @twUI), 'TWEnableDSUIOnly');

TWDSEnabled := True;
end;
end;

procedure TWDisableDS;
var
twUI: TW_USERINTERFACE;
begin
Assert(TWDSOpen, 'DS must be open');

if TWDSEnabled then
begin
twUI.hParent := hMainWnd;
twUI.ShowUI := TW_BOOL(TWON_DONTCARE8); (*!!!!*)

TwainCheckDSM(CallDSMEntry(@dsID, DG_CONTROL, DAT_USERINTERFACE,
MSG_DISABLEDS, @twUI), 'TWDisableDS');

TWDSEnabled := False;
end;
end;

function TWIsDSOpen: Boolean;
begin
Result := TWDSOpen;
end;

function TWIsDSEnabled: Boolean;
begin
Result := TWDSEnabled;
end;

procedure TWSelectDS;
var
NewDSIdentity: TW_IDENTITY;
twRC: TW_UINT16;
begin
Assert(not TWDSOpen, 'Source must not be open');

TwainCheckDSM(CallDSMEntry(nil, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT,
@NewDSIdentity), 'TWSelectDS:Select Default');

twRC := CallDSMEntry(nil, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT,
@NewDSIdentity);

case twRC of
TWRC_SUCCESS:
dsID := NewDSIdentity; // log in new Source
TWRC_CANCEL:
; // keep the current Source
else
TwainCheckDSM(twRC, 'TWSelectDS:User Select');
end;
end;

(*******************************************************************
Functions from CAPTEST.C
*******************************************************************)
procedure TWXferMech(transfer: TTWTransfer);
var
cap: TW_CAPABILITY;
pVal: pTW_ONEVALUE;
begin
cap.Cap := ICAP_XFERMECH;
cap.ConType := TWON_ONEVALUE;

cap.hContainer := GlobalAlloc(GHND, SizeOf(TW_ONEVALUE));
Assert(cap.hContainer <> 0);
try

pval := pTW_ONEVALUE(GlobalLock(cap.hContainer));
Assert(pval <> nil);
try
pval.ItemType := TWTY_UINT16;
case transfer of
ttMemory:
pval.Item := TWSX_MEMORY;
ttFile:
pval.Item := TWSX_FILE;
else
pval.Item := TWSX_NATIVE
end;
finally
GlobalUnlock(cap.hContainer);
end;

TwainCheckDS(DSCall(DG_CONTROL, DAT_CAPABILITY, MSG_SET, @cap),
'Set Xfer Mech');

finally
GlobalFree(cap.hContainer);
end;

end;


(*******************************************************************
Functions from DCA_ACQ.C
*******************************************************************)
function ProcessSourceMessage(var Msg: TMsg): Boolean;
var
twRC: TW_UINT16;
event: TW_EVENT;
pending: TW_PENDINGXFERS;
begin
Result := False;

if TWDSMOpen and TWDSOpen then
begin
event.pEvent := @Msg;
event.TWMessage := 0;

twRC := DSCall(DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, @event);

case event.TWMessage of
MSG_XFERREADY:
begin
// ToDo!
TWNativeTransfer;

TwainCheckDS(DSCall(DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, @pending),
'Check for Pending Transfers');

if pending.Count > 0 then
TwainCheckDS(DSCall(DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET,
@pending), 'Abort Pending Transfers');

TWDisableDS;
TWCloseDS;
end;
MSG_CLOSEDSOK, MSG_CLOSEDSREQ:
begin
TWDisableDS;
TWCloseDS;
end;
end;

Result := not (twRC = TWRC_NOTDSEVENT);
end;
end;

procedure TWAcquire(hWnd: HWND; aBmp: TBitmap; show: Boolean);
begin
bmp := aBmp;

TWOpenDSM(hWnd);
TWOpenDS;
TWXferMech(ttNative);
TWEnableDS(True);

// Here could be my own message loop with processSourceMessage
// inside? (similar to TCustomForm.ShowModal)

// Or the alternative:
// An 'invisible' Form (Size=0) shown per ShowModal ?!
end;

function TWNativeTransfer: Boolean;

function DibNumColors(dib: Pointer): Integer;
var
lpbi: PBITMAPINFOHEADER;
lpbc: PBITMAPCOREHEADER;
bits: Integer;
begin
lpbi := dib;
lpbc := dib;

if lpbi.biSize <> SizeOf(BITMAPCOREHEADER) then
begin
if lpbi.biClrUsed <> 0 then
begin
Result := lpbi.biClrUsed;
Exit;
end;
bits := lpbi.biBitCount;
end
else
bits := lpbc.bcBitCount;

case bits of
1:
Result := 2;
4:
Result := 4;
8:
Result := 8;
else
Result := 0;
end;
end;

var
twRC: TW_UINT16;
hDIB: TW_UINT32;
hBmp: HBITMAP;
lpDib: ^TBITMAPINFO;
lpBits: PChar;
ColorTableSize: Integer;
dc: HDC;

begin
Result := False;

twRC := DSCall(DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, @hDIB);

case twRC of
TWRC_XFERDONE:
begin
lpDib := GlobalLock(hDIB);
try
ColorTableSize := (DibNumColors(lpDib) * SizeOf(RGBQUAD));

lpBits := PChar(lpDib);
Inc(lpBits, lpDib.bmiHeader.biSize);
Inc(lpBits, ColorTableSize);

dc := GetDC(0);
try
hBMP := CreateDIBitmap(dc, lpdib.bmiHeader, CBM_INIT,
lpBits, lpDib^, DIB_RGB_COLORS);

bmp.Handle := hBMP;

Result := True;
finally
ReleaseDC(0, dc);
end;
finally
GlobalUnlock(hDIB);
GlobalFree(hDIB);
end;
end;

TWRC_CANCEL:
;

TWRC_FAILURE:
RaiseLastDSMCondition('Native Transfer');
end;
end;

end.
 
讨论主题以前让我们先来了解今天的主角「TWAIN」到底是什么?早期的Developer为了发展具备「截取图形」的应用程式,伤透了脑筋,他们必须从各个发展平台(plateform)的SDK(Software Development Kit)中寻求各厂牌扫描机的技术支援资料,也因此花费了许多的人力与时间。主要的原因是各家的标准不一。直到1992年春,业界的几个龙头∶Aldus, Caere, Eastman-Kodak, Hewlett-Packard, Logitech Corporations共同制定了一套标准技术来解决长期困扰的问题,(题外话∶台湾的罗技电子也在其中,大家是否与有荣焉?)业界称这个标准为TWAIN,它适用於MS-WIN, UNIX, MAC这几个平台。当然大家也知道∶尔後陆续发展出来的影像输入设备,几乎都支援这个标准;大约有175家软应体发展公司也加入这个组织。如果对它有兴趣的狐友可至www.twain.org去看看。当然我们今天讨论主题所使用的「EZTWAIN」也是由这个组织所发展的。狐友必须先到前面所提的web site 去download 「eztw105.zip」这支档案,才有办法去达成扫图的目的(假设您不采用直接呼叫twain.dll(16bit)或twain_32.dll(32bit),及使用OLE技术的话)。

探讨:

为什么不直接使用呼叫twain.dll的技术却使用了eztwain.dll ?其实在很多情况下AP所要求的功能是「有图就好」,譬如∶员工、会员、产品资料库等等。在这些资料的维护程序中「图」只是一个辅助资料,Users并不需要太去关心影像的品质(如:解析度、色相、亮度对比…..)。更何况要user去了解这些影像专有名词或去操作影像处理(应用)程式只会增加user的困扰(透过OLE的方式来操作也是如此)。既然如此,developer就应该让user在不需切换程式的前题下去取得影像,共用的UI使用起来将方便很多。既然如此,吾人便必需去「驾驭」twain.dll。可是「驾驭」何其容易?动态联结函数库dll的使用原本就蛮麻烦的(如果您手头没有资料,至少取得其相关参数、资料型态或传回值是挺累人的)。更何况坊间要取得twain.dll这个「影像专用」的函式库相关资讯好像蛮难的。就算拿到了,里头对影像的相关规范会让很多人望之却步。前面谈到∶「了解那么多干嘛?又不是写影像处理软体!」确实,如果只是要扫图,只需用到某些函式就可以了。於是乎,TWAIN写了「简易版」来解决这样的问题,那就是eztwain.dll的由来。利用eztwain中的少数几个函式便可达到统一UI的目的。请注意∶只是「统一UI」而已,并不是完全使用自设的界面。也就是说∶利用eztwain在user不必切换程式的情形下来呼叫原硬体厂商所提供的影像输入使用者界面。扫图後可以直接回存至通用栏位或先在萤幕上显示後再决定
 

Similar threads

D
回复
0
查看
758
DelphiTeacher的专栏
D
D
回复
0
查看
766
DelphiTeacher的专栏
D
D
回复
0
查看
782
DelphiTeacher的专栏
D
S
回复
0
查看
745
SUNSTONE的Delphi笔记
S
S
回复
0
查看
754
SUNSTONE的Delphi笔记
S
后退
顶部