Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

990 lines
25 KiB

/*++
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;
}