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

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. All Rights Reserved
  4. Module Name:
  5. BasePort.cpp
  6. Abstract:
  7. Basic Port Class
  8. Implementation of the CBasePort class.
  9. Author: M. Fenelon
  10. Revision History:
  11. --*/
  12. //
  13. //////////////////////////////////////////////////////////////////////
  14. #include "precomp.h"
  15. #include "ntddpar.h"
  16. TCHAR cszMonitorName[] = TEXT("Dynamic Print Monitor");
  17. //////////////////////////////////////////////////////////////////////
  18. // Construction/Destruction
  19. //////////////////////////////////////////////////////////////////////
  20. CBasePort::CBasePort()
  21. : m_cRef(0), m_dwFlags(0), m_hDeviceHandle(INVALID_HANDLE_VALUE),
  22. m_hPrinter(INVALID_HANDLE_VALUE), m_pWriteBuffer(NULL), m_dwBufferSize(0),
  23. m_dwDataSize(0), m_dwDataCompleted(0), m_dwDataScheduled(0), m_dwReadTimeoutMultiplier(READ_TIMEOUT_MULTIPLIER),
  24. m_dwReadTimeoutConstant(READ_TIMEOUT_CONSTANT), m_dwWriteTimeoutMultiplier(WRITE_TIMEOUT_MULTIPLIER),
  25. m_dwWriteTimeoutConstant(WRITE_TIMEOUT_CONSTANT), m_dwMaxBufferSize(0)
  26. {
  27. }
  28. CBasePort::CBasePort( BOOL bActive, LPTSTR pszPortName, LPTSTR pszDevicePath, LPTSTR pszPortDesc )
  29. : m_cRef(0), m_dwFlags(0), m_bActive(bActive), m_hDeviceHandle(INVALID_HANDLE_VALUE),
  30. m_hPrinter(INVALID_HANDLE_VALUE), m_pWriteBuffer(NULL), m_dwBufferSize(0),
  31. m_dwDataSize(0), m_dwDataCompleted(0), m_dwDataScheduled(0), m_dwReadTimeoutMultiplier(READ_TIMEOUT_MULTIPLIER),
  32. m_dwReadTimeoutConstant(READ_TIMEOUT_CONSTANT), m_dwWriteTimeoutMultiplier(WRITE_TIMEOUT_MULTIPLIER),
  33. m_dwWriteTimeoutConstant(WRITE_TIMEOUT_CONSTANT), m_dwMaxBufferSize(0)
  34. {
  35. // Setup the Port Name
  36. ::SafeCopy( MAX_PORT_LEN, pszPortName, m_szPortName );
  37. // Setup the DevicePath
  38. ::SafeCopy( MAX_PATH, pszDevicePath, m_szDevicePath );
  39. // Setup Port Description
  40. ::SafeCopy( MAX_PORT_DESC_LEN, pszPortDesc, m_szPortDescription );
  41. }
  42. CBasePort::~CBasePort()
  43. {
  44. // Cleanup any left over resources
  45. if ( m_hDeviceHandle != INVALID_HANDLE_VALUE )
  46. {
  47. CloseHandle( m_hDeviceHandle );
  48. CloseHandle( m_Ov.hEvent );
  49. }
  50. }
  51. BOOL CBasePort::open()
  52. {
  53. BOOL bRet = FALSE;
  54. ECS( m_CritSec );
  55. if ( m_hDeviceHandle == INVALID_HANDLE_VALUE )
  56. {
  57. //
  58. // If we have an invalid handle and refcount is non-zero we want the
  59. // job to fail and restart to accept writes. In other words if the
  60. // handle got closed prematurely, because of failing writes, then we
  61. // need the ref count to go down to 0 before calling CreateFile again
  62. //
  63. if ( m_cRef )
  64. goto Done;
  65. m_hDeviceHandle = CreateFile( m_szDevicePath,
  66. GENERIC_WRITE | GENERIC_READ,
  67. FILE_SHARE_READ | FILE_SHARE_WRITE,
  68. NULL,
  69. OPEN_EXISTING,
  70. FILE_FLAG_OVERLAPPED,
  71. NULL);
  72. //
  73. // If we failed to open the port - test to see if it is a Dot4 port.
  74. //
  75. if ( m_hDeviceHandle == INVALID_HANDLE_VALUE )
  76. {
  77. //
  78. // ERROR_FILE_NOT_FOUND -> Error code for port not there.
  79. //
  80. if ( ERROR_FILE_NOT_FOUND != GetLastError() ||
  81. !checkPnP() )
  82. goto Done;
  83. }
  84. m_Ov.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
  85. if ( m_Ov.hEvent == NULL )
  86. {
  87. CloseHandle(m_hDeviceHandle);
  88. m_hDeviceHandle = INVALID_HANDLE_VALUE;
  89. goto Done;
  90. }
  91. }
  92. ++m_cRef;
  93. bRet = TRUE;
  94. Done:
  95. LCS( m_CritSec );
  96. return bRet;
  97. }
  98. BOOL CBasePort::close()
  99. {
  100. BOOL bRet = TRUE;
  101. ECS( m_CritSec );
  102. --m_cRef;
  103. if ( m_cRef != 0 )
  104. goto Done;
  105. bRet = CloseHandle( m_hDeviceHandle);
  106. CloseHandle( m_Ov.hEvent);
  107. m_hDeviceHandle = INVALID_HANDLE_VALUE;
  108. Done:
  109. LCS( m_CritSec );
  110. return bRet;
  111. }
  112. BOOL CBasePort::startDoc(LPTSTR pPrinterName, DWORD dwJobId, DWORD dwLevel, LPBYTE pDocInfo)
  113. {
  114. BOOL bRet;
  115. SPLASSERT( notInWrite() );
  116. if ( !openPrinter( pPrinterName ) )
  117. return FALSE;
  118. m_dwJobId = dwJobId;
  119. bRet = open();
  120. if ( !bRet )
  121. closePrinter();
  122. else
  123. m_dwFlags |= DYNAMON_STARTDOC;
  124. return bRet;
  125. }
  126. BOOL CBasePort::endDoc()
  127. {
  128. DWORD dwLastError = ERROR_SUCCESS;
  129. dwLastError = sendQueuedData();
  130. freeWriteBuffer();
  131. m_dwFlags &= ~DYNAMON_STARTDOC;
  132. close();
  133. setJobStatus( JOB_CONTROL_SENT_TO_PRINTER );
  134. closePrinter();
  135. return TRUE;
  136. }
  137. BOOL CBasePort::read(LPBYTE pBuffer, DWORD cbBuffer, LPDWORD pcbRead)
  138. {
  139. DWORD dwLastError = ERROR_SUCCESS;
  140. DWORD dwTimeout;
  141. HANDLE hReadHandle;
  142. OVERLAPPED Ov;
  143. //
  144. // Create separate read handle since we have to cancel reads which do
  145. // not complete within the specified timeout without cancelling writes
  146. //
  147. hReadHandle = CreateFile( m_szDevicePath,
  148. GENERIC_WRITE | GENERIC_READ,
  149. FILE_SHARE_READ | FILE_SHARE_WRITE,
  150. NULL,
  151. OPEN_EXISTING,
  152. FILE_FLAG_OVERLAPPED,
  153. NULL);
  154. if ( hReadHandle == INVALID_HANDLE_VALUE )
  155. return FALSE;
  156. ZeroMemory( &Ov, sizeof(Ov) );
  157. if ( !( Ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL) ) )
  158. goto Done;
  159. if ( !ReadFile( hReadHandle, pBuffer, cbBuffer, pcbRead, &Ov ) &&
  160. ( dwLastError = GetLastError() ) != ERROR_IO_PENDING )
  161. goto Done;
  162. dwTimeout = m_dwReadTimeoutConstant +
  163. m_dwReadTimeoutMultiplier * cbBuffer;
  164. if ( dwTimeout == 0 )
  165. dwTimeout=MAX_TIMEOUT;
  166. if ( WaitForSingleObject( Ov.hEvent, dwTimeout ) == WAIT_TIMEOUT )
  167. {
  168. CancelIo( hReadHandle );
  169. WaitForSingleObject( Ov.hEvent, INFINITE );
  170. }
  171. if ( !GetOverlappedResult( hReadHandle, &Ov, pcbRead, FALSE ) )
  172. {
  173. *pcbRead = 0;
  174. dwLastError = GetLastError();
  175. }
  176. else
  177. dwLastError = ERROR_SUCCESS;
  178. Done:
  179. if ( Ov.hEvent )
  180. CloseHandle( Ov.hEvent );
  181. CloseHandle( hReadHandle );
  182. if ( dwLastError )
  183. SetLastError(dwLastError);
  184. return dwLastError == ERROR_SUCCESS;
  185. }
  186. BOOL CBasePort::write(LPBYTE pBuffer, DWORD cbBuffer, LPDWORD pcbWritten)
  187. {
  188. DWORD dwLastError = ERROR_SUCCESS;
  189. DWORD dwBytesLeft, dwBytesSent;
  190. DWORD dwStartTime, dwTimeLeft, dwTimeout;
  191. BYTE bPrinterStatus;
  192. BOOL bStartDoc = ( ( m_dwFlags & DYNAMON_STARTDOC ) != 0 );
  193. *pcbWritten = 0;
  194. dwStartTime = GetTickCount();
  195. dwTimeout = m_dwWriteTimeoutConstant + m_dwWriteTimeoutMultiplier * cbBuffer;
  196. if ( dwTimeout == 0 )
  197. dwTimeout = MAX_TIMEOUT;
  198. // Usbprint currently can't handle write greater than 4K.
  199. // For Win2K we will make a fix here, later usbprint will be fixed
  200. //
  201. // It is ok to change the size here since spooler will resubmit the rest
  202. // later
  203. //
  204. cbBuffer = adjustWriteSize( cbBuffer );
  205. //
  206. // For writes outside startdoc/enddoc we do not carry them across WritePort
  207. // calls. These are typically from language monitors (i.e. not job data)
  208. //
  209. SPLASSERT(bStartDoc || m_pWriteBuffer == NULL);
  210. if ( bStartDoc && ( m_hDeviceHandle == INVALID_HANDLE_VALUE ) )
  211. {
  212. setJobStatus( JOB_CONTROL_RESTART );
  213. SetLastError(ERROR_CANCELLED);
  214. return FALSE;
  215. }
  216. if ( !open() )
  217. return FALSE;
  218. // First complete any data from previous WritePort call
  219. while ( m_dwDataSize > m_dwDataCompleted )
  220. {
  221. if ( m_dwDataScheduled )
  222. {
  223. dwTimeLeft = getTimeLeft( dwStartTime, dwTimeout );
  224. dwLastError = getWriteStatus( dwTimeLeft );
  225. }
  226. else
  227. dwLastError = writeData();
  228. if ( dwLastError != ERROR_SUCCESS )
  229. goto Done;
  230. }
  231. SPLASSERT(m_dwDataSize == m_dwDataCompleted &&
  232. m_dwDataScheduled == 0 &&
  233. dwLastError == ERROR_SUCCESS);
  234. //
  235. // Copy the data to our own buffer
  236. //
  237. if ( m_dwBufferSize < cbBuffer )
  238. {
  239. freeWriteBuffer();
  240. if ( m_pWriteBuffer = (LPBYTE) AllocSplMem( cbBuffer ) )
  241. m_dwBufferSize = cbBuffer;
  242. else
  243. {
  244. dwLastError = ERROR_OUTOFMEMORY;
  245. goto Done;
  246. }
  247. }
  248. // We have to clear the counters
  249. m_dwDataCompleted = m_dwDataScheduled = 0;
  250. CopyMemory( m_pWriteBuffer, pBuffer, cbBuffer );
  251. m_dwDataSize = cbBuffer;
  252. //
  253. // Now do the write for the data for this WritePort call
  254. //
  255. while ( m_dwDataSize > m_dwDataCompleted )
  256. {
  257. if ( m_dwDataScheduled )
  258. {
  259. dwTimeLeft = getTimeLeft( dwStartTime, dwTimeout );
  260. dwLastError = getWriteStatus( dwTimeLeft );
  261. }
  262. else
  263. dwLastError = writeData();
  264. if ( dwLastError != ERROR_SUCCESS )
  265. break;
  266. }
  267. //
  268. // For writes outside startdoc/enddoc, which are from language monitors,
  269. // do not carry pending writes to next WritePort.
  270. //
  271. if ( !bStartDoc && m_dwDataSize > m_dwDataCompleted )
  272. {
  273. CancelIo( m_hDeviceHandle );
  274. dwLastError = getWriteStatus( INFINITE );
  275. *pcbWritten = m_dwDataCompleted;
  276. freeWriteBuffer();
  277. }
  278. //
  279. // We will tell spooler we wrote all the data if some data got scheduled
  280. // (or scheduled and completed)
  281. //
  282. if ( m_dwDataCompleted > 0 || m_dwDataScheduled != 0 )
  283. *pcbWritten = cbBuffer;
  284. else
  285. freeWriteBuffer();
  286. Done:
  287. if ( needToResubmitJob( dwLastError ) )
  288. invalidatePortHandle();
  289. else if ( dwLastError == ERROR_TIMEOUT )
  290. {
  291. if (getLPTStatus( m_hDeviceHandle, &bPrinterStatus ))
  292. {
  293. if ( bPrinterStatus & LPT_PAPER_EMPTY )
  294. dwLastError=ERROR_OUT_OF_PAPER;
  295. }
  296. }
  297. close();
  298. SetLastError(dwLastError);
  299. return dwLastError == ERROR_SUCCESS;
  300. }
  301. BOOL CBasePort::getPrinterDataFromPort( DWORD dwControlID, LPTSTR pValueName, LPWSTR lpInBuffer, DWORD cbInBuffer,
  302. LPWSTR lpOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbReturned )
  303. {
  304. BOOL bRet = FALSE;
  305. OVERLAPPED Ov;
  306. HANDLE hDeviceHandle;
  307. DWORD dwWaitResult;
  308. *lpcbReturned = 0;
  309. if ( dwControlID == 0 )
  310. {
  311. SetLastError(ERROR_INVALID_PARAMETER);
  312. return FALSE;
  313. }
  314. ZeroMemory(&Ov, sizeof(Ov));
  315. if ( !(Ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) )
  316. return FALSE;
  317. if ( !open() )
  318. {
  319. CloseHandle(Ov.hEvent);
  320. return FALSE;
  321. }
  322. if ( dwControlID == IOCTL_PAR_QUERY_DEVICE_ID )
  323. {
  324. hDeviceHandle = CreateFile( m_szDevicePath,
  325. GENERIC_WRITE | GENERIC_READ,
  326. FILE_SHARE_READ | FILE_SHARE_WRITE,
  327. NULL,
  328. OPEN_EXISTING,
  329. FILE_FLAG_OVERLAPPED,
  330. NULL);
  331. if ( hDeviceHandle == INVALID_HANDLE_VALUE )
  332. goto Done;
  333. if ( !DeviceIoControl( m_hDeviceHandle, dwControlID, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, lpcbReturned, &Ov)
  334. && GetLastError() != ERROR_IO_PENDING )
  335. {
  336. CloseHandle( hDeviceHandle );
  337. goto Done;
  338. }
  339. if ( WaitForSingleObject( Ov.hEvent, PAR_QUERY_TIMEOUT ) != WAIT_OBJECT_0 )
  340. CancelIo( hDeviceHandle );
  341. bRet = GetOverlappedResult( m_hDeviceHandle, &Ov, lpcbReturned, TRUE );
  342. CloseHandle( hDeviceHandle );
  343. }
  344. else
  345. {
  346. if ( !DeviceIoControl( m_hDeviceHandle, dwControlID,
  347. lpInBuffer, cbInBuffer,
  348. lpOutBuffer, cbOutBuffer, lpcbReturned, &Ov) &&
  349. GetLastError() != ERROR_IO_PENDING )
  350. goto Done;
  351. bRet = GetOverlappedResult( m_hDeviceHandle, &Ov, lpcbReturned, TRUE);
  352. }
  353. Done:
  354. CloseHandle(Ov.hEvent);
  355. close();
  356. return bRet;
  357. }
  358. BOOL CBasePort::setPortTimeOuts( LPCOMMTIMEOUTS lpCTO )
  359. {
  360. m_dwReadTimeoutConstant = lpCTO->ReadTotalTimeoutConstant;
  361. m_dwReadTimeoutMultiplier = lpCTO->ReadTotalTimeoutMultiplier;
  362. m_dwWriteTimeoutConstant = lpCTO->WriteTotalTimeoutConstant;
  363. m_dwWriteTimeoutMultiplier = lpCTO->WriteTotalTimeoutMultiplier;
  364. return TRUE;
  365. }
  366. void CBasePort::InitCS()
  367. {
  368. ICS( m_CritSec );
  369. }
  370. void CBasePort::ClearCS()
  371. {
  372. DCS( m_CritSec );
  373. }
  374. PORTTYPE CBasePort::getPortType()
  375. {
  376. return USBPORT;
  377. }
  378. LPTSTR CBasePort::getPortDesc()
  379. {
  380. return m_szPortDescription;
  381. }
  382. void CBasePort::setPortDesc( LPTSTR pszPortDesc )
  383. {
  384. if ( pszPortDesc )
  385. ::SafeCopy( MAX_PORT_DESC_LEN, pszPortDesc, m_szPortDescription );
  386. }
  387. BOOL CBasePort::isActive( void )
  388. {
  389. return m_bActive;
  390. }
  391. void CBasePort::setActive( BOOL bValue )
  392. {
  393. m_bActive = bValue;
  394. }
  395. BOOL CBasePort::compActiveState( BOOL bValue )
  396. {
  397. return (m_bActive == bValue);
  398. }
  399. LPTSTR CBasePort::getPortName()
  400. {
  401. return m_szPortName;
  402. }
  403. void CBasePort::setPortName(LPTSTR pszPortName)
  404. {
  405. if ( pszPortName )
  406. ::SafeCopy( MAX_PORT_LEN, pszPortName, m_szPortName );
  407. }
  408. INT CBasePort::compPortName(LPTSTR pszPortName)
  409. {
  410. return _tcsicmp( pszPortName, m_szPortName );
  411. }
  412. LPTSTR CBasePort::getDevicePath()
  413. {
  414. return m_szDevicePath;
  415. }
  416. void CBasePort::setDevicePath(LPTSTR pszDevicePath)
  417. {
  418. if ( pszDevicePath )
  419. ::SafeCopy( MAX_PATH, pszDevicePath, m_szDevicePath );
  420. }
  421. INT CBasePort::compDevicePath(LPTSTR pszDevicePath)
  422. {
  423. return _tcsicmp( pszDevicePath, m_szDevicePath );
  424. }
  425. DWORD CBasePort::getEnumInfoSize(DWORD dwLevel )
  426. {
  427. // Need to calcualted how much data will be used for this port
  428. DWORD dwBytesNeeded = 0;
  429. switch ( dwLevel )
  430. {
  431. case 1:
  432. // Start with size of Port Info struct
  433. dwBytesNeeded += sizeof( PORT_INFO_1 );
  434. // Add the length of the string
  435. dwBytesNeeded += ( _tcslen( m_szPortName ) + 1 ) * sizeof(TCHAR);
  436. break;
  437. case 2:
  438. // Start with size of Port Info struct
  439. dwBytesNeeded += sizeof( PORT_INFO_2 );
  440. // Add the length of the strings
  441. dwBytesNeeded += ( _tcslen( m_szPortName ) + 1 ) * sizeof(TCHAR);
  442. dwBytesNeeded += ( _tcslen( m_szPortDescription ) + 1 ) * sizeof(TCHAR);
  443. dwBytesNeeded += ( _tcslen( cszMonitorName ) + 1 ) * sizeof(TCHAR);
  444. break;
  445. }
  446. return dwBytesNeeded;
  447. }
  448. LPBYTE CBasePort::copyEnumInfo(DWORD dwLevel, LPBYTE pPort, LPBYTE pEnd)
  449. {
  450. LPTSTR pStrStart;
  451. PPORT_INFO_1 pPort1 = (PPORT_INFO_1) pPort;
  452. PPORT_INFO_2 pPort2 = (PPORT_INFO_2) pPort;
  453. switch ( dwLevel )
  454. {
  455. case 2:
  456. // Assign the Port name
  457. pStrStart = (LPTSTR) ( pEnd - ( ( _tcslen( m_szPortDescription ) + 1 ) * sizeof(TCHAR) ) );
  458. if (pPort < (LPBYTE) pStrStart)
  459. {
  460. (VOID) StringCchCopy (pStrStart, COUNTOF (m_szPortDescription), m_szPortDescription);
  461. }
  462. pPort2->pDescription = pStrStart;
  463. pEnd = (LPBYTE) pStrStart;
  464. // Assign the Port name
  465. pStrStart = (LPTSTR) ( pEnd - ( ( _tcslen( cszMonitorName ) + 1 ) * sizeof(TCHAR) ) );
  466. if (pPort < (LPBYTE) pStrStart)
  467. {
  468. (VOID) StringCchCopy (pStrStart, COUNTOF (cszMonitorName), cszMonitorName);
  469. }
  470. pPort2->pMonitorName = pStrStart;
  471. pEnd = (LPBYTE) pStrStart;
  472. case 1:
  473. // Assign the Port name
  474. pStrStart = (LPTSTR) ( pEnd - ( ( _tcslen( m_szPortName ) + 1 ) * sizeof(TCHAR) ) );
  475. if (pPort < (LPBYTE) pStrStart)
  476. {
  477. (VOID) StringCchCopy (pStrStart, COUNTOF (m_szPortName), m_szPortName);
  478. }
  479. pPort1->pName = pStrStart;
  480. }
  481. return (LPBYTE) pStrStart;
  482. }
  483. BOOL CBasePort::notInWrite()
  484. {
  485. return( m_pWriteBuffer == NULL &&
  486. m_dwBufferSize == 0 &&
  487. m_dwDataSize == 0 &&
  488. m_dwDataCompleted == 0 &&
  489. m_dwDataScheduled == 0 );
  490. }
  491. BOOL CBasePort::openPrinter(LPTSTR pPrinterName)
  492. {
  493. if (INVALID_HANDLE_VALUE != m_hPrinter)
  494. {
  495. //
  496. // Printer is already opened
  497. //
  498. return TRUE;
  499. }
  500. //
  501. // Opening the printer...
  502. //
  503. BOOL bRet =
  504. OpenPrinter (
  505. pPrinterName,
  506. &m_hPrinter,
  507. NULL
  508. );
  509. if (!bRet)
  510. {
  511. //
  512. // ...printer is not opened...
  513. //
  514. m_hPrinter = INVALID_HANDLE_VALUE;
  515. }
  516. return bRet;
  517. }
  518. void CBasePort::closePrinter()
  519. {
  520. if (INVALID_HANDLE_VALUE != m_hPrinter)
  521. {
  522. ClosePrinter( m_hPrinter );
  523. m_hPrinter = INVALID_HANDLE_VALUE;
  524. }
  525. }
  526. void CBasePort::setJobStatus( DWORD dwJobStatus )
  527. {
  528. // Make sure that we have a valid printer handle
  529. if ( m_hPrinter != INVALID_HANDLE_VALUE )
  530. SetJob( m_hPrinter, m_dwJobId, 0, NULL, dwJobStatus );
  531. }
  532. void CBasePort::setJobID(DWORD dwJobID)
  533. {
  534. m_dwJobId = dwJobID;
  535. }
  536. DWORD CBasePort::getJobID()
  537. {
  538. return m_dwJobId;
  539. }
  540. BOOL CBasePort::checkPnP()
  541. {
  542. // If a class wants to do something, it needs to override
  543. return FALSE;
  544. }
  545. DWORD CBasePort::sendQueuedData()
  546. {
  547. DWORD dwLastError = ERROR_SUCCESS;
  548. // Wait for any outstanding write to complete
  549. while ( m_dwDataSize > m_dwDataCompleted )
  550. {
  551. // If job needs to be aborted ask KM driver to cancel the I/O
  552. //
  553. if ( abortThisJob() )
  554. {
  555. if ( m_dwDataScheduled )
  556. {
  557. CancelIo( m_hDeviceHandle);
  558. dwLastError = getWriteStatus( INFINITE );
  559. }
  560. return dwLastError;
  561. }
  562. if ( m_dwDataScheduled )
  563. dwLastError = getWriteStatus( JOB_ABORTCHECK_TIMEOUT );
  564. else
  565. {
  566. // If for some reason KM is failing to complete all write do not
  567. // send data in a busy loop. Use 1 sec between Writes
  568. //
  569. if ( dwLastError != ERROR_SUCCESS )
  570. Sleep(1*1000);
  571. dwLastError = writeData();
  572. }
  573. //
  574. // Check if we can use the same handle and continue
  575. //
  576. if ( needToResubmitJob( dwLastError ) )
  577. {
  578. invalidatePortHandle();
  579. setJobStatus( JOB_CONTROL_RESTART );
  580. }
  581. }
  582. return dwLastError;
  583. }
  584. BOOL CBasePort::abortThisJob()
  585. {
  586. BOOL bRet = FALSE;
  587. DWORD dwNeeded;
  588. LPJOB_INFO_1 pJobInfo = NULL;
  589. dwNeeded = 0;
  590. //
  591. if (INVALID_HANDLE_VALUE == m_hPrinter)
  592. {
  593. SetLastError (
  594. ERROR_INVALID_HANDLE
  595. );
  596. goto Done;
  597. }
  598. //
  599. GetJob( m_hPrinter, m_dwJobId, 1, NULL, 0, &dwNeeded);
  600. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  601. goto Done;
  602. if ( !(pJobInfo = (LPJOB_INFO_1) AllocSplMem(dwNeeded)) ||
  603. !GetJob( m_hPrinter, m_dwJobId,
  604. 1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded)
  605. )
  606. goto Done;
  607. bRet = (pJobInfo->Status & JOB_STATUS_DELETING) ||
  608. (pJobInfo->Status & JOB_STATUS_DELETED) ||
  609. (pJobInfo->Status & JOB_STATUS_RESTART);
  610. Done:
  611. FreeSplMem(pJobInfo);
  612. return bRet;
  613. }
  614. /*++
  615. Routine Description:
  616. Arguments:
  617. Return Value:
  618. ERROR_SUCCESS : Write got done succesfully
  619. ERROR_TIMEOUT : Timeout occured
  620. Others : Write completed with a failure
  621. --*/
  622. DWORD CBasePort::getWriteStatus(DWORD dwTimeOut)
  623. {
  624. DWORD dwLastError = ERROR_SUCCESS;
  625. DWORD dwWritten = 0;
  626. SPLASSERT( m_dwDataScheduled > 0);
  627. if ( WAIT_TIMEOUT == WaitForSingleObject( m_Ov.hEvent, dwTimeOut) )
  628. {
  629. dwLastError = ERROR_TIMEOUT;
  630. goto Done;
  631. }
  632. if ( !GetOverlappedResult( m_hDeviceHandle, &m_Ov,
  633. &dwWritten, FALSE) )
  634. {
  635. if ( (dwLastError = GetLastError()) == ERROR_SUCCESS )
  636. dwLastError = STG_E_UNKNOWN;
  637. }
  638. ResetEvent( m_Ov.hEvent );
  639. // We are here because either a write completed succesfully,
  640. // or failed but the error is not serious enough to resubmit job
  641. if ( dwWritten <= m_dwDataScheduled )
  642. m_dwDataCompleted += dwWritten;
  643. else
  644. SPLASSERT( dwWritten <= m_dwDataScheduled );
  645. m_dwDataScheduled = 0;
  646. Done:
  647. // Either we timed out, or write sheduled completed (success of failure)
  648. SPLASSERT( dwLastError == ERROR_TIMEOUT || m_dwDataScheduled == 0 );
  649. return dwLastError;
  650. }
  651. /*++
  652. Routine Description:
  653. Arguments:
  654. Return Value:
  655. ERROR_SUCCESS : Write got succesfully scheduled
  656. (may or may not have completed on return)
  657. pPortInfo->dwScheduledData is the amount that got scheduled
  658. Others: Write failed, return code is the Win32 error
  659. --*/
  660. DWORD CBasePort::writeData()
  661. {
  662. DWORD dwLastError = ERROR_SUCCESS, dwDontCare;
  663. // When a sheduled write is pending we should not try to send data
  664. // any more
  665. SPLASSERT( m_dwDataScheduled == 0);
  666. // Send all the data that is not confirmed
  667. SPLASSERT( m_dwDataSize >= m_dwDataCompleted);
  668. m_dwDataScheduled = m_dwDataSize - m_dwDataCompleted;
  669. // Clear Overlapped fields before sending
  670. m_Ov.Offset = m_Ov.OffsetHigh = 0x00;
  671. if ( !WriteFile( m_hDeviceHandle, m_pWriteBuffer + m_dwDataCompleted,
  672. m_dwDataScheduled, &dwDontCare, &m_Ov) )
  673. {
  674. if ( (dwLastError = GetLastError()) == ERROR_SUCCESS )
  675. dwLastError = STG_E_UNKNOWN;
  676. else if ( dwLastError == ERROR_IO_PENDING )
  677. dwLastError = ERROR_SUCCESS;
  678. }
  679. // If scheduling of the write failed then no data is pending
  680. if ( dwLastError != ERROR_SUCCESS )
  681. m_dwDataScheduled = 0;
  682. return dwLastError;
  683. }
  684. BOOL CBasePort::needToResubmitJob(DWORD dwError)
  685. {
  686. //
  687. // I used winerror -s ntstatus to map KM error codes to user mode errors
  688. //
  689. // 5 ERROR_ACCESS_DENIED <--> c0000056 STATUS_DELETE_PENDING
  690. // 6 ERROR_INVALID_HANDLE <--> c0000008 STATUS_INVALID_HANDLE
  691. // 23 ERROR_CRC <--> c000003e STATUS_DATA_ERROR
  692. // 23 ERROR_CRC <--> c000003f STATUS_CRC_ERROR
  693. // 23 ERROR_CRC <--> c000009c STATUS_DEVICE_DATA_ERROR
  694. // 55 ERROR_DEV_NOT_EXIST <--> c00000c0 STATUS_DEVICE_DOES_NOT_EXIST
  695. // 303 ERROR_DELETE_PENDING <--> c0000056 STATUS_DELETE_PENDING
  696. // 995 ERROR_OPERATION_ABORTED
  697. //
  698. return dwError == ERROR_ACCESS_DENIED ||
  699. dwError == ERROR_INVALID_HANDLE ||
  700. dwError == ERROR_CRC ||
  701. dwError == ERROR_DELETE_PENDING ||
  702. dwError == ERROR_DEV_NOT_EXIST ||
  703. dwError == ERROR_OPERATION_ABORTED;
  704. }
  705. void CBasePort::invalidatePortHandle()
  706. {
  707. SPLASSERT( m_hDeviceHandle != INVALID_HANDLE_VALUE );
  708. CloseHandle( m_hDeviceHandle );
  709. m_hDeviceHandle = INVALID_HANDLE_VALUE;
  710. CloseHandle( m_Ov.hEvent );
  711. m_Ov.hEvent = NULL;
  712. freeWriteBuffer();
  713. }
  714. void CBasePort::freeWriteBuffer()
  715. {
  716. FreeSplMem( m_pWriteBuffer );
  717. m_pWriteBuffer=NULL;
  718. m_dwBufferSize = m_dwDataSize
  719. = m_dwDataCompleted
  720. = m_dwDataScheduled = 0;
  721. }
  722. void CBasePort::setMaxBuffer(DWORD dwMaxBufferSize)
  723. {
  724. m_dwMaxBufferSize = dwMaxBufferSize;
  725. }
  726. DWORD CBasePort::adjustWriteSize(DWORD dwBytesToWrite)
  727. {
  728. // If this port has a data size limit....
  729. if ( m_dwMaxBufferSize )
  730. {
  731. // Check and adjust the current write size.
  732. if ( dwBytesToWrite > m_dwMaxBufferSize )
  733. dwBytesToWrite = m_dwMaxBufferSize;
  734. }
  735. return dwBytesToWrite;
  736. }
  737. DWORD CBasePort::getTimeLeft(DWORD dwStartTime, DWORD dwTimeout)
  738. {
  739. DWORD dwCurrentTime;
  740. DWORD dwTimeLeft;
  741. if ( dwTimeout == MAX_TIMEOUT )
  742. return MAX_TIMEOUT;
  743. dwCurrentTime = GetTickCount();
  744. if ( dwTimeout < ( dwCurrentTime - dwStartTime ) )
  745. dwTimeLeft=0;
  746. else
  747. dwTimeLeft = dwTimeout - ( dwCurrentTime - dwStartTime );
  748. return dwTimeLeft;
  749. }
  750. BOOL CBasePort::getLPTStatus(HANDLE hDeviceHandle, BYTE *Status)
  751. {
  752. BYTE StatusByte;
  753. OVERLAPPED Ov = {0};
  754. BOOL bResult;
  755. DWORD dwBytesReturned;
  756. DWORD dwLastError;
  757. Ov.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
  758. if (Ov.hEvent)
  759. {
  760. bResult = DeviceIoControl( hDeviceHandle, IOCTL_USBPRINT_GET_LPT_STATUS, NULL,
  761. 0, &StatusByte, 1, &dwBytesReturned, &Ov );
  762. dwLastError=GetLastError();
  763. if ( bResult || ( dwLastError == ERROR_IO_PENDING ) )
  764. bResult = GetOverlappedResult( hDeviceHandle, &Ov, &dwBytesReturned, TRUE );
  765. if ( bResult )
  766. *Status=StatusByte;
  767. else
  768. *Status=LPT_BENIGN_STATUS; //benign printer status... 0 would indicate a particular error status from the printer
  769. CloseHandle( Ov.hEvent );
  770. }
  771. else
  772. {
  773. bResult = FALSE;
  774. }
  775. return bResult;
  776. }