Read the documentation again more carefully. The portion you quoted tells you EXACTLY how to get the image data.
When you receive the WM_XFERSTATUS
window message, it will tell you the image size. Allocate a data buffer that is large enough to accomodate that size, and then pass the buffer to SNAPI_SetImageBuffer()
. The DLL will then fill that buffer with image data. When it is finished, you will receive a WM_IMAGE
message telling you the buffer is ready.
The documentation explains this in more detail in the Data Returned by DLL and Windows Messages Sent to Calling Process sections of Chapter 1.
Update: For example:
type
TScanner = class
public
Device: THandle;
Connected: Boolean;
ImageData: array of Byte;
Pending: Boolean;
procedure Connect;
procedure Disconnect;
procedure RequestSnapshot;
procedure SetImageBuffer(Size: Integer);
end;
const
SNAPI_DLL = 'snapi.dll';
function SNAPI_Init(wnd: HWND; var DeviceHandles: THandle, var NumDevices: Integer): Integer; stdcall; external SNAPI_DLL;
function SNAPI_Connect(DeviceHandle: THandle): Integer; stdcall; external SNAPI_DLL;
function SNAPI_Disconnect(DeviceHandle: THandle): Integer; stdcall; external SNAPI_DLL;
function SNAPI_SetImageBuffer(DeviceHandle: THandle; Data: Pointer; MaxLength: Longint): Integer; stdcall; external SNAPI_DLL;
function SNAPI_SnapShot(DeviceHandle: THandle): Integer; stdcall; external SNAPI_DLL;
const
MAX_SCANNER = ...; // you will have to look this up
BUFFERSIZE_ERROR = $0000;
NOBUFFER_ERROR = $0001;
BUFFERSIZE_GOOD = $0003;
BUFFERSIZE_MASK = $0003;
WM_IMAGE = WM_APP+2;
WM_ERROR = WM_APP+4;
WM_TIMEOUT = WM_APP+5;
WM_XFERSTATUS = WM_APP+7;
WM_DEVICENOTIFICATION := WM_APP+12;
IMAGE_DATA_TIMEOUT = $B1;
type
PDWPARAM = ^DWPARAM;
DWPARAM = record
dwHigh: DWORD;
dwLow: DWORD;
end;
function HIDWORD(wParam: PDWPARAM): DWORD;
begin
Result := wParam^.dwHigh;
end;
function LODWORD(wParam: PDWPARAM): DWORD;
begin
Result := wParam^.dwLow;
end;
type
ESNAPIError = class(Exception)
public
Status: Integer;
constructor CreateErr(AStatus: Integer);
end;
constructor ESNAPIError.CreateErr(AStatus: Integer);
begin
inherited CreateFmt('SNAPI Error %d', [AStatus]);
Status := AStatus;
end;
procedure CheckSNAPIStatus(AStatus: Integer);
begin
if AStatus <> 0 then
raise ESNAPIError.CreateErr(AStatus);
end;
procedure TScanner.Connect;
begin
if not Connected then
begin
CheckSNAPIStatus(SNAPI_Connect(Device));
Connected := True;
end;
end;
procedure TScanner.Disconnect;
begin
if Connected then
begin
SNAPI_Disconnect(Device);
Connected := False;
end;
end;
procedure TScanner.RequestSnapshot;
begin
Connect;
if Pending then
raise Exception.Create('Scanner is busy, try again later');
SetLength(ImageData, 0);
CheckSNAPIStatus(SNAPI_SnapShot(Device));
Pending := True;
end;
procedure TScanner.SetImageBuffer(Size: Integer);
begin
SetLength(ImageData, Size);
CheckSNAPIStatus(SNAPI_SetImageBuffer(Device, Pointer(ImageData), Size));
end;
type
TMyForm = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
ScannerWnd: HWND;
Scanners: TObjectList;
function FindScanner(Device: THandle): TScanner;
procedure ConnectScanner(int Index);
procedure DisconnectScanner(int Index);
procedure RequestSnapshot(int Index);
procedure ScannerWndProc(var Message: TMessage);
end;
procedure TMyForm.FormCreate(Sender: TObject);
var
Devices: array[0..MAX_SCANNER-1] of THandle;
NumScanners, I: Integer;
Scanner: TScanner;
begin
Scanners := TObjectList.Create(True);
ScannerWnd := AllocateHWnd(ScannerWndProc);
CheckSNAPIStatus(SNAPI_Init(ScannerWnd, Devices[0], NumScanners));
for I := 0 to NumScanners-1 do
begin
Scanner := TScanner.Create;
Scanner.Device := Devices[I];
Scanners.Add(Scanner);
// add it to the UI somewhere...
end;
end;
procedure TMyForm.FormDestroy(Sender: TObject);
begin
DeallocateHWnd(ScannerWnd);
Scanners.Free;
end;
function TMyForm.FindScanner(Device: THandle): TScanner;
var
I: Integer;
begin
for I := 0 to Scanners.Count-1 do
begin
Result := TScanner(Scanners[I]);
if Scanner.Device = Device then
Exit;
end;
Result := nil;
end;
procedure TMyForm.ConnectScanner(int Index);
begin
TScanner(Scanners[Index]).Connect;
end;
procedure TMyForm.DisconnectScanner(int Index);
begin
TScanner(Scanners[Index]).Disconnect;
end;
procedure TMyForm.RequestSnapshot(int Index);
begin
TScanner(Scanners[Index]).RequestSnapshot;
end;
procedure TMyForm.ScannerWndProc(var Message: TMessage);
var
Scanner: TScanner;
Param: PDWPARAM;
begin
case Message.Msg of
WM_XFERSTATUS:
begin
Scanner := FindScanner(THandle(Message.LParam));
if Scanner = nil then Exit;
Param := PDWPARAM(Message.WParam);
//BytesRecv := LODWORD(Param)
//BytesTotal := HIDWORD(Param)
if Scanner.ImageData = nil then
Scanner.SetImageBuffer(Integer(HIDWORD(Param)));
end;
WM_IMAGE:
begin
Scanner := FindScanner(THandle(Message.LParam));
if Scanner = nil then Exit;
Scanner.Pending := False;
Param := PDWPARAM(Message.WParam);
// Status := LODWORD(Param)
// BytesTotal := HIDWORD(Param)
if (LODWORD(Param) and BUFFERSIZE_MASK) <> BUFFERSIZE_GOOD then
raise Exception.Create('Image buffer error');
// use Scanner.ImageData as needed...
SetLength(Scanner.ImageData, 0);
end;
WM_DEVICENOTIFICATION:
begin
Param := PDWPARAM(Message.WParam);
// NotifyCode := LODWORD(Param)
case LODWORD(Param) of
DEVICE_ARRIVE:
begin
Scanner := TScanner.Create;
Scanner.Device := THandle(Message.LParam);
Scanners.Add(Scanner);
// add it to the UI somewhere...
end;
DEVICE_REMOVE:
begin
Scanner := FindScanner(THandle(Message.LParam));
if Scanner <> nil then
begin
Scanners.Remove(Scanner);
// remove it from the UI...
end;
end;
end;
end;
WM_TIMEOUT:
begin
Scanner := FindScanner(THandle(Message.LParam));
if Scanner = nil then Exit;
Scanner.Pending := False;
// NotifyCode := HIDWORD(Param)
case HIDWORD(Param) of
IMAGE_DATA_TIMEOUT:
begin
raise Exception.Create('Image timeout');
end;
end;
end;
WM_ERROR:
begin
Scanner := FindScanner(THandle(Message.LParam));
if Scanner = nil then Exit;
Scanner.Pending := False;
Param := PDWPARAM(Message.WParam);
// Status := LODWORD(Param)
CheckSNAPIStatus(Integer(LODWORD(Param)));
end;
else
Message.Result := DefWindowProc(ScannerWnd, Message.Msg, Message.WParam, Message.LParam);
end;
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…