rpnoble419 has asked for the wisdom of the Perl Monks concerning the following question:
I bow to the monks
I'm writing an interface to a barcode scanner from Socket mobile. I have the latest SDK and all seamed to work just fine untill I needed to get the scanned data from the scanner.
Using Win32::API, I created the following link to the scanner's dll
my $ScanGetData = Win32::API->new('ScanAPI.dll','long ScanGetData(HANDLE hScanner, LPSTR lpBuff, LPINT BufSize)');
When I called the $ScanGetData function it caused perl to crash. I spent the next 9 hours debugging my function calls and parameters. What I found to work was:
sub WMSCANNERDATA { print "Scanner Has data waiting\n"; my ($object, $wParam, $lParam, $type, $msgcode) = @_; return unless $type == 0; return unless $msgcode == WM_SCANNERDATA; print "Data size: $wParam\n"; my $buffer= 0 x $wParam; my $ret=$ScanGetData->Call($ScannerHandle, $buffer, \$buffersi +ze); print "Return code: $ret"; if ($ret != SR_SUCCESS) { &DisplayScanError($ret); exit; } print $buffer."\n\n"; return 1; }
This code would work for the first scan and then cause perl to crash on the second scan. I figured out the the \$buffersize was not being dereferenced. After much searching I found that this code would work:
sub WMSCANNERDATA { print "Scanner Has data waiting\n"; my ($object, $wParam, $lParam, $type, $msgcode) = @_; return unless $type == 0; return unless $msgcode == WM_SCANNERDATA; print "Data size: $wParam\n"; my $buffer= 0 x $wParam; # added this line to make function call work my $buffersize= \$wParam; my $ret=$ScanGetData->Call($ScannerHandle, $buffer, $buffersiz +e); # Inform scanApi.dll this application does nor handle call bac +ks print "Return code: $ret"; if ($ret != SR_SUCCESS) { &DisplayScanError($ret); exit; } print $buffer."\n\n"; return 1; }
Here is the actual function description from the scanner docs
SCANGETDATA() Prototype: SCAN_RESULT ScanGetData(HANDLE hScanner, TCHAR * lpBuff, LPINT BufSize +); Purpose: Returns scanned data after a successful read operation on the scanner +device. Arguments: [in] hScanner is the value received by the client application in lPara +m of the WM_INSERTION message specified when ScanInit() was called. If the application program doesn’t support callbacks, use 1 for the HA +NDLE (if multi-scanner disabled) . [out] lpBuff points to the buffer to receive the scanned data. [in/out] BufSize points to the size of the buffer in bytes (not charac +ters). Upon return, BufSize will be set to the number of bytes writte +n into lpBuff. This can be converted to a character count by dividing + BufSize by sizeof(TCHAR). Typically the buffer size will be equal to + the character count on Win32 Desktop systems.
My question to the monks is, why does this my $buffersize= \$wParam; allow my function to work for multiple scans. If I understand the Win32::API docs, all perl variables are passed as reference so \$buffersize should not have been needed, and creating a var that is a reference to another var should not be needed. Does it have to due with the BuffSize being rewritten to the $buffersize parameter by the scanner dll? I'm confused. Happy I got it to work but confused. Here is the complete test script.
#!perl -w use strict; use warnings; use Win32::GUI(); use Win32::API; use Win32::API::Prototype; use Carp qw(croak); use Data::Dumper; # Preloaded methods go here. ################################################################### +######## # Supported C types ################################################################### +######## # ATOM s HWINSTA L # BOOL L HWND L # BOOLEAN c INT i # BYTE C INT32 i # CHAR c INT64 q # COLORREF L LANGID s # DWORD L LCID L # DWORD32 L LCSCSTYPE L # DWORD64 Q LCSGAMUTMATCH L # FLOAT f LCTYPE L # HACCEL L LONG l # HANDLE L LONG32 l # HBITMAP L LONG64 q # HBRUSH L LONGLONG q # HCOLORSPACE L LPARAM L # HCONV L LRESULT L # HCONVLIST L REGSAM L # HCURSOR L SC_HANDLE L # HDC L SC_LOCK L # HDDEDATA L SERVICE_STATUS_HANDLE L # HDESK L SHORT s # HDROP L SIZE_T L # HDWP L SSIZE_T L # HENHMETAFILE L TBYTE c # HFILE L TCHAR C # HFONT L UCHAR C # HGDIOBJ L UINT I # HGLOBAL L UINT_PTR L # HHOOK L UINT32 I # HICON L UINT64 Q # HIMC L ULONG L # HINSTANCE L ULONG32 L # HKEY L ULONG64 Q # HKL L ULONGLONG Q # HLOCAL L USHORT S # HMENU L WCHAR S # HMETAFILE L WORD S # HMODULE L WPARAM L # HPALETTE L VOID c # HPEN L int i # HRGN L long l # HRSRC L float f # HSZ L double d # char c ################################################################### +######## # DLL Function call setup ################################################################### +######## my $ScanInit = Win32::API->new('ScanAPI.dll','long ScanInit(HWND hW +nd, long wminseriton, long wmRemoval)'); # my $ScanErrToText = Win32::API->new('ScanAPI.dll','long ScanErrToT +ext(int Err, TCHAR lpBuff, int BuffSize)'); my $ScanOpenDevice = Win32::API->new('ScanAPI.dll','long ScanOpenDe +vice(HANDLE hScanner)'); my $ScanCloseDevice = Win32::API->new('ScanAPI.dll','long ScanClose +Device(HANDLE hScanner)'); my $ScanRequestDataEvents = Win32::API->new('ScanAPI.dll','long Sca +nRequestDataEvents(HANDLE hScanner, HWND hWnd, long wmScannerData)'); my $ScanTrigger = Win32::API->new('ScanAPI.dll','long ScanTrigger(H +ANDLE hScanner)'); my $ScanGetData = Win32::API->new('ScanAPI.dll','long ScanGetData(H +ANDLE hScanner, LPSTR lpBuff, LPINT BufSize)'); # my $ScanGetData = Win32::API->new('ScanAPI.dll','ScanGetData',['N' +,'P','N'],'N'); # sub hWnd(){0}; # tell the ScanAPI function that no ca +ll back is needed sub WM_USER() {1024}; sub WM_INSERTION(){WM_USER + 1}; # the message we want on device + insertions sub WM_REMOVAL(){WM_USER + 2}; # the message we want on device r +emovals sub WM_SCANNERDATA(){WM_USER + 3}; # the message we want when da +ta is available sub WM_CHS_STATUS(){WM_USER + 4}; # the message we want when CHS + status changes sub NOCALLBACK(){1}; # SCANAPI retunr values use constant SR_SUCCESS => 0; use constant SR_INVALID_WMINSERTION => 1; use constant SR_INVALID_WMREMOVAL => 2; use constant SR_PLUG_THREAD_FAILURE => 3; use constant SR_DEVICE_THREAD_FAILURE => 4; use constant SR_INVALID_SCANNER_HANDLE => 5; use constant SR_OPEN_FAILURE => 6; use constant SR_INVALID_WMSCANNERDATA => 7; use constant SR_NO_DATA => 8; use constant SR_BUFFER_TOO_SMALL => 9; use constant SR_SCANNER_NOT_OPEN => 10; use constant SR_INVALID_SOUND_TYPE => 11; use constant SR_WAVFILE_NOT_FOUND => 12; use constant SR_MEMORY_FAILURE => 13; use constant SR_INVALID_ERR => 14; use constant SR_TOO_MANY_USERS => 15; use constant SR_NOT_INITIALIZED => 16; use constant SR_DEVICE_FAILURE => 17; use constant SR_INTERNAL_FAILURE => 18; use constant SR_INVALID_STRUCTURE => 19; use constant SR_HOTSWAP_ERROR => 20; use constant SR_SCANNER_REMOVED => 21; use constant SR_INVALID_WMCHSSTATUS => 22; our $ret; our $ScannerHandle; sub Buffersize(){1024}; # Create a window, saving it in variable $main my $main = Win32::GUI::Window->new( -name => 'Main', -width => 100, -height => 100, ); # Add a label to the window (by default a label # has size big enough for its text and is positioned # in the top left of its containing window) $main->AddLabel( -text => $main->{-handle}, ); $main->AddButton( -name => 'button1', -text => "click", ); $main->AddButton( -name => 'button2', -text => "scan", -left => 50, ); $main->Hook(WM_INSERTION, \&WMINSERTION); $main->Hook(WM_REMOVAL, \&WMREMOVAL); $main->Hook(WM_SCANNERDATA, \&WMSCANNERDATA); # Show our main window $main->Show(); # Enter the windows message loop, often referred # to as the "dialog phase". Win32::GUI::Dialog(); # When the message loopreturns control to our # perl program, then the interaction with the # GUI is complete, so we exit. exit(0); ###################### ###################### # The Terminate event handler for a window # named 'Main'. Returning -1 causes the # windows message loop to exit and return # control to our perl program. sub Main_Terminate { return -1; } sub button1_Click { $ret=$ScanInit->Call($main->{-handle},WM_INSERTION,WM_REMOVAL); if ($ret != SR_SUCCESS) { &DisplayScanError($ret); exit; } print "Scanner Interface Started\n"; } 1; sub button2_Click { $ret=$ScanTrigger->Call($ScannerHandle); if ($ret != SR_SUCCESS) { &DisplayScanError($ret); exit; } print "Scanner Triggered\n"; } 1; sub WMINSERTION { my ($object, $wParam, $lParam, $type, $msgcode) = @_; return unless $type == 0; return unless $msgcode == WM_INSERTION; $ScannerHandle=$lParam; print "Scanner inserted\n\nscanner handle: $lParam\n"; my $ret=$ScanOpenDevice->Call($lParam); # Inform scanApi.dl +l this application does nor handle call backs print "Return code: $ret\n"; if ($ret != SR_SUCCESS) { &DisplayScanError($ret); return -1; } print "Scanner opened\n"; $ret=$ScanRequestDataEvents->Call($lParam, $main->{-handle}, W +M_SCANNERDATA); if ($ret != SR_SUCCESS) { &DisplayScanError($ret); return -1; } print "Scanner Events Monitoring started\n"; return; } sub WMREMOVAL { my ($object, $wParam, $lParam, $type, $msgcode) = @_; return unless $type == 0; return unless $msgcode == WM_REMOVAL; print "Scanner Removed\n\nscanner handle: $lParam\n"; my $ret=$ScanCloseDevice->Call($lParam); print "Return + code: $ret\n"; if ($ret != SR_SUCCESS) { &DisplayScanError($ret); exit; } print "Scanner Closed\n"; return; } sub WMSCANNERDATA { print "Scanner Has data waiting\n"; my ($object, $wParam, $lParam, $type, $msgcode) = @_; return unless $type == 0; return unless $msgcode == WM_SCANNERDATA; print "Data size: $wParam\n"; my $buffer= 0 x $wParam; my $buffersize= \$wParam; my $ret=$ScanGetData->Call($ScannerHandle, $buffer, $buffersiz +e); # Inform scanApi.dll this application does nor handle call bac +ks print "Return code: $ret"; if ($ret != SR_SUCCESS) { &DisplayScanError($ret); exit; } print $buffer."\n\n"; # undef @_; # undef $object; # undef $wParam; # undef $lParam; # undef $type; # undef $msgcode; return 1; } sub DisplayScanError() { my $ErrorCode=$_[0]; my $ErrorText=''; if ($ErrorCode == SR_INVALID_WMINSERTION) { $ErrorText= "ScanAPI Error: Invalid WM_INSERTION Value"; } if ($ErrorCode == SR_INVALID_WMREMOVAL) { $ErrorText= "ScanAPI Error: Invalid WM_REMOVAL Value"; } if ($ErrorCode == SR_PLUG_THREAD_FAILURE) { $ErrorText= "ScanAPI Error: SR_PLUG_THREAD_FAILURE"; } if ($ErrorCode == SR_DEVICE_THREAD_FAILURE) { $ErrorText= "ScanAPI Error: SR_DEVICE_THREAD_FAILURE"; } if ($ErrorCode == SR_INVALID_SCANNER_HANDLE) { $ErrorText= "ScanAPI Error: SR_INVALID_SCANNER_HANDLE"; } if ($ErrorCode == SR_OPEN_FAILURE) { $ErrorText= "ScanAPI Error: SR_OPEN_FAILURE"; } if ($ErrorCode == SR_INVALID_WMSCANNERDATA) { $ErrorText= "ScanAPI Error: SR_INVALID_WMSCANNERDATA"; } if ($ErrorCode == SR_NO_DATA) { $ErrorText= "ScanAPI Error: SR_NO_DATA"; } if ($ErrorCode == SR_BUFFER_TOO_SMALL) { $ErrorText= "ScanAPI Error: SR_BUFFER_TOO_SMALL"; } if ($ErrorCode == SR_SCANNER_NOT_OPEN) { $ErrorText= "ScanAPI Error: SR_SCANNER_NOT_OPEN"; } if ($ErrorCode == SR_INVALID_SOUND_TYPE) { $ErrorText= "ScanAPI Error: SR_INVALID_SOUND_TYPE"; } if ($ErrorCode == SR_WAVFILE_NOT_FOUND) { $ErrorText= "ScanAPI Error: SR_WAVFILE_NOT_FOUND"; } if ($ErrorCode == SR_MEMORY_FAILURE) { $ErrorText= "ScanAPI Error: SR_MEMORY_FAILURE"; } if ($ErrorCode == SR_INVALID_ERR) { $ErrorText= "ScanAPI Error: SR_INVALID_ERR"; } if ($ErrorCode == SR_TOO_MANY_USERS) { $ErrorText= "ScanAPI Error: SR_TOO_MANY_USERS"; } if ($ErrorCode == SR_NOT_INITIALIZED) { $ErrorText= "ScanAPI Error: SR_NOT_INITIALIZED"; } if ($ErrorCode == SR_DEVICE_FAILURE) { $ErrorText= "ScanAPI Error: SR_DEVICE_FAILURE"; } if ($ErrorCode == SR_INTERNAL_FAILURE) { $ErrorText= "ScanAPI Error: SR_INTERNAL_FAILURE"; } if ($ErrorCode == SR_INVALID_STRUCTURE) { $ErrorText= "ScanAPI Error: SR_INVALID_STRUCTURE"; } if ($ErrorCode == SR_HOTSWAP_ERROR) { $ErrorText= "ScanAPI Error: SR_HOTSWAP_ERROR"; } if ($ErrorCode == SR_SCANNER_REMOVED) { $ErrorText= "ScanAPI Error: SR_SCANNER_REMOVED"; } if ($ErrorCode == SR_INVALID_WMCHSSTATUS) { $ErrorText= "ScanAPI Error: SR_INVALID_WMCHSSTATUS"; } print "Error Message: $ErrorText\n"; return 1; }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Win32::API passing a parameter by reference issue
by ikegami (Patriarch) on Jun 22, 2008 at 07:57 UTC | |
by rpnoble419 (Pilgrim) on Jun 22, 2008 at 12:36 UTC | |
by karamorf (Initiate) on Oct 17, 2008 at 18:04 UTC | |
|
Re: Win32::API passing a parameter by reference issue
by Anonymous Monk on Jun 22, 2008 at 13:56 UTC | |
|
Re: Win32::API passing a parameter by reference issue
by DrBrain (Initiate) on Jul 13, 2008 at 10:48 UTC |