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.

1720 lines
45 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. w32draut
  5. Abstract:
  6. This module defines a special subclass of the Win32 client-side RDP
  7. printer redirection "device" class. The subclass, W32DrAutoPrn manages
  8. a queue that is automatically discovered by the client via enumerating
  9. client-side printer queues.
  10. Author:
  11. Tad Brockway 3/23/99
  12. Revision History:
  13. --*/
  14. #include <precom.h>
  15. #define TRC_FILE "W32DrAut"
  16. #include "regapi.h"
  17. #include "w32draut.h"
  18. #include "proc.h"
  19. #include "drdbg.h"
  20. #include "w32utl.h"
  21. #include "utl.h"
  22. ///////////////////////////////////////////////////////////////
  23. //
  24. // Defines
  25. //
  26. #define COM_PORT_NAME _T("COM")
  27. #define COM_PORT_NAMELEN 3
  28. #define LPT_PORT_NAME _T("LPT")
  29. #define LPT_PORT_NAMELEN 3
  30. #define USB_PORT_NAME _T("USB")
  31. #define USB_PORT_NAMELEN 3
  32. #define RDP_PORT_NAME _T("TS")
  33. #define RDP_PORT_NAMELEN 2
  34. ///////////////////////////////////////////////////////////////
  35. //
  36. // W32DrAutoPrn Members
  37. //
  38. W32DrAutoPrn::W32DrAutoPrn(
  39. IN ProcObj *processObject,
  40. IN const DRSTRING printerName,
  41. IN const DRSTRING driverName,
  42. IN const DRSTRING portName,
  43. IN BOOL isDefault,
  44. IN ULONG deviceID,
  45. IN const TCHAR *devicePath
  46. ) : W32DrPRN(processObject, printerName, driverName,
  47. portName, NULL, isDefault, deviceID, devicePath)
  48. /*++
  49. Routine Description:
  50. Constructor
  51. Arguments:
  52. processObject - Associated Process Object.
  53. printerName - Name of automatic printer queue.
  54. driverName - Print Driver Name
  55. portName - Client Port Name
  56. isDefault - Is this the default printer?
  57. deviceID - Unique Device Identifier
  58. devicePath - Path to pass to OpenPrinter when opening the
  59. device.
  60. Return Value:
  61. NA
  62. --*/
  63. {
  64. DC_BEGIN_FN("W32DrAutoPrn");
  65. _jobID = 0;
  66. _printerHandle = INVALID_HANDLE_VALUE;
  67. memset(_szLocalPrintingDocName, 0, sizeof(_szLocalPrintingDocName));
  68. ASSERT(processObject);
  69. PRDPDR_DATA prdpdrData = processObject->GetVCMgr().GetInitData();
  70. ASSERT(prdpdrData);
  71. LPTSTR szDocName = prdpdrData->szLocalPrintingDocName;
  72. ASSERT(szDocName);
  73. ASSERT(szDocName[0] != 0);
  74. _tcsncpy(_szLocalPrintingDocName, szDocName,
  75. sizeof(_szLocalPrintingDocName)/sizeof(TCHAR));
  76. OSVERSIONINFO osVersion;
  77. osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  78. _bRunningOn9x = TRUE;
  79. if (GetVersionEx(&osVersion)) {
  80. if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  81. _bRunningOn9x = FALSE;
  82. }
  83. }
  84. else
  85. {
  86. TRC_ERR((TB, _T("GetVersionEx: %08X"), GetLastError()));
  87. }
  88. DC_END_FN();
  89. }
  90. W32DrAutoPrn::~W32DrAutoPrn()
  91. /*++
  92. Routine Description:
  93. Destructor
  94. Arguments:
  95. NA
  96. Return Value:
  97. NA
  98. --*/
  99. {
  100. //
  101. // Make sure all docs are finished and the printer handle closed.
  102. //
  103. ClosePrinter();
  104. }
  105. BOOL
  106. W32DrAutoPrn::ShouldAddThisPrinter(
  107. DWORD queueFilter,
  108. DWORD userSessionID,
  109. PPRINTERINFO pPrinterInfo,
  110. DWORD printerSessionID
  111. )
  112. /*++
  113. Routine Description:
  114. Detemine if we should redirect this printer.
  115. Arguments:
  116. queueFilter - redirect printer filter type.
  117. userSessionID - current user session ID.
  118. pPrinterInfo - printer info
  119. printerSessionID - Printer session ID or INVALID_SESSIONID if printers
  120. is not a TS printer.
  121. Return Value:
  122. TRUE to add printer, FALSE otherwise
  123. --*/
  124. {
  125. BOOL fAddThisPrinter = FALSE;
  126. DWORD sessionID;
  127. DC_BEGIN_FN("W32DrAutoPrn::AddThisPrinter");
  128. //
  129. // Check filters.
  130. //
  131. if (queueFilter == FILTER_ALL_QUEUES ) {
  132. fAddThisPrinter = TRUE;
  133. }
  134. else if ((queueFilter & FILTER_NET_QUEUES) &&
  135. (pPrinterInfo->Attributes & PRINTER_ATTRIBUTE_NETWORK)) {
  136. fAddThisPrinter = TRUE;
  137. }
  138. //
  139. // If it's a non-network printer then get the port name.
  140. //
  141. else if((queueFilter & FILTER_LPT_QUEUES) &&
  142. (_tcsnicmp(
  143. pPrinterInfo->pPortName,
  144. LPT_PORT_NAME,
  145. LPT_PORT_NAMELEN) == 0) ) {
  146. fAddThisPrinter = TRUE;
  147. }
  148. else if ((queueFilter & FILTER_COM_QUEUES) &&
  149. (_tcsnicmp(
  150. pPrinterInfo->pPortName,
  151. COM_PORT_NAME,
  152. COM_PORT_NAMELEN) == 0) ) {
  153. fAddThisPrinter = TRUE;
  154. }
  155. else if ((queueFilter & FILTER_USB_QUEUES) &&
  156. (_tcsnicmp(
  157. pPrinterInfo->pPortName,
  158. USB_PORT_NAME,
  159. USB_PORT_NAMELEN) == 0) ) {
  160. fAddThisPrinter = TRUE;
  161. }
  162. else if ((queueFilter & FILTER_RDP_QUEUES) &&
  163. (_tcsnicmp(
  164. pPrinterInfo->pPortName,
  165. RDP_PORT_NAME,
  166. RDP_PORT_NAMELEN) == 0) ) {
  167. fAddThisPrinter = TRUE;
  168. }
  169. if ((TRUE == fAddThisPrinter) &&
  170. (userSessionID != INVALID_SESSIONID) &&
  171. (printerSessionID != INVALID_SESSIONID)) {
  172. //
  173. // Compare this with our session ID
  174. //
  175. if( printerSessionID != userSessionID ) {
  176. // this printer is from different session,
  177. // don't redirect it.
  178. fAddThisPrinter = FALSE;
  179. }
  180. }
  181. DC_END_FN();
  182. return fAddThisPrinter;
  183. }
  184. LPTSTR
  185. W32DrAutoPrn::GetRDPDefaultPrinter()
  186. /*++
  187. Routine Description:
  188. Get the printer name of the default printer.
  189. This function allocates memory and returns a pointer
  190. to the allocated string, if successful. Otherwise, it returns NULL.
  191. Arguments:
  192. NA
  193. Return Value:
  194. The default printer name. The caller has to free the memory.
  195. --*/
  196. {
  197. TCHAR* szIniEntry = NULL;
  198. LPTSTR pPrinterName = NULL;
  199. DC_BEGIN_FN("DrPRN::GetRDPDefaultPrinter");
  200. szIniEntry = new TCHAR[ MAX_DEF_PRINTER_ENTRY ];
  201. if( NULL == szIniEntry )
  202. {
  203. TRC_ERR((TB, _T("Memory allocation failed:%ld."),
  204. GetLastError()));
  205. goto Cleanup;
  206. }
  207. szIniEntry[0] = _T('\0');
  208. //
  209. // Get the default printer key from the win.ini file.
  210. //
  211. DWORD dwResult = GetProfileString(_T("windows"),
  212. _T("device"),
  213. _T(""),
  214. szIniEntry,
  215. MAX_DEF_PRINTER_ENTRY);
  216. if (dwResult && szIniEntry[0]) {
  217. //
  218. // Get the printer name. The device value is of the form
  219. // <printer name>,<driver name>,<port>
  220. //
  221. TCHAR *pComma = _tcschr( szIniEntry, _T(','));
  222. if( pComma ) {
  223. *pComma = _T('\0');
  224. UINT cchLen = _tcslen( szIniEntry ) + 1;
  225. pPrinterName = new TCHAR [cchLen];
  226. if (pPrinterName) {
  227. StringCchCopy(pPrinterName, cchLen, szIniEntry);
  228. TRC_NRM((TB, _T("Def. is: %s"), pPrinterName));
  229. }
  230. else {
  231. TRC_ERR((TB, _T("Memory allocation failed:%ld."),
  232. GetLastError()));
  233. }
  234. }
  235. else {
  236. TRC_ERR((TB, _T("Invalid device entry in win.ini.")));
  237. }
  238. }
  239. else {
  240. TRC_NRM((TB, _T("Device entry not found in win.ini.")));
  241. }
  242. Cleanup:
  243. DC_END_FN();
  244. delete[] szIniEntry;
  245. return pPrinterName;
  246. }
  247. DWORD
  248. W32DrAutoPrn::GetPrinterInfoAndSessionID(
  249. IN ProcObj *procObj,
  250. IN LPTSTR printerName,
  251. IN DWORD printerAttribs,
  252. IN OUT BYTE **pPrinterInfoBuf,
  253. IN OUT DWORD *pPrinterInfoBufSize,
  254. OUT DWORD *sessionID,
  255. OUT PPRINTERINFO printerInfo
  256. )
  257. /*++
  258. Routine Description:
  259. Get printer info for a printer and its corresponding TS session ID,
  260. if it exists.
  261. Arguments:
  262. procObj - Active Proc Obj
  263. printerName - Name of printer.
  264. printerAttribs - Printer Attribs
  265. pPrinterInfoBuf - This function may resize this buffer.
  266. pPrinterInfoBufsSize - Current size of the pPrinterInfo2 buf.
  267. sessionID - TS session ID, if applicable. Otherwise INVALID_SESSIONID.
  268. printerInfo - Printer information is returned here. We avoid
  269. pulling in level 2 info if possible. Fields in this data
  270. structure should not be free'd.
  271. Return Value:
  272. ERROR_SUCCESS on success. Otherwise, an error status is returned.
  273. --*/
  274. {
  275. HANDLE hPrinter = NULL;
  276. DWORD status = ERROR_SUCCESS;
  277. DWORD bytesRequired;
  278. DWORD type;
  279. DWORD cbNeeded;
  280. DWORD ret;
  281. DC_BEGIN_FN("W32DrAutoPrn::GetPrinterInfoAndSessionID");
  282. //
  283. // No unicode wrappers for GetPrinter on 9x.
  284. //
  285. ASSERT(!procObj->Is9x());
  286. //
  287. // Get a printer handle
  288. //
  289. if (!OpenPrinter(printerName, &hPrinter, NULL)) {
  290. status = GetLastError();
  291. TRC_ALT((TB, L"OpenPrinter: %ld", status));
  292. goto CLEANUPANDEXIT;
  293. }
  294. //
  295. // Check the proc obj shutdown state since we just left an RPC call.
  296. //
  297. if (procObj->IsShuttingDown()) {
  298. status = ERROR_SHUTDOWN_IN_PROGRESS;
  299. TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
  300. goto CLEANUPANDEXIT;
  301. }
  302. //
  303. // If the printer is a network printer then we try to avoid hitting the
  304. // network for additional info. For a non-network printer, we need info level 2
  305. // for info about the port.
  306. //
  307. if (printerAttribs & PRINTER_ATTRIBUTE_NETWORK) {
  308. //
  309. // Just need the driver name.
  310. //
  311. if (!GetPrinterDriver(hPrinter, NULL, 1, *pPrinterInfoBuf,
  312. *pPrinterInfoBufSize, &bytesRequired)) {
  313. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  314. *pPrinterInfoBuf = (PBYTE)new BYTE[bytesRequired];
  315. if (*pPrinterInfoBuf == NULL) {
  316. TRC_ERR((TB, L"Failed to allocate printer driver info"));
  317. *pPrinterInfoBufSize = 0;
  318. status = ERROR_INSUFFICIENT_BUFFER;
  319. goto CLEANUPANDEXIT;
  320. }
  321. else {
  322. *pPrinterInfoBufSize = bytesRequired;
  323. }
  324. }
  325. if (!GetPrinterDriver(hPrinter, NULL, 1, *pPrinterInfoBuf,
  326. *pPrinterInfoBufSize, &bytesRequired)) {
  327. status = GetLastError();
  328. TRC_ERR((TB, _T("GetPrinter: %08X"), status));
  329. goto CLEANUPANDEXIT;
  330. }
  331. }
  332. PDRIVER_INFO_1 p1 = (PDRIVER_INFO_1)*pPrinterInfoBuf;
  333. printerInfo->pPrinterName = printerName;
  334. printerInfo->pPortName = NULL;
  335. printerInfo->pDriverName = p1->pName;
  336. printerInfo->Attributes = printerAttribs;
  337. }
  338. else {
  339. if (!GetPrinter(hPrinter, 2, *pPrinterInfoBuf,
  340. *pPrinterInfoBufSize, &bytesRequired)) {
  341. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  342. *pPrinterInfoBuf = (PBYTE)new BYTE[bytesRequired];
  343. if (*pPrinterInfoBuf == NULL) {
  344. TRC_ERR((TB, L"Failed to allocate printer info 2"));
  345. *pPrinterInfoBufSize = 0;
  346. status = ERROR_INSUFFICIENT_BUFFER;
  347. goto CLEANUPANDEXIT;
  348. }
  349. else {
  350. *pPrinterInfoBufSize = bytesRequired;
  351. }
  352. if (!GetPrinter(hPrinter, 2, *pPrinterInfoBuf,
  353. *pPrinterInfoBufSize, &bytesRequired)) {
  354. status = GetLastError();
  355. TRC_ERR((TB, _T("GetPrinter: %08X"), status));
  356. goto CLEANUPANDEXIT;
  357. }
  358. }
  359. else {
  360. status = GetLastError();
  361. TRC_ERR((TB, _T("GetPrinter: %08X"), status));
  362. goto CLEANUPANDEXIT;
  363. }
  364. }
  365. PPRINTER_INFO_2 p2 = (PPRINTER_INFO_2)*pPrinterInfoBuf;
  366. printerInfo->pPrinterName = p2->pPrinterName;
  367. printerInfo->pPortName = p2->pPortName;
  368. printerInfo->pDriverName = p2->pDriverName;
  369. printerInfo->Attributes = p2->Attributes;
  370. }
  371. //
  372. // Check the proc obj shutdown state since we just left an RPC call.
  373. //
  374. if (procObj->IsShuttingDown()) {
  375. status = ERROR_SHUTDOWN_IN_PROGRESS;
  376. TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
  377. goto CLEANUPANDEXIT;
  378. }
  379. //
  380. // Get the session ID, if it exists.
  381. //
  382. ret = GetPrinterData(
  383. hPrinter,
  384. DEVICERDR_SESSIONID,
  385. &type,
  386. (PBYTE)sessionID,
  387. sizeof(DWORD),
  388. &cbNeeded
  389. );
  390. if (ret != ERROR_SUCCESS || type != REG_DWORD) {
  391. *sessionID = INVALID_SESSIONID;
  392. }
  393. CLEANUPANDEXIT:
  394. if (hPrinter != NULL) {
  395. ::ClosePrinter(hPrinter);
  396. }
  397. DC_END_FN();
  398. return status;
  399. }
  400. DWORD
  401. W32DrAutoPrn::Enumerate(
  402. IN ProcObj *procObj,
  403. IN DrDeviceMgr *deviceMgr
  404. )
  405. {
  406. ULONG ulBufSizeNeeded;
  407. ULONG ulNumStructs;
  408. ULONG i;
  409. LPTSTR szDefaultPrinter = NULL;
  410. PRINTER_INFO_4 *pPrinterInfo4Buf = NULL;
  411. DWORD pPrinterInfo4BufSize = 0;
  412. PBYTE pPrinterInfoBuf = NULL;
  413. DWORD pPrinterInfoBufSize = 0;
  414. W32DrPRN *prnDevice = NULL;
  415. DWORD result = ERROR_SUCCESS;
  416. DWORD queueFilter;
  417. LPTSTR friendlyName = NULL;
  418. LPTSTR pName;
  419. DWORD userSessionID;
  420. DWORD printerSessionID;
  421. BOOL ret;
  422. PRINTERINFO currentPrinter;
  423. HRESULT hr;
  424. DC_BEGIN_FN("W32DrAutoPrn::Enumerate");
  425. if(!procObj->GetVCMgr().GetInitData()->fEnableRedirectPrinters)
  426. {
  427. TRC_DBG((TB,_T("Printer redirection disabled, bailing out")));
  428. return ERROR_SUCCESS;
  429. }
  430. queueFilter = GetPrinterFilterMask(procObj);
  431. //
  432. // Get the size of the printer buffer required to enumerate.
  433. //
  434. if (!procObj->Is9x()) {
  435. //
  436. // Level 2 can hang on NT if a network print server is down.
  437. //
  438. ret = EnumPrinters(
  439. PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
  440. NULL, 4, NULL, 0,
  441. &ulBufSizeNeeded, &ulNumStructs
  442. );
  443. }
  444. else {
  445. //
  446. // Level 4 is not supported on 9x and level 2 doesn't hang anyway.
  447. //
  448. // !!!!Note!!!!
  449. // For 9x the Unicode wrapper function, EnumPrintersWrapW takes over.
  450. // Also, note that level 2 is partially supported.
  451. //
  452. ret = EnumPrinters(
  453. PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
  454. NULL, 2, NULL, 0,
  455. &ulBufSizeNeeded, &ulNumStructs
  456. );
  457. }
  458. if (!ret && (result = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) {
  459. TRC_ERR((TB, _T("EnumPrinter failed: %ld."),
  460. result));
  461. goto Cleanup;
  462. }
  463. //
  464. // Check the proc obj shutdown state since we just left an RPC call.
  465. //
  466. if (procObj->IsShuttingDown()) {
  467. TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
  468. goto Cleanup;
  469. }
  470. //
  471. // Allocate the printer enumeration buffer.
  472. //
  473. if (!procObj->Is9x()) {
  474. pPrinterInfo4Buf = (PRINTER_INFO_4 *)(new BYTE[ulBufSizeNeeded]);
  475. if (pPrinterInfo4Buf == NULL) {
  476. TRC_ERR((TB, _T("Alloc failed.")));
  477. result = ERROR_INSUFFICIENT_BUFFER;
  478. goto Cleanup;
  479. }
  480. else {
  481. pPrinterInfo4BufSize = ulBufSizeNeeded;
  482. }
  483. }
  484. else {
  485. pPrinterInfoBuf = (PBYTE)(new BYTE[ulBufSizeNeeded]);
  486. if (pPrinterInfoBuf == NULL) {
  487. TRC_ERR((TB, _T("Alloc failed.")));
  488. result = ERROR_INSUFFICIENT_BUFFER;
  489. goto Cleanup;
  490. }
  491. else {
  492. pPrinterInfoBufSize = ulBufSizeNeeded;
  493. }
  494. }
  495. //
  496. // Get the printers.
  497. //
  498. if (!procObj->Is9x()) {
  499. ret = EnumPrinters(
  500. PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
  501. NULL,
  502. 4,
  503. (PBYTE)pPrinterInfo4Buf,
  504. pPrinterInfo4BufSize,
  505. &ulBufSizeNeeded,
  506. &ulNumStructs);
  507. }
  508. else {
  509. //
  510. // !!!!Note!!!!
  511. // For 9x the Unicode wrapper function, EnumPrintersWrapW takes over.
  512. // Also, note that level 2 is only partially supported.
  513. //
  514. ret = EnumPrinters(
  515. PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
  516. NULL,
  517. 2,
  518. (PBYTE)pPrinterInfoBuf,
  519. pPrinterInfoBufSize,
  520. &ulBufSizeNeeded,
  521. &ulNumStructs);
  522. }
  523. if (!ret) {
  524. result = GetLastError();
  525. TRC_ALT((TB, _T("EnumPrinter failed, %ld."),
  526. result));
  527. goto Cleanup;
  528. }
  529. //
  530. // Check the proc obj shutdown state since we just left an RPC call.
  531. //
  532. if (procObj->IsShuttingDown()) {
  533. TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
  534. goto Cleanup;
  535. }
  536. //
  537. // Trace the results of EnumPrinters.
  538. //
  539. TRC_NRM((TB, _T("Number of Printers found, %ld."),
  540. ulNumStructs));
  541. //
  542. // Get the name of the current default printer.
  543. //
  544. szDefaultPrinter = GetRDPDefaultPrinter();
  545. //
  546. // Get User Session ID
  547. //
  548. userSessionID = GetUserSessionID();
  549. //
  550. // Iterate through the results of EnumPrinters and add each printer to the
  551. // device manager that passes the printer adding filter.
  552. //
  553. for (i = 0; i < ulNumStructs; i++) {
  554. if (friendlyName != NULL) {
  555. delete friendlyName;
  556. friendlyName = NULL;
  557. }
  558. //
  559. // Get info for the printer and its corresponding TS session ID,
  560. // if it exists.
  561. //
  562. if (!procObj->Is9x()) {
  563. if (GetPrinterInfoAndSessionID(
  564. procObj,
  565. pPrinterInfo4Buf[i].pPrinterName,
  566. pPrinterInfo4Buf[i].Attributes,
  567. &pPrinterInfoBuf,
  568. &pPrinterInfoBufSize,
  569. &printerSessionID,
  570. &currentPrinter
  571. ) != ERROR_SUCCESS) {
  572. continue;
  573. }
  574. }
  575. else {
  576. PPRINTER_INFO_2 p2;
  577. p2 = (PPRINTER_INFO_2)pPrinterInfoBuf;
  578. if (p2 != NULL) {
  579. currentPrinter.pPrinterName = p2[i].pPrinterName;
  580. currentPrinter.pPortName = p2[i].pPortName;
  581. currentPrinter.pDriverName = p2[i].pDriverName;
  582. currentPrinter.Attributes = p2[i].Attributes;
  583. }
  584. printerSessionID = INVALID_SESSIONID;
  585. }
  586. //
  587. // Check the proc obj shutdown state since we just left an RPC call.
  588. //
  589. if (procObj->IsShuttingDown()) {
  590. TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
  591. goto Cleanup;
  592. }
  593. if( FALSE == ShouldAddThisPrinter( queueFilter, userSessionID, &currentPrinter,
  594. printerSessionID) ) {
  595. continue;
  596. }
  597. TCHAR UniquePortName[MAX_PATH];
  598. ULONG DeviceId;
  599. //
  600. // Is this one the default queue.
  601. //
  602. BOOL fDefault = ((szDefaultPrinter) && (currentPrinter.pPrinterName) &&
  603. (_tcsicmp(szDefaultPrinter, currentPrinter.pPrinterName) == 0));
  604. //
  605. // Generate a "friendly" name if this is a network
  606. // queue.
  607. //
  608. BOOL fNetwork = FALSE, fTSqueue = FALSE;
  609. RDPDR_VERSION serverVer;
  610. serverVer = procObj->serverVersion();
  611. // 4 is minor version of post win2000
  612. if (COMPARE_VERSION(serverVer.Minor, serverVer.Major, 4, 1) < 0) {
  613. // the server is Win2000 or lower
  614. if (currentPrinter.Attributes & PRINTER_ATTRIBUTE_NETWORK) {
  615. friendlyName = CreateFriendlyNameFromNetworkName(
  616. currentPrinter.pPrinterName,
  617. TRUE
  618. );
  619. // We don't set the fNetwork flag for Win2K because it can't
  620. // do anything with it anyway.
  621. }
  622. } else {
  623. // the server is higher than Win2000
  624. // is it a network printer?
  625. if (currentPrinter.Attributes & PRINTER_ATTRIBUTE_NETWORK) {
  626. fNetwork = TRUE;
  627. }
  628. // is it a TS queue?
  629. if ((currentPrinter.pPortName != NULL) &&
  630. _tcsnicmp(currentPrinter.pPortName,
  631. RDP_PORT_NAME,
  632. RDP_PORT_NAMELEN) == 0) {
  633. fTSqueue = TRUE;
  634. friendlyName = CreateNestedName(currentPrinter.pPrinterName, &fNetwork);
  635. // should we set fNetwork and fTSqueue only in case of success?
  636. } else if (fNetwork) {
  637. friendlyName = CreateFriendlyNameFromNetworkName(
  638. currentPrinter.pPrinterName, FALSE
  639. );
  640. }
  641. }
  642. //
  643. // Create a new printer device object.
  644. //
  645. pName = (friendlyName != NULL) ? friendlyName : currentPrinter.pPrinterName;
  646. DeviceId = deviceMgr->GetUniqueObjectID();
  647. //
  648. // The unique port name is going to be passed to the server
  649. // as preferred dos name (max 7 characters long). As we want to
  650. // keep a unique dos name for each printer device, we need
  651. // to fake our own port name. e.g.
  652. // For network printer, they share same port name if it's
  653. // same printer with different network printer names.
  654. // We use the format of PRN# as our unique port name
  655. hr = StringCchPrintf(UniquePortName,
  656. SIZE_TCHARS(UniquePortName),
  657. TEXT("PRN%ld"), DeviceId);
  658. if (FAILED(hr)) {
  659. TRC_ERR((TB,_T("Error copying portname :0x%x"),hr));
  660. result = ERROR_INSUFFICIENT_BUFFER;
  661. goto Cleanup;
  662. }
  663. UniquePortName[7] = TEXT('\0');
  664. prnDevice = new W32DrAutoPrn(
  665. procObj,
  666. pName,
  667. currentPrinter.pDriverName,
  668. UniquePortName,
  669. fDefault,
  670. DeviceId,
  671. currentPrinter.pPrinterName
  672. );
  673. //
  674. // Add to the device manager if we got a valid object.
  675. //
  676. if (prnDevice != NULL) {
  677. prnDevice->SetNetwork(fNetwork);
  678. prnDevice->SetTSqueue(fTSqueue);
  679. prnDevice->Initialize();
  680. if (!(prnDevice->IsValid() &&
  681. (deviceMgr->AddObject(prnDevice) == STATUS_SUCCESS))) {
  682. delete prnDevice;
  683. }
  684. }
  685. else {
  686. TRC_ERR((TB, _T("Failed to allocate W32DrPRN.")));
  687. result = ERROR_INSUFFICIENT_BUFFER;
  688. goto Cleanup;
  689. }
  690. }
  691. Cleanup:
  692. //
  693. // Release the "friendly" printer name.
  694. //
  695. if (friendlyName != NULL) {
  696. delete friendlyName;
  697. }
  698. //
  699. // Release the default printer buffer.
  700. //
  701. if (szDefaultPrinter) {
  702. delete[] szDefaultPrinter;
  703. }
  704. //
  705. // Release the level 4 printer enumeration buffer.
  706. //
  707. if (pPrinterInfo4Buf != NULL) {
  708. delete pPrinterInfo4Buf;
  709. }
  710. //
  711. // Release the printer enumeration buffer.
  712. //
  713. if (pPrinterInfoBuf != NULL) {
  714. delete pPrinterInfoBuf;
  715. }
  716. DC_END_FN();
  717. return result;
  718. }
  719. LPTSTR
  720. W32DrAutoPrn::CreateNestedName(LPTSTR printerName, BOOL* pfNetwork)
  721. /*++
  722. Routine Description:
  723. Create a printer name from the names stored in the registry.
  724. Arguments:
  725. printerName - Name returned by EnumPrinters
  726. Return Value:
  727. Nested name on success, that should be released by a call to
  728. delete. NULL is returned on error.
  729. --*/
  730. {
  731. DWORD printerNameLen;
  732. LPTSTR name = NULL;
  733. HANDLE hPrinter = NULL;
  734. DWORD i, cbNeeded, dwError;
  735. BOOL fFail = TRUE;
  736. DC_BEGIN_FN("W32DrAutoPrn::CreateNestedName");
  737. if (OpenPrinter(printerName, &hPrinter, NULL)) {
  738. // In all cases the name will begin with "__"
  739. printerNameLen = 2;
  740. // try the Server name
  741. // WARNING: it returns ERROR_SUCCESS under Win9X if nSize = 0
  742. dwError = GetPrinterData(hPrinter, DEVICERDR_PRINT_SERVER_NAME, NULL, NULL, 0, &cbNeeded);
  743. if( (dwError == ERROR_MORE_DATA) || (dwError == ERROR_SUCCESS)) {
  744. printerNameLen += cbNeeded / sizeof(TCHAR);
  745. *pfNetwork = TRUE;
  746. } else {
  747. *pfNetwork = FALSE;
  748. }
  749. // try the Client name
  750. dwError = GetPrinterData(hPrinter, DEVICERDR_CLIENT_NAME, NULL, NULL, 0, &cbNeeded);
  751. if( (dwError == ERROR_MORE_DATA) || (dwError == ERROR_SUCCESS)) {
  752. printerNameLen += cbNeeded / sizeof(TCHAR);
  753. if (*pfNetwork) {
  754. // if there's already a print server name, add a '\'
  755. printerNameLen += 1;
  756. }
  757. } else if(!*pfNetwork) {
  758. // no print server, no client name, things are going bad...
  759. DC_QUIT;
  760. }
  761. // try the Printer name
  762. dwError = GetPrinterData(hPrinter, DEVICERDR_PRINTER_NAME, NULL, NULL, 0, &cbNeeded);
  763. if( (dwError == ERROR_MORE_DATA) || (dwError == ERROR_SUCCESS)) {
  764. // add also a '\'
  765. printerNameLen += 1 + cbNeeded / sizeof(TCHAR);
  766. } else {
  767. // no printer name
  768. DC_QUIT;
  769. }
  770. //
  771. // Allocate space for the nested name.
  772. //
  773. name = new TCHAR[printerNameLen + 1];
  774. if (name == NULL) {
  775. TRC_ERR((TB, _T("Can't allocate %ld bytes for printer name."), printerNameLen));
  776. } else {
  777. name[0] = _T('!');
  778. name[1] = _T('!');
  779. i = 2;
  780. // try the Server name
  781. if (*pfNetwork) {
  782. if (ERROR_SUCCESS == GetPrinterData(hPrinter,
  783. DEVICERDR_PRINT_SERVER_NAME,
  784. NULL,
  785. (LPBYTE)(name + i),
  786. (printerNameLen - i) * sizeof(TCHAR),
  787. &cbNeeded)) {
  788. i = _tcslen(name);
  789. name[i++] = _T('!');
  790. } else {
  791. // weird...
  792. DC_QUIT;
  793. }
  794. }
  795. // try the Client name
  796. if (ERROR_SUCCESS == GetPrinterData(hPrinter,
  797. DEVICERDR_CLIENT_NAME,
  798. NULL,
  799. (LPBYTE)(name + i),
  800. (printerNameLen - i) * sizeof(TCHAR),
  801. &cbNeeded)) {
  802. i = _tcslen(name);
  803. name[i++] = _T('!');
  804. } else {
  805. if(!*pfNetwork) {
  806. // no print server, no client name, things are going bad...
  807. DC_QUIT;
  808. }
  809. }
  810. // try the Printer name
  811. if (ERROR_SUCCESS == GetPrinterData(hPrinter,
  812. DEVICERDR_PRINTER_NAME,
  813. NULL,
  814. (LPBYTE)(name + i),
  815. (printerNameLen - i) * sizeof(TCHAR),
  816. &cbNeeded)) {
  817. fFail = FALSE;
  818. } else {
  819. DC_QUIT;
  820. }
  821. }
  822. }
  823. DC_EXIT_POINT:
  824. if (hPrinter) {
  825. ::ClosePrinter(hPrinter);
  826. }
  827. if (fFail && name) {
  828. delete[] name;
  829. name = NULL;
  830. }
  831. DC_END_FN();
  832. return name;
  833. }
  834. LPTSTR
  835. W32DrAutoPrn::CreateFriendlyNameFromNetworkName(LPTSTR printerName,
  836. BOOL serverIsWin2K)
  837. /*++
  838. Routine Description:
  839. Create a "friendly" printer name from the printer name of a
  840. network printer.
  841. Arguments:
  842. printerName - Name returned by EnumPrinters
  843. serverIsWin2K - For Win2K servers, we format the name as it will appear
  844. on the server. Whistler servers and beyond do the
  845. formatting for us.
  846. Return Value:
  847. Friendly name on success, that should be released by a call to
  848. delete. NULL is returned on error.
  849. --*/
  850. {
  851. DWORD printerNameLen;
  852. LPTSTR name;
  853. DWORD i;
  854. WCHAR replaceChar;
  855. DC_BEGIN_FN("W32DrAutoPrn::CreateFriendlyNameFromNetworkName");
  856. //
  857. // The \ placeholder is '_' for Win2K because Win2K doesn't reformat
  858. // printer names. The '_' will actually be visible.
  859. //
  860. replaceChar = serverIsWin2K ? TEXT('_') : TEXT('!');
  861. //
  862. // Get the length of the printer name.
  863. //
  864. printerNameLen = _tcslen(printerName);
  865. //
  866. // Allocate space for ther "friendly" name.
  867. //
  868. name = new TCHAR[printerNameLen + 1];
  869. if (name == NULL) {
  870. TRC_ERR((TB, _T("Can't allocate %ld bytes for printer name."),
  871. printerNameLen));
  872. }
  873. //
  874. // Copy and convert the name.
  875. //
  876. if (name != NULL) {
  877. for (i=0; i<printerNameLen; i++) {
  878. if (printerName[i] != TEXT('\\')) {
  879. name[i] = printerName[i];
  880. }
  881. else {
  882. name[i] = replaceChar;
  883. }
  884. }
  885. name[i] = TEXT('\0');
  886. }
  887. DC_END_FN();
  888. return name;
  889. }
  890. LPTSTR
  891. W32DrAutoPrn::GetLocalPrintingDocName()
  892. /*++
  893. Routine Description:
  894. Read Local printer Doc Name from the passed in struct
  895. Arguments:
  896. NA
  897. Return Value:
  898. Local Printer Document Name
  899. --*/
  900. {
  901. DC_BEGIN_FN("W32DrAutoPrn::GetLocalPrintingDocName");
  902. DC_END_FN();
  903. return _szLocalPrintingDocName;
  904. }
  905. VOID W32DrAutoPrn::MsgIrpCreate(
  906. IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
  907. IN UINT32 packetLen
  908. )
  909. /*++
  910. Routine Description:
  911. Handle a Create IRP from the server.
  912. Arguments:
  913. params - Context for the IO request.
  914. Return Value:
  915. NA
  916. --*/
  917. {
  918. W32DRDEV_ASYNCIO_PARAMS *params = NULL;
  919. DWORD result = ERROR_SUCCESS;
  920. DC_BEGIN_FN("W32DrAutoPrn::MsgIrpCreate");
  921. params = new W32DRDEV_ASYNCIO_PARAMS(this, pIoRequestPacket);
  922. if (params != NULL) {
  923. params->thrPoolReq = _threadPool->SubmitRequest(
  924. _AsyncMsgIrpCreateFunc,
  925. params, NULL
  926. );
  927. if (params->thrPoolReq == NULL) {
  928. result = ERROR_NOT_ENOUGH_MEMORY;
  929. goto CLEANUPANDEXIT;
  930. }
  931. }
  932. else {
  933. TRC_ERR((TB, L"Can't allocate parms."));
  934. result = ERROR_NOT_ENOUGH_MEMORY;
  935. goto CLEANUPANDEXIT;
  936. }
  937. CLEANUPANDEXIT:
  938. if (result != ERROR_SUCCESS) {
  939. //
  940. // Return the failed result back to the server and clean up.
  941. //
  942. DefaultIORequestMsgHandle(pIoRequestPacket, result);
  943. if (params != NULL) {
  944. params->pIoRequestPacket = NULL;
  945. delete params;
  946. }
  947. }
  948. DC_END_FN();
  949. }
  950. DWORD
  951. W32DrAutoPrn::AsyncMsgIrpCreateFunc(
  952. IN W32DRDEV_ASYNCIO_PARAMS *params
  953. )
  954. /*++
  955. Routine Description:
  956. Handle a "Close" IO request from the server, in a background thread.
  957. Arguments:
  958. params - Context for the IO request.
  959. Return Value:
  960. NA
  961. --*/
  962. {
  963. PRDPDR_DEVICE_IOREQUEST pIoRequest;
  964. ULONG ulRetCode;
  965. DWORD result;
  966. DOC_INFO_1 sDocInfo1;
  967. DC_BEGIN_FN("W32DrAutoPrn::AsyncMsgIrpCreateFunc");
  968. //
  969. // This version does not work without a printer name.
  970. //
  971. ASSERT(_tcslen(GetPrinterName()));
  972. //
  973. // Get IO request pointer.
  974. //
  975. pIoRequest = &params->pIoRequestPacket->IoRequest;
  976. //
  977. // Finish/Cancel any Current Jobs and Close, if Open.
  978. //
  979. ClosePrinter();
  980. //
  981. // Open the printer.
  982. //
  983. if (!W32DrOpenPrinter(_devicePath, &_printerHandle)) {
  984. ulRetCode = GetLastError();
  985. TRC_ERR((TB, _T("OpenPrinter %ld."), ulRetCode));
  986. goto Cleanup;
  987. }
  988. //
  989. // Start Doc.
  990. //
  991. sDocInfo1.pDocName = GetLocalPrintingDocName();
  992. sDocInfo1.pOutputFile = NULL;
  993. sDocInfo1.pDatatype = _T("RAW");
  994. _jobID = StartDocPrinter(_printerHandle, 1, (PBYTE)&sDocInfo1);
  995. if (_jobID == 0) {
  996. ulRetCode = GetLastError();
  997. TRC_ERR((TB, _T("StartDocPrinter %ld."), ulRetCode));
  998. ClosePrinter();
  999. goto Cleanup;
  1000. }
  1001. //
  1002. // Attempt to disable annoying printer pop up if we have sufficient
  1003. // privilege. Not a big deal, if we fail.
  1004. //
  1005. DisablePrinterPopup(_printerHandle, _jobID);
  1006. //
  1007. // Start the first page.
  1008. //
  1009. if (!StartPagePrinter(_printerHandle)) {
  1010. ulRetCode = GetLastError();
  1011. TRC_ERR((TB, _T("StartPagePrinter %ld."), ulRetCode));
  1012. ClosePrinter();
  1013. goto Cleanup;
  1014. }
  1015. //
  1016. // We are done successfully, say so.
  1017. //
  1018. ulRetCode = ERROR_SUCCESS;
  1019. Cleanup:
  1020. //
  1021. // Send the result to the server.
  1022. //
  1023. result = (ulRetCode == ERROR_SUCCESS) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  1024. DefaultIORequestMsgHandle(params->pIoRequestPacket, result);
  1025. //
  1026. // Clean up the IO request parameters. DefaultIORequestMsgHandle cleans up
  1027. // the request packet.
  1028. //
  1029. if (params->thrPoolReq != INVALID_THREADPOOLREQUEST) {
  1030. _threadPool->CloseRequest(params->thrPoolReq);
  1031. params->thrPoolReq = INVALID_THREADPOOLREQUEST;
  1032. }
  1033. params->pIoRequestPacket = NULL;
  1034. delete params;
  1035. DC_END_FN();
  1036. return result;
  1037. }
  1038. VOID
  1039. W32DrAutoPrn::ClosePrinter()
  1040. /*++
  1041. Routine Description:
  1042. End any jobs in progress and close the printer.
  1043. Arguments:
  1044. NA
  1045. Return Value:
  1046. NA
  1047. --*/
  1048. {
  1049. DC_BEGIN_FN("W32DrAutoPrn::ClosePrinter");
  1050. if (_printerHandle != INVALID_HANDLE_VALUE) {
  1051. //
  1052. // Finish the current page for the current print job.
  1053. //
  1054. if (!EndPagePrinter(_printerHandle)) {
  1055. TRC_ERR((TB, _T("EndPagePrinter %ld."), GetLastError()));
  1056. }
  1057. //
  1058. // End the current print job.
  1059. //
  1060. if (!EndDocPrinter(_printerHandle)) {
  1061. TRC_ERR((TB, _T("EndDocPrinter %ld."), GetLastError()));
  1062. }
  1063. //
  1064. // Close the printer.
  1065. //
  1066. if (!::ClosePrinter(_printerHandle)) {
  1067. TRC_ERR((TB, _T("ClosePrinter %ld."), GetLastError()));
  1068. }
  1069. //
  1070. // Negate the handle and the pending job ID.
  1071. //
  1072. _printerHandle = INVALID_HANDLE_VALUE;
  1073. _jobID = 0;
  1074. }
  1075. DC_END_FN();
  1076. }
  1077. VOID
  1078. W32DrAutoPrn::MsgIrpClose(
  1079. IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
  1080. IN UINT32 packetLen
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. Handle a "Close" IO request from the server by dispatching
  1085. the request to the thread pool. TODO: move this async
  1086. dispatch to the parent class in a future release. All closes
  1087. should be handled outside the main thread.-TadB
  1088. Arguments:
  1089. pIoRequestPacket - Server IO request packet.
  1090. Return Value:
  1091. NA
  1092. --*/
  1093. {
  1094. W32DRDEV_ASYNCIO_PARAMS *params = NULL;
  1095. DWORD result = ERROR_SUCCESS;
  1096. DC_BEGIN_FN("W32DrAutoPrn::MsgIrpClose");
  1097. params = new W32DRDEV_ASYNCIO_PARAMS(this, pIoRequestPacket);
  1098. if (params != NULL) {
  1099. params->thrPoolReq = _threadPool->SubmitRequest(
  1100. _AsyncMsgIrpCloseFunc,
  1101. params, NULL
  1102. );
  1103. if (params->thrPoolReq == NULL) {
  1104. result = ERROR_NOT_ENOUGH_MEMORY;
  1105. goto CLEANUPANDEXIT;
  1106. }
  1107. }
  1108. else {
  1109. TRC_ERR((TB, L"Can't allocate parms."));
  1110. result = ERROR_NOT_ENOUGH_MEMORY;
  1111. goto CLEANUPANDEXIT;
  1112. }
  1113. CLEANUPANDEXIT:
  1114. if (result != ERROR_SUCCESS) {
  1115. //
  1116. // Return the failed result back to the server and clean up.
  1117. //
  1118. DefaultIORequestMsgHandle(pIoRequestPacket, result);
  1119. if (params != NULL) {
  1120. params->pIoRequestPacket = NULL;
  1121. delete params;
  1122. }
  1123. }
  1124. DC_END_FN();
  1125. }
  1126. DWORD
  1127. W32DrAutoPrn::AsyncMsgIrpCloseFunc(
  1128. IN W32DRDEV_ASYNCIO_PARAMS *params
  1129. )
  1130. /*++
  1131. Routine Description:
  1132. Handle a "Close" IO request from the server, in a background thread.
  1133. Arguments:
  1134. params - Context for the IO request.
  1135. Return Value:
  1136. NA
  1137. --*/
  1138. {
  1139. PRDPDR_DEVICE_IOREQUEST pIoRequest;
  1140. DWORD returnValue = STATUS_SUCCESS;
  1141. DC_BEGIN_FN("W32DrAutoPrn::MsgIrpClose");
  1142. //
  1143. // Close the printer.
  1144. //
  1145. ClosePrinter();
  1146. //
  1147. // Send the result to the server.
  1148. //
  1149. DefaultIORequestMsgHandle(params->pIoRequestPacket, returnValue);
  1150. //
  1151. // Clean up the IO request parameters. DefaultIORequestMsgHandle cleans up
  1152. // the request packet.
  1153. //
  1154. if (params->thrPoolReq != INVALID_THREADPOOLREQUEST) {
  1155. _threadPool->CloseRequest(params->thrPoolReq);
  1156. params->thrPoolReq = INVALID_THREADPOOLREQUEST;
  1157. }
  1158. params->pIoRequestPacket = NULL;
  1159. delete params;
  1160. DC_END_FN();
  1161. return returnValue;
  1162. }
  1163. DWORD
  1164. W32DrAutoPrn::GetPrinterFilterMask(
  1165. IN ProcObj *procObj
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. Returns the configurable print redirection filter mask.
  1170. Arguments:
  1171. procObj - The relevant process object.
  1172. Return Value:
  1173. Configurable Filter Mask
  1174. --*/
  1175. {
  1176. DWORD filter;
  1177. //
  1178. // Read FilterQueueType parameters so we know which devices
  1179. // to redirect.
  1180. //
  1181. if (procObj->GetDWordParameter(
  1182. REG_RDPDR_FILTER_QUEUE_TYPE,
  1183. &filter) != ERROR_SUCCESS) {
  1184. //
  1185. // Default.
  1186. //
  1187. filter = FILTER_ALL_QUEUES;
  1188. }
  1189. return filter;
  1190. }
  1191. BOOL
  1192. W32DrAutoPrn::W32DrOpenPrinter(
  1193. IN LPTSTR pPrinterName,
  1194. IN LPHANDLE phPrinter
  1195. )
  1196. /*++
  1197. Routine Description:
  1198. Open a printer with highest access possible.
  1199. Arguments:
  1200. pPrinterName - Pointer to printer or server name.
  1201. phPrinter - Pointer to printer or server handle.
  1202. Return Value:
  1203. TRUE on success. FALSE, otherwise.
  1204. --*/
  1205. {
  1206. PRINTER_DEFAULTS sPrinter;
  1207. BOOL result;
  1208. DC_BEGIN_FN("W32DrAutoPrn::W32DrOpenPrinter");
  1209. //
  1210. // Open printer.
  1211. //
  1212. sPrinter.pDatatype = NULL;
  1213. sPrinter.pDevMode = NULL;
  1214. sPrinter.DesiredAccess = PRINTER_ACCESS_USE;
  1215. result = OpenPrinter(pPrinterName, phPrinter, &sPrinter);
  1216. if (!result) {
  1217. TRC_ALT((TB, _T("Full-Access OpenPrinter %ld."), GetLastError()));
  1218. //
  1219. // Try with default access.
  1220. //
  1221. result = OpenPrinter(pPrinterName, phPrinter, NULL);
  1222. if (!result) {
  1223. TRC_ERR((TB, _T("OpenPrinter %ld."), GetLastError()));
  1224. }
  1225. }
  1226. DC_END_FN();
  1227. return result;
  1228. }
  1229. VOID
  1230. W32DrAutoPrn::DisablePrinterPopup(
  1231. HANDLE hPrinterHandle,
  1232. ULONG ulJobID
  1233. )
  1234. /*++
  1235. Routine Description:
  1236. Disable annoying printer pop up for the specified printer
  1237. and print job.
  1238. Arguments:
  1239. hPrinterHandle - handle to a printer device.
  1240. ulJobID - ID of the job.
  1241. Return Value:
  1242. NA
  1243. --*/
  1244. {
  1245. JOB_INFO_2* pJobInfo2 = NULL;
  1246. ULONG ulJobBufSize;
  1247. DC_BEGIN_FN("W32DrAutoPrn::DisablePrinterPopup");
  1248. ulJobBufSize = 2 * 1024;
  1249. pJobInfo2 = (JOB_INFO_2 *)new BYTE[ulJobBufSize];
  1250. //
  1251. // Note we call the ANSI version of the API
  1252. // because we don't have a UNICODE wrapper for Get/SetJob.
  1253. // Main reason is we don't actually use any returned string
  1254. // data directly.
  1255. //
  1256. if(!_bRunningOn9x)
  1257. {
  1258. //Call unicode API's
  1259. if( pJobInfo2 != NULL ) {
  1260. //
  1261. // Get job info.
  1262. //
  1263. if( GetJob(
  1264. hPrinterHandle,
  1265. ulJobID,
  1266. 2,
  1267. (PBYTE)pJobInfo2,
  1268. ulJobBufSize,
  1269. &ulJobBufSize )) {
  1270. //
  1271. // Disable popup notification by setting pNotifyName
  1272. // NULL.
  1273. //
  1274. pJobInfo2->pNotifyName = NULL;
  1275. pJobInfo2->Position = JOB_POSITION_UNSPECIFIED;
  1276. if( !SetJob(
  1277. hPrinterHandle,
  1278. ulJobID,
  1279. 2,
  1280. (PBYTE)pJobInfo2,
  1281. 0 )) {
  1282. TRC_ERR((TB, _T("SetJob %ld."), GetLastError()));
  1283. }
  1284. }
  1285. else {
  1286. TRC_ERR((TB, _T("GetJob %ld."), GetLastError()));
  1287. }
  1288. delete (PBYTE)pJobInfo2;
  1289. }
  1290. else {
  1291. TRC_ERR((TB, _T("Memory Allocation failed.")));
  1292. }
  1293. }
  1294. else
  1295. {
  1296. //Call ANSI API's
  1297. if( pJobInfo2 != NULL ) {
  1298. //
  1299. // Get job info.
  1300. //
  1301. if( GetJobA(
  1302. hPrinterHandle,
  1303. ulJobID,
  1304. 2,
  1305. (PBYTE)pJobInfo2,
  1306. ulJobBufSize,
  1307. &ulJobBufSize )) {
  1308. //
  1309. // Disable popup notification by setting pNotifyName
  1310. // NULL.
  1311. //
  1312. pJobInfo2->pNotifyName = NULL;
  1313. if( !SetJobA(
  1314. hPrinterHandle,
  1315. ulJobID,
  1316. 2,
  1317. (PBYTE)pJobInfo2,
  1318. 0 )) {
  1319. TRC_ERR((TB, _T("SetJob %ld."), GetLastError()));
  1320. }
  1321. }
  1322. else {
  1323. TRC_ERR((TB, _T("GetJob %ld."), GetLastError()));
  1324. }
  1325. delete (PBYTE)pJobInfo2;
  1326. }
  1327. else {
  1328. TRC_ERR((TB, _T("Memory Allocation failed.")));
  1329. }
  1330. }
  1331. DC_END_FN();
  1332. }
  1333. DWORD
  1334. W32DrAutoPrn::AsyncWriteIOFunc(
  1335. IN W32DRDEV_ASYNCIO_PARAMS *params
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. Asynchronous Write Operation
  1340. Arguments:
  1341. params - Context for the IO request.
  1342. Return Value:
  1343. Returns 0 on success. Otherwise, a Windows error code is returned.
  1344. --*/
  1345. {
  1346. PBYTE pDataBuffer;
  1347. PRDPDR_IOCOMPLETION_PACKET pReplyPacket;
  1348. PRDPDR_DEVICE_IOREQUEST pIoRequest;
  1349. ULONG ulReplyPacketSize = 0;
  1350. DWORD status;
  1351. DC_BEGIN_FN("W32DrAutoPrn::AsyncWriteIOFunc");
  1352. // Assert the integrity of the IO context
  1353. ASSERT(params->magicNo == GOODMEMMAGICNUMBER);
  1354. //
  1355. // Get the IO request and reply..
  1356. //
  1357. pIoRequest = &params->pIoRequestPacket->IoRequest;
  1358. pReplyPacket = params->pIoReplyPacket;
  1359. //
  1360. // Get the data buffer pointer.
  1361. //
  1362. pDataBuffer = (PBYTE)(pIoRequest + 1);
  1363. //
  1364. // Write the data to the print queue with the help of the spooler.
  1365. //
  1366. if (!WritePrinter(
  1367. _printerHandle,
  1368. pDataBuffer,
  1369. pIoRequest->Parameters.Write.Length,
  1370. &(pReplyPacket->IoCompletion.Parameters.Write.Length)) ) {
  1371. status = GetLastError();
  1372. TRC_ERR((TB, _T("WritePrinter %ld."), status));
  1373. }
  1374. else {
  1375. TRC_NRM((TB, _T("WritePrinter completed.")));
  1376. status = ERROR_SUCCESS;
  1377. }
  1378. DC_END_FN();
  1379. return status;
  1380. }