Prev: V02Ado error
Next: OwnerDraw StatusBar
From: Gunter on 3 Jun 2010 09:25 Who can help me? I want to read out the content ( hexbyte sequence) of an image scanner (honeywell 4600g). It is installed as USB COM port emulation, that provides the Port COM3 (IT4600 Area Imager). The Barcode I have to read out is Datamatrixcode with 42 byte. thanks for help Gunter Huebner
From: Ginny Caughey on 3 Jun 2010 10:04 There are a couple of serial classes for VO around - I wrote one called just Serial I think, and Fabrice wrote one too - FabSerial maybe? -- Ginny Caughey www.wasteworks.com
From: Gunter on 3 Jun 2010 10:36 On Jun 3, 4:04 pm, "Ginny Caughey" <ginny.caughey.onl...(a)wasteworks.com> wrote: > There are a couple of serial classes for VO around - I wrote one called just > Serial I think, and Fabrice wrote one too - FabSerial maybe? > > -- > > Ginny Caugheywww.wasteworks.com Thanks, where can I find your serial class? Gunter Huebenr
From: Ginny Caughey on 3 Jun 2010 11:09 I'm not sure where it's available these days. Anyway this is the code I'm using currently: STRUCTURE CommData MEMBER hCommFile AS PTR // Handle to the serial session MEMBER hWindowToNotify AS PTR // Which window to notify MEMBER dwEvent AS DWORD // Which comm events to watch for MEMBER lWorkerMustStop AS LOGIC // Tells worker thread to stop running MEMBER lWorkerIsStopped AS LOGIC // Indicates if worker thread is running CLASS Serial ~"ONLYEARLY+" PROTECT hCommFile AS PTR // Handle to comm "file" PROTECT lEventsEnabled AS LOGIC // Flag to notify a window with events // This structure must be declared using AS rather than IS // because it's shared by more than one thread. In other words, // you have to Memalloc() memory for it in static storage. PROTECT struCommData AS CommData // Communication data structure // And these structures must be decalred using AS rather than IS // because they are passed by reference to Windows. PROTECT struDCB AS _WinDCB // Device control block structure PROTECT struTimeOuts AS _WinCommTimeOuts // Timeouts structure PROTECT nErrorCode AS INT // Error code from the communication session PROTECT sErrorDesc AS STRING // Error message from the communication session PROTECT hWindowToNotify AS PTR // Window to notify with communication events PROTECT nTxBufferSize AS DWORD // Size of the transmission buffer PROTECT nRxBufferSize AS DWORD // Size of the reception buffer PROTECT lIsOpen AS LOGIC // Flag for an open communication session DECLARE ACCESS Baud DECLARE ASSIGN Baud DECLARE ACCESS ByteSize DECLARE ASSIGN ByteSize DECLARE ACCESS ErrorCode DECLARE ACCESS ErrorDesc DECLARE ACCESS Handle DECLARE ACCESS IsOpen DECLARE ACCESS Parity DECLARE ASSIGN Parity DECLARE ACCESS StopBits DECLARE ASSIGN StopBits DECLARE ACCESS ReadIntervalTimeout DECLARE ASSIGN ReadIntervalTimeout DECLARE ACCESS ReadTimeoutConstant DECLARE ASSIGN ReadTimeoutConstant DECLARE ACCESS ReadTimeoutMultiplier DECLARE ASSIGN ReadTimeoutMultiplier DECLARE ACCESS ReceiveBufferSize DECLARE ASSIGN ReceiveBufferSize DECLARE ACCESS ReceiverPending DECLARE ACCESS TransmitBufferSize DECLARE ASSIGN TransmitBufferSize DECLARE ACCESS WriteTimeoutConstant DECLARE ASSIGN WriteTimeoutConstant DECLARE ACCESS WriteTimeoutMultiplier DECLARE ASSIGN WriteTimeoutMultiplier DECLARE METHOD Close DECLARE METHOD DisableEvents DECLARE METHOD EnableEvents DECLARE METHOD Flush DECLARE METHOD GetProtocol DECLARE METHOD GetTimeout DECLARE METHOD Open DECLARE METHOD Read DECLARE METHOD SetProtocol DECLARE METHOD SetTimeout DECLARE METHOD Write ~"ONLYEARLY-" METHOD Init( hWindow ) CLASS Serial ~"ONLYEARLY+" // If a valid window handle was passed... IF !( IsNil( hWindow ) ) // Store the window handle for later use. SELF:hWindowToNotify := hWindow ENDIF // Allocate storage for structure used by worker thread. SELF:struCommData := MemAlloc( _SIZEOF( CommData ) ) SELF:struDCB := MemAlloc( _SIZEOF( _WinDCB ) ) SELF:struTimeOuts := MemAlloc( _SIZEOF( _WinCommTimeOuts ) ) // Set default value SELF:hCommFile := INVALID_HANDLE_VALUE // Set the size of the transmit and receive buffers. SELF:nTxBufferSize := 4096 SELF:nRxBufferSize := 4096 // Register the Axit() method with the garbage collector. RegisterAxit( SELF ) RETURN( SELF ) ~"ONLYEARLY-" METHOD Axit() CLASS Serial ~"ONLYEARLY+" // If we are not in the garbage collector... IF !( InCollect() ) // Unregister the Axit() method with the garbage collector. UnRegisterAxit( SELF ) ENDIF // Release memory used by AS structure instance variable. // Note that memory used by the IS structures are released when // Serial objects are out of scope by the garbage collector. MemFree( SELF:struCommData ) MemFree( SELF:struDCB ) MemFree( SELF:struTimeOuts ) RETURN( SELF ) ~"ONLYEARLY-" ACCESS Baud() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struDCB.BaudRate ) ~"ONLYEARLY-" ASSIGN Baud( nNew AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" // If a valid baud rate was passed... IF ( ( nNew == CBR_110 ) .OR. ; ( nNew == CBR_300 ) .OR. ; ( nNew == CBR_600 ) .OR. ; ( nNew == CBR_1200 ) .OR. ; ( nNew == CBR_2400 ) .OR. ; ( nNew == CBR_4800 ) .OR. ; ( nNew == CBR_9600 ) .OR. ; ( nNew == CBR_14400 ) .OR. ; ( nNew == CBR_19200 ) .OR. ; ( nNew == CBR_38400 ) .OR. ; ( nNew == CBR_56000 ) .OR. ; ( nNew == CBR_128000 ) .OR. ; ( nNew == CBR_256000 ) ) // Change the baud rate. SELF:struDCB.BaudRate := nNew ENDIF RETURN( struDCB.BaudRate ) ~"ONLYEARLY-" ACCESS ByteSize() AS BYTE PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struDCB.ByteSize ) ~"ONLYEARLY-" ASSIGN ByteSize( nNew AS BYTE ) AS BYTE PASCAL CLASS Serial ~"ONLYEARLY+" // If a valid byte size was passed... IF ( ( nNew == 07 ) .OR. ; ( nNew == 08 ) ) // Change the byte size. SELF:struDCB.ByteSize := nNew ENDIF RETURN( SELF:struDCB.ByteSize ) ~"ONLYEARLY-" METHOD Close() AS LOGIC PASCAL CLASS Serial LOCAL lResult AS LOGIC // Flag for a successful close of the session ~"ONLYEARLY+" // If we have a valid communications session... IF !( SELF:hCommFile == INVALID_HANDLE_VALUE ) // If window events were enabled... IF ( SELF:lEventsEnabled ) // Shut down worker thread if running. SELF:DisableEvents() ENDIF // Flush data buffers. SELF:Flush() // Close device handle. lResult := CloseHandle( SELF:hCommFile ) // If the communication session was successfully closed... IF ( lResult ) // Invalidate the handle. SELF:lIsOpen := FALSE SELF:hCommFile := INVALID_HANDLE_VALUE ELSE // Report the error. SELF:sErrorDesc := "CloseHandle failed." SELF:nErrorCode := GetLastError() ENDIF ENDIF RETURN( lResult ) ~"ONLYEARLY-" METHOD DisableEvents() AS LOGIC PASCAL CLASS Serial LOCAL lResult AS LOGIC // Flag for a successful disable of the events ~"ONLYEARLY-" // If event notification was enabled... IF ( SELF:lEventsEnabled ) // Set global quit flag so CommWatchProc will stop running. struCommData.lWorkerMustStop := TRUE // If event notification was NOT successfully disabled... IF !( SetCommMask( SELF:hCommFile, 00 ) ) // Report the error. SELF:sErrorDesc := "SetCommMask failed in DisableEvents." SELF:nErrorCode := GetLastError() ELSE // While the thread is still running... WHILE !( struCommData.lWorkerIsStopped ) // Wait for thread to shut down but give rest of time // slice for this thread back to Windows while waiting. Sleep( 00 ) ENDDO // Disable event notification. SELF:lEventsEnabled := FALSE // Return the success. lResult := TRUE ENDIF ELSE // Return the success. lResult := TRUE ENDIF RETURN( lResult ) ~"ONLYEARLY-" METHOD EnableEvents( nEvents AS DWORD ) AS LOGIC PASCAL CLASS Serial LOCAL ptrCommWatchThread AS PTR // Handle to the thread LOCAL nWorkerthreadID AS DWORD // Value for the thread ID ~"ONLYEARLY+" // If event notification was enabled... IF ( SELF:lEventsEnabled ) RETURN( FALSE ) ENDIF // Fill CommData structure with the data the worker thread // will need to have access to. SELF:struCommData.hCommFile := SELF:hCommFile SELF:struCommData.hWindowToNotify := SELF:hWindowToNotify SELF:struCommData.dwEvent := nEvents SELF:struCommData.lWorkerMustStop := FALSE SELF:struCommData.lWorkerIsStopped := TRUE BEGIN SEQUENCE // Create 2nd thread to watch for comm events. ptrCommWatchThread := CreateThread( ; // Use VO Wrapper to CreateThread() NULL, ; // Pointer to security attributes 00, ; // Initial thread stack size @CommWatchProc(), ; // Pointer to thread function struCommData, ; // Argument for new thread - no '@' ; // because AS STRUCTURE IS pointer already 00, ; // Creation flags for thread @nWorkerthreadID ) // Pointer to returned thread ID // If the secondary thread was NOT created successfully... IF ( ptrCommWatchThread == NULL ) // Report the error. SELF:sErrorDesc := "CreateThread failed in EnableEvent." SELF:nErrorCode := GetLastError() // Raise an exception. BREAK ELSE // Lower the thread priority. SetThreadPriority( nWorkerThreadID, THREAD_PRIORITY_LOWEST ) // Enable the reporting of the events. SELF:lEventsEnabled := TRUE SELF:struCommData.lWorkerIsStopped := FALSE ENDIF END SEQUENCE RETURN( SELF:lEventsEnabled ) ~"ONLYEARLY-" ACCESS ErrorDesc() AS STRING PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:sErrorDesc ) ~"ONLYEARLY-" ACCESS ErrorCode() AS STRING PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( AsString( SELF:nErrorCode ) ) ~"ONLYEARLY-" METHOD Flush() AS LOGIC PASCAL CLASS Serial LOCAL lResult AS LOGIC // Flag for a successful flush of the buffers ~"ONLYEARLY+" // Purge the communications buffers. lResult := PurgeComm( SELF:hCommFile, _OR( PURGE_TXCLEAR, PURGE_RXCLEAR, ; PURGE_TXABORT, PURGE_RXABORT ) ) // If the communication buffers were NOT successfully flushed... IF !( lResult ) // Report the error. SELF:sErrorDesc := "PurgeComm failed." SELF:nErrorCode := GetLastError() ENDIF RETURN( lResult ) ~"ONLYEARLY-" METHOD GetProtocol() AS LOGIC PASCAL CLASS Serial LOCAL lResult AS LOGIC // Flag for a successful get of the protocol ~"ONLYEARLY+" // If we have a valid communications session... IF !( SELF:hCommFile == INVALID_HANDLE_VALUE ) // Get the communications protocol for the session. lResult := GetCommState( SELF:hCommFile, SELF:struDCB ) // If the communication protocol was NOT successfully gotten... IF !( lResult ) // Report the error. SELF:sErrorDesc := "GetCommState failed in GetProtocol." SELF:nErrorCode := GetLastError() ENDIF ENDIF RETURN( lResult ) ~"ONLYEARLY-" METHOD GetTimeOut() AS LOGIC PASCAL CLASS Serial LOCAL lResult AS LOGIC // Flag for a successful get of the timeout ~"ONLYEARLY+" // If we have a valid communications session... IF !( SELF:hCommFile == INVALID_HANDLE_VALUE ) // Get the communications timeout for the session. lResult := GetCommTimeouts( SELF:hCommFile, SELF:struTimeOuts ) // If the communication protocol was NOT successfully gotten... IF !( lResult ) // Report the error. SELF:sErrorDesc := "GetCommTimeouts failed in GetTimeOut." SELF:nErrorCode := GetLastError() ENDIF ENDIF RETURN( lResult ) ~"ONLYEARLY-" ACCESS Handle() AS PTR PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:hCommFile ) ~"ONLYEARLY-" ACCESS IsOpen() AS LOGIC PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:lIsOpen ) ~"ONLYEARLY-" METHOD Open( sPort AS STRING ) AS LOGIC PASCAL CLASS Serial LOCAL lStatus AS LOGIC /* IF Right(sPort,1) != ":" sPort += ":" ENDIF */ IF Left(sPort,4) != "\\.\" sPort := "\\.\" + sPort ENDIF SELF:hCommFile := CreateFile( PSZ( sPort ), ; // Name of file DWORD( _CAST, _OR( GENERIC_READ, GENERIC_WRITE ) ), ; // Read-write mode 00, ; // Share mode - not shared NULL, ; // Pointer to security descriptor (WinNT only) OPEN_EXISTING, ; // Must be Open_Existing for devices _OR( FILE_ATTRIBUTE_NORMAL, FILE_FLAG_OVERLAPPED ), ; // File attributes NULL ) // Handle to file with more attributes to copy BEGIN SEQUENCE IF ( SELF:hCommFile == INVALID_HANDLE_VALUE ) SELF:sErrorDesc := "CreateFile failed in Open." SELF:nErrorCode := GetLastError() BREAK ENDIF // Allocate storage for input and output buffers. lStatus := setupComm( SELF:hCommFile, SELF:nRxBufferSize, SELF:nTxBufferSize ) IF !( lStatus ) SELF:sErrorDesc := "SetupComm failed in Open." SELF:nErrorCode := GetLastError() BREAK ENDIF // Flush data buffers IF !( SELF:Flush() ) BREAK ENDIF // Set up default time out values for comm session. // (This is needed for overlapped I/O.) SELF:ReadIntervalTimeout := 0xffffffff SELF:ReadTimeoutMultiplier := 500 SELF:ReadTimeoutConstant := 1000 SELF:WriteTimeoutMultiplier := 00 SELF:WriteTimeoutConstant := 1000 IF !( SELF:SetTimeOut() ) BREAK ENDIF // Set up default values for DCB structure IF !( SELF:GetProtocol() ) BREAK ENDIF SELF:Baud := 9600 SELF:Parity := NOPARITY SELF:ByteSize := 08 SELF:StopBits := ONESTOPBIT IF !( SELF:SetProtocol() ) BREAK ENDIF END SEQUENCE SELF:lIsOpen := lStatus RETURN( lStatus ) ~"ONLYEARLY-" ACCESS Parity() AS BYTE PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struDCB.Parity ) ~"ONLYEARLY-" ASSIGN Parity( nNew AS BYTE ) AS BYTE PASCAL CLASS Serial ~"ONLYEARLY+" // If a valid parity was passed... IF ( ( nNew == ODDPARITY ) .OR. ; ( nNew == EVENPARITY ) .OR. ; ( nNew == MARKPARITY ) .OR. ; ( nNew == SPACEPARITY ) .OR. ; ( nNew == NOPARITY ) ) // Change the parity. SELF:struDCB.Parity := nNew ENDIF RETURN( SELF:struDCB.Parity ) ~"ONLYEARLY-" METHOD Read( nMaxLength AS DWORD ) AS STRING PASCAL CLASS Serial LOCAL lStatus AS LOGIC LOCAL struComStat IS _WinComStat LOCAL struOverlapped IS _WinOverlapped LOCAL pszBuffer AS BYTE PTR LOCAL sResult AS STRING LOCAL dwErrorFlags AS DWORD LOCAL dwError AS DWORD LOCAL dwLength AS DWORD ~"ONLYEARLY+" IF ( IsNil( nMaxLength ) ) nMaxLength := 01 ENDIF // Allocate storage for incoming data. pszBuffer := MemAlloc( nMaxLength ) BEGIN SEQUENCE // Create event for overlapped structure. struOverlapped.hEvent := CreateEvent( NULL, TRUE, FALSE, NULL ) IF ( struOverlapped.hEvent == NULL ) SELF:sErrorDesc := "CreateEvent failed in Read." SELF:nErrorCode := GetLastError() BREAK ENDIF dwLength := nMaxLength // Force timeout situation IF ( dwLength > 00 ) lStatus := ReadFile( SELF:hCommFile, pszBuffer, dwLength, ; @dwLength, @struOverlapped ) IF !( lStatus ) IF ( GetLastError() == ERROR_IO_PENDING ) // We have to wait for read to complete. // This function will timeout according to the // CommTimeOuts.ReadTotalTimeoutConstant variable // Every time it times out, check for port errors WHILE !( GetOverlappedResult( SELF:hCommFile, ; @struOverlapped, ; @dwLength, TRUE ) ) dwError := GetLastError() IF ( dwError == ERROR_IO_INCOMPLETE ) // Normal if IO still in progress. LOOP ELSE // A real error occurred. SELF:sErrorDesc := "ReadFile failed in Serial:ReadCommBlock(1)." SELF:nErrorCode := GetLastError() ClearCommError( SELF:hCommFile, @dwErrorFlags, @struComStat ) BREAK ENDIF ENDDO ELSE // Some other error occurred. dwLength := 00 SELF:sErrorDesc := "ReadFile failed in Serial:ReadCommBlock(2)." SELF:nErrorCode := GetLastError() ClearCommError( SELF:hCommFile, @dwErrorFlags, @struComStat ) ENDIF ENDIF ENDIF IF ( dwLength > 00 ) sResult := Mem2String( pszBuffer, dwLength ) IF ( dwLength < nMaxLength ) /* Handle error processing in calling app instead MessageBox( 00, PSZ( "Not all bytes requested returned." ), ; PSZ( "ReadTest" ), MB_OK ) */ ENDIF ENDIF END SEQUENCE // Free resources no longer needed. MemFree( pszBuffer ) IF !( struOverlapped.hEvent == NULL ) CloseHandle( struOverlapped.hEvent ) ENDIF RETURN( sResult ) ~"ONLYEARLY-" ACCESS ReadIntervalTimeout() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struTimeOuts.ReadIntervalTimeout ) ~"ONLYEARLY-" ASSIGN ReadIntervalTimeout( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" SELF:struTimeOuts.ReadIntervalTimeout := nMilliseconds RETURN( SELF:struTimeOuts.ReadIntervalTimeout ) ~"ONLYEARLY-" ACCESS ReadTimeoutConstant() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struTimeOuts.ReadTotalTimeoutConstant ) ~"ONLYEARLY-" ASSIGN ReadTimeoutConstant( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" SELF:struTimeOuts.ReadTotalTimeoutConstant := nMilliseconds RETURN( SELF:struTimeOuts.ReadTotalTimeoutConstant ) ~"ONLYEARLY-" ACCESS ReadTimeoutMultiplier() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struTimeOuts.ReadTotalTimeoutMultiplier ) ~"ONLYEARLY-" ASSIGN ReadTimeoutMultiplier( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" SELF:struTimeOuts.ReadTotalTimeoutMultiplier := nMilliseconds RETURN( SELF:struTimeOuts.ReadTotalTimeoutMultiplier ) ~"ONLYEARLY-" ACCESS ReceiveBufferSize() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:nRxBufferSize ) ~"ONLYEARLY-" ASSIGN ReceiveBufferSize( nNewSize AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" SELF:nRxBufferSize := nNewSize RETURN( SELF:nRxBufferSize ) ~"ONLYEARLY-" ACCESS ReceiverPending() AS DWORD PASCAL CLASS Serial LOCAL struComStat IS _WinComStat // Communication status LOCAL nErrorFlags AS DWORD // Error flags LOCAL nResult AS DWORD // Number of bytes to return ~"ONLYEARLY+" // If we have a valid communications session... IF !( SELF:hCommFile == INVALID_HANDLE_VALUE ) // Clear the communications error. ClearCommError( SELF:hCommFile, @nErrorFlags, @struComStat ) // How many bytes are queued at input device? nResult := struComStat.cbInQue ENDIF RETURN( nResult ) ~"ONLYEARLY-" METHOD SetProtocol() AS LOGIC PASCAL CLASS Serial LOCAL lResult AS LOGIC // Flag for a successful set of the protocol ~"ONLYEARLY+" // If we have a valid communications session... IF !( SELF:hCommFile == INVALID_HANDLE_VALUE ) // Set the communications protocol for the session. lResult := SetCommState( SELF:hCommFile, SELF:struDCB ) // If the communication protocol was NOT successfully set... IF !( lResult ) // Report the error. SELF:sErrorDesc := "SetCommState failed in SetProtocol." SELF:nErrorCode := GetLastError() ENDIF ENDIF RETURN( lResult ) ~"ONLYEARLY-" METHOD SetTimeOut() AS LOGIC PASCAL CLASS Serial LOCAL lResult AS LOGIC // Flag for a successful set of the timeout ~"ONLYEARLY+" // If we have a valid communications session... IF !( SELF:hCommFile == INVALID_HANDLE_VALUE ) // Set the communications timeout for the session. lResult := SetCommTimeouts( SELF:hCommFile, SELF:struTimeOuts ) // If the communication timeout was NOT successfully set... IF !( lResult ) // Report the error. SELF:sErrorDesc := "SetCommTimeouts failed in SetTimeOut." SELF:nErrorCode := GetLastError() ENDIF ENDIF RETURN( lResult ) ~"ONLYEARLY-" ACCESS StopBits() AS BYTE PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struDCB.StopBits ) ~"ONLYEARLY-" ASSIGN StopBits( nNew AS BYTE ) AS BYTE PASCAL CLASS Serial ~"ONLYEARLY+" // If a valid number of stop bits was passed... IF ( ( nNew == ONESTOPBIT ) .OR. ; ( nNew == ONE5STOPBITS ) .OR. ; ( nNew == TWOSTOPBITS ) ) // Change the stop bits. SELF:struDCB.StopBits := nNew ENDIF RETURN( SELF:struDCB.StopBits ) ~"ONLYEARLY-" ACCESS TransmitBufferSize() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:nTxBufferSize ) ~"ONLYEARLY-" ASSIGN TransmitBufferSize( nNewSize AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" SELF:nTxBufferSize := nNewSize RETURN( SELF:nTxBufferSize ) ~"ONLYEARLY-" METHOD Write( sString AS STRING ) AS DWORD PASCAL CLASS Serial LOCAL lStatus AS LOGIC LOCAL nBytesWritten AS DWORD LOCAL struOverlapped IS _WinOverlapped ~"ONLYEARLY+" BEGIN SEQUENCE // Create event for overlapped structure. struOverlapped.hEvent := CreateEvent( NULL, ; // Pointer to Security Attributes structure TRUE, ; // State must be manually reset to non-signaled FALSE, ; // Initial state is non-signaled NULL ) // Name of the event object (none in this case) IF ( struOverlapped.hEvent == NULL ) SELF:sErrorDesc := "CreateEvent failed in Serial:Write." SELF:nErrorCode := GetLastError() BREAK ENDIF lStatus := WriteFile( SELF:hCommFile, PSZ( sString ), ; SLen( sString ), ; @nBytesWritten, @struOverlapped ) IF ( ( !lStatus ) .AND. ( GetLastError() == ERROR_IO_PENDING ) ) // Tell Windows to attempt this write operation asynchronously // in the background for up to 1000 milliseconds. IF !( WaitForSingleObject( struOverlapped.hEvent, 1000 ) == 00 ) // Still can't complete the write operation. nBytesWritten := 00 ELSE // Windows has processed this I/O request now // so let's get the result. GetOverlappedResult( SELF:hCommFile, ; // The file to use @struOverlapped, ; // The _WinOverlapped structure @nBytesWritten, ; // Actual number of bytes tranferred TRUE ) // Do wait for transfer to be completed // With overlapped I/O, it is your responsibility to // update the record pointer. struOverlapped.Offset += nBytesWritten ENDIF ELSEIF !( lStatus ) // WriteFile failed for some reason other than IO pending. SELF:sErrorDesc := "WriteFile failed in Serial:Write." SELF:nErrorCode := GetLastError() // Should ClearCommError() be called here? BREAK ENDIF IF !( nBytesWritten == SLen( sString ) ) SELF:sErrorDesc := "Error writing to device." SELF:nErrorCode := GetLastError() ENDIF END SEQUENCE // Close down overlapped event. IF !( struOverlapped.hEvent == NULL ) CloseHandle( struOverlapped.hEvent ) ENDIF RETURN( nBytesWritten ) ~"ONLYEARLY-" ACCESS WriteTimeoutConstant() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struTimeOuts.WriteTotalTimeoutConstant ) ~"ONLYEARLY-" ASSIGN WriteTimeoutConstant( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" SELF:struTimeOuts.WriteTotalTimeoutConstant := nMilliseconds RETURN( SELF:struTimeOuts.WriteTotalTimeoutConstant ) ~"ONLYEARLY-" ACCESS WriteTimeoutMultiplier() AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" RETURN( SELF:struTimeOuts.WriteTotalTimeoutMultiplier ) ~"ONLYEARLY-" ASSIGN WriteTimeoutMultiplier( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS Serial ~"ONLYEARLY+" SELF:struTimeOuts.WriteTotalTimeoutMultiplier := nMilliseconds RETURN( SELF:struTimeOuts.WriteTotalTimeoutMultiplier ) ~"ONLYEARLY-" FUNCTION SetBit( nValue AS DWORD, nPos AS INT ) AS DWORD PASCAL ~"ONLYEARLY+" // Set bit at nPos to 1 (based on first bit is pos 0). RETURN( _OR( nValue, DWORD( 02 ^ nPos ) ) ) ~"ONLYEARLY-" FUNCTION TestBit( nValue AS DWORD, nPos AS INT ) AS DWORD PASCAL ~"ONLYEARLY+" // Test bit at nPos for 1 (based on first bit is pos 0). RETURN( _AND( nValue, DWORD( 02 ^ nPos ) ) ) ~"ONLYEARLY-" FUNCTION CommWatchProc( ptrCommData AS PTR ) AS LONG STRICT // This FUNCTION executes AS a separate thread so no data types // that might trigger the VO garbage collector are used here. // ptrCommData is a pointer to a structure that holds all the // data needed by this function from the class // (We only get one parameter so it has to be multi-functional) LOCAL struCommData AS CommData LOCAL nEventMask AS DWORD LOCAL nResult AS LONG ~"ONLYEARLY+" struCommData := ptrCommData nResult := 00 WHILE ( TRUE ) // Use of BEGIN SEQUENCE not recommended inside secondary thread. IF !( SetCommMask( struCommData.hCommFile, struCommData.dwEvent ) ) MessageBox( 00, PSZ( "SetCommMask failed!" ), ; PSZ( "CommWatchProc Error" ), MB_OK ) nResult := 0 EXIT // Breaks out of outer Loop ENDIF struCommData.lWorkerIsStopped := FALSE nResult := 01 WHILE !( struCommData.lWorkerMustStop ) nEventMask := 00 IF !( WaitCommEvent( struCommData.hCommFile, ; @nEventMask, NULL ) ) nResult := 00 EXIT // Break out on Error ENDIF IF ( _AND( nEventMask, EV_RXCHAR ) == EV_RXCHAR ) // We have a receiver pending event so notify the window about it. // ( The Win32 API no longer supports the WM_COMMNOTIFY // message, but I just reused it for backward compatibility. ) // You could use VOSendMessage() here instead of PostMessage(), // but do not use plain SendMessage() as it will cause timing // problems in a multi-threaded function //PostMessage( struCommData.hWindowToNotify, ; // WM_COMMNOTIFY, EV_RXCHAR, 0L ) VOSendMessage( struCommData.hWindowToNotify, ; WM_COMMNOTIFY, EV_RXCHAR, 0L ) ENDIF ENDDO EXIT // Breaks us out of outer Loop ENDDO // Signal primary thread that we're done struCommData.lWorkerIsStopped := TRUE RETURN( nResult ) ~"ONLYEARLY-" DEFINE ASCII_XOFF := 0x13 DEFINE WM_COMMNOTIFY := 0x0044 -- Ginny Caughey www.wasteworks.com
From: Gunter on 4 Jun 2010 06:12 Hi, Ginny, many thanks for the delivered code. I shell try it. Gunter
|
Pages: 1 Prev: V02Ado error Next: OwnerDraw StatusBar |