|
|
/*++
Copyright (c) 2000 Microsoft Corporation All Rights Reserved
Module Name: BasePort.cpp
Abstract: Basic Port Class Implementation of the CBasePort class.
Author: M. Fenelon
Revision History:
--*/
//
//////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "ntddpar.h"
TCHAR cszMonitorName[] = TEXT("Dynamic Print Monitor");
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CBasePort::CBasePort() : m_cRef(0), m_dwFlags(0), m_hDeviceHandle(INVALID_HANDLE_VALUE), m_hPrinter(INVALID_HANDLE_VALUE), m_pWriteBuffer(NULL), m_dwBufferSize(0), m_dwDataSize(0), m_dwDataCompleted(0), m_dwDataScheduled(0), m_dwReadTimeoutMultiplier(READ_TIMEOUT_MULTIPLIER), m_dwReadTimeoutConstant(READ_TIMEOUT_CONSTANT), m_dwWriteTimeoutMultiplier(WRITE_TIMEOUT_MULTIPLIER), m_dwWriteTimeoutConstant(WRITE_TIMEOUT_CONSTANT), m_dwMaxBufferSize(0) {
}
CBasePort::CBasePort( BOOL bActive, LPTSTR pszPortName, LPTSTR pszDevicePath, LPTSTR pszPortDesc ) : m_cRef(0), m_dwFlags(0), m_bActive(bActive), m_hDeviceHandle(INVALID_HANDLE_VALUE), m_hPrinter(INVALID_HANDLE_VALUE), m_pWriteBuffer(NULL), m_dwBufferSize(0), m_dwDataSize(0), m_dwDataCompleted(0), m_dwDataScheduled(0), m_dwReadTimeoutMultiplier(READ_TIMEOUT_MULTIPLIER), m_dwReadTimeoutConstant(READ_TIMEOUT_CONSTANT), m_dwWriteTimeoutMultiplier(WRITE_TIMEOUT_MULTIPLIER), m_dwWriteTimeoutConstant(WRITE_TIMEOUT_CONSTANT), m_dwMaxBufferSize(0) { // Setup the Port Name
::SafeCopy( MAX_PORT_LEN, pszPortName, m_szPortName ); // Setup the DevicePath
::SafeCopy( MAX_PATH, pszDevicePath, m_szDevicePath ); // Setup Port Description
::SafeCopy( MAX_PORT_DESC_LEN, pszPortDesc, m_szPortDescription ); }
CBasePort::~CBasePort() { // Cleanup any left over resources
if ( m_hDeviceHandle != INVALID_HANDLE_VALUE ) { CloseHandle( m_hDeviceHandle ); CloseHandle( m_Ov.hEvent ); } }
BOOL CBasePort::open() { BOOL bRet = FALSE;
ECS( m_CritSec );
if ( m_hDeviceHandle == INVALID_HANDLE_VALUE ) { //
// If we have an invalid handle and refcount is non-zero we want the
// job to fail and restart to accept writes. In other words if the
// handle got closed prematurely, because of failing writes, then we
// need the ref count to go down to 0 before calling CreateFile again
//
if ( m_cRef ) goto Done;
m_hDeviceHandle = CreateFile( m_szDevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); //
// If we failed to open the port - test to see if it is a Dot4 port.
//
if ( m_hDeviceHandle == INVALID_HANDLE_VALUE ) { //
// ERROR_FILE_NOT_FOUND -> Error code for port not there.
//
if ( ERROR_FILE_NOT_FOUND != GetLastError() || !checkPnP() ) goto Done; }
m_Ov.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); if ( m_Ov.hEvent == NULL ) { CloseHandle(m_hDeviceHandle); m_hDeviceHandle = INVALID_HANDLE_VALUE; goto Done; }
}
++m_cRef; bRet = TRUE;
Done:
LCS( m_CritSec ); return bRet;
}
BOOL CBasePort::close() { BOOL bRet = TRUE;
ECS( m_CritSec );
--m_cRef; if ( m_cRef != 0 ) goto Done;
bRet = CloseHandle( m_hDeviceHandle); CloseHandle( m_Ov.hEvent); m_hDeviceHandle = INVALID_HANDLE_VALUE;
Done: LCS( m_CritSec ); return bRet;
}
BOOL CBasePort::startDoc(LPTSTR pPrinterName, DWORD dwJobId, DWORD dwLevel, LPBYTE pDocInfo) { BOOL bRet; SPLASSERT( notInWrite() );
if ( !openPrinter( pPrinterName ) ) return FALSE;
m_dwJobId = dwJobId; bRet = open();
if ( !bRet ) closePrinter(); else m_dwFlags |= DYNAMON_STARTDOC;
return bRet; }
BOOL CBasePort::endDoc() { DWORD dwLastError = ERROR_SUCCESS;
dwLastError = sendQueuedData(); freeWriteBuffer();
m_dwFlags &= ~DYNAMON_STARTDOC;
close(); setJobStatus( JOB_CONTROL_SENT_TO_PRINTER );
closePrinter();
return TRUE; }
BOOL CBasePort::read(LPBYTE pBuffer, DWORD cbBuffer, LPDWORD pcbRead) { DWORD dwLastError = ERROR_SUCCESS; DWORD dwTimeout; HANDLE hReadHandle; OVERLAPPED Ov;
//
// Create separate read handle since we have to cancel reads which do
// not complete within the specified timeout without cancelling writes
//
hReadHandle = CreateFile( m_szDevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if ( hReadHandle == INVALID_HANDLE_VALUE ) return FALSE;
ZeroMemory( &Ov, sizeof(Ov) );
if ( !( Ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL) ) ) goto Done;
if ( !ReadFile( hReadHandle, pBuffer, cbBuffer, pcbRead, &Ov ) && ( dwLastError = GetLastError() ) != ERROR_IO_PENDING ) goto Done;
dwTimeout = m_dwReadTimeoutConstant + m_dwReadTimeoutMultiplier * cbBuffer;
if ( dwTimeout == 0 ) dwTimeout=MAX_TIMEOUT;
if ( WaitForSingleObject( Ov.hEvent, dwTimeout ) == WAIT_TIMEOUT ) { CancelIo( hReadHandle ); WaitForSingleObject( Ov.hEvent, INFINITE ); }
if ( !GetOverlappedResult( hReadHandle, &Ov, pcbRead, FALSE ) ) { *pcbRead = 0; dwLastError = GetLastError(); } else dwLastError = ERROR_SUCCESS;
Done: if ( Ov.hEvent ) CloseHandle( Ov.hEvent );
CloseHandle( hReadHandle );
if ( dwLastError ) SetLastError(dwLastError);
return dwLastError == ERROR_SUCCESS; }
BOOL CBasePort::write(LPBYTE pBuffer, DWORD cbBuffer, LPDWORD pcbWritten) { DWORD dwLastError = ERROR_SUCCESS; DWORD dwBytesLeft, dwBytesSent; DWORD dwStartTime, dwTimeLeft, dwTimeout; BYTE bPrinterStatus; BOOL bStartDoc = ( ( m_dwFlags & DYNAMON_STARTDOC ) != 0 );
*pcbWritten = 0; dwStartTime = GetTickCount(); dwTimeout = m_dwWriteTimeoutConstant + m_dwWriteTimeoutMultiplier * cbBuffer;
if ( dwTimeout == 0 ) dwTimeout = MAX_TIMEOUT;
// Usbprint currently can't handle write greater than 4K.
// For Win2K we will make a fix here, later usbprint will be fixed
//
// It is ok to change the size here since spooler will resubmit the rest
// later
//
cbBuffer = adjustWriteSize( cbBuffer );
//
// For writes outside startdoc/enddoc we do not carry them across WritePort
// calls. These are typically from language monitors (i.e. not job data)
//
SPLASSERT(bStartDoc || m_pWriteBuffer == NULL);
if ( bStartDoc && ( m_hDeviceHandle == INVALID_HANDLE_VALUE ) ) { setJobStatus( JOB_CONTROL_RESTART ); SetLastError(ERROR_CANCELLED); return FALSE; }
if ( !open() ) return FALSE;
// First complete any data from previous WritePort call
while ( m_dwDataSize > m_dwDataCompleted ) {
if ( m_dwDataScheduled ) { dwTimeLeft = getTimeLeft( dwStartTime, dwTimeout ); dwLastError = getWriteStatus( dwTimeLeft ); } else dwLastError = writeData();
if ( dwLastError != ERROR_SUCCESS ) goto Done; }
SPLASSERT(m_dwDataSize == m_dwDataCompleted && m_dwDataScheduled == 0 && dwLastError == ERROR_SUCCESS);
//
// Copy the data to our own buffer
//
if ( m_dwBufferSize < cbBuffer ) { freeWriteBuffer(); if ( m_pWriteBuffer = (LPBYTE) AllocSplMem( cbBuffer ) ) m_dwBufferSize = cbBuffer; else { dwLastError = ERROR_OUTOFMEMORY; goto Done; } }
// We have to clear the counters
m_dwDataCompleted = m_dwDataScheduled = 0;
CopyMemory( m_pWriteBuffer, pBuffer, cbBuffer ); m_dwDataSize = cbBuffer;
//
// Now do the write for the data for this WritePort call
//
while ( m_dwDataSize > m_dwDataCompleted ) {
if ( m_dwDataScheduled ) {
dwTimeLeft = getTimeLeft( dwStartTime, dwTimeout ); dwLastError = getWriteStatus( dwTimeLeft ); } else dwLastError = writeData();
if ( dwLastError != ERROR_SUCCESS ) break; }
//
// For writes outside startdoc/enddoc, which are from language monitors,
// do not carry pending writes to next WritePort.
//
if ( !bStartDoc && m_dwDataSize > m_dwDataCompleted ) { CancelIo( m_hDeviceHandle ); dwLastError = getWriteStatus( INFINITE ); *pcbWritten = m_dwDataCompleted; freeWriteBuffer(); }
//
// We will tell spooler we wrote all the data if some data got scheduled
// (or scheduled and completed)
//
if ( m_dwDataCompleted > 0 || m_dwDataScheduled != 0 ) *pcbWritten = cbBuffer; else freeWriteBuffer();
Done:
if ( needToResubmitJob( dwLastError ) ) invalidatePortHandle(); else if ( dwLastError == ERROR_TIMEOUT ) { if (getLPTStatus( m_hDeviceHandle, &bPrinterStatus )) { if ( bPrinterStatus & LPT_PAPER_EMPTY ) dwLastError=ERROR_OUT_OF_PAPER; } }
close(); SetLastError(dwLastError); return dwLastError == ERROR_SUCCESS;
}
BOOL CBasePort::getPrinterDataFromPort( DWORD dwControlID, LPTSTR pValueName, LPWSTR lpInBuffer, DWORD cbInBuffer, LPWSTR lpOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbReturned ) { BOOL bRet = FALSE; OVERLAPPED Ov; HANDLE hDeviceHandle; DWORD dwWaitResult;
*lpcbReturned = 0;
if ( dwControlID == 0 ) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
ZeroMemory(&Ov, sizeof(Ov)); if ( !(Ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) ) return FALSE;
if ( !open() ) { CloseHandle(Ov.hEvent); return FALSE; }
if ( dwControlID == IOCTL_PAR_QUERY_DEVICE_ID ) { hDeviceHandle = CreateFile( m_szDevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if ( hDeviceHandle == INVALID_HANDLE_VALUE ) goto Done;
if ( !DeviceIoControl( m_hDeviceHandle, dwControlID, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, lpcbReturned, &Ov) && GetLastError() != ERROR_IO_PENDING ) { CloseHandle( hDeviceHandle ); goto Done; }
if ( WaitForSingleObject( Ov.hEvent, PAR_QUERY_TIMEOUT ) != WAIT_OBJECT_0 ) CancelIo( hDeviceHandle );
bRet = GetOverlappedResult( m_hDeviceHandle, &Ov, lpcbReturned, TRUE ); CloseHandle( hDeviceHandle ); } else { if ( !DeviceIoControl( m_hDeviceHandle, dwControlID, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, lpcbReturned, &Ov) && GetLastError() != ERROR_IO_PENDING ) goto Done;
bRet = GetOverlappedResult( m_hDeviceHandle, &Ov, lpcbReturned, TRUE); }
Done: CloseHandle(Ov.hEvent); close();
return bRet; }
BOOL CBasePort::setPortTimeOuts( LPCOMMTIMEOUTS lpCTO ) { m_dwReadTimeoutConstant = lpCTO->ReadTotalTimeoutConstant; m_dwReadTimeoutMultiplier = lpCTO->ReadTotalTimeoutMultiplier; m_dwWriteTimeoutConstant = lpCTO->WriteTotalTimeoutConstant; m_dwWriteTimeoutMultiplier = lpCTO->WriteTotalTimeoutMultiplier;
return TRUE; }
void CBasePort::InitCS() { ICS( m_CritSec ); }
void CBasePort::ClearCS() { DCS( m_CritSec ); }
PORTTYPE CBasePort::getPortType() { return USBPORT; }
LPTSTR CBasePort::getPortDesc() { return m_szPortDescription; }
void CBasePort::setPortDesc( LPTSTR pszPortDesc ) { if ( pszPortDesc ) ::SafeCopy( MAX_PORT_DESC_LEN, pszPortDesc, m_szPortDescription ); }
BOOL CBasePort::isActive( void ) { return m_bActive; }
void CBasePort::setActive( BOOL bValue ) { m_bActive = bValue; }
BOOL CBasePort::compActiveState( BOOL bValue ) { return (m_bActive == bValue); }
LPTSTR CBasePort::getPortName() { return m_szPortName; }
void CBasePort::setPortName(LPTSTR pszPortName) { if ( pszPortName ) ::SafeCopy( MAX_PORT_LEN, pszPortName, m_szPortName ); }
INT CBasePort::compPortName(LPTSTR pszPortName) { return _tcsicmp( pszPortName, m_szPortName ); }
LPTSTR CBasePort::getDevicePath() { return m_szDevicePath; }
void CBasePort::setDevicePath(LPTSTR pszDevicePath) { if ( pszDevicePath ) ::SafeCopy( MAX_PATH, pszDevicePath, m_szDevicePath ); }
INT CBasePort::compDevicePath(LPTSTR pszDevicePath) { return _tcsicmp( pszDevicePath, m_szDevicePath ); }
DWORD CBasePort::getEnumInfoSize(DWORD dwLevel ) { // Need to calcualted how much data will be used for this port
DWORD dwBytesNeeded = 0;
switch ( dwLevel ) { case 1: // Start with size of Port Info struct
dwBytesNeeded += sizeof( PORT_INFO_1 ); // Add the length of the string
dwBytesNeeded += ( _tcslen( m_szPortName ) + 1 ) * sizeof(TCHAR); break; case 2: // Start with size of Port Info struct
dwBytesNeeded += sizeof( PORT_INFO_2 ); // Add the length of the strings
dwBytesNeeded += ( _tcslen( m_szPortName ) + 1 ) * sizeof(TCHAR); dwBytesNeeded += ( _tcslen( m_szPortDescription ) + 1 ) * sizeof(TCHAR); dwBytesNeeded += ( _tcslen( cszMonitorName ) + 1 ) * sizeof(TCHAR); break; }
return dwBytesNeeded; }
LPBYTE CBasePort::copyEnumInfo(DWORD dwLevel, LPBYTE pPort, LPBYTE pEnd) { LPTSTR pStrStart; PPORT_INFO_1 pPort1 = (PPORT_INFO_1) pPort; PPORT_INFO_2 pPort2 = (PPORT_INFO_2) pPort;
switch ( dwLevel ) { case 2: // Assign the Port name
pStrStart = (LPTSTR) ( pEnd - ( ( _tcslen( m_szPortDescription ) + 1 ) * sizeof(TCHAR) ) ); if (pPort < (LPBYTE) pStrStart) { (VOID) StringCchCopy (pStrStart, COUNTOF (m_szPortDescription), m_szPortDescription); } pPort2->pDescription = pStrStart; pEnd = (LPBYTE) pStrStart;
// Assign the Port name
pStrStart = (LPTSTR) ( pEnd - ( ( _tcslen( cszMonitorName ) + 1 ) * sizeof(TCHAR) ) ); if (pPort < (LPBYTE) pStrStart) { (VOID) StringCchCopy (pStrStart, COUNTOF (cszMonitorName), cszMonitorName); } pPort2->pMonitorName = pStrStart; pEnd = (LPBYTE) pStrStart;
case 1: // Assign the Port name
pStrStart = (LPTSTR) ( pEnd - ( ( _tcslen( m_szPortName ) + 1 ) * sizeof(TCHAR) ) ); if (pPort < (LPBYTE) pStrStart) { (VOID) StringCchCopy (pStrStart, COUNTOF (m_szPortName), m_szPortName); } pPort1->pName = pStrStart; }
return (LPBYTE) pStrStart; }
BOOL CBasePort::notInWrite() { return( m_pWriteBuffer == NULL && m_dwBufferSize == 0 && m_dwDataSize == 0 && m_dwDataCompleted == 0 && m_dwDataScheduled == 0 ); }
BOOL CBasePort::openPrinter(LPTSTR pPrinterName) { if (INVALID_HANDLE_VALUE != m_hPrinter) { //
// Printer is already opened
//
return TRUE; } //
// Opening the printer...
//
BOOL bRet = OpenPrinter ( pPrinterName, &m_hPrinter, NULL ); if (!bRet) { //
// ...printer is not opened...
//
m_hPrinter = INVALID_HANDLE_VALUE; } return bRet; }
void CBasePort::closePrinter() { if (INVALID_HANDLE_VALUE != m_hPrinter) { ClosePrinter( m_hPrinter ); m_hPrinter = INVALID_HANDLE_VALUE; } }
void CBasePort::setJobStatus( DWORD dwJobStatus ) { // Make sure that we have a valid printer handle
if ( m_hPrinter != INVALID_HANDLE_VALUE ) SetJob( m_hPrinter, m_dwJobId, 0, NULL, dwJobStatus ); }
void CBasePort::setJobID(DWORD dwJobID) { m_dwJobId = dwJobID; }
DWORD CBasePort::getJobID() { return m_dwJobId; }
BOOL CBasePort::checkPnP() { // If a class wants to do something, it needs to override
return FALSE; }
DWORD CBasePort::sendQueuedData() { DWORD dwLastError = ERROR_SUCCESS;
// Wait for any outstanding write to complete
while ( m_dwDataSize > m_dwDataCompleted ) { // If job needs to be aborted ask KM driver to cancel the I/O
//
if ( abortThisJob() ) { if ( m_dwDataScheduled ) { CancelIo( m_hDeviceHandle); dwLastError = getWriteStatus( INFINITE ); } return dwLastError; }
if ( m_dwDataScheduled ) dwLastError = getWriteStatus( JOB_ABORTCHECK_TIMEOUT ); else { // If for some reason KM is failing to complete all write do not
// send data in a busy loop. Use 1 sec between Writes
//
if ( dwLastError != ERROR_SUCCESS ) Sleep(1*1000);
dwLastError = writeData(); }
//
// Check if we can use the same handle and continue
//
if ( needToResubmitJob( dwLastError ) ) { invalidatePortHandle(); setJobStatus( JOB_CONTROL_RESTART ); } }
return dwLastError; }
BOOL CBasePort::abortThisJob() { BOOL bRet = FALSE; DWORD dwNeeded; LPJOB_INFO_1 pJobInfo = NULL;
dwNeeded = 0; //
if (INVALID_HANDLE_VALUE == m_hPrinter) { SetLastError ( ERROR_INVALID_HANDLE ); goto Done; } //
GetJob( m_hPrinter, m_dwJobId, 1, NULL, 0, &dwNeeded);
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) goto Done;
if ( !(pJobInfo = (LPJOB_INFO_1) AllocSplMem(dwNeeded)) || !GetJob( m_hPrinter, m_dwJobId, 1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded) ) goto Done;
bRet = (pJobInfo->Status & JOB_STATUS_DELETING) || (pJobInfo->Status & JOB_STATUS_DELETED) || (pJobInfo->Status & JOB_STATUS_RESTART); Done: FreeSplMem(pJobInfo);
return bRet; }
/*++
Routine Description:
Arguments:
Return Value: ERROR_SUCCESS : Write got done succesfully ERROR_TIMEOUT : Timeout occured Others : Write completed with a failure
--*/ DWORD CBasePort::getWriteStatus(DWORD dwTimeOut) { DWORD dwLastError = ERROR_SUCCESS; DWORD dwWritten = 0;
SPLASSERT( m_dwDataScheduled > 0);
if ( WAIT_TIMEOUT == WaitForSingleObject( m_Ov.hEvent, dwTimeOut) ) { dwLastError = ERROR_TIMEOUT; goto Done; }
if ( !GetOverlappedResult( m_hDeviceHandle, &m_Ov, &dwWritten, FALSE) ) { if ( (dwLastError = GetLastError()) == ERROR_SUCCESS ) dwLastError = STG_E_UNKNOWN; }
ResetEvent( m_Ov.hEvent );
// We are here because either a write completed succesfully,
// or failed but the error is not serious enough to resubmit job
if ( dwWritten <= m_dwDataScheduled ) m_dwDataCompleted += dwWritten; else SPLASSERT( dwWritten <= m_dwDataScheduled );
m_dwDataScheduled = 0;
Done: // Either we timed out, or write sheduled completed (success of failure)
SPLASSERT( dwLastError == ERROR_TIMEOUT || m_dwDataScheduled == 0 ); return dwLastError; }
/*++
Routine Description:
Arguments:
Return Value: ERROR_SUCCESS : Write got succesfully scheduled (may or may not have completed on return) pPortInfo->dwScheduledData is the amount that got scheduled Others: Write failed, return code is the Win32 error
--*/ DWORD CBasePort::writeData() { DWORD dwLastError = ERROR_SUCCESS, dwDontCare;
// When a sheduled write is pending we should not try to send data
// any more
SPLASSERT( m_dwDataScheduled == 0);
// Send all the data that is not confirmed
SPLASSERT( m_dwDataSize >= m_dwDataCompleted); m_dwDataScheduled = m_dwDataSize - m_dwDataCompleted;
// Clear Overlapped fields before sending
m_Ov.Offset = m_Ov.OffsetHigh = 0x00; if ( !WriteFile( m_hDeviceHandle, m_pWriteBuffer + m_dwDataCompleted, m_dwDataScheduled, &dwDontCare, &m_Ov) ) { if ( (dwLastError = GetLastError()) == ERROR_SUCCESS ) dwLastError = STG_E_UNKNOWN; else if ( dwLastError == ERROR_IO_PENDING ) dwLastError = ERROR_SUCCESS; }
// If scheduling of the write failed then no data is pending
if ( dwLastError != ERROR_SUCCESS ) m_dwDataScheduled = 0;
return dwLastError; }
BOOL CBasePort::needToResubmitJob(DWORD dwError) { //
// I used winerror -s ntstatus to map KM error codes to user mode errors
//
// 5 ERROR_ACCESS_DENIED <--> c0000056 STATUS_DELETE_PENDING
// 6 ERROR_INVALID_HANDLE <--> c0000008 STATUS_INVALID_HANDLE
// 23 ERROR_CRC <--> c000003e STATUS_DATA_ERROR
// 23 ERROR_CRC <--> c000003f STATUS_CRC_ERROR
// 23 ERROR_CRC <--> c000009c STATUS_DEVICE_DATA_ERROR
// 55 ERROR_DEV_NOT_EXIST <--> c00000c0 STATUS_DEVICE_DOES_NOT_EXIST
// 303 ERROR_DELETE_PENDING <--> c0000056 STATUS_DELETE_PENDING
// 995 ERROR_OPERATION_ABORTED
//
return dwError == ERROR_ACCESS_DENIED || dwError == ERROR_INVALID_HANDLE || dwError == ERROR_CRC || dwError == ERROR_DELETE_PENDING || dwError == ERROR_DEV_NOT_EXIST || dwError == ERROR_OPERATION_ABORTED;
}
void CBasePort::invalidatePortHandle() { SPLASSERT( m_hDeviceHandle != INVALID_HANDLE_VALUE );
CloseHandle( m_hDeviceHandle ); m_hDeviceHandle = INVALID_HANDLE_VALUE;
CloseHandle( m_Ov.hEvent ); m_Ov.hEvent = NULL;
freeWriteBuffer(); }
void CBasePort::freeWriteBuffer() { FreeSplMem( m_pWriteBuffer ); m_pWriteBuffer=NULL;
m_dwBufferSize = m_dwDataSize = m_dwDataCompleted = m_dwDataScheduled = 0; }
void CBasePort::setMaxBuffer(DWORD dwMaxBufferSize) { m_dwMaxBufferSize = dwMaxBufferSize; }
DWORD CBasePort::adjustWriteSize(DWORD dwBytesToWrite) { // If this port has a data size limit....
if ( m_dwMaxBufferSize ) { // Check and adjust the current write size.
if ( dwBytesToWrite > m_dwMaxBufferSize ) dwBytesToWrite = m_dwMaxBufferSize; }
return dwBytesToWrite; }
DWORD CBasePort::getTimeLeft(DWORD dwStartTime, DWORD dwTimeout) { DWORD dwCurrentTime; DWORD dwTimeLeft;
if ( dwTimeout == MAX_TIMEOUT ) return MAX_TIMEOUT; dwCurrentTime = GetTickCount(); if ( dwTimeout < ( dwCurrentTime - dwStartTime ) ) dwTimeLeft=0; else dwTimeLeft = dwTimeout - ( dwCurrentTime - dwStartTime ); return dwTimeLeft; }
BOOL CBasePort::getLPTStatus(HANDLE hDeviceHandle, BYTE *Status) { BYTE StatusByte; OVERLAPPED Ov = {0};
BOOL bResult; DWORD dwBytesReturned; DWORD dwLastError; Ov.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); if (Ov.hEvent) { bResult = DeviceIoControl( hDeviceHandle, IOCTL_USBPRINT_GET_LPT_STATUS, NULL, 0, &StatusByte, 1, &dwBytesReturned, &Ov ); dwLastError=GetLastError(); if ( bResult || ( dwLastError == ERROR_IO_PENDING ) ) bResult = GetOverlappedResult( hDeviceHandle, &Ov, &dwBytesReturned, TRUE );
if ( bResult ) *Status=StatusByte; else *Status=LPT_BENIGN_STATUS; //benign printer status... 0 would indicate a particular error status from the printer
CloseHandle( Ov.hEvent ); } else { bResult = FALSE; } return bResult;
}
|