Source code of Windows XP (NT5)
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.

11304 lines
308 KiB

  1. /*++
  2. Copyright (c) 1990-1996 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. Winspool.c
  6. Abstract:
  7. Bulk of winspool.drv code
  8. Author:
  9. Environment:
  10. User Mode -Win32
  11. Revision History:
  12. mattfe april 14 94 added caching to writeprinter
  13. mattfe jan 95 Add SetAllocFailCount api
  14. 13-Jun-1996 Thu 15:07:16 updated -by- Daniel Chou (danielc)
  15. Make PrinterProperties call PrinterPropertySheets and
  16. DocumentProperties call DocumentPropertySheets
  17. SWilson Dec 1996 - added GetPrinterDataEx, SetPrinterDataEx, EnumPrinterDataEx,
  18. EnumPrinterKey, DeletePrinterDataEx, and DeletePrinterKey
  19. khaleds Feb 2000 - Added DocumentPropertiesThunk,
  20. AddPortWThunk,
  21. CongigurePortWThunk,
  22. DeleteProtWThunk,
  23. DeviceCapabilitesWThunk,
  24. PrinterPropertiesWThunk,
  25. DocmentEvenThunk,
  26. SpoolerPrinterEventThunk
  27. Renamed the above native functions from xx to xxNative
  28. Khaleds Mar 2000 - Added SendRecvBidiData
  29. Khaleds Mar 2001 - Fix for WritePrinter
  30. LazarI - Oct-30-2000 added GetCurrentThreadLastPopup & fixed StartDocDlgW
  31. --*/
  32. #include "precomp.h"
  33. #pragma hdrstop
  34. #include "client.h"
  35. #include "winsprlp.h"
  36. #include "pfdlg.h"
  37. #include "splwow64.h"
  38. #include "drvsetup.h"
  39. MODULE_DEBUG_INIT( DBG_ERROR, DBG_ERROR );
  40. HANDLE hInst = NULL;
  41. CRITICAL_SECTION ProcessHndlCS;
  42. HANDLE hSurrogateProcess;
  43. WndHndlList* GWndHndlList=NULL;
  44. LPWSTR szEnvironment = LOCAL_ENVIRONMENT;
  45. LPWSTR szIA64Environment = L"Windows IA64";
  46. HANDLE hShell32 = INVALID_HANDLE_VALUE;
  47. // pointer to the start of the list containing the driver file handles
  48. PDRVLIBNODE pStartDrvLib = NULL;
  49. CRITICAL_SECTION ListAccessSem;
  50. DWORD gcClientICHandle = 0;
  51. #define DM_MATCH( dm, sp ) ((((sp)+50)/100-dm)<15&&(((sp)+50)/100-dm)>-15)
  52. #define DM_PAPER_WL (DM_PAPERWIDTH | DM_PAPERLENGTH)
  53. #define JOB_CANCEL_CHECK_INTERVAL 2000 // 2 seconds
  54. #define MAX_RETRY_INVALID_HANDLE 2 // 2 retries
  55. LONG
  56. CallCommonPropertySheetUI(
  57. HWND hWndOwner,
  58. PFNPROPSHEETUI pfnPropSheetUI,
  59. LPARAM lParam,
  60. LPDWORD pResult
  61. )
  62. /*++
  63. Routine Description:
  64. This function dymically load the compstui.dll and call its entry
  65. Arguments:
  66. pfnPropSheetUI - Pointer to callback function
  67. lParam - lParam for the pfnPropSheetUI
  68. pResult - pResult for the CommonPropertySheetUI
  69. Return Value:
  70. LONG - as describe in compstui.h
  71. Author:
  72. 01-Nov-1995 Wed 13:11:19 created -by- Daniel Chou (danielc)
  73. Revision History:
  74. --*/
  75. {
  76. HINSTANCE hInstCPSUI;
  77. FARPROC pProc;
  78. LONG Result = ERR_CPSUI_GETLASTERROR;
  79. //
  80. // ONLY need to call the ANSI version of LoadLibrary
  81. //
  82. if ((hInstCPSUI = LoadLibraryA(szCompstuiDll)) &&
  83. (pProc = GetProcAddress(hInstCPSUI, szCommonPropertySheetUIW))) {
  84. RpcTryExcept {
  85. Result = (LONG)((*pProc)(hWndOwner, pfnPropSheetUI, lParam, pResult));
  86. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  87. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  88. Result = ERR_CPSUI_GETLASTERROR;
  89. } RpcEndExcept
  90. }
  91. if (hInstCPSUI) {
  92. FreeLibrary(hInstCPSUI);
  93. }
  94. return(Result);
  95. }
  96. // Simple for Now !!!
  97. DWORD
  98. TranslateExceptionCode(
  99. DWORD ExceptionCode
  100. )
  101. {
  102. switch (ExceptionCode) {
  103. case EXCEPTION_ACCESS_VIOLATION:
  104. case EXCEPTION_DATATYPE_MISALIGNMENT:
  105. case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  106. case EXCEPTION_FLT_DENORMAL_OPERAND:
  107. case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  108. case EXCEPTION_FLT_INEXACT_RESULT:
  109. case EXCEPTION_FLT_INVALID_OPERATION:
  110. case EXCEPTION_FLT_OVERFLOW:
  111. case EXCEPTION_FLT_STACK_CHECK:
  112. case EXCEPTION_FLT_UNDERFLOW:
  113. case EXCEPTION_INT_DIVIDE_BY_ZERO:
  114. case EXCEPTION_INT_OVERFLOW:
  115. case EXCEPTION_PRIV_INSTRUCTION:
  116. case ERROR_NOACCESS:
  117. case RPC_S_INVALID_BOUND:
  118. return ERROR_INVALID_PARAMETER;
  119. break;
  120. default:
  121. return ExceptionCode;
  122. }
  123. }
  124. BOOL
  125. EnumPrintersW(
  126. DWORD Flags,
  127. LPWSTR Name,
  128. DWORD Level,
  129. LPBYTE pPrinterEnum,
  130. DWORD cbBuf,
  131. LPDWORD pcbNeeded,
  132. LPDWORD pcReturned
  133. )
  134. {
  135. BOOL ReturnValue;
  136. DWORD cbStruct;
  137. FieldInfo *pFieldInfo;
  138. switch (Level) {
  139. case STRESSINFOLEVEL:
  140. pFieldInfo = PrinterInfoStressFields;
  141. cbStruct = sizeof(PRINTER_INFO_STRESS);
  142. break;
  143. case 1:
  144. pFieldInfo = PrinterInfo1Fields;
  145. cbStruct = sizeof(PRINTER_INFO_1);
  146. break;
  147. case 2:
  148. pFieldInfo = PrinterInfo2Fields;
  149. cbStruct = sizeof(PRINTER_INFO_2);
  150. break;
  151. case 4:
  152. pFieldInfo = PrinterInfo4Fields;
  153. cbStruct = sizeof(PRINTER_INFO_4);
  154. break;
  155. case 5:
  156. pFieldInfo = PrinterInfo5Fields;
  157. cbStruct = sizeof(PRINTER_INFO_5);
  158. break;
  159. default:
  160. SetLastError(ERROR_INVALID_LEVEL);
  161. return FALSE;
  162. }
  163. RpcTryExcept {
  164. if (pPrinterEnum)
  165. memset(pPrinterEnum, 0, cbBuf);
  166. if (ReturnValue = RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf,
  167. pcbNeeded, pcReturned)) {
  168. SetLastError(ReturnValue);
  169. ReturnValue = FALSE;
  170. } else {
  171. ReturnValue = TRUE;
  172. if (pPrinterEnum) {
  173. ReturnValue = MarshallUpStructuresArray(pPrinterEnum, *pcReturned, pFieldInfo, cbStruct, RPC_CALL);
  174. }
  175. }
  176. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  177. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  178. ReturnValue = FALSE;
  179. } RpcEndExcept
  180. return ReturnValue;
  181. }
  182. BOOL
  183. ResetPrinterW(
  184. HANDLE hPrinter,
  185. LPPRINTER_DEFAULTS pDefault
  186. )
  187. {
  188. BOOL ReturnValue = FALSE;
  189. DEVMODE_CONTAINER DevModeContainer;
  190. PSPOOL pSpool = (PSPOOL)hPrinter;
  191. DWORD dwFlags = 0;
  192. LPWSTR pDatatype = NULL;
  193. UINT cRetry = 0;
  194. if( eProtectHandle( hPrinter, FALSE )){
  195. return FALSE;
  196. }
  197. FlushBuffer(pSpool, NULL);
  198. if( !UpdatePrinterDefaults( pSpool, NULL, pDefault )){
  199. goto Done;
  200. }
  201. if (pDefault && pDefault->pDatatype) {
  202. if (pDefault->pDatatype == (LPWSTR)-1) {
  203. pDatatype = NULL;
  204. dwFlags |= RESET_PRINTER_DATATYPE;
  205. } else {
  206. pDatatype = pDefault->pDatatype;
  207. }
  208. } else {
  209. pDatatype = NULL;
  210. }
  211. DevModeContainer.cbBuf = 0;
  212. DevModeContainer.pDevMode = NULL;
  213. if( pDefault ){
  214. if (pDefault->pDevMode == (LPDEVMODE)-1) {
  215. dwFlags |= RESET_PRINTER_DEVMODE;
  216. } else if( bValidDevModeW( pDefault->pDevMode )){
  217. DevModeContainer.cbBuf = pDefault->pDevMode->dmSize +
  218. pDefault->pDevMode->dmDriverExtra;
  219. DevModeContainer.pDevMode = (LPBYTE)pDefault->pDevMode;
  220. }
  221. }
  222. do {
  223. RpcTryExcept {
  224. if (ReturnValue = RpcResetPrinterEx(pSpool->hPrinter,
  225. pDatatype, &DevModeContainer,
  226. dwFlags
  227. )) {
  228. SetLastError(ReturnValue);
  229. ReturnValue = FALSE;
  230. } else
  231. ReturnValue = TRUE;
  232. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  233. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  234. ReturnValue = FALSE;
  235. } RpcEndExcept
  236. } while( !ReturnValue &&
  237. GetLastError() == ERROR_INVALID_HANDLE &&
  238. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  239. RevalidateHandle( pSpool ));
  240. Done:
  241. vUnprotectHandle( hPrinter );
  242. return ReturnValue;
  243. }
  244. BOOL
  245. SetJobW(
  246. HANDLE hPrinter,
  247. DWORD JobId,
  248. DWORD Level,
  249. LPBYTE pJob,
  250. DWORD Command
  251. )
  252. {
  253. BOOL ReturnValue = FALSE;
  254. GENERIC_CONTAINER GenericContainer;
  255. GENERIC_CONTAINER *pGenericContainer;
  256. PSPOOL pSpool = (PSPOOL)hPrinter;
  257. UINT cRetry = 0;
  258. if( eProtectHandle( hPrinter, FALSE )){
  259. return FALSE;
  260. }
  261. switch (Level) {
  262. case 0:
  263. break;
  264. case 1:
  265. case 2:
  266. case 3:
  267. if (!pJob) {
  268. SetLastError(ERROR_INVALID_PARAMETER);
  269. goto Done;
  270. }
  271. break;
  272. default:
  273. SetLastError(ERROR_INVALID_LEVEL);
  274. goto Done;
  275. }
  276. do {
  277. RpcTryExcept {
  278. if (pJob) {
  279. GenericContainer.Level = Level;
  280. GenericContainer.pData = pJob;
  281. pGenericContainer = &GenericContainer;
  282. } else
  283. pGenericContainer = NULL;
  284. if (bLoadedBySpooler && fpYSetJob && pSpool->hSplPrinter) {
  285. ReturnValue = (*fpYSetJob)(pSpool->hSplPrinter,
  286. JobId,
  287. (JOB_CONTAINER *)pGenericContainer,
  288. Command,
  289. NATIVE_CALL);
  290. }
  291. else {
  292. ReturnValue = RpcSetJob(pSpool->hPrinter,
  293. JobId,
  294. (JOB_CONTAINER *)pGenericContainer,
  295. Command);
  296. }
  297. if (ReturnValue != ERROR_SUCCESS) {
  298. SetLastError(ReturnValue);
  299. ReturnValue = FALSE;
  300. } else {
  301. ReturnValue = TRUE;
  302. }
  303. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  304. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  305. ReturnValue = FALSE;
  306. } RpcEndExcept
  307. } while( !ReturnValue &&
  308. GetLastError() == ERROR_INVALID_HANDLE &&
  309. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  310. RevalidateHandle( pSpool ));
  311. Done:
  312. vUnprotectHandle( hPrinter );
  313. return ReturnValue;
  314. }
  315. BOOL
  316. GetJobW(
  317. HANDLE hPrinter,
  318. DWORD JobId,
  319. DWORD Level,
  320. LPBYTE pJob,
  321. DWORD cbBuf,
  322. LPDWORD pcbNeeded
  323. )
  324. {
  325. BOOL ReturnValue = FALSE;
  326. FieldInfo *pFieldInfo;
  327. SIZE_T cbStruct;
  328. PSPOOL pSpool = (PSPOOL)hPrinter;
  329. UINT cRetry = 0;
  330. if( eProtectHandle( hPrinter, FALSE )){
  331. return FALSE;
  332. }
  333. FlushBuffer(pSpool, NULL);
  334. switch (Level) {
  335. case 1:
  336. pFieldInfo = JobInfo1Fields;
  337. cbStruct = sizeof(JOB_INFO_1);
  338. break;
  339. case 2:
  340. pFieldInfo = JobInfo2Fields;
  341. cbStruct = sizeof(JOB_INFO_2);
  342. break;
  343. case 3:
  344. pFieldInfo = JobInfo3Fields;
  345. cbStruct = sizeof(JOB_INFO_3);
  346. break;
  347. default:
  348. SetLastError(ERROR_INVALID_LEVEL);
  349. goto Done;
  350. }
  351. do {
  352. RpcTryExcept {
  353. if (pJob)
  354. memset(pJob, 0, cbBuf);
  355. if (ReturnValue = RpcGetJob(pSpool->hPrinter, JobId, Level, pJob, cbBuf,
  356. pcbNeeded)) {
  357. SetLastError(ReturnValue);
  358. ReturnValue = FALSE;
  359. } else {
  360. ReturnValue = MarshallUpStructure(pJob, pFieldInfo, cbStruct, RPC_CALL);
  361. }
  362. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  363. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  364. ReturnValue = FALSE;
  365. } RpcEndExcept
  366. } while( !ReturnValue &&
  367. GetLastError() == ERROR_INVALID_HANDLE &&
  368. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  369. RevalidateHandle( pSpool ));
  370. Done:
  371. vUnprotectHandle( hPrinter );
  372. return ReturnValue;
  373. }
  374. BOOL
  375. EnumJobsW(
  376. HANDLE hPrinter,
  377. DWORD FirstJob,
  378. DWORD NoJobs,
  379. DWORD Level,
  380. LPBYTE pJob,
  381. DWORD cbBuf,
  382. LPDWORD pcbNeeded,
  383. LPDWORD pcReturned
  384. )
  385. {
  386. BOOL ReturnValue = FALSE;
  387. DWORD i, cbStruct;
  388. FieldInfo *pFieldInfo;
  389. PSPOOL pSpool = (PSPOOL)hPrinter;
  390. UINT cRetry = 0;
  391. if( eProtectHandle( hPrinter, FALSE )){
  392. return FALSE;
  393. }
  394. FlushBuffer(pSpool, NULL);
  395. switch (Level) {
  396. case 1:
  397. pFieldInfo = JobInfo1Fields;
  398. cbStruct = sizeof(JOB_INFO_1);
  399. break;
  400. case 2:
  401. pFieldInfo = JobInfo2Fields;
  402. cbStruct = sizeof(JOB_INFO_2);
  403. break;
  404. case 3:
  405. pFieldInfo = JobInfo3Fields;
  406. cbStruct = sizeof(JOB_INFO_3);
  407. break;
  408. default:
  409. SetLastError(ERROR_INVALID_LEVEL);
  410. goto Done;
  411. }
  412. do {
  413. RpcTryExcept {
  414. if (pJob)
  415. memset(pJob, 0, cbBuf);
  416. if (ReturnValue = RpcEnumJobs(pSpool->hPrinter, FirstJob, NoJobs, Level, pJob,
  417. cbBuf, pcbNeeded, pcReturned)) {
  418. SetLastError(ReturnValue);
  419. ReturnValue = FALSE;
  420. } else {
  421. ReturnValue = MarshallUpStructuresArray(pJob, *pcReturned, pFieldInfo, cbStruct, RPC_CALL);
  422. }
  423. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  424. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  425. ReturnValue = FALSE;
  426. } RpcEndExcept
  427. } while( !ReturnValue &&
  428. GetLastError() == ERROR_INVALID_HANDLE &&
  429. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  430. RevalidateHandle( pSpool ));
  431. Done:
  432. vUnprotectHandle( hPrinter );
  433. return ReturnValue;
  434. }
  435. HANDLE
  436. AddPrinterW(
  437. LPWSTR pName,
  438. DWORD Level,
  439. LPBYTE pPrinter
  440. )
  441. {
  442. DWORD ReturnValue;
  443. PRINTER_CONTAINER PrinterContainer;
  444. DEVMODE_CONTAINER DevModeContainer;
  445. SECURITY_CONTAINER SecurityContainer;
  446. HANDLE hPrinter;
  447. PSPOOL pSpool = NULL;
  448. PVOID pNewSecurityDescriptor = NULL;
  449. SECURITY_DESCRIPTOR_CONTROL SecurityDescriptorControl = 0;
  450. PPRINTER_INFO_2 pPrinterInfo = (PPRINTER_INFO_2)pPrinter;
  451. switch (Level) {
  452. case 2:
  453. break;
  454. default:
  455. SetLastError(ERROR_INVALID_LEVEL);
  456. return NULL;
  457. }
  458. if ( !pPrinter ) {
  459. SetLastError(ERROR_INVALID_PARAMETER);
  460. return NULL;
  461. }
  462. PrinterContainer.Level = Level;
  463. PrinterContainer.PrinterInfo.pPrinterInfo1 = (PPRINTER_INFO_1)pPrinter;
  464. DevModeContainer.cbBuf = 0;
  465. DevModeContainer.pDevMode = NULL;
  466. SecurityContainer.cbBuf = 0;
  467. SecurityContainer.pSecurity = NULL;
  468. if (Level == 2) {
  469. //
  470. // If valid (non-NULL and properly formatted), then update the
  471. // global DevMode (not per-user).
  472. //
  473. if( bValidDevModeW( pPrinterInfo->pDevMode )){
  474. DevModeContainer.cbBuf = pPrinterInfo->pDevMode->dmSize +
  475. pPrinterInfo->pDevMode->dmDriverExtra;
  476. DevModeContainer.pDevMode = (LPBYTE)pPrinterInfo->pDevMode;
  477. }
  478. if (pPrinterInfo->pSecurityDescriptor) {
  479. DWORD sedlen = 0;
  480. //
  481. // We must construct a self relative security descriptor from
  482. // whatever we get as input: If we get an Absolute SD we should
  483. // convert it to a self-relative one. (this is a given) and we
  484. // should also convert any self -relative input SD into a a new
  485. // self relative security descriptor; this will take care of
  486. // any holes in the Dacl or the Sacl in the self-relative sd
  487. //
  488. pNewSecurityDescriptor = BuildInputSD(
  489. pPrinterInfo->pSecurityDescriptor,
  490. &sedlen);
  491. if (pNewSecurityDescriptor) {
  492. SecurityContainer.cbBuf = sedlen;
  493. SecurityContainer.pSecurity = pNewSecurityDescriptor;
  494. }
  495. }
  496. }
  497. RpcTryExcept {
  498. if (ReturnValue = RpcAddPrinter(pName,
  499. (PPRINTER_CONTAINER)&PrinterContainer,
  500. (PDEVMODE_CONTAINER)&DevModeContainer,
  501. (PSECURITY_CONTAINER)&SecurityContainer,
  502. &hPrinter)) {
  503. SetLastError(ReturnValue);
  504. hPrinter = FALSE;
  505. }
  506. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  507. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  508. hPrinter = FALSE;
  509. } RpcEndExcept
  510. if (hPrinter) {
  511. WCHAR szFullPrinterName[MAX_UNC_PRINTER_NAME];
  512. szFullPrinterName[0] = 0;
  513. pSpool = AllocSpool();
  514. if( pPrinterInfo->pServerName ){
  515. wcscpy( szFullPrinterName, pPrinterInfo->pServerName );
  516. wcscat( szFullPrinterName, L"\\" );
  517. }
  518. wcscat( szFullPrinterName, pPrinterInfo->pPrinterName );
  519. if ( pSpool &&
  520. UpdatePrinterDefaults( pSpool, szFullPrinterName, NULL ) &&
  521. ( !DevModeContainer.pDevMode ||
  522. WriteCurDevModeToRegistry(pPrinterInfo->pPrinterName,
  523. (LPDEVMODEW)DevModeContainer.pDevMode)) ) {
  524. pSpool->hPrinter = hPrinter;
  525. //
  526. // Update the access.
  527. //
  528. pSpool->Default.DesiredAccess = PRINTER_ALL_ACCESS;
  529. } else {
  530. RpcDeletePrinter(hPrinter);
  531. RpcClosePrinter(&hPrinter);
  532. FreeSpool(pSpool);
  533. pSpool = NULL;
  534. }
  535. }
  536. //
  537. // Free Memory allocated for the SecurityDescriptor
  538. //
  539. if (pNewSecurityDescriptor) {
  540. LocalFree(pNewSecurityDescriptor);
  541. }
  542. //
  543. // Some apps check for last error instead of return value
  544. // and report failures even if the return handle is not NULL.
  545. // For success case, set last error to ERROR_SUCCESS.
  546. //
  547. if (pSpool) {
  548. SetLastError(ERROR_SUCCESS);
  549. }
  550. return pSpool;
  551. }
  552. BOOL
  553. DeletePrinter(
  554. HANDLE hPrinter
  555. )
  556. {
  557. BOOL ReturnValue;
  558. PSPOOL pSpool = (PSPOOL)hPrinter;
  559. UINT cRetry = 0;
  560. if( eProtectHandle( hPrinter, FALSE )){
  561. return FALSE;
  562. }
  563. FlushBuffer(pSpool, NULL);
  564. do {
  565. RpcTryExcept {
  566. if (ReturnValue = RpcDeletePrinter(pSpool->hPrinter)) {
  567. SetLastError(ReturnValue);
  568. ReturnValue = FALSE;
  569. } else {
  570. DeleteCurDevModeFromRegistry(pSpool->pszPrinter);
  571. ReturnValue = TRUE;
  572. }
  573. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  574. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  575. ReturnValue = FALSE;
  576. } RpcEndExcept
  577. } while( !ReturnValue &&
  578. GetLastError() == ERROR_INVALID_HANDLE &&
  579. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  580. RevalidateHandle( pSpool ));
  581. vUnprotectHandle( hPrinter );
  582. return ReturnValue;
  583. }
  584. BOOL
  585. SpoolerPrinterEventNative(
  586. LPWSTR pName,
  587. INT PrinterEvent,
  588. DWORD Flags,
  589. LPARAM lParam
  590. )
  591. /*++
  592. //
  593. // Some printer drivers, like the FAX driver want to do per client
  594. // initialization at the time a connection is established
  595. // For example in the FAX case they want to push up UI to get all
  596. // the client info - Name, Number etc.
  597. // Or they might want to run Setup, in initialize some other components
  598. // Thus on a successful conenction we call into the Printer Drivers UI
  599. // DLL to give them this oportunity
  600. //
  601. // mattfe may 1 96
  602. --*/
  603. {
  604. BOOL ReturnValue = FALSE;
  605. HANDLE hPrinter;
  606. HANDLE hModule;
  607. INT_FARPROC pfn;
  608. if (OpenPrinter((LPWSTR)pName, &hPrinter, NULL)) {
  609. if (hModule = LoadPrinterDriver(hPrinter)) {
  610. if (pfn = (INT_FARPROC)GetProcAddress(hModule, "DrvPrinterEvent")) {
  611. try {
  612. ReturnValue = (*pfn)( pName, PrinterEvent, Flags, lParam );
  613. } except(1) {
  614. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  615. }
  616. }
  617. RefCntUnloadDriver(hModule, TRUE);
  618. }
  619. ClosePrinter(hPrinter);
  620. }
  621. return ReturnValue;
  622. }
  623. BOOL
  624. SpoolerPrinterEventThunk(
  625. LPWSTR pName,
  626. INT PrinterEvent,
  627. DWORD Flags,
  628. LPARAM lParam
  629. )
  630. /*++
  631. //
  632. // Some printer drivers, like the FAX driver want to do per client
  633. // initialization at the time a connection is established
  634. // For example in the FAX case they want to push up UI to get all
  635. // the client info - Name, Number etc.
  636. // Or they might want to run Setup, in initialize some other components
  637. // Thus on a successful conenction we call into the Printer Drivers UI
  638. // DLL to give them this oportunity
  639. --*/
  640. {
  641. BOOL ReturnValue = FALSE;
  642. HANDLE hPrinter;
  643. HANDLE hModule;
  644. DWORD dwRet = ERROR_SUCCESS;
  645. INT_FARPROC pfn;
  646. RpcTryExcept
  647. {
  648. if((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS)
  649. {
  650. if((ReturnValue = RPCSplWOW64SpoolerPrinterEvent(pName,
  651. PrinterEvent,
  652. Flags,
  653. lParam,
  654. &dwRet))==FALSE)
  655. {
  656. SetLastError(dwRet);
  657. }
  658. }
  659. else
  660. {
  661. SetLastError(dwRet);
  662. }
  663. }
  664. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  665. {
  666. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  667. }
  668. RpcEndExcept
  669. return ReturnValue;
  670. }
  671. BOOL
  672. SpoolerPrinterEvent(
  673. LPWSTR pName,
  674. INT PrinterEvent,
  675. DWORD Flags,
  676. LPARAM lParam
  677. )
  678. {
  679. if(RunInWOW64())
  680. {
  681. return(SpoolerPrinterEventThunk(pName,
  682. PrinterEvent,
  683. Flags,
  684. lParam));
  685. }
  686. else
  687. {
  688. return(SpoolerPrinterEventNative(pName,
  689. PrinterEvent,
  690. Flags,
  691. lParam));
  692. }
  693. }
  694. VOID
  695. CopyFileEventForAKey(
  696. HANDLE hPrinter,
  697. LPWSTR pszPrinterName,
  698. LPWSTR pszModule,
  699. LPWSTR pszKey,
  700. DWORD dwEvent
  701. )
  702. {
  703. DWORD dwNeeded, dwVersion = 0;
  704. HMODULE hModule = NULL;
  705. LPDRIVER_INFO_5 pDriverInfo5 = NULL;
  706. WCHAR szPath[MAX_PATH];
  707. LPWSTR psz;
  708. BOOL (*pfn)(LPWSTR, LPWSTR, DWORD);
  709. BOOL bAllocBuffer = FALSE, bLoadedDriver = FALSE;
  710. BYTE btBuffer[MAX_STATIC_ALLOC];
  711. pDriverInfo5 = (LPDRIVER_INFO_5) btBuffer;
  712. if (!pszModule || !*pszModule) {
  713. goto CleanUp;
  714. }
  715. // Get the Driver config file name
  716. if (!GetPrinterDriverW(hPrinter, NULL, 5, (LPBYTE) pDriverInfo5,
  717. MAX_STATIC_ALLOC, &dwNeeded)) {
  718. if ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  719. (pDriverInfo5 = (LPDRIVER_INFO_5)LocalAlloc(LMEM_FIXED, dwNeeded))) {
  720. bAllocBuffer = TRUE;
  721. if (!GetPrinterDriverW(hPrinter, NULL, 5,
  722. (LPBYTE)pDriverInfo5, dwNeeded, &dwNeeded)) {
  723. goto CleanUp;
  724. }
  725. } else goto CleanUp;
  726. }
  727. // If module name is the same as the config file, use reference counting
  728. wcscpy(szPath, pDriverInfo5->pConfigFile);
  729. // Get the pointer to just the file name
  730. psz = wcsrchr(szPath, L'\\');
  731. if (psz && !_wcsicmp(pszModule, (psz+1))) {
  732. if (hModule = RefCntLoadDriver(szPath,
  733. LOAD_WITH_ALTERED_SEARCH_PATH,
  734. pDriverInfo5->dwConfigVersion,
  735. TRUE)) {
  736. bLoadedDriver = TRUE;
  737. }
  738. }
  739. if (!hModule) {
  740. hModule = LoadLibraryEx(pszModule, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  741. }
  742. if (!hModule) {
  743. if (GetLastError() != ERROR_MOD_NOT_FOUND) {
  744. // Fail the call
  745. goto CleanUp;
  746. }
  747. // The module could not be found in users path check if it is there
  748. // in the printer driver directory
  749. dwNeeded = (DWORD) (psz - szPath + wcslen(pszModule) + 1);
  750. if (dwNeeded > MAX_PATH) {
  751. // Sanity check for file name size
  752. goto CleanUp;
  753. }
  754. wcscpy(psz, pszModule);
  755. hModule = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  756. }
  757. // Call the SpoolerCopyFileEvent export
  758. if (hModule &&
  759. ((FARPROC)pfn = GetProcAddress(hModule, "SpoolerCopyFileEvent"))) {
  760. pfn(pszPrinterName, pszKey, dwEvent);
  761. }
  762. CleanUp:
  763. if (bAllocBuffer) {
  764. LocalFree(pDriverInfo5);
  765. }
  766. // Use reference counting for config file and FreeLibrary for others
  767. if (hModule) {
  768. if (bLoadedDriver) {
  769. RefCntUnloadDriver(hModule, TRUE);
  770. } else {
  771. FreeLibrary(hModule);
  772. }
  773. }
  774. }
  775. VOID
  776. DoCopyFileEventForAllKeys(
  777. LPWSTR pszPrinterName,
  778. DWORD dwEvent
  779. )
  780. {
  781. DWORD dwLastError, dwNeeded, dwType;
  782. LPWSTR pszBuf = NULL, psz, pszSubKey, pszModule;
  783. HANDLE hPrinter;
  784. WCHAR szKey[MAX_PATH];
  785. BOOL bAllocBufferEnum = FALSE, bAllocBufferGPD = FALSE;
  786. BYTE btBuffer[MAX_STATIC_ALLOC], btBufferGPD[MAX_STATIC_ALLOC];
  787. pszBuf = (LPTSTR) btBuffer;
  788. ZeroMemory(pszBuf, MAX_STATIC_ALLOC);
  789. if ( !OpenPrinter(pszPrinterName, &hPrinter, NULL) )
  790. return;
  791. dwLastError = EnumPrinterKeyW(hPrinter,
  792. L"CopyFiles",
  793. pszBuf,
  794. MAX_STATIC_ALLOC,
  795. &dwNeeded);
  796. //
  797. // If CopyFiles key is not found there is nothing to do
  798. //
  799. if ( dwLastError != ERROR_SUCCESS )
  800. goto Cleanup;
  801. if (dwNeeded > MAX_STATIC_ALLOC) {
  802. if (pszBuf = (LPWSTR) LocalAlloc(LPTR, dwNeeded)) {
  803. bAllocBufferEnum = TRUE;
  804. if (EnumPrinterKeyW(hPrinter,
  805. L"CopyFiles",
  806. pszBuf,
  807. dwNeeded,
  808. &dwNeeded) != ERROR_SUCCESS) {
  809. goto Cleanup;
  810. }
  811. } else goto Cleanup;
  812. }
  813. for ( psz = (LPWSTR) pszBuf ; *psz ; psz += wcslen(psz) + 1 ) {
  814. if ( wcslen(psz) + wcslen(L"CopyFiles") + 2
  815. > sizeof(szKey)/sizeof(szKey[0]) )
  816. continue;
  817. wcscpy(szKey, L"CopyFiles\\");
  818. wcscat(szKey, psz);
  819. bAllocBufferGPD = FALSE;
  820. pszModule = (LPTSTR) btBufferGPD;
  821. ZeroMemory(pszModule, MAX_STATIC_ALLOC);
  822. dwLastError = GetPrinterDataExW(hPrinter,
  823. szKey,
  824. L"Module",
  825. &dwType,
  826. (LPBYTE) pszModule,
  827. MAX_STATIC_ALLOC,
  828. &dwNeeded);
  829. if (dwLastError != ERROR_SUCCESS) {
  830. continue;
  831. }
  832. if (dwNeeded > MAX_STATIC_ALLOC) {
  833. if (pszModule = (LPWSTR) LocalAlloc(LPTR, dwNeeded)) {
  834. bAllocBufferGPD = TRUE;
  835. dwLastError = GetPrinterDataExW(hPrinter,
  836. szKey,
  837. L"Module",
  838. &dwType,
  839. (LPBYTE) pszModule,
  840. MAX_STATIC_ALLOC,
  841. &dwNeeded);
  842. if (dwLastError != ERROR_SUCCESS) {
  843. LocalFree((LPBYTE)pszModule);
  844. continue;
  845. }
  846. } else continue;
  847. }
  848. CopyFileEventForAKey(hPrinter, pszPrinterName, pszModule,
  849. szKey, dwEvent);
  850. if (bAllocBufferGPD) {
  851. LocalFree((LPBYTE)pszModule);
  852. }
  853. }
  854. Cleanup:
  855. ClosePrinter(hPrinter);
  856. if (bAllocBufferEnum) {
  857. LocalFree((LPBYTE)pszBuf);
  858. }
  859. return;
  860. }
  861. BOOL
  862. AddPrinterConnectionW(
  863. LPWSTR pName
  864. )
  865. {
  866. BOOL ReturnValue;
  867. HANDLE hPrinter, hModule;
  868. FARPROC pfn;
  869. RpcTryExcept {
  870. if (ReturnValue = RpcAddPrinterConnection(pName)) {
  871. SetLastError(ReturnValue);
  872. ReturnValue = FALSE;
  873. } else
  874. ReturnValue = TRUE;
  875. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  876. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  877. ReturnValue=FALSE;
  878. } RpcEndExcept
  879. if ( ReturnValue ) {
  880. SpoolerPrinterEvent( pName, PRINTER_EVENT_ADD_CONNECTION, 0, (LPARAM)NULL );
  881. DoCopyFileEventForAllKeys(pName, COPYFILE_EVENT_ADD_PRINTER_CONNECTION);
  882. }
  883. return ReturnValue;
  884. }
  885. BOOL
  886. DeletePrinterConnectionW(
  887. LPWSTR pName
  888. )
  889. {
  890. BOOL ReturnValue;
  891. DWORD LastError;
  892. SpoolerPrinterEvent( pName, PRINTER_EVENT_DELETE_CONNECTION, 0, (LPARAM)NULL );
  893. DoCopyFileEventForAllKeys(pName, COPYFILE_EVENT_DELETE_PRINTER_CONNECTION);
  894. RpcTryExcept {
  895. if (LastError = RpcDeletePrinterConnection(pName)) {
  896. SetLastError(LastError);
  897. ReturnValue = FALSE;
  898. } else
  899. ReturnValue = TRUE;
  900. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  901. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  902. ReturnValue=FALSE;
  903. } RpcEndExcept
  904. return ReturnValue;
  905. }
  906. BOOL
  907. SetPrinterW(
  908. HANDLE hPrinter,
  909. DWORD Level,
  910. LPBYTE pPrinter,
  911. DWORD Command
  912. )
  913. {
  914. BOOL ReturnValue = FALSE;
  915. PRINTER_CONTAINER PrinterContainer;
  916. DEVMODE_CONTAINER DevModeContainer;
  917. SECURITY_CONTAINER SecurityContainer;
  918. PPRINTER_INFO_2 pPrinterInfo2;
  919. PPRINTER_INFO_3 pPrinterInfo3;
  920. PRINTER_INFO_6 PrinterInfo6;
  921. PSPOOL pSpool = (PSPOOL)hPrinter;
  922. PVOID pNewSecurityDescriptor = NULL;
  923. DWORD sedlen = 0;
  924. PDEVMODE pDevModeWow = NULL;
  925. DWORD dwSize = 0;
  926. UINT cRetry = 0;
  927. if( eProtectHandle( hPrinter, FALSE )){
  928. return FALSE;
  929. }
  930. DevModeContainer.cbBuf = 0;
  931. DevModeContainer.pDevMode = NULL;
  932. SecurityContainer.cbBuf = 0;
  933. SecurityContainer.pSecurity = NULL;
  934. switch (Level) {
  935. case STRESSINFOLEVEL:
  936. //
  937. // Internally we treat the Level 0, Command PRINTER_CONTROL_SET_STATUS
  938. // as Level 6 since level 0 could be STRESS_INFO (for rpc)
  939. //
  940. if ( Command == PRINTER_CONTROL_SET_STATUS ) {
  941. PrinterInfo6.dwStatus = (DWORD)(ULONG_PTR)pPrinter;
  942. pPrinter = (LPBYTE)&PrinterInfo6;
  943. Command = 0;
  944. Level = 6;
  945. }
  946. break;
  947. case 2:
  948. pPrinterInfo2 = (PPRINTER_INFO_2)pPrinter;
  949. if (pPrinterInfo2 == NULL) {
  950. DBGMSG(DBG_TRACE, ("Error: SetPrinter pPrinterInfo2 is NULL\n"));
  951. SetLastError(ERROR_INVALID_PARAMETER);
  952. goto Done;
  953. }
  954. //
  955. // If valid (non-NULL and properly formatted), then update the
  956. // per-user DevMode. Note that we don't remove the per-user DevMode
  957. // if this is NULL--client should user INFO_LEVEL_9 instead.
  958. //
  959. if( bValidDevModeW( pPrinterInfo2->pDevMode )){
  960. //
  961. // We won't setup the container, since setting a DevMode
  962. // with INFO_2 doesn't change the global default.
  963. // Use INFO_8 instead.
  964. //
  965. pDevModeWow = pPrinterInfo2->pDevMode;
  966. DevModeContainer.cbBuf = pPrinterInfo2->pDevMode->dmSize +
  967. pPrinterInfo2->pDevMode->dmDriverExtra;
  968. DevModeContainer.pDevMode = (LPBYTE)pPrinterInfo2->pDevMode;
  969. }
  970. if (pPrinterInfo2->pSecurityDescriptor) {
  971. //
  972. // We must construct a self relative security descriptor from
  973. // whatever we get as input: If we get an Absolute SD we should
  974. // convert it to a self-relative one. (this is a given) and we
  975. // should also convert any self -relative input SD into a a new
  976. // self relative security descriptor; this will take care of
  977. // any holes in the Dacl or the Sacl in the self-relative sd
  978. //
  979. pNewSecurityDescriptor = BuildInputSD(pPrinterInfo2->pSecurityDescriptor,
  980. &sedlen);
  981. if (pNewSecurityDescriptor) {
  982. SecurityContainer.cbBuf = sedlen;
  983. SecurityContainer.pSecurity = pNewSecurityDescriptor;
  984. }
  985. }
  986. break;
  987. case 3:
  988. pPrinterInfo3 = (PPRINTER_INFO_3)pPrinter;
  989. if (pPrinterInfo3 == NULL) {
  990. DBGMSG(DBG_TRACE, ("Error: SetPrinter pPrinterInfo3 is NULL\n"));
  991. SetLastError(ERROR_INVALID_PARAMETER);
  992. goto Done;
  993. }
  994. if (pPrinterInfo3->pSecurityDescriptor) {
  995. //
  996. // We must construct a self relative security descriptor from
  997. // whatever we get as input: If we get an Absolute SD we should
  998. // convert it to a self-relative one. (this is a given) and we
  999. // should also convert any self -relative input SD into a a new
  1000. // self relative security descriptor; this will take care of
  1001. // any holes in the Dacl or the Sacl in the self-relative sd
  1002. //
  1003. pNewSecurityDescriptor = BuildInputSD(pPrinterInfo3->pSecurityDescriptor,
  1004. &sedlen);
  1005. if (pNewSecurityDescriptor) {
  1006. SecurityContainer.cbBuf = sedlen;
  1007. SecurityContainer.pSecurity = pNewSecurityDescriptor;
  1008. }
  1009. }
  1010. break;
  1011. case 4:
  1012. case 5:
  1013. if ( pPrinter == NULL ) {
  1014. DBGMSG(DBG_TRACE,("Error SetPrinter pPrinter is NULL\n"));
  1015. SetLastError(ERROR_INVALID_PARAMETER);
  1016. goto Done;
  1017. }
  1018. break;
  1019. case 6:
  1020. if ( pPrinter == NULL ) {
  1021. DBGMSG(DBG_TRACE,("Error SetPrinter pPrinter is NULL\n"));
  1022. SetLastError(ERROR_INVALID_PARAMETER);
  1023. goto Done;
  1024. }
  1025. break;
  1026. case 7:
  1027. if ( pPrinter == NULL ) {
  1028. DBGMSG(DBG_TRACE,("Error SetPrinter pPrinter is NULL\n"));
  1029. SetLastError(ERROR_INVALID_PARAMETER);
  1030. goto Done;
  1031. }
  1032. break;
  1033. case 8:
  1034. {
  1035. PPRINTER_INFO_8 pPrinterInfo8;
  1036. //
  1037. // Global DevMode
  1038. //
  1039. pPrinterInfo8 = (PPRINTER_INFO_8)pPrinter;
  1040. if( !pPrinterInfo8 || !bValidDevModeW( pPrinterInfo8->pDevMode )){
  1041. DBGMSG(DBG_TRACE,("Error SetPrinter 8 pPrinter\n"));
  1042. SetLastError( ERROR_INVALID_PARAMETER );
  1043. goto Done;
  1044. }
  1045. pDevModeWow = pPrinterInfo8->pDevMode;
  1046. DevModeContainer.cbBuf = pPrinterInfo8->pDevMode->dmSize +
  1047. pPrinterInfo8->pDevMode->dmDriverExtra;
  1048. DevModeContainer.pDevMode = (LPBYTE)pPrinterInfo8->pDevMode;
  1049. break;
  1050. }
  1051. case 9:
  1052. {
  1053. PPRINTER_INFO_9 pPrinterInfo9;
  1054. //
  1055. // Per-user DevMode
  1056. //
  1057. pPrinterInfo9 = (PPRINTER_INFO_9)pPrinter;
  1058. //
  1059. // Update the per-user DevMode if it's a valid DevMode,
  1060. // or it is NULL, which indicates that the per-user DevMode
  1061. // should be removed.
  1062. //
  1063. if( !pPrinterInfo9 ||
  1064. ( pPrinterInfo9->pDevMode &&
  1065. !bValidDevModeW( pPrinterInfo9->pDevMode ))){
  1066. DBGMSG(DBG_TRACE,("Error SetPrinter 9 pPrinter\n"));
  1067. SetLastError( ERROR_INVALID_PARAMETER );
  1068. goto Done;
  1069. }
  1070. if( pPrinterInfo9->pDevMode ){
  1071. pDevModeWow = pPrinterInfo9->pDevMode;
  1072. DevModeContainer.cbBuf = pPrinterInfo9->pDevMode->dmSize +
  1073. pPrinterInfo9->pDevMode->dmDriverExtra;
  1074. DevModeContainer.pDevMode = (LPBYTE)pPrinterInfo9->pDevMode;
  1075. }
  1076. break;
  1077. }
  1078. default:
  1079. SetLastError(ERROR_INVALID_LEVEL);
  1080. goto Done;
  1081. }
  1082. PrinterContainer.Level = Level;
  1083. PrinterContainer.PrinterInfo.pPrinterInfo1 = (PPRINTER_INFO_1)pPrinter;
  1084. do {
  1085. RpcTryExcept {
  1086. if (ReturnValue = RpcSetPrinter(
  1087. pSpool->hPrinter,
  1088. (PPRINTER_CONTAINER)&PrinterContainer,
  1089. (PDEVMODE_CONTAINER)&DevModeContainer,
  1090. (PSECURITY_CONTAINER)&SecurityContainer,
  1091. Command)) {
  1092. SetLastError(ReturnValue);
  1093. ReturnValue = FALSE;
  1094. } else
  1095. ReturnValue = TRUE;
  1096. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1097. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1098. ReturnValue = FALSE;
  1099. } RpcEndExcept
  1100. } while( !ReturnValue &&
  1101. GetLastError() == ERROR_INVALID_HANDLE &&
  1102. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  1103. RevalidateHandle( pSpool ));
  1104. //
  1105. // Need to write DevMode to registry so that dos apps doing
  1106. // ExtDeviceMode can pick up the new devmode
  1107. //
  1108. if( ReturnValue && pDevModeWow ){
  1109. if( !WriteCurDevModeToRegistry( pSpool->pszPrinter,
  1110. pDevModeWow )){
  1111. DBGMSG( DBG_WARN,
  1112. ( "Write wow DevMode failed: %d\n", GetLastError( )));
  1113. }
  1114. //
  1115. // Per-user DevMode is handled in the client's spoolsv process.
  1116. //
  1117. }
  1118. //
  1119. // Did we allocate memory for a new self-relative SD?
  1120. // If we did, let's free it.
  1121. //
  1122. if (pNewSecurityDescriptor) {
  1123. LocalFree(pNewSecurityDescriptor);
  1124. }
  1125. Done:
  1126. vUnprotectHandle( hPrinter );
  1127. return ReturnValue;
  1128. }
  1129. BOOL
  1130. GetPrinterW(
  1131. HANDLE hPrinter,
  1132. DWORD Level,
  1133. LPBYTE pPrinter,
  1134. DWORD cbBuf,
  1135. LPDWORD pcbNeeded
  1136. )
  1137. {
  1138. BOOL ReturnValue = FALSE;
  1139. FieldInfo *pFieldInfo;
  1140. SIZE_T cbStruct;
  1141. PSPOOL pSpool = (PSPOOL)hPrinter;
  1142. UINT cRetry = 0;
  1143. if( eProtectHandle( hPrinter, FALSE )){
  1144. return FALSE;
  1145. }
  1146. switch (Level) {
  1147. case STRESSINFOLEVEL:
  1148. pFieldInfo = PrinterInfoStressFields;
  1149. cbStruct = sizeof(PRINTER_INFO_STRESS);
  1150. break;
  1151. case 1:
  1152. pFieldInfo = PrinterInfo1Fields;
  1153. cbStruct = sizeof(PRINTER_INFO_1);
  1154. break;
  1155. case 2:
  1156. pFieldInfo = PrinterInfo2Fields;
  1157. cbStruct = sizeof(PRINTER_INFO_2);
  1158. break;
  1159. case 3:
  1160. pFieldInfo = PrinterInfo3Fields;
  1161. cbStruct = sizeof(PRINTER_INFO_3);
  1162. break;
  1163. case 4:
  1164. pFieldInfo = PrinterInfo4Fields;
  1165. cbStruct = sizeof(PRINTER_INFO_4);
  1166. break;
  1167. case 5:
  1168. pFieldInfo = PrinterInfo5Fields;
  1169. cbStruct = sizeof(PRINTER_INFO_5);
  1170. break;
  1171. case 6:
  1172. pFieldInfo = PrinterInfo6Fields;
  1173. cbStruct = sizeof(PRINTER_INFO_6);
  1174. break;
  1175. case 7:
  1176. pFieldInfo = PrinterInfo7Fields;
  1177. cbStruct = sizeof(PRINTER_INFO_7);
  1178. break;
  1179. case 8:
  1180. pFieldInfo = PrinterInfo8Fields;
  1181. cbStruct = sizeof(PRINTER_INFO_8);
  1182. break;
  1183. case 9:
  1184. pFieldInfo = PrinterInfo9Fields;
  1185. cbStruct = sizeof(PRINTER_INFO_9);
  1186. break;
  1187. default:
  1188. SetLastError(ERROR_INVALID_LEVEL);
  1189. goto Done;
  1190. }
  1191. if (pPrinter)
  1192. memset(pPrinter, 0, cbBuf);
  1193. do {
  1194. RpcTryExcept {
  1195. if (ReturnValue = RpcGetPrinter(pSpool->hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) {
  1196. SetLastError(ReturnValue);
  1197. ReturnValue = FALSE;
  1198. } else {
  1199. ReturnValue = TRUE;
  1200. if (pPrinter) {
  1201. ReturnValue = MarshallUpStructure(pPrinter, pFieldInfo, cbStruct, RPC_CALL);
  1202. }
  1203. }
  1204. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1205. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1206. ReturnValue = FALSE;
  1207. } RpcEndExcept
  1208. } while( !ReturnValue &&
  1209. GetLastError() == ERROR_INVALID_HANDLE &&
  1210. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  1211. RevalidateHandle( pSpool ));
  1212. Done:
  1213. vUnprotectHandle( hPrinter );
  1214. return ReturnValue;
  1215. }
  1216. BOOL
  1217. GetOSVersion(
  1218. IN LPCTSTR pszServerName, OPTIONAL
  1219. OUT OSVERSIONINFO *pOSVer
  1220. )
  1221. {
  1222. DWORD dwStatus = ERROR_SUCCESS;
  1223. dwStatus = pOSVer ? S_OK : ERROR_INVALID_PARAMETER;
  1224. if (ERROR_SUCCESS == dwStatus)
  1225. {
  1226. ZeroMemory(pOSVer, sizeof(OSVERSIONINFO));
  1227. pOSVer->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1228. if(!pszServerName || !*pszServerName) // allow string to be empty?
  1229. {
  1230. dwStatus = GetVersionEx((POSVERSIONINFO) pOSVer) ? ERROR_SUCCESS : GetLastError();
  1231. }
  1232. else
  1233. {
  1234. HANDLE hPrinter = NULL;
  1235. DWORD dwNeeded = 0;
  1236. DWORD dwType = REG_BINARY;
  1237. PRINTER_DEFAULTS Defaults = { NULL, NULL, SERVER_READ };
  1238. //
  1239. // Open the server for read access.
  1240. //
  1241. dwStatus = OpenPrinter((LPTSTR) pszServerName, &hPrinter, &Defaults) ? ERROR_SUCCESS : GetLastError();
  1242. //
  1243. // Get the os version from the remote spooler.
  1244. //
  1245. if (ERROR_SUCCESS == dwStatus)
  1246. {
  1247. dwStatus = GetPrinterData(hPrinter,
  1248. SPLREG_OS_VERSION,
  1249. &dwType,
  1250. (PBYTE)pOSVer,
  1251. sizeof(OSVERSIONINFO),
  1252. &dwNeeded);
  1253. }
  1254. if (ERROR_INVALID_PARAMETER == dwStatus)
  1255. {
  1256. //
  1257. // Assume that we're on NT4 as it doesn't support SPLREG_OS_VERSION
  1258. // at it's the only OS that doesn't that could land up in this remote code path.
  1259. //
  1260. dwStatus = ERROR_SUCCESS;
  1261. pOSVer->dwMajorVersion = 4;
  1262. pOSVer->dwMinorVersion = 0;
  1263. }
  1264. if (NULL != hPrinter )
  1265. {
  1266. ClosePrinter(hPrinter);
  1267. }
  1268. }
  1269. }
  1270. SetLastError(dwStatus);
  1271. return ERROR_SUCCESS == dwStatus ? TRUE : FALSE ;
  1272. }
  1273. BOOL
  1274. AddPrinterDriverExW(
  1275. LPWSTR pName,
  1276. DWORD Level,
  1277. PBYTE lpbDriverInfo,
  1278. DWORD dwFileCopyFlags
  1279. )
  1280. {
  1281. BOOL ReturnValue;
  1282. DRIVER_CONTAINER DriverContainer;
  1283. BOOL bDefaultEnvironmentUsed = FALSE;
  1284. LPRPC_DRIVER_INFO_4W pRpcDriverInfo4 = NULL;
  1285. DRIVER_INFO_4 *pDriverInfo4 = NULL;
  1286. LPRPC_DRIVER_INFO_6W pRpcDriverInfo6 = NULL;
  1287. DRIVER_INFO_6 *pDriverInfo6 = NULL;
  1288. BOOL bShowUI = FALSE;
  1289. BOOL bMapUnknownPrinterDriverToBlockedDriver = FALSE;
  1290. OSVERSIONINFO OsVer;
  1291. LPWSTR pStr;
  1292. //
  1293. // Validate Input Parameters
  1294. //
  1295. if (!lpbDriverInfo) {
  1296. SetLastError(ERROR_INVALID_PARAMETER);
  1297. return(FALSE);
  1298. }
  1299. DriverContainer.Level = Level;
  1300. switch (Level) {
  1301. case 2:
  1302. if ( (((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment == NULL ) ||
  1303. (*((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment == L'\0') ) {
  1304. bDefaultEnvironmentUsed = TRUE;
  1305. ((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment = szEnvironment;
  1306. }
  1307. DriverContainer.DriverInfo.Level2 = (DRIVER_INFO_2 *)lpbDriverInfo;
  1308. break;
  1309. case 3:
  1310. case 4:
  1311. //
  1312. // DRIVER_INFO_4 is 3 + pszzPreviousNames field
  1313. // We will use RPC_DRIVER_INFO_4 for both cases
  1314. //
  1315. DriverContainer.Level = Level;
  1316. if ( (((LPDRIVER_INFO_4)lpbDriverInfo)->pEnvironment == NULL ) ||
  1317. (*((LPDRIVER_INFO_4)lpbDriverInfo)->pEnvironment == L'\0') ) {
  1318. bDefaultEnvironmentUsed = TRUE;
  1319. ((LPDRIVER_INFO_4)lpbDriverInfo)->pEnvironment = szEnvironment;
  1320. }
  1321. if ( !(pRpcDriverInfo4=AllocSplMem(sizeof(RPC_DRIVER_INFO_4W))) ) {
  1322. return FALSE;
  1323. }
  1324. pDriverInfo4 = (DRIVER_INFO_4 *)lpbDriverInfo;
  1325. pRpcDriverInfo4->cVersion = pDriverInfo4->cVersion;
  1326. pRpcDriverInfo4->pName = pDriverInfo4->pName;
  1327. pRpcDriverInfo4->pEnvironment = pDriverInfo4->pEnvironment;
  1328. pRpcDriverInfo4->pDriverPath = pDriverInfo4->pDriverPath;
  1329. pRpcDriverInfo4->pDataFile = pDriverInfo4->pDataFile;
  1330. pRpcDriverInfo4->pConfigFile = pDriverInfo4->pConfigFile;
  1331. pRpcDriverInfo4->pHelpFile = pDriverInfo4->pHelpFile;
  1332. pRpcDriverInfo4->pDependentFiles = pDriverInfo4->pDependentFiles;
  1333. pRpcDriverInfo4->pMonitorName = pDriverInfo4->pMonitorName;
  1334. pRpcDriverInfo4->pDefaultDataType = pDriverInfo4->pDefaultDataType;
  1335. //
  1336. // Set the char count of the mz string.
  1337. // NULL --- 0
  1338. // szNULL --- 1
  1339. // string --- number of characters in the string including the last '\0'
  1340. //
  1341. if ( pStr = pDriverInfo4->pDependentFiles ) {
  1342. while ( *pStr )
  1343. pStr += wcslen(pStr) + 1;
  1344. pRpcDriverInfo4->cchDependentFiles
  1345. = (DWORD) (pStr - pDriverInfo4->pDependentFiles + 1);
  1346. } else {
  1347. pRpcDriverInfo4->cchDependentFiles = 0;
  1348. }
  1349. pRpcDriverInfo4->cchPreviousNames = 0;
  1350. if ( Level == 4 &&
  1351. (pStr = pDriverInfo4->pszzPreviousNames) &&
  1352. *pStr ) {
  1353. pRpcDriverInfo4->pszzPreviousNames = pStr;
  1354. while ( *pStr )
  1355. pStr += wcslen(pStr) + 1;
  1356. pRpcDriverInfo4->cchPreviousNames
  1357. = (DWORD) (pStr - pDriverInfo4->pszzPreviousNames + 1);
  1358. }
  1359. DriverContainer.DriverInfo.Level4 = pRpcDriverInfo4;
  1360. break;
  1361. case 6:
  1362. DriverContainer.Level = Level;
  1363. if ( (((LPDRIVER_INFO_6)lpbDriverInfo)->pEnvironment == NULL ) ||
  1364. (*((LPDRIVER_INFO_6)lpbDriverInfo)->pEnvironment == L'\0') ) {
  1365. bDefaultEnvironmentUsed = TRUE;
  1366. ((LPDRIVER_INFO_6)lpbDriverInfo)->pEnvironment = szEnvironment;
  1367. }
  1368. if ( !(pRpcDriverInfo6=AllocSplMem(sizeof(RPC_DRIVER_INFO_6W))) ) {
  1369. return FALSE;
  1370. }
  1371. pDriverInfo6 = (DRIVER_INFO_6 *)lpbDriverInfo;
  1372. pRpcDriverInfo6->cVersion = pDriverInfo6->cVersion;
  1373. pRpcDriverInfo6->pName = pDriverInfo6->pName;
  1374. pRpcDriverInfo6->pEnvironment = pDriverInfo6->pEnvironment;
  1375. pRpcDriverInfo6->pDriverPath = pDriverInfo6->pDriverPath;
  1376. pRpcDriverInfo6->pDataFile = pDriverInfo6->pDataFile;
  1377. pRpcDriverInfo6->pConfigFile = pDriverInfo6->pConfigFile;
  1378. pRpcDriverInfo6->pHelpFile = pDriverInfo6->pHelpFile;
  1379. pRpcDriverInfo6->pDependentFiles = pDriverInfo6->pDependentFiles;
  1380. pRpcDriverInfo6->pMonitorName = pDriverInfo6->pMonitorName;
  1381. pRpcDriverInfo6->pDefaultDataType = pDriverInfo6->pDefaultDataType;
  1382. pRpcDriverInfo6->ftDriverDate = pDriverInfo6->ftDriverDate;
  1383. pRpcDriverInfo6->dwlDriverVersion = pDriverInfo6->dwlDriverVersion;
  1384. pRpcDriverInfo6->pMfgName = pDriverInfo6->pszMfgName;
  1385. pRpcDriverInfo6->pOEMUrl = pDriverInfo6->pszOEMUrl;
  1386. pRpcDriverInfo6->pHardwareID = pDriverInfo6->pszHardwareID;
  1387. pRpcDriverInfo6->pProvider = pDriverInfo6->pszProvider;
  1388. //
  1389. // Set the char count of the mz string.
  1390. // NULL --- 0
  1391. // szNULL --- 1
  1392. // string --- number of characters in the string including the last '\0'
  1393. //
  1394. if ( pStr = pDriverInfo6->pDependentFiles ) {
  1395. while ( *pStr )
  1396. pStr += wcslen(pStr) + 1;
  1397. pRpcDriverInfo6->cchDependentFiles = (DWORD) (pStr - pDriverInfo6->pDependentFiles + 1);
  1398. } else {
  1399. pRpcDriverInfo6->cchDependentFiles = 0;
  1400. }
  1401. pRpcDriverInfo6->cchPreviousNames = 0;
  1402. if ( Level == 6 &&
  1403. (pStr = pDriverInfo6->pszzPreviousNames) &&
  1404. *pStr ) {
  1405. pRpcDriverInfo6->pszzPreviousNames = pStr;
  1406. while ( *pStr )
  1407. pStr += wcslen(pStr) + 1;
  1408. pRpcDriverInfo6->cchPreviousNames
  1409. = (DWORD) (pStr - pDriverInfo6->pszzPreviousNames + 1);
  1410. }
  1411. DriverContainer.DriverInfo.Level6 = pRpcDriverInfo6;
  1412. break;
  1413. default:
  1414. SetLastError(ERROR_INVALID_LEVEL);
  1415. return FALSE;
  1416. }
  1417. //
  1418. // The driver path is at the same location in all of the DRIVER_INFO_X
  1419. // structures, as is the driver name. If this changes, the
  1420. // CheckForBlockedDrivers() call will have to do different things
  1421. // depending on the level.
  1422. //
  1423. SPLASSERT(Level >= 2 && Level <= 6);
  1424. //
  1425. // APD_NO_UI has no meaning at the server side, so clear it before the
  1426. // RPC call.
  1427. //
  1428. bShowUI = !(dwFileCopyFlags & APD_NO_UI);
  1429. dwFileCopyFlags &= ~APD_NO_UI;
  1430. //
  1431. // GetOSVersionEx has set last error correctly.
  1432. //
  1433. ReturnValue = GetOSVersion(pName, &OsVer);
  1434. if (!ReturnValue) {
  1435. goto Cleanup;
  1436. }
  1437. //
  1438. // If the server is Whistler or later, instruct the spooler to
  1439. // return the actual blocking code ERROR_PRINTER_DRIVER_BLOCKED or
  1440. // ERROR_PRINTER_DRIVER_WARNED.
  1441. //
  1442. // A win2k server returns ERROR_UNKNOWN_PRINTER_DRIVER for blocked
  1443. // driver, so we need to re-map this code to the correct blocking
  1444. // code.
  1445. //
  1446. if (OsVer.dwMajorVersion >= 5 && OsVer.dwMinorVersion > 0)
  1447. {
  1448. dwFileCopyFlags |= APD_RETURN_BLOCKING_STATUS_CODE;
  1449. }
  1450. else
  1451. {
  1452. //
  1453. // APD_DONT_SET_CHECKPOINT has no meaning at the server side, so clear it
  1454. // before the RPC call.
  1455. //
  1456. dwFileCopyFlags &= ~APD_DONT_SET_CHECKPOINT;
  1457. dwFileCopyFlags &= ~APD_INSTALL_WARNED_DRIVER;
  1458. if (OsVer.dwMajorVersion == 5 && OsVer.dwMinorVersion == 0)
  1459. {
  1460. bMapUnknownPrinterDriverToBlockedDriver = TRUE;
  1461. }
  1462. }
  1463. RpcTryExcept {
  1464. ReturnValue = RpcAddPrinterDriverEx(pName,
  1465. &DriverContainer,
  1466. dwFileCopyFlags);
  1467. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1468. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  1469. } RpcEndExcept
  1470. if (bMapUnknownPrinterDriverToBlockedDriver && (ERROR_UNKNOWN_PRINTER_DRIVER == ReturnValue))
  1471. {
  1472. ReturnValue = ERROR_PRINTER_DRIVER_BLOCKED;
  1473. }
  1474. //
  1475. // Popup UI but do not offer replacement for all cases.
  1476. //
  1477. if (bShowUI && ((ERROR_PRINTER_DRIVER_BLOCKED == ReturnValue) || (ERROR_PRINTER_DRIVER_WARNED == ReturnValue))) {
  1478. ReturnValue = ShowPrintUpgUI(ReturnValue);
  1479. //
  1480. // For warned driver and the user instructs to install it, retry it
  1481. // with APD_INSTALL_WARNED_DRIVER.
  1482. //
  1483. if ((ERROR_SUCCESS == ReturnValue)) {
  1484. dwFileCopyFlags |= APD_INSTALL_WARNED_DRIVER;
  1485. RpcTryExcept {
  1486. ReturnValue = RpcAddPrinterDriverEx(pName,
  1487. &DriverContainer,
  1488. dwFileCopyFlags);
  1489. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1490. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  1491. } RpcEndExcept
  1492. }
  1493. }
  1494. if (ERROR_SUCCESS != ReturnValue) {
  1495. SetLastError(ReturnValue);
  1496. ReturnValue = FALSE;
  1497. } else {
  1498. ReturnValue = TRUE;
  1499. }
  1500. if (bDefaultEnvironmentUsed) {
  1501. if ( Level == 2 )
  1502. ((LPDRIVER_INFO_2)lpbDriverInfo)->pEnvironment = NULL;
  1503. else //Level == 3
  1504. ((LPDRIVER_INFO_3)lpbDriverInfo)->pEnvironment = NULL;
  1505. }
  1506. Cleanup:
  1507. FreeSplMem(pRpcDriverInfo4);
  1508. FreeSplMem(pRpcDriverInfo6);
  1509. return ReturnValue;
  1510. }
  1511. BOOL
  1512. AddDriverCatalog(
  1513. HANDLE hPrinter,
  1514. DWORD dwLevel,
  1515. VOID *pvDriverInfCatInfo,
  1516. DWORD dwCatalogCopyFlags
  1517. )
  1518. {
  1519. HRESULT hRetval = E_FAIL;
  1520. PSPOOL pSpool = (PSPOOL)hPrinter;
  1521. UINT cRetry = 0;
  1522. DRIVER_INFCAT_CONTAINER DriverInfCatContainer;
  1523. hRetval = pvDriverInfCatInfo && hPrinter ? S_OK : E_INVALIDARG;
  1524. if (SUCCEEDED(hRetval))
  1525. {
  1526. hRetval = eProtectHandle(hPrinter, FALSE) ? S_OK : GetLastErrorAsHResult();
  1527. }
  1528. if (SUCCEEDED(hRetval))
  1529. {
  1530. switch (dwLevel)
  1531. {
  1532. case 1:
  1533. DriverInfCatContainer.dwLevel = dwLevel;
  1534. DriverInfCatContainer.DriverInfCatInfo.pDriverInfCatInfo1 = (LPRPC_DRIVER_INFCAT_INFO_1) pvDriverInfCatInfo;
  1535. break;
  1536. case 2:
  1537. DriverInfCatContainer.dwLevel = dwLevel;
  1538. DriverInfCatContainer.DriverInfCatInfo.pDriverInfCatInfo2 = (LPRPC_DRIVER_INFCAT_INFO_2) pvDriverInfCatInfo;
  1539. break;
  1540. default:
  1541. hRetval = HRESULT_FROM_WIN32(ERROR_INVALID_LEVEL);
  1542. break;
  1543. }
  1544. if (SUCCEEDED(hRetval))
  1545. {
  1546. do
  1547. {
  1548. RpcTryExcept
  1549. {
  1550. hRetval = HResultFromWin32(RpcAddDriverCatalog(pSpool->hPrinter,
  1551. &DriverInfCatContainer,
  1552. dwCatalogCopyFlags));
  1553. }
  1554. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  1555. {
  1556. hRetval = HResultFromWin32(TranslateExceptionCode(RpcExceptionCode()));
  1557. }
  1558. RpcEndExcept
  1559. } while (FAILED(hRetval) && (HRESULT_CODE(hRetval) == ERROR_INVALID_HANDLE) &&
  1560. (cRetry++ < MAX_RETRY_INVALID_HANDLE) &&
  1561. RevalidateHandle( pSpool ));
  1562. }
  1563. vUnprotectHandle(hPrinter);
  1564. }
  1565. if (FAILED(hRetval))
  1566. {
  1567. SetLastError(HRESULT_CODE(hRetval));
  1568. }
  1569. return SUCCEEDED(hRetval);
  1570. }
  1571. BOOL
  1572. AddPrinterDriverW(
  1573. LPWSTR pName,
  1574. DWORD Level,
  1575. PBYTE lpbDriverInfo
  1576. )
  1577. {
  1578. return AddPrinterDriverExW(pName, Level, lpbDriverInfo, APD_COPY_NEW_FILES);
  1579. }
  1580. BOOL
  1581. EnumPrinterDriversW(
  1582. LPWSTR pName,
  1583. LPWSTR pEnvironment,
  1584. DWORD Level,
  1585. LPBYTE pDriverInfo,
  1586. DWORD cbBuf,
  1587. LPDWORD pcbNeeded,
  1588. LPDWORD pcReturned
  1589. )
  1590. {
  1591. BOOL ReturnValue;
  1592. DWORD i, cbStruct;
  1593. FieldInfo *pFieldInfo;
  1594. switch (Level) {
  1595. case 1:
  1596. pFieldInfo = DriverInfo1Fields;
  1597. cbStruct = sizeof(DRIVER_INFO_1);
  1598. break;
  1599. case 2:
  1600. pFieldInfo = DriverInfo2Fields;
  1601. cbStruct = sizeof(DRIVER_INFO_2);
  1602. break;
  1603. case 3:
  1604. pFieldInfo = DriverInfo3Fields;
  1605. cbStruct = sizeof(DRIVER_INFO_3);
  1606. break;
  1607. case 4:
  1608. pFieldInfo = DriverInfo4Fields;
  1609. cbStruct = sizeof(DRIVER_INFO_4);
  1610. break;
  1611. case 5:
  1612. pFieldInfo = DriverInfo5Fields;
  1613. cbStruct = sizeof(DRIVER_INFO_5);
  1614. break;
  1615. case 6:
  1616. pFieldInfo = DriverInfo6Fields;
  1617. cbStruct = sizeof(DRIVER_INFO_6);
  1618. break;
  1619. default:
  1620. SetLastError(ERROR_INVALID_LEVEL);
  1621. return FALSE;
  1622. }
  1623. RpcTryExcept {
  1624. if (!pEnvironment || !*pEnvironment)
  1625. pEnvironment = szEnvironment;
  1626. if (ReturnValue = RpcEnumPrinterDrivers(pName, pEnvironment, Level,
  1627. pDriverInfo, cbBuf,
  1628. pcbNeeded, pcReturned)) {
  1629. SetLastError(ReturnValue);
  1630. ReturnValue = FALSE;
  1631. } else {
  1632. ReturnValue = TRUE;
  1633. if (pDriverInfo) {
  1634. ReturnValue = MarshallUpStructuresArray(pDriverInfo, *pcReturned, pFieldInfo, cbStruct, RPC_CALL);
  1635. }
  1636. }
  1637. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1638. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1639. ReturnValue = FALSE;
  1640. } RpcEndExcept
  1641. return ReturnValue;
  1642. }
  1643. BOOL
  1644. GetPrinterDriverW(
  1645. HANDLE hPrinter,
  1646. LPWSTR pEnvironment,
  1647. DWORD Level,
  1648. LPBYTE pDriverInfo,
  1649. DWORD cbBuf,
  1650. LPDWORD pcbNeeded
  1651. )
  1652. {
  1653. BOOL ReturnValue = FALSE;
  1654. FieldInfo *pFieldInfo;
  1655. SIZE_T cbStruct;
  1656. PSPOOL pSpool = (PSPOOL)hPrinter;
  1657. DWORD dwMajorVersionNeeded = (DWORD)-1, dwMinorVersionNeeded = (DWORD)-1;
  1658. DWORD dwServerMajorVersion;
  1659. DWORD dwServerMinorVersion;
  1660. UINT cRetry = 0;
  1661. CALL_ROUTE Route;
  1662. if( eProtectHandle( hPrinter, FALSE )){
  1663. return FALSE;
  1664. }
  1665. switch (Level) {
  1666. case 1:
  1667. pFieldInfo = DriverInfo1Fields;
  1668. cbStruct = sizeof(DRIVER_INFO_1);
  1669. break;
  1670. case 2:
  1671. pFieldInfo = DriverInfo2Fields;
  1672. cbStruct = sizeof(DRIVER_INFO_2);
  1673. break;
  1674. case 3:
  1675. pFieldInfo = DriverInfo3Fields;
  1676. cbStruct = sizeof(DRIVER_INFO_3);
  1677. break;
  1678. case 4:
  1679. pFieldInfo = DriverInfo4Fields;
  1680. cbStruct = sizeof(DRIVER_INFO_4);
  1681. break;
  1682. case 5:
  1683. pFieldInfo = DriverInfo5Fields;
  1684. cbStruct = sizeof(DRIVER_INFO_5);
  1685. break;
  1686. case 6:
  1687. pFieldInfo = DriverInfo6Fields;
  1688. cbStruct = sizeof(DRIVER_INFO_6);
  1689. break;
  1690. default:
  1691. SetLastError(ERROR_INVALID_LEVEL);
  1692. goto Done;
  1693. }
  1694. do {
  1695. RpcTryExcept {
  1696. if (pDriverInfo)
  1697. memset(pDriverInfo, 0, cbBuf);
  1698. if (!pEnvironment || !*pEnvironment)
  1699. pEnvironment = RunInWOW64() ? szIA64Environment : szEnvironment;
  1700. else if ( !lstrcmp(pEnvironment, cszWin95Environment) )
  1701. dwMajorVersionNeeded = dwMinorVersionNeeded = 0;
  1702. if (bLoadedBySpooler && fpYGetPrinterDriver2 && pSpool->hSplPrinter) {
  1703. ReturnValue = (*fpYGetPrinterDriver2)(pSpool->hSplPrinter,
  1704. pEnvironment,
  1705. Level, pDriverInfo, cbBuf,
  1706. pcbNeeded,
  1707. dwMajorVersionNeeded,
  1708. dwMinorVersionNeeded,
  1709. &dwServerMajorVersion,
  1710. &dwServerMinorVersion,
  1711. NATIVE_CALL
  1712. );
  1713. Route = NATIVE_CALL;
  1714. } else {
  1715. ReturnValue = RpcGetPrinterDriver2(pSpool->hPrinter,
  1716. pEnvironment,
  1717. Level, pDriverInfo, cbBuf,
  1718. pcbNeeded,
  1719. dwMajorVersionNeeded,
  1720. dwMinorVersionNeeded,
  1721. &dwServerMajorVersion,
  1722. &dwServerMinorVersion
  1723. );
  1724. Route = RPC_CALL;
  1725. }
  1726. if (ReturnValue) {
  1727. SetLastError(ReturnValue);
  1728. ReturnValue = FALSE;
  1729. } else {
  1730. ReturnValue = TRUE;
  1731. if (pDriverInfo) {
  1732. if (!MarshallUpStructure(pDriverInfo, pFieldInfo, cbStruct, Route))
  1733. {
  1734. ReturnValue = FALSE;
  1735. break;
  1736. }
  1737. }
  1738. }
  1739. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1740. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1741. ReturnValue = FALSE;
  1742. } RpcEndExcept
  1743. } while( !ReturnValue &&
  1744. GetLastError() == ERROR_INVALID_HANDLE &&
  1745. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  1746. RevalidateHandle( pSpool ));
  1747. Done:
  1748. vUnprotectHandle( hPrinter );
  1749. return ReturnValue;
  1750. }
  1751. BOOL
  1752. GetPrinterDriverDirectoryW(
  1753. LPWSTR pName,
  1754. LPWSTR pEnvironment,
  1755. DWORD Level,
  1756. LPBYTE pDriverDirectory,
  1757. DWORD cbBuf,
  1758. LPDWORD pcbNeeded
  1759. )
  1760. {
  1761. BOOL ReturnValue;
  1762. switch (Level) {
  1763. case 1:
  1764. break;
  1765. default:
  1766. SetLastError(ERROR_INVALID_LEVEL);
  1767. return FALSE;
  1768. }
  1769. RpcTryExcept {
  1770. if (!pEnvironment || !*pEnvironment)
  1771. pEnvironment = pEnvironment = RunInWOW64() ? szIA64Environment : szEnvironment;
  1772. if (bLoadedBySpooler && fpYGetPrinterDriverDirectory) {
  1773. ReturnValue = (*fpYGetPrinterDriverDirectory)(pName, pEnvironment,
  1774. Level,
  1775. pDriverDirectory,
  1776. cbBuf, pcbNeeded,
  1777. FALSE);
  1778. } else {
  1779. ReturnValue = RpcGetPrinterDriverDirectory(pName,
  1780. pEnvironment,
  1781. Level,
  1782. pDriverDirectory,
  1783. cbBuf, pcbNeeded);
  1784. }
  1785. if (ReturnValue) {
  1786. SetLastError(ReturnValue);
  1787. ReturnValue = FALSE;
  1788. } else {
  1789. ReturnValue = TRUE;
  1790. }
  1791. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1792. DWORD Error;
  1793. Error = TranslateExceptionCode(RpcExceptionCode());
  1794. if (Error == RPC_S_SERVER_UNAVAILABLE)
  1795. {
  1796. ReturnValue = BuildSpoolerObjectPath(gszPrinterDriversPath,
  1797. pName,
  1798. pEnvironment,
  1799. Level,
  1800. pDriverDirectory,
  1801. cbBuf,
  1802. pcbNeeded);
  1803. }
  1804. else
  1805. {
  1806. SetLastError(Error);
  1807. ReturnValue = FALSE;
  1808. }
  1809. } RpcEndExcept
  1810. return ReturnValue;
  1811. }
  1812. BOOL
  1813. DeletePrinterDriverExW(
  1814. LPWSTR pName,
  1815. LPWSTR pEnvironment,
  1816. LPWSTR pDriverName,
  1817. DWORD dwDeleteFlag,
  1818. DWORD dwVersionNum
  1819. )
  1820. {
  1821. BOOL ReturnValue;
  1822. if (!pDriverName || !*pDriverName) {
  1823. SetLastError(ERROR_INVALID_PARAMETER);
  1824. return (FALSE);
  1825. }
  1826. RpcTryExcept {
  1827. if (!pEnvironment || !*pEnvironment)
  1828. pEnvironment = szEnvironment;
  1829. if (ReturnValue = RpcDeletePrinterDriverEx(pName,
  1830. pEnvironment,
  1831. pDriverName,
  1832. dwDeleteFlag,
  1833. dwVersionNum)) {
  1834. SetLastError(ReturnValue);
  1835. ReturnValue = FALSE;
  1836. } else
  1837. ReturnValue = TRUE;
  1838. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1839. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1840. ReturnValue = FALSE;
  1841. } RpcEndExcept
  1842. return ReturnValue;
  1843. }
  1844. BOOL
  1845. DeletePrinterDriverW(
  1846. LPWSTR pName,
  1847. LPWSTR pEnvironment,
  1848. LPWSTR pDriverName
  1849. )
  1850. {
  1851. BOOL ReturnValue;
  1852. if (!pDriverName || !*pDriverName) {
  1853. SetLastError(ERROR_INVALID_PARAMETER);
  1854. return (FALSE);
  1855. }
  1856. RpcTryExcept {
  1857. if (!pEnvironment || !*pEnvironment)
  1858. pEnvironment = szEnvironment;
  1859. if (ReturnValue = RpcDeletePrinterDriver(pName,
  1860. pEnvironment,
  1861. pDriverName)) {
  1862. SetLastError(ReturnValue);
  1863. ReturnValue = FALSE;
  1864. } else
  1865. ReturnValue = TRUE;
  1866. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1867. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1868. ReturnValue = FALSE;
  1869. } RpcEndExcept
  1870. return ReturnValue;
  1871. }
  1872. BOOL
  1873. AddPerMachineConnectionW(
  1874. LPCWSTR pServer,
  1875. LPCWSTR pPrinterName,
  1876. LPCWSTR pPrintServer,
  1877. LPCWSTR pProvider
  1878. )
  1879. {
  1880. BOOL ReturnValue;
  1881. WCHAR DummyStr[] = L"";
  1882. if (!pPrinterName || !*pPrinterName) {
  1883. SetLastError(ERROR_INVALID_PARAMETER);
  1884. return FALSE;
  1885. }
  1886. if (!pPrintServer || !*pPrintServer) {
  1887. SetLastError(ERROR_INVALID_PARAMETER);
  1888. return FALSE;
  1889. }
  1890. // pProvider is an optional parameter and can be NULL. Since RPC does not
  1891. // accept NULL pointers we have to pass some dummy pointer to szNULL.
  1892. if (!pProvider) {
  1893. pProvider = (LPCWSTR) DummyStr;
  1894. }
  1895. RpcTryExcept {
  1896. if (ReturnValue = RpcAddPerMachineConnection((LPWSTR) pServer,
  1897. pPrinterName,
  1898. pPrintServer,
  1899. pProvider)) {
  1900. SetLastError(ReturnValue);
  1901. ReturnValue = FALSE;
  1902. } else
  1903. ReturnValue = TRUE;
  1904. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1905. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1906. ReturnValue = FALSE;
  1907. } RpcEndExcept
  1908. return ReturnValue;
  1909. }
  1910. BOOL
  1911. DeletePerMachineConnectionW(
  1912. LPCWSTR pServer,
  1913. LPCWSTR pPrinterName
  1914. )
  1915. {
  1916. BOOL ReturnValue;
  1917. if (!pPrinterName || !*pPrinterName) {
  1918. SetLastError(ERROR_INVALID_PARAMETER);
  1919. return (FALSE);
  1920. }
  1921. RpcTryExcept {
  1922. if (ReturnValue = RpcDeletePerMachineConnection((LPWSTR) pServer,
  1923. pPrinterName)) {
  1924. SetLastError(ReturnValue);
  1925. ReturnValue = FALSE;
  1926. } else
  1927. ReturnValue = TRUE;
  1928. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1929. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1930. ReturnValue = FALSE;
  1931. } RpcEndExcept
  1932. return ReturnValue;
  1933. }
  1934. BOOL
  1935. EnumPerMachineConnectionsW(
  1936. LPCWSTR pServer,
  1937. LPBYTE pPrinterEnum,
  1938. DWORD cbBuf,
  1939. LPDWORD pcbNeeded,
  1940. LPDWORD pcReturned
  1941. )
  1942. {
  1943. BOOL ReturnValue;
  1944. DWORD cbStruct, index;
  1945. FieldInfo *pFieldInfo;
  1946. pFieldInfo = PrinterInfo4Fields;
  1947. cbStruct = sizeof(PRINTER_INFO_4);
  1948. RpcTryExcept {
  1949. if (pPrinterEnum)
  1950. memset(pPrinterEnum, 0, cbBuf);
  1951. if (ReturnValue = RpcEnumPerMachineConnections((LPWSTR) pServer,
  1952. pPrinterEnum,
  1953. cbBuf,
  1954. pcbNeeded,
  1955. pcReturned)) {
  1956. SetLastError(ReturnValue);
  1957. ReturnValue = FALSE;
  1958. } else {
  1959. ReturnValue = TRUE;
  1960. if (pPrinterEnum) {
  1961. ReturnValue = MarshallUpStructuresArray(pPrinterEnum, *pcReturned, pFieldInfo, cbStruct, RPC_CALL);
  1962. }
  1963. }
  1964. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1965. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1966. ReturnValue = FALSE;
  1967. } RpcEndExcept
  1968. return ReturnValue;
  1969. }
  1970. BOOL
  1971. AddPrintProcessorW(
  1972. LPWSTR pName,
  1973. LPWSTR pEnvironment,
  1974. LPWSTR pPathName,
  1975. LPWSTR pPrintProcessorName
  1976. )
  1977. {
  1978. BOOL ReturnValue;
  1979. if (!pPrintProcessorName || !*pPrintProcessorName) {
  1980. SetLastError(ERROR_INVALID_PARAMETER);
  1981. return FALSE;
  1982. }
  1983. if (!pPathName || !*pPathName) {
  1984. SetLastError(ERROR_INVALID_PARAMETER);
  1985. return FALSE;
  1986. }
  1987. RpcTryExcept {
  1988. if (!pEnvironment || !*pEnvironment)
  1989. pEnvironment = szEnvironment;
  1990. if (ReturnValue = RpcAddPrintProcessor(pName, pEnvironment, pPathName,
  1991. pPrintProcessorName)) {
  1992. SetLastError(ReturnValue);
  1993. ReturnValue = FALSE;
  1994. } else
  1995. ReturnValue = TRUE;
  1996. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1997. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  1998. ReturnValue = FALSE;
  1999. } RpcEndExcept
  2000. return ReturnValue;
  2001. }
  2002. BOOL
  2003. EnumPrintProcessorsW(
  2004. LPWSTR pName,
  2005. LPWSTR pEnvironment,
  2006. DWORD Level,
  2007. LPBYTE pPrintProcessorInfo,
  2008. DWORD cbBuf,
  2009. LPDWORD pcbNeeded,
  2010. LPDWORD pcReturned
  2011. )
  2012. {
  2013. BOOL ReturnValue;
  2014. DWORD i, cbStruct;
  2015. FieldInfo *pFieldInfo;
  2016. switch (Level) {
  2017. case 1:
  2018. pFieldInfo = PrintProcessorInfo1Fields;
  2019. cbStruct = sizeof(PRINTPROCESSOR_INFO_1);
  2020. break;
  2021. default:
  2022. SetLastError(ERROR_INVALID_LEVEL);
  2023. return FALSE;
  2024. }
  2025. RpcTryExcept {
  2026. if (!pEnvironment || !*pEnvironment)
  2027. pEnvironment = szEnvironment;
  2028. if (ReturnValue = RpcEnumPrintProcessors(pName, pEnvironment, Level,
  2029. pPrintProcessorInfo, cbBuf,
  2030. pcbNeeded, pcReturned)) {
  2031. SetLastError(ReturnValue);
  2032. ReturnValue = FALSE;
  2033. } else {
  2034. ReturnValue = TRUE;
  2035. if (pPrintProcessorInfo) {
  2036. ReturnValue = MarshallUpStructuresArray(pPrintProcessorInfo, *pcReturned,
  2037. pFieldInfo, cbStruct, RPC_CALL);
  2038. }
  2039. }
  2040. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2041. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2042. ReturnValue = FALSE;
  2043. } RpcEndExcept
  2044. return ReturnValue;
  2045. }
  2046. BOOL
  2047. GetPrintProcessorDirectoryW(
  2048. LPWSTR pName,
  2049. LPWSTR pEnvironment,
  2050. DWORD Level,
  2051. LPBYTE pPrintProcessorInfo,
  2052. DWORD cbBuf,
  2053. LPDWORD pcbNeeded
  2054. )
  2055. {
  2056. BOOL ReturnValue;
  2057. switch (Level) {
  2058. case 1:
  2059. break;
  2060. default:
  2061. SetLastError(ERROR_INVALID_LEVEL);
  2062. return FALSE;
  2063. }
  2064. RpcTryExcept {
  2065. if (!pEnvironment || !*pEnvironment)
  2066. pEnvironment = pEnvironment = RunInWOW64() ? szIA64Environment : szEnvironment;
  2067. if (ReturnValue = RpcGetPrintProcessorDirectory(pName,
  2068. pEnvironment,
  2069. Level,
  2070. pPrintProcessorInfo,
  2071. cbBuf,
  2072. pcbNeeded)) {
  2073. SetLastError(ReturnValue);
  2074. ReturnValue = FALSE;
  2075. } else {
  2076. ReturnValue = TRUE;
  2077. }
  2078. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2079. DWORD Error;
  2080. Error = TranslateExceptionCode(RpcExceptionCode());
  2081. if (Error == RPC_S_SERVER_UNAVAILABLE)
  2082. {
  2083. ReturnValue = BuildSpoolerObjectPath(gszPrintProcessorsPath,
  2084. pName,
  2085. pEnvironment,
  2086. Level,
  2087. pPrintProcessorInfo,
  2088. cbBuf,
  2089. pcbNeeded);
  2090. }
  2091. else
  2092. {
  2093. SetLastError(Error);
  2094. ReturnValue = FALSE;
  2095. }
  2096. } RpcEndExcept
  2097. return ReturnValue;
  2098. }
  2099. BOOL
  2100. EnumPrintProcessorDatatypesW(
  2101. LPWSTR pName,
  2102. LPWSTR pPrintProcessorName,
  2103. DWORD Level,
  2104. LPBYTE pDatatypes,
  2105. DWORD cbBuf,
  2106. LPDWORD pcbNeeded,
  2107. LPDWORD pcReturned
  2108. )
  2109. {
  2110. BOOL ReturnValue;
  2111. DWORD i, cbStruct;
  2112. FieldInfo *pFieldInfo;
  2113. switch (Level) {
  2114. case 1:
  2115. pFieldInfo = PrintProcessorInfo1Fields;
  2116. cbStruct = sizeof(DATATYPES_INFO_1);
  2117. break;
  2118. default:
  2119. SetLastError(ERROR_INVALID_LEVEL);
  2120. return FALSE;
  2121. }
  2122. RpcTryExcept {
  2123. if (ReturnValue = RpcEnumPrintProcessorDatatypes(pName,
  2124. pPrintProcessorName,
  2125. Level,
  2126. pDatatypes,
  2127. cbBuf,
  2128. pcbNeeded,
  2129. pcReturned)) {
  2130. SetLastError(ReturnValue);
  2131. ReturnValue = FALSE;
  2132. } else {
  2133. ReturnValue = TRUE;
  2134. if (pDatatypes) {
  2135. ReturnValue = MarshallUpStructuresArray(pDatatypes, *pcReturned,
  2136. pFieldInfo, cbStruct, RPC_CALL);
  2137. }
  2138. }
  2139. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2140. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2141. ReturnValue = FALSE;
  2142. } RpcEndExcept
  2143. return ReturnValue;
  2144. }
  2145. DWORD
  2146. StartDocPrinterW(
  2147. HANDLE hPrinter,
  2148. DWORD Level,
  2149. LPBYTE pDocInfo
  2150. )
  2151. {
  2152. DWORD ReturnValue = 0;
  2153. BOOL EverythingWorked = FALSE;
  2154. BOOL PrintingToFile = FALSE;
  2155. PSPOOL pSpool = (PSPOOL)hPrinter;
  2156. PDOC_INFO_1 pDocInfo1 = NULL;
  2157. PDOC_INFO_3 pDocInfo3 = NULL;
  2158. LPBYTE pBuffer = NULL;
  2159. DWORD cbBuffer = MAX_STATIC_ALLOC;
  2160. DWORD cbNeeded;
  2161. BOOL bReturn;
  2162. if( eProtectHandle( hPrinter, FALSE )){
  2163. return FALSE;
  2164. }
  2165. if ( pSpool->Status & SPOOL_STATUS_STARTDOC ) {
  2166. SetLastError(ERROR_INVALID_PRINTER_STATE);
  2167. goto Done;
  2168. }
  2169. DBGMSG(DBG_TRACE,("Entered StartDocPrinterW client side hPrinter = %x\n", hPrinter));
  2170. // level 2 is supported on win95 and not on NT
  2171. switch (Level) {
  2172. case 1:
  2173. pDocInfo1 = (PDOC_INFO_1)pDocInfo;
  2174. break;
  2175. case 3:
  2176. pDocInfo1 = (PDOC_INFO_1)pDocInfo;
  2177. pDocInfo3 = (PDOC_INFO_3)pDocInfo;
  2178. break;
  2179. default:
  2180. SetLastError(ERROR_INVALID_LEVEL);
  2181. goto Done;
  2182. }
  2183. pBuffer = AllocSplMem(cbBuffer);
  2184. if (!pBuffer) {
  2185. goto Done;
  2186. }
  2187. try {
  2188. //
  2189. // Earlier on, if we had a non-null string, we assumed it to be
  2190. // printing to file. Print to file will not go thru the client-side
  2191. // optimization code. Now gdi is passing us pOutputFile name
  2192. // irrespective of whether it is file or not. We must determine if
  2193. // pOutputFile is really a file name
  2194. //
  2195. if (pDocInfo1->pOutputFile &&
  2196. (*(pDocInfo1->pOutputFile) != L'\0') &&
  2197. IsaFileName(pDocInfo1->pOutputFile, (LPWSTR)pBuffer, cbBuffer / sizeof(WCHAR))){
  2198. PrintingToFile = TRUE;
  2199. }
  2200. if (!PrintingToFile &&
  2201. !((Level == 3) && (pDocInfo3->dwFlags & DI_MEMORYMAP_WRITE)) &&
  2202. AddJobW(hPrinter, 1, pBuffer, cbBuffer, &cbNeeded)) {
  2203. PADDJOB_INFO_1 pAddJob = (PADDJOB_INFO_1)pBuffer;
  2204. pSpool->JobId = pAddJob->JobId;
  2205. pSpool->hFile = CreateFile(pAddJob->Path,
  2206. GENERIC_WRITE,
  2207. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2208. NULL,
  2209. CREATE_ALWAYS,
  2210. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  2211. NULL);
  2212. if (pSpool->hFile != INVALID_HANDLE_VALUE) {
  2213. if (pSpool->JobId == (DWORD)-1) {
  2214. IO_STATUS_BLOCK Iosb;
  2215. NTSTATUS Status;
  2216. QUERY_PRINT_JOB_INFO JobInfo;
  2217. Status = NtFsControlFile(pSpool->hFile, NULL, NULL, NULL,
  2218. &Iosb,
  2219. FSCTL_GET_PRINT_ID,
  2220. NULL, 0,
  2221. &JobInfo, sizeof(JobInfo));
  2222. if (NT_SUCCESS(Status)) {
  2223. pSpool->JobId = JobInfo.JobId;
  2224. }
  2225. }
  2226. ZeroMemory(pBuffer, cbBuffer);
  2227. if (!(bReturn = GetJob(hPrinter, pSpool->JobId, 1, pBuffer, cbBuffer, &cbNeeded))) {
  2228. if ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  2229. FreeSplMem(pBuffer) &&
  2230. (pBuffer = AllocSplMem(cbNeeded))) {
  2231. //
  2232. // Update the new size of our work buffer
  2233. //
  2234. cbBuffer = cbNeeded;
  2235. bReturn = GetJob(hPrinter, pSpool->JobId, 1, pBuffer, cbBuffer, &cbNeeded);
  2236. }
  2237. }
  2238. if (bReturn) {
  2239. PJOB_INFO_1 pJob = (PJOB_INFO_1)pBuffer;
  2240. pJob->pDocument = pDocInfo1->pDocName;
  2241. if (pDocInfo1->pDatatype) {
  2242. pJob->pDatatype = pDocInfo1->pDatatype;
  2243. }
  2244. pJob->Position = JOB_POSITION_UNSPECIFIED;
  2245. if (SetJob(hPrinter, pSpool->JobId,
  2246. 1, (LPBYTE)pJob, 0)) {
  2247. EverythingWorked = TRUE;
  2248. }
  2249. }
  2250. }
  2251. if (!PrintingToFile && !EverythingWorked) {
  2252. if (pSpool->hFile != INVALID_HANDLE_VALUE) {
  2253. if (CloseHandle(pSpool->hFile)) {
  2254. pSpool->hFile = INVALID_HANDLE_VALUE;
  2255. }
  2256. }
  2257. SetJob(hPrinter,pSpool->JobId, 0, NULL, JOB_CONTROL_CANCEL);
  2258. ScheduleJob(hPrinter, pSpool->JobId);
  2259. pSpool->JobId = 0;
  2260. }
  2261. }
  2262. if (EverythingWorked) {
  2263. ReturnValue = pSpool->JobId;
  2264. } else {
  2265. UINT cRetry = 0;
  2266. //
  2267. // If it's invalid datatype, fail immediately instead of trying
  2268. // StartDocPrinter.
  2269. //
  2270. if( GetLastError() == ERROR_INVALID_DATATYPE ){
  2271. ReturnValue = 0;
  2272. } else {
  2273. GENERIC_CONTAINER DocInfoContainer;
  2274. DWORD JobId;
  2275. pSpool->hFile = INVALID_HANDLE_VALUE;
  2276. pSpool->JobId = 0;
  2277. // Level 3 data is required only on the client
  2278. DocInfoContainer.Level = 1;
  2279. DocInfoContainer.pData = pDocInfo;
  2280. do {
  2281. RpcTryExcept {
  2282. if (ReturnValue = RpcStartDocPrinter(
  2283. pSpool->hPrinter,
  2284. (LPDOC_INFO_CONTAINER)&DocInfoContainer,
  2285. &JobId)) {
  2286. SetLastError(ReturnValue);
  2287. ReturnValue = 0;
  2288. } else
  2289. ReturnValue = JobId;
  2290. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2291. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2292. ReturnValue = 0;
  2293. } RpcEndExcept
  2294. } while( !ReturnValue &&
  2295. GetLastError() == ERROR_INVALID_HANDLE &&
  2296. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  2297. RevalidateHandle( pSpool ));
  2298. }
  2299. }
  2300. if (ReturnValue) {
  2301. pSpool->Status |= SPOOL_STATUS_STARTDOC;
  2302. }
  2303. //
  2304. // If the tray icon has not been notified, then do so now. Set
  2305. // the flag so that we won't call it multiple times.
  2306. //
  2307. if( ReturnValue && !( pSpool->Status & SPOOL_STATUS_TRAYICON_NOTIFIED )){
  2308. vUpdateTrayIcon( hPrinter, ReturnValue );
  2309. }
  2310. } except (1) {
  2311. SetLastError(TranslateExceptionCode(GetExceptionCode()));
  2312. ReturnValue = 0;
  2313. }
  2314. Done:
  2315. FreeSplMem(pBuffer);
  2316. vUnprotectHandle( hPrinter );
  2317. return ReturnValue;
  2318. }
  2319. BOOL
  2320. StartPagePrinter(
  2321. HANDLE hPrinter
  2322. )
  2323. {
  2324. BOOL ReturnValue;
  2325. PSPOOL pSpool = (PSPOOL)hPrinter;
  2326. if( eProtectHandle( hPrinter, FALSE )){
  2327. return FALSE;
  2328. }
  2329. try {
  2330. FlushBuffer(pSpool, NULL);
  2331. RpcTryExcept {
  2332. if (ReturnValue = RpcStartPagePrinter(pSpool->hPrinter)) {
  2333. SetLastError(ReturnValue);
  2334. ReturnValue = FALSE;
  2335. } else
  2336. ReturnValue = TRUE;
  2337. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2338. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2339. ReturnValue = FALSE;
  2340. } RpcEndExcept
  2341. } except (1) {
  2342. SetLastError(ERROR_INVALID_HANDLE);
  2343. ReturnValue = FALSE;
  2344. }
  2345. vUnprotectHandle( hPrinter );
  2346. return ReturnValue;
  2347. }
  2348. BOOL
  2349. FlushBuffer(
  2350. PSPOOL pSpool,
  2351. PDWORD pcbWritten
  2352. )
  2353. {
  2354. DWORD ReturnValue = TRUE;
  2355. DWORD cbWritten = 0;
  2356. SPLASSERT (pSpool != NULL);
  2357. SPLASSERT (pSpool->signature == SP_SIGNATURE);
  2358. DBGMSG(DBG_TRACE, ("FlushBuffer - pSpool %x\n",pSpool));
  2359. if (pSpool->cbBuffer) {
  2360. SPLASSERT(pSpool->pBuffer != NULL);
  2361. DBGMSG(DBG_TRACE, ("FlushBuffer - Number Cached WritePrinters before Flush %d\n", pSpool->cCacheWrite));
  2362. pSpool->cCacheWrite = 0;
  2363. pSpool->cFlushBuffers++;
  2364. if (pSpool->hFile != INVALID_HANDLE_VALUE) {
  2365. // FileIO
  2366. ReturnValue = WriteFile( pSpool->hFile,
  2367. pSpool->pBuffer,
  2368. pSpool->cbBuffer,
  2369. &cbWritten, NULL);
  2370. DBGMSG(DBG_TRACE, ("FlushBuffer - WriteFile pSpool %x hFile %x pBuffer %x cbBuffer %d cbWritten %d\n",
  2371. pSpool, pSpool->hFile, pSpool->pBuffer, pSpool->cbBuffer, cbWritten));
  2372. } else {
  2373. // RPC IO
  2374. RpcTryExcept {
  2375. if (bLoadedBySpooler && fpYWritePrinter && pSpool->hSplPrinter) {
  2376. ReturnValue = (*fpYWritePrinter)(pSpool->hSplPrinter,
  2377. pSpool->pBuffer,
  2378. pSpool->cbBuffer,
  2379. &cbWritten,
  2380. FALSE);
  2381. } else {
  2382. ReturnValue = RpcWritePrinter(pSpool->hPrinter,
  2383. pSpool->pBuffer,
  2384. pSpool->cbBuffer,
  2385. &cbWritten);
  2386. }
  2387. if (ReturnValue) {
  2388. SetLastError(ReturnValue);
  2389. ReturnValue = FALSE;
  2390. DBGMSG(DBG_WARNING, ("FlushBuffer - RpcWritePrinter Failed Error %d\n",GetLastError() ));
  2391. } else {
  2392. ReturnValue = TRUE;
  2393. DBGMSG(DBG_TRACE, ("FlushBuffer - RpcWritePrinter Success hPrinter %x pBuffer %x cbBuffer %x cbWritten %x\n",
  2394. pSpool->hPrinter, pSpool->pBuffer,
  2395. pSpool->cbBuffer, cbWritten));
  2396. }
  2397. //
  2398. // This routine seems messed up.
  2399. // If it doesn't flush the entire buffer, it apparently still
  2400. // returns TRUE. It correctly updates the buffer pointers
  2401. // so it doesn't send duplicate information, but it
  2402. // doesn't send back bytes written. When WritePrinter
  2403. // sees success, it assumes that all bytes have been written.
  2404. //
  2405. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2406. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2407. ReturnValue = FALSE;
  2408. DBGMSG(DBG_WARNING, ("RpcWritePrinter Exception Error %d\n",GetLastError()));
  2409. } RpcEndExcept
  2410. }
  2411. //
  2412. // We have sent more data to the printer. If we had any bytes
  2413. // from the previous write, we have just sent part of them to the
  2414. // printer. Update the cbFlushPending count to reflect the
  2415. // sent bytes. cbWritten may be > cbFlushPending, since we
  2416. // may have sent new bytes too.
  2417. //
  2418. if (pSpool->cbFlushPending < cbWritten) {
  2419. pSpool->cbFlushPending = 0;
  2420. } else {
  2421. pSpool->cbFlushPending -= cbWritten;
  2422. }
  2423. if (pSpool->cbBuffer <= cbWritten) {
  2424. if ( pSpool->cbBuffer < cbWritten) {
  2425. DBGMSG( DBG_WARNING, ("FlushBuffer cbBuffer %d < cbWritten %d ReturnValue %x LastError %d\n",
  2426. pSpool->cbBuffer, cbWritten, ReturnValue, GetLastError() ));
  2427. }
  2428. // Successful IO
  2429. // Empty the cache buffer count
  2430. pSpool->cbBuffer = 0;
  2431. } else if ( cbWritten != 0 ) {
  2432. // Partial IO
  2433. // Adjust the buffer so it contains the data that was not
  2434. // written
  2435. SPLASSERT(pSpool->cbBuffer <= BUFFER_SIZE);
  2436. SPLASSERT(cbWritten <= BUFFER_SIZE);
  2437. SPLASSERT(pSpool->cbBuffer >= cbWritten);
  2438. DBGMSG(DBG_WARNING, ("Partial IO adjusting buffer data\n"));
  2439. MoveMemory(pSpool->pBuffer,
  2440. pSpool->pBuffer + cbWritten,
  2441. BUFFER_SIZE - cbWritten);
  2442. pSpool->cbBuffer -= cbWritten;
  2443. }
  2444. }
  2445. DBGMSG(DBG_TRACE, ("FlushBuffer returns %d\n",ReturnValue));
  2446. if (pcbWritten) {
  2447. *pcbWritten = cbWritten;
  2448. }
  2449. if(!pSpool->cOKFlushBuffers &&
  2450. ReturnValue &&
  2451. cbWritten)
  2452. {
  2453. pSpool->cOKFlushBuffers=1;
  2454. }
  2455. return ReturnValue;
  2456. }
  2457. BOOL
  2458. SeekPrinter(
  2459. HANDLE hPrinter,
  2460. LARGE_INTEGER liDistanceToMove,
  2461. PLARGE_INTEGER pliNewPointer,
  2462. DWORD dwMoveMethod,
  2463. BOOL bWritePrinter
  2464. )
  2465. {
  2466. DWORD dwReturnValue;
  2467. BOOL bReturnValue = FALSE;
  2468. PSPOOL pSpool = (PSPOOL)hPrinter;
  2469. LARGE_INTEGER liUnused;
  2470. if( eProtectHandle( hPrinter, FALSE )){
  2471. return FALSE;
  2472. }
  2473. if( !pliNewPointer ){
  2474. pliNewPointer = &liUnused;
  2475. }
  2476. RpcTryExcept {
  2477. if (bLoadedBySpooler && fpYSeekPrinter && pSpool->hSplPrinter) {
  2478. dwReturnValue = (*fpYSeekPrinter)( pSpool->hSplPrinter,
  2479. liDistanceToMove,
  2480. pliNewPointer,
  2481. dwMoveMethod,
  2482. bWritePrinter,
  2483. FALSE );
  2484. } else {
  2485. dwReturnValue = RpcSeekPrinter( pSpool->hPrinter,
  2486. liDistanceToMove,
  2487. pliNewPointer,
  2488. dwMoveMethod,
  2489. bWritePrinter );
  2490. }
  2491. if( dwReturnValue == ERROR_SUCCESS ){
  2492. bReturnValue = TRUE;
  2493. } else {
  2494. SetLastError( dwReturnValue );
  2495. }
  2496. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2497. SetLastError(RpcExceptionCode());
  2498. } RpcEndExcept
  2499. vUnprotectHandle( hPrinter );
  2500. return bReturnValue;
  2501. }
  2502. BOOL
  2503. FlushPrinter(
  2504. HANDLE hPrinter,
  2505. LPVOID pBuf,
  2506. DWORD cbBuf,
  2507. LPDWORD pcWritten,
  2508. DWORD cSleep
  2509. )
  2510. /*++
  2511. Function Description: FlushPrinter is typically used by the driver to send a burst of zeros
  2512. to the printer and introduce a delay in the i/o line to the printer.
  2513. The spooler does not schedule any job for cSleep milliseconds.
  2514. Parameters: hPrinter - printer handle
  2515. pBuf - buffer to be sent to the printer
  2516. cbBuf - size of the buffer
  2517. pcWritten - pointer to return the number of bytes written
  2518. cSleep - sleep time in milliseconds.
  2519. Return Values: TRUE if successful;
  2520. FALSE otherwise
  2521. --*/
  2522. {
  2523. DWORD dwError, cWritten, Buffer;
  2524. BOOL bReturn = FALSE;
  2525. PSPOOL pSpool = (PSPOOL)hPrinter;
  2526. if (eProtectHandle( hPrinter, FALSE ))
  2527. {
  2528. return FALSE;
  2529. }
  2530. //
  2531. // In case the job was canceled or a printer failure
  2532. // occured before priting any part of the document, we
  2533. // just short circuit and return to prevent any unnecessary
  2534. // delays in returning to the caller.
  2535. //
  2536. if (!pSpool->cOKFlushBuffers)
  2537. {
  2538. bReturn = TRUE;
  2539. goto Done;
  2540. }
  2541. //
  2542. // Use temp variables since RPC does not take NULL pointers
  2543. //
  2544. if (!pcWritten)
  2545. {
  2546. pcWritten = &cWritten;
  2547. }
  2548. if (!pBuf)
  2549. {
  2550. if (cbBuf == 0)
  2551. {
  2552. pBuf = (LPVOID) &Buffer;
  2553. }
  2554. else
  2555. {
  2556. SetLastError(ERROR_INVALID_PARAMETER);
  2557. goto Done;
  2558. }
  2559. }
  2560. //
  2561. // Rpc to the spooler
  2562. //
  2563. RpcTryExcept {
  2564. if(bLoadedBySpooler && fpYFlushPrinter && pSpool->hSplPrinter)
  2565. {
  2566. dwError = (*fpYFlushPrinter)(pSpool->hSplPrinter,
  2567. pBuf,
  2568. cbBuf,
  2569. pcWritten,
  2570. cSleep,
  2571. FALSE);
  2572. }
  2573. else
  2574. {
  2575. dwError = RpcFlushPrinter( pSpool->hPrinter,
  2576. pBuf,
  2577. cbBuf,
  2578. pcWritten,
  2579. cSleep );
  2580. }
  2581. if (dwError == ERROR_SUCCESS)
  2582. {
  2583. bReturn = TRUE;
  2584. }
  2585. else
  2586. {
  2587. SetLastError( dwError );
  2588. }
  2589. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2590. SetLastError(RpcExceptionCode());
  2591. } RpcEndExcept
  2592. Done:
  2593. vUnprotectHandle( hPrinter );
  2594. return bReturn;
  2595. }
  2596. BOOL
  2597. WritePrinter(
  2598. HANDLE hPrinter,
  2599. LPVOID pBuf,
  2600. DWORD cbBuf,
  2601. LPDWORD pcWritten
  2602. )
  2603. {
  2604. BOOL ReturnValue=TRUE, bAllocBuffer = FALSE;
  2605. BYTE btBuffer[MAX_STATIC_ALLOC];
  2606. DWORD cb;
  2607. DWORD cbWritten = 0;
  2608. DWORD cTotalWritten = 0;
  2609. LPBYTE pBuffer = pBuf;
  2610. LPBYTE pInitialBuf = pBuf;
  2611. PSPOOL pSpool = (PSPOOL)hPrinter;
  2612. PJOB_INFO_1 pJob;
  2613. DWORD cbNeeded;
  2614. DWORD dwTickCount, dwTickCount1;
  2615. DWORD FlushPendingDataSize;
  2616. DWORD ReqTotalDataSize;
  2617. DWORD ReqToWriteDataSize = cbBuf;
  2618. DWORD NumOfCmpltWrts = 0;
  2619. DBGMSG(DBG_TRACE, ("WritePrinter - hPrinter %x pBuf %x cbBuf %d pcWritten %x\n",
  2620. hPrinter, pBuf, cbBuf, pcWritten));
  2621. if( eProtectHandle( hPrinter, FALSE ))
  2622. {
  2623. return FALSE;
  2624. }
  2625. if (pSpool && pSpool->Flushed)
  2626. {
  2627. ReturnValue = FALSE;
  2628. goto EndWritePrinter;
  2629. }
  2630. FlushPendingDataSize = pSpool->cbFlushPending;
  2631. ReqTotalDataSize = FlushPendingDataSize + ReqToWriteDataSize;
  2632. *pcWritten = 0;
  2633. if ( !(pSpool->Status & SPOOL_STATUS_STARTDOC) ) {
  2634. SetLastError(ERROR_SPL_NO_STARTDOC);
  2635. ReturnValue = FALSE;
  2636. goto EndWritePrinter;
  2637. }
  2638. // Check if local job is cancelled every JOB_CANCEL_CHECK_INTERVAL bytes
  2639. if (!pSpool->cWritePrinters) {
  2640. pSpool->dwTickCount = GetTickCount();
  2641. pSpool->dwCheckJobInterval = JOB_CANCEL_CHECK_INTERVAL;
  2642. }
  2643. if (pSpool->hFile != INVALID_HANDLE_VALUE &&
  2644. pSpool->dwTickCount + pSpool->dwCheckJobInterval < (dwTickCount = GetTickCount())) {
  2645. bAllocBuffer = FALSE;
  2646. pJob = (PJOB_INFO_1) btBuffer;
  2647. ZeroMemory(pJob, MAX_STATIC_ALLOC);
  2648. ReturnValue = GetJob((HANDLE) pSpool, pSpool->JobId, 1, (LPBYTE)pJob,
  2649. MAX_STATIC_ALLOC, &cbNeeded);
  2650. if (!ReturnValue &&
  2651. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  2652. (pJob = (PJOB_INFO_1) AllocSplMem(cbNeeded))) {
  2653. bAllocBuffer = TRUE;
  2654. ReturnValue = GetJob(hPrinter, pSpool->JobId, 1, (LPBYTE)pJob,
  2655. cbNeeded, &cbNeeded);
  2656. }
  2657. if (ReturnValue) {
  2658. // Don't allow GetJob calls to take more than 1% pSpool->dwCheckJobInterval
  2659. dwTickCount1 = GetTickCount();
  2660. if (dwTickCount1 > dwTickCount + (pSpool->dwCheckJobInterval/100)) {
  2661. pSpool->dwCheckJobInterval *= 2;
  2662. } else if (dwTickCount1 - dwTickCount < JOB_CANCEL_CHECK_INTERVAL/100) {
  2663. pSpool->dwCheckJobInterval = JOB_CANCEL_CHECK_INTERVAL;
  2664. }
  2665. if (!pJob->pStatus && (pJob->Status & JOB_STATUS_DELETING)) {
  2666. SetLastError(ERROR_PRINT_CANCELLED);
  2667. if (bAllocBuffer) {
  2668. FreeSplMem(pJob);
  2669. }
  2670. ReturnValue = FALSE;
  2671. goto EndWritePrinter;
  2672. }
  2673. }
  2674. if (bAllocBuffer) {
  2675. FreeSplMem(pJob);
  2676. }
  2677. pSpool->dwTickCount = GetTickCount();
  2678. }
  2679. pSpool->cWritePrinters++;
  2680. // WritePrinter will cache on the client side all IO's
  2681. // into BUFFER_SIZE writes. This is done to minimize
  2682. // the number of RPC calls if the app is doing a lot of small
  2683. // sized IO's.
  2684. while (cbBuf && ReturnValue) {
  2685. // Special Case FileIO's since file system prefers large
  2686. // writes, RPC is optimal with smaller writes.
  2687. //
  2688. // RPC should manage its own buffer size. I'm not sure why we
  2689. // only do this optimization for file writes.
  2690. //
  2691. if ((pSpool->hFile != INVALID_HANDLE_VALUE) &&
  2692. (pSpool->cbBuffer == 0) &&
  2693. (cbBuf > BUFFER_SIZE)) {
  2694. ReturnValue = WriteFile(pSpool->hFile, pBuffer, cbBuf, &cbWritten, NULL);
  2695. DBGMSG(DBG_TRACE, ("WritePrinter - WriteFile pSpool %x hFile %x pBuffer %x cbBuffer %d cbWritten %d\n",
  2696. pSpool, pSpool->hFile, pBuffer, pSpool->cbBuffer, *pcWritten));
  2697. } else {
  2698. // Fill cache buffer so IO is optimal size.
  2699. SPLASSERT(pSpool->cbBuffer <= BUFFER_SIZE);
  2700. //
  2701. // cb is the amount of new data we want to put in the buffer.
  2702. // It is the min of the space remaining, and the size of the
  2703. // input buffer.
  2704. //
  2705. cb = min((BUFFER_SIZE - pSpool->cbBuffer), cbBuf);
  2706. if (cb != 0) {
  2707. if (pSpool->pBuffer == NULL) {
  2708. pSpool->pBuffer = VirtualAlloc(NULL, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE);
  2709. if (pSpool->pBuffer == NULL) {
  2710. DBGMSG(DBG_WARNING, ("VirtualAlloc Failed to allocate 4k buffer %d\n",GetLastError()));
  2711. ReturnValue = FALSE;
  2712. goto EndWritePrinter;
  2713. }
  2714. }
  2715. CopyMemory( pSpool->pBuffer + pSpool->cbBuffer, pBuffer, cb);
  2716. pSpool->cbBuffer += cb;
  2717. cbWritten = cb;
  2718. pSpool->cCacheWrite++;
  2719. }
  2720. //
  2721. // cbWritten is the amount of new data that has been put into
  2722. // the buffer. It may not have been written to the device, but
  2723. // since it is in our buffer, the driver can assume it has been
  2724. // written (e.g., the *pcbWritten out parameter to WritePrinter
  2725. // includes this data).
  2726. //
  2727. if (pSpool->cbBuffer == BUFFER_SIZE)
  2728. {
  2729. DWORD cbPending = pSpool->cbFlushPending;
  2730. DWORD cbFlushed = 0;
  2731. ReturnValue = FlushBuffer(pSpool, &cbFlushed);
  2732. if(!NumOfCmpltWrts && ReturnValue)
  2733. {
  2734. NumOfCmpltWrts = 1;
  2735. }
  2736. if(!ReturnValue &&
  2737. (ERROR_PRINT_CANCELLED == GetLastError()) &&
  2738. pSpool->hSplPrinter &&
  2739. pSpool->cOKFlushBuffers)
  2740. {
  2741. SJobCancelInfo JobCancelInfo;
  2742. JobCancelInfo.pSpool = pSpool;
  2743. JobCancelInfo.pInitialBuf = pInitialBuf;
  2744. JobCancelInfo.pcbWritten = &cbWritten;
  2745. JobCancelInfo.pcTotalWritten = &cTotalWritten;
  2746. JobCancelInfo.NumOfCmpltWrts = NumOfCmpltWrts;
  2747. JobCancelInfo.cbFlushed = cbFlushed;
  2748. JobCancelInfo.ReqTotalDataSize = ReqTotalDataSize;
  2749. JobCancelInfo.ReqToWriteDataSize = ReqToWriteDataSize;
  2750. JobCancelInfo.FlushPendingDataSize = FlushPendingDataSize;
  2751. JobCancelInfo.ReturnValue = ReturnValue;
  2752. ReturnValue = JobCanceled(&JobCancelInfo);
  2753. }
  2754. }
  2755. }
  2756. // Update Total Byte Count after the Flush or File IO
  2757. // This is done because the IO might fail and thus
  2758. // the correct value written might have changed.
  2759. if(!pSpool->Flushed)
  2760. {
  2761. SPLASSERT(cbBuf >= cbWritten);
  2762. cbBuf -= cbWritten;
  2763. pBuffer += cbWritten;
  2764. cTotalWritten += cbWritten;
  2765. }
  2766. else
  2767. break;
  2768. }
  2769. // Return the number of bytes written.
  2770. *pcWritten = cTotalWritten;
  2771. DBGMSG(DBG_TRACE, ("WritePrinter cbWritten %d ReturnValue %d\n",*pcWritten, ReturnValue));
  2772. //
  2773. // Remember if there is a flush pending on this WritePrinter. If there
  2774. // is, then when we return, we say we've written all the bytes, but
  2775. // we really haven't since there's some left in the buffer. If the
  2776. // user cancels the next job, then we need to flush out the last
  2777. // bytes, since the driver assumes that we've written it out and
  2778. // tracks the printer state.
  2779. //
  2780. if(!pSpool->Flushed)
  2781. pSpool->cbFlushPending = pSpool->cbBuffer;
  2782. EndWritePrinter:
  2783. vUnprotectHandle( hPrinter );
  2784. return ReturnValue;
  2785. }
  2786. BOOL
  2787. EndPagePrinter(
  2788. HANDLE hPrinter
  2789. )
  2790. {
  2791. BOOL ReturnValue = TRUE;
  2792. PSPOOL pSpool = (PSPOOL)hPrinter;
  2793. if( eProtectHandle( hPrinter, FALSE )){
  2794. return FALSE;
  2795. }
  2796. try {
  2797. FlushBuffer(pSpool, NULL);
  2798. if( pSpool->hFile == INVALID_HANDLE_VALUE ){
  2799. RpcTryExcept {
  2800. if (ReturnValue = RpcEndPagePrinter(pSpool->hPrinter)) {
  2801. SetLastError(ReturnValue);
  2802. ReturnValue = FALSE;
  2803. } else
  2804. ReturnValue = TRUE;
  2805. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2806. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2807. ReturnValue = FALSE;
  2808. } RpcEndExcept
  2809. }
  2810. } except (1) {
  2811. SetLastError(ERROR_INVALID_HANDLE);
  2812. ReturnValue = FALSE;
  2813. }
  2814. vUnprotectHandle( hPrinter );
  2815. return ReturnValue;
  2816. }
  2817. BOOL
  2818. AbortPrinter(
  2819. HANDLE hPrinter
  2820. )
  2821. {
  2822. BOOL ReturnValue;
  2823. PSPOOL pSpool = (PSPOOL)hPrinter;
  2824. DWORD dwNumWritten = 0;
  2825. DWORD dwPointer = 0;
  2826. if( eProtectHandle( hPrinter, FALSE )){
  2827. return FALSE;
  2828. }
  2829. //
  2830. // No longer in StartDoc mode; also resetting the tray icon notification
  2831. // flag so that upcoming StartDocPrinter/AddJobs indicate a new job.
  2832. //
  2833. pSpool->Status &= ~(SPOOL_STATUS_STARTDOC|SPOOL_STATUS_TRAYICON_NOTIFIED);
  2834. if (pSpool->hFile != INVALID_HANDLE_VALUE) {
  2835. if (pSpool->Status & SPOOL_STATUS_ADDJOB) {
  2836. // Close your handle to the .SPL file, otherwise the
  2837. // DeleteJob will fail in the Spooler
  2838. CloseSpoolFileHandles( pSpool );
  2839. if (!SetJob(hPrinter,pSpool->JobId, 0, NULL, JOB_CONTROL_DELETE)) {
  2840. DBGMSG(DBG_WARNING, ("Error: SetJob cancel returned failure with %d\n", GetLastError()));
  2841. }
  2842. ReturnValue = ScheduleJob(hPrinter, pSpool->JobId);
  2843. goto Done;
  2844. } else {
  2845. DBGMSG(DBG_WARNING, ("Error: pSpool->hFile != INVALID_HANDLE_VALUE and pSpool's status is not SPOOL_STATUS_ADDJOB\n"));
  2846. }
  2847. }
  2848. RpcTryExcept {
  2849. if (ReturnValue = RpcAbortPrinter(pSpool->hPrinter)) {
  2850. SetLastError(ReturnValue);
  2851. ReturnValue = FALSE;
  2852. } else
  2853. ReturnValue = TRUE;
  2854. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2855. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2856. ReturnValue = FALSE;
  2857. } RpcEndExcept
  2858. Done:
  2859. vUnprotectHandle( hPrinter );
  2860. return ReturnValue;
  2861. }
  2862. BOOL
  2863. ReadPrinter(
  2864. HANDLE hPrinter,
  2865. LPVOID pBuf,
  2866. DWORD cbBuf,
  2867. LPDWORD pNoBytesRead
  2868. )
  2869. {
  2870. BOOL bReturn = FALSE;
  2871. DWORD dwStatus;
  2872. PSPOOL pSpool = (PSPOOL)hPrinter;
  2873. if( eProtectHandle( hPrinter, FALSE )){
  2874. return FALSE;
  2875. }
  2876. FlushBuffer(pSpool, NULL);
  2877. if (pSpool->hFile != INVALID_HANDLE_VALUE) {
  2878. SetLastError(ERROR_INVALID_HANDLE);
  2879. goto Done;
  2880. }
  2881. RpcTryExcept {
  2882. cbBuf = min(BUFFER_SIZE, cbBuf);
  2883. if (bLoadedBySpooler && fpYReadPrinter && pSpool->hSplPrinter) {
  2884. dwStatus = (*fpYReadPrinter)(pSpool->hSplPrinter, pBuf, cbBuf, pNoBytesRead, FALSE);
  2885. } else {
  2886. dwStatus = RpcReadPrinter(pSpool->hPrinter, pBuf, cbBuf, pNoBytesRead);
  2887. }
  2888. if (dwStatus) {
  2889. SetLastError(dwStatus);
  2890. } else {
  2891. bReturn = TRUE;
  2892. }
  2893. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2894. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  2895. } RpcEndExcept
  2896. Done:
  2897. vUnprotectHandle( hPrinter );
  2898. return bReturn;
  2899. }
  2900. BOOL
  2901. SplReadPrinter(
  2902. HANDLE hPrinter,
  2903. LPBYTE *pBuf,
  2904. DWORD cbBuf
  2905. )
  2906. /*++
  2907. Function Description: This is an internal function used by the spooler during playback of
  2908. EMF jobs. It is called from gdi32.dll. SplReadPrinter is equivalent
  2909. to ReadPrinter in all respects except that it returns a pointer to the
  2910. buffer in pBuf. The spool file is memory mapped.
  2911. Parameters: hPrinter -- handle to the printer
  2912. pBuf -- pointer to the buffer
  2913. cbBuf -- number to bytes to read
  2914. Return Values: TRUE if sucessful (pBuf contains the required pointer)
  2915. FALSE otherwise
  2916. --*/
  2917. {
  2918. BOOL bReturn = FALSE;
  2919. DWORD dwStatus = 0;
  2920. PSPOOL pSpool = (PSPOOL)hPrinter;
  2921. if( eProtectHandle( hPrinter, FALSE )){
  2922. return FALSE;
  2923. }
  2924. // This function is to be used only internally. Hence no RPC interface is required.
  2925. if (!bLoadedBySpooler || !fpYSplReadPrinter || !pSpool->hSplPrinter) {
  2926. SetLastError(ERROR_NOT_SUPPORTED);
  2927. goto Done;
  2928. }
  2929. FlushBuffer(pSpool, NULL);
  2930. if (pSpool->hFile != INVALID_HANDLE_VALUE) {
  2931. SetLastError(ERROR_INVALID_HANDLE);
  2932. goto Done;
  2933. }
  2934. // Optimal buffer size of 4K need not be used for non RPC code paths.
  2935. dwStatus = (*fpYSplReadPrinter)(pSpool->hSplPrinter, pBuf, cbBuf, FALSE);
  2936. if (dwStatus) {
  2937. SetLastError(dwStatus);
  2938. } else {
  2939. bReturn = TRUE;
  2940. }
  2941. Done:
  2942. vUnprotectHandle( hPrinter );
  2943. return bReturn;
  2944. }
  2945. BOOL
  2946. EndDocPrinter(
  2947. HANDLE hPrinter
  2948. )
  2949. {
  2950. BOOL ReturnValue;
  2951. PSPOOL pSpool = (PSPOOL)hPrinter;
  2952. DWORD dwRetryTimes;
  2953. DWORD dwNeeded;
  2954. USEROBJECTFLAGS uof;
  2955. if( eProtectHandle( hPrinter, FALSE )){
  2956. return FALSE;
  2957. }
  2958. if (GetUserObjectInformation(GetProcessWindowStation(), UOI_FLAGS, &uof, sizeof(uof), &dwNeeded) && (WSF_VISIBLE & uof.dwFlags)) {
  2959. //
  2960. // hack: if we are in interactive window station (i.e. not in a service)
  2961. // we need to wait the tray code to startup, so we don't miss balloon
  2962. // notifications. there is still possibility of missing balloon notifications
  2963. // but very unlikely. the complete fix will come with CSR in place (i.e. in
  2964. // Blackcomb)
  2965. //
  2966. dwRetryTimes = 20;
  2967. while (dwRetryTimes--){
  2968. if (NULL == FindWindow(cszTrayListenerClassName, NULL)){
  2969. Sleep(100);
  2970. continue;
  2971. }
  2972. Sleep(100);
  2973. break;
  2974. }
  2975. }
  2976. try {
  2977. FlushBuffer(pSpool, NULL);
  2978. //
  2979. // No longer in StartDoc mode; also resetting the tray icon
  2980. // notification flag so that upcoming StartDocPrinter/AddJobs
  2981. // indicate a new job.
  2982. //
  2983. pSpool->Status &= ~(SPOOL_STATUS_STARTDOC|SPOOL_STATUS_TRAYICON_NOTIFIED);
  2984. if (pSpool->hFile != INVALID_HANDLE_VALUE) {
  2985. if (CloseHandle(pSpool->hFile)) {
  2986. pSpool->hFile = INVALID_HANDLE_VALUE;
  2987. }
  2988. ReturnValue = ScheduleJob(hPrinter, pSpool->JobId);
  2989. pSpool->Status &= ~SPOOL_STATUS_ADDJOB;
  2990. DBGMSG(DBG_TRACE, ("Exit EndDocPrinter - client side hPrinter %x\n", hPrinter));
  2991. } else {
  2992. RpcTryExcept {
  2993. if(bLoadedBySpooler && fpYEndDocPrinter && pSpool->hSplPrinter)
  2994. {
  2995. ReturnValue = (*fpYEndDocPrinter)(pSpool->hSplPrinter,FALSE);
  2996. }
  2997. else
  2998. {
  2999. ReturnValue = RpcEndDocPrinter(pSpool->hPrinter);
  3000. }
  3001. if (ReturnValue)
  3002. {
  3003. SetLastError(ReturnValue);
  3004. ReturnValue = FALSE;
  3005. }
  3006. else
  3007. ReturnValue = TRUE;
  3008. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3009. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  3010. ReturnValue = FALSE;
  3011. } RpcEndExcept
  3012. DBGMSG(DBG_TRACE, ("Exit EndDocPrinter - client side hPrinter %x\n", hPrinter));
  3013. }
  3014. } except (1) {
  3015. SetLastError(ERROR_INVALID_HANDLE);
  3016. ReturnValue = FALSE;
  3017. }
  3018. vUnprotectHandle( hPrinter );
  3019. return ReturnValue;
  3020. }
  3021. BOOL
  3022. AddJobW(
  3023. HANDLE hPrinter,
  3024. DWORD Level,
  3025. LPBYTE pData,
  3026. DWORD cbBuf,
  3027. LPDWORD pcbNeeded
  3028. )
  3029. {
  3030. BOOL ReturnValue = FALSE;
  3031. PSPOOL pSpool = (PSPOOL)hPrinter;
  3032. UINT cRetry = 0;
  3033. FieldInfo *pFieldInfo;
  3034. DWORD cbStruct;
  3035. switch (Level) {
  3036. case 1:
  3037. pFieldInfo = AddJobFields;
  3038. cbStruct = sizeof(ADDJOB_INFO_1W);
  3039. break;
  3040. case 2:
  3041. case 3:
  3042. {
  3043. //
  3044. // Level 3 is meant to be used only by RDR/SRV. The spooler needs
  3045. // to know whether the job comes from RDR/SRV. See LocalScheduleJob
  3046. // in localspl.dll for details
  3047. //
  3048. //
  3049. // This is an internal call used by the server when it needs
  3050. // to submit a job with a specific machine name (used for
  3051. // netbiosless notifications, or if the user want the notification
  3052. // to go to the computer instead of the user).
  3053. //
  3054. // IN: (PADDJOB_INFO_2W)pData - points to buffer that receives the
  3055. // path and ID. On input, pData points to the computer name.
  3056. // pData->pData must not point to a string inside of the pData
  3057. // buffer, and it must be smaller than cbBuf -
  3058. // sizeof( ADDJOB_INFO_2W ). It must not be szNull or NULL.
  3059. //
  3060. PADDJOB_INFO_2W pInfo2;
  3061. pInfo2 = (PADDJOB_INFO_2W)pData;
  3062. //
  3063. // Check valid pointer and buffer.
  3064. //
  3065. if( !pInfo2 ||
  3066. !pInfo2->pData ||
  3067. !pInfo2->pData[0] ||
  3068. cbBuf < sizeof( *pInfo2 ) +
  3069. (wcslen( pInfo2->pData ) + 1) * sizeof( WCHAR )){
  3070. SetLastError( ERROR_INVALID_PARAMETER );
  3071. return FALSE;
  3072. }
  3073. //
  3074. // Simple marshalling.
  3075. //
  3076. wcscpy( (LPWSTR)(pInfo2 + 1), pInfo2->pData );
  3077. pInfo2->pData = (LPWSTR)sizeof( *pInfo2 );
  3078. pFieldInfo = AddJob2Fields;
  3079. cbStruct = sizeof(ADDJOB_INFO_2W);
  3080. break;
  3081. }
  3082. default:
  3083. SetLastError(ERROR_INVALID_LEVEL);
  3084. return FALSE;
  3085. }
  3086. if( eProtectHandle( hPrinter, FALSE )){
  3087. return FALSE;
  3088. }
  3089. try {
  3090. do {
  3091. RpcTryExcept {
  3092. if (ReturnValue = RpcAddJob(pSpool->hPrinter, Level, pData,
  3093. cbBuf, pcbNeeded)) {
  3094. SetLastError(ReturnValue);
  3095. ReturnValue = FALSE;
  3096. } else {
  3097. ReturnValue = MarshallUpStructure(pData, pFieldInfo, cbStruct, RPC_CALL);
  3098. pSpool->Status |= SPOOL_STATUS_ADDJOB;
  3099. }
  3100. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3101. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  3102. ReturnValue = FALSE;
  3103. } RpcEndExcept
  3104. } while( !ReturnValue &&
  3105. GetLastError() == ERROR_INVALID_HANDLE &&
  3106. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3107. RevalidateHandle( pSpool ));
  3108. if( ReturnValue ){
  3109. //
  3110. // Notify the tray icon that a new job has been sent.
  3111. //
  3112. vUpdateTrayIcon( hPrinter, ((PADDJOB_INFO_1)pData)->JobId );
  3113. }
  3114. } except (1) {
  3115. SetLastError(TranslateExceptionCode(GetExceptionCode()));
  3116. ReturnValue = FALSE;
  3117. }
  3118. vUnprotectHandle( hPrinter );
  3119. return ReturnValue;
  3120. }
  3121. BOOL
  3122. ScheduleJob(
  3123. HANDLE hPrinter,
  3124. DWORD JobId
  3125. )
  3126. {
  3127. PSPOOL pSpool = (PSPOOL)hPrinter;
  3128. BOOL bReturn;
  3129. if( eProtectHandle( hPrinter, FALSE )){
  3130. return FALSE;
  3131. }
  3132. bReturn = ScheduleJobWorker( pSpool, JobId );
  3133. vUnprotectHandle( hPrinter );
  3134. return bReturn;
  3135. }
  3136. BOOL
  3137. ScheduleJobWorker(
  3138. PSPOOL pSpool,
  3139. DWORD JobId
  3140. )
  3141. {
  3142. BOOL ReturnValue;
  3143. try {
  3144. //
  3145. // The job has been scheduled, so reset the flag that indicates
  3146. // the tray icon has been notified. Any new AddJob/StartDocPrinter/
  3147. // StartDoc events should send a new notification, since it's really
  3148. // a new job.
  3149. //
  3150. pSpool->Status &= ~SPOOL_STATUS_TRAYICON_NOTIFIED;
  3151. FlushBuffer(pSpool, NULL);
  3152. RpcTryExcept {
  3153. if (ReturnValue = RpcScheduleJob(pSpool->hPrinter, JobId)) {
  3154. SetLastError(ReturnValue);
  3155. ReturnValue = FALSE;
  3156. } else {
  3157. pSpool->Status &= ~SPOOL_STATUS_ADDJOB;
  3158. ReturnValue = TRUE;
  3159. }
  3160. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3161. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  3162. ReturnValue = FALSE;
  3163. } RpcEndExcept
  3164. return ReturnValue;
  3165. } except (1) {
  3166. SetLastError(TranslateExceptionCode(GetExceptionCode()));
  3167. return(FALSE);
  3168. }
  3169. }
  3170. DWORD WINAPI
  3171. AsyncPrinterProperties(
  3172. PVOID pData
  3173. )
  3174. {
  3175. PrtPropsData *ThrdData = (PrtPropsData *)pData;
  3176. RpcTryExcept
  3177. {
  3178. RPCSplWOW64PrinterProperties(ThrdData->hWnd,
  3179. ThrdData->PrinterName,
  3180. ThrdData->Flag,
  3181. ThrdData->dwRet);
  3182. }
  3183. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3184. {
  3185. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  3186. }
  3187. RpcEndExcept
  3188. return(0);
  3189. }
  3190. BOOL
  3191. PrinterPropertiesNative(
  3192. HWND hWnd,
  3193. HANDLE hPrinter
  3194. )
  3195. /*++
  3196. Routine Description:
  3197. This is main PrinterProperties entri point and will call into the
  3198. our DevicePropertySheets() for UI pop up
  3199. Arguments:
  3200. hWnd - Handle to the window parent
  3201. hPrinter - Handle to the printer interested
  3202. Return Value:
  3203. If the function succeeds, the return value is TRUE.
  3204. If the function fails, the return value is FALSE.
  3205. To get extended error information, call GetLastError.
  3206. Author:
  3207. 13-Jun-1996 Thu 15:22:36 created -by- Daniel Chou (danielc)
  3208. Revision History:
  3209. --*/
  3210. {
  3211. PRINTER_INFO_2 *pPI2 = NULL;
  3212. DEVICEPROPERTYHEADER DPHdr;
  3213. LONG Result;
  3214. DWORD cb;
  3215. DWORD dwValue = 1;
  3216. BOOL bAllocBuffer = FALSE, bReturn;
  3217. BYTE btBuffer[MAX_STATIC_ALLOC];
  3218. //
  3219. // Ensure the printer handle is valid
  3220. //
  3221. if( eProtectHandle( hPrinter, FALSE )){
  3222. return FALSE;
  3223. }
  3224. DPHdr.cbSize = sizeof(DPHdr);
  3225. DPHdr.hPrinter = hPrinter;
  3226. DPHdr.Flags = DPS_NOPERMISSION;
  3227. //
  3228. // Do a GetPrinter() level2 to get the printer name.
  3229. //
  3230. pPI2 = (PPRINTER_INFO_2) btBuffer;
  3231. bReturn = GetPrinter(hPrinter, 2, (LPBYTE)pPI2, MAX_STATIC_ALLOC, &cb);
  3232. if (!bReturn &&
  3233. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  3234. (pPI2 = (PPRINTER_INFO_2)LocalAlloc(LMEM_FIXED, cb))) {
  3235. bAllocBuffer = TRUE;
  3236. bReturn = GetPrinter(hPrinter, 2, (LPBYTE)pPI2, cb, &cb);
  3237. }
  3238. //
  3239. // Set the printer name.
  3240. //
  3241. if (bReturn) {
  3242. DPHdr.pszPrinterName = pPI2->pPrinterName;
  3243. } else {
  3244. DPHdr.pszPrinterName = NULL;
  3245. }
  3246. //
  3247. // Attempt to set the printer data to determine access privilages.
  3248. //
  3249. if (SetPrinterData( hPrinter,
  3250. TEXT( "PrinterPropertiesPermission" ),
  3251. REG_DWORD,
  3252. (LPBYTE)&dwValue,
  3253. sizeof( dwValue ) ) == STATUS_SUCCESS ) {
  3254. //
  3255. // Indicate we have permissions.
  3256. //
  3257. DPHdr.Flags &= ~DPS_NOPERMISSION;
  3258. }
  3259. //
  3260. // Call Common UI to call do the and call the driver.
  3261. //
  3262. if ( CallCommonPropertySheetUI(hWnd,
  3263. (PFNPROPSHEETUI)DevicePropertySheets,
  3264. (LPARAM)&DPHdr,
  3265. (LPDWORD)&Result) < 0 ) {
  3266. Result = FALSE;
  3267. } else {
  3268. Result = TRUE;
  3269. }
  3270. if (bAllocBuffer) {
  3271. LocalFree((HLOCAL)pPI2);
  3272. }
  3273. vUnprotectHandle( hPrinter );
  3274. return Result;
  3275. }
  3276. BOOL
  3277. PrinterPropertiesThunk(
  3278. HWND hWnd,
  3279. HANDLE hPrinter
  3280. )
  3281. /*++
  3282. Routine Description:
  3283. This is main PrinterProperties entri point and will call into the
  3284. our DevicePropertySheets() for UI pop up
  3285. Arguments:
  3286. hWnd - Handle to the window parent
  3287. hPrinter - Handle to the printer interested
  3288. Return Value:
  3289. If the function succeeds, the return value is TRUE.
  3290. If the function fails, the return value is FALSE.
  3291. To get extended error information, call GetLastError.
  3292. --*/
  3293. {
  3294. PRINTER_INFO_2 *pPI2 = NULL;
  3295. DEVICEPROPERTYHEADER DPHdr;
  3296. LONG Result;
  3297. DWORD cb;
  3298. DWORD dwValue = 1;
  3299. BOOL bAllocBuffer = FALSE, bReturn;
  3300. BYTE btBuffer[MAX_STATIC_ALLOC];
  3301. DWORD dwRet;
  3302. //
  3303. // Ensure the printer handle is valid
  3304. //
  3305. if( eProtectHandle( hPrinter, FALSE )){
  3306. return FALSE;
  3307. }
  3308. DPHdr.cbSize = sizeof(DPHdr);
  3309. DPHdr.hPrinter = hPrinter;
  3310. DPHdr.Flags = DPS_NOPERMISSION;
  3311. //
  3312. // Do a GetPrinter() level2 to get the printer name.
  3313. //
  3314. pPI2 = (PPRINTER_INFO_2) btBuffer;
  3315. bReturn = GetPrinter(hPrinter, 2, (LPBYTE)pPI2, MAX_STATIC_ALLOC, &cb);
  3316. if (!bReturn &&
  3317. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  3318. (pPI2 = (PPRINTER_INFO_2)LocalAlloc(LMEM_FIXED, cb))) {
  3319. bAllocBuffer = TRUE;
  3320. bReturn = GetPrinter(hPrinter, 2, (LPBYTE)pPI2, cb, &cb);
  3321. }
  3322. //
  3323. // Set the printer name.
  3324. //
  3325. if (bReturn)
  3326. {
  3327. if(pPI2->pPrinterName)
  3328. {
  3329. //
  3330. // Attempt to set the printer data to determine access privilages.
  3331. //
  3332. DWORD Flag = DPS_NOPERMISSION;
  3333. if (SetPrinterData( hPrinter,
  3334. TEXT( "PrinterPropertiesPermission" ),
  3335. REG_DWORD,
  3336. (LPBYTE)&dwValue,
  3337. sizeof( dwValue ) ) == STATUS_SUCCESS )
  3338. {
  3339. //
  3340. // Indicate we have permissions.
  3341. //
  3342. Flag &= ~DPS_NOPERMISSION;
  3343. }
  3344. RpcTryExcept
  3345. {
  3346. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  3347. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  3348. {
  3349. HANDLE hUIMsgThrd = NULL;
  3350. DWORD UIMsgThrdId = 0;
  3351. PrtPropsData ThrdData;
  3352. ThrdData.hWnd = (ULONG_PTR)hWnd;
  3353. ThrdData.dwRet = &dwRet;
  3354. ThrdData.PrinterName = (LPWSTR)pPI2->pPrinterName;
  3355. ThrdData.Flag = Flag;
  3356. if(!(hUIMsgThrd = CreateThread(NULL,
  3357. INITIAL_STACK_COMMIT,
  3358. AsyncPrinterProperties,
  3359. (PVOID)&ThrdData,
  3360. 0,
  3361. &UIMsgThrdId)))
  3362. {
  3363. dwRet = GetLastError();
  3364. }
  3365. //
  3366. // The following is the required message loop for processing messages
  3367. // from the UI in case we have a window handle.
  3368. //
  3369. //
  3370. if(hUIMsgThrd)
  3371. {
  3372. MSG msg;
  3373. while (GetMessage(&msg, NULL, 0, 0))
  3374. {
  3375. //
  3376. // In This message loop We should trap a User defined message
  3377. // which indicates the success or the failure of the operation
  3378. //
  3379. if(msg.message == WM_ENDPRINTERPROPERTIES)
  3380. {
  3381. Result = (LONG)msg.wParam;
  3382. if(Result == FALSE)
  3383. SetLastError((DWORD)msg.lParam);
  3384. DelHandleFromList(hWnd);
  3385. break;
  3386. }
  3387. else if(msg.message == WM_SURROGATEFAILURE)
  3388. {
  3389. //
  3390. // This means that the server process died and we have
  3391. // break from the message loop
  3392. //
  3393. Result = FALSE;
  3394. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  3395. break;
  3396. }
  3397. TranslateMessage(&msg);
  3398. DispatchMessage(&msg);
  3399. }
  3400. }
  3401. if(hUIMsgThrd)
  3402. {
  3403. WaitForSingleObject(hUIMsgThrd,INFINITE);
  3404. CloseHandle(hUIMsgThrd);
  3405. }
  3406. }
  3407. else
  3408. {
  3409. SetLastError(dwRet);
  3410. }
  3411. }
  3412. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3413. {
  3414. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  3415. }
  3416. RpcEndExcept
  3417. }
  3418. else
  3419. {
  3420. Result = FALSE;
  3421. }
  3422. }
  3423. else
  3424. {
  3425. Result = FALSE;
  3426. }
  3427. if (bAllocBuffer) {
  3428. LocalFree((HLOCAL)pPI2);
  3429. }
  3430. vUnprotectHandle( hPrinter );
  3431. return Result;
  3432. }
  3433. BOOL
  3434. PrinterProperties(
  3435. HWND hWnd,
  3436. HANDLE hPrinter
  3437. )
  3438. {
  3439. if(RunInWOW64())
  3440. {
  3441. return(PrinterPropertiesThunk(hWnd,
  3442. hPrinter));
  3443. }
  3444. else
  3445. {
  3446. return(PrinterPropertiesNative(hWnd,
  3447. hPrinter));
  3448. }
  3449. }
  3450. DWORD
  3451. GetPrinterDataW(
  3452. HANDLE hPrinter,
  3453. LPWSTR pValueName,
  3454. LPDWORD pType,
  3455. LPBYTE pData,
  3456. DWORD nSize,
  3457. LPDWORD pcbNeeded
  3458. )
  3459. {
  3460. DWORD ReturnValue = 0;
  3461. DWORD ReturnType = 0;
  3462. PSPOOL pSpool = (PSPOOL)hPrinter;
  3463. WCHAR szEMFDatatype[] = L"PrintProcCaps_EMF";
  3464. WCHAR szEMFDatatypeWithVersion[] = L"PrintProcCaps_NT EMF 1.008";
  3465. UINT cRetry = 0;
  3466. if( eProtectHandle( hPrinter, FALSE )){
  3467. return ERROR_INVALID_HANDLE;
  3468. }
  3469. //
  3470. // The user should be able to pass in NULL for buffer, and
  3471. // 0 for size. However, the RPC interface specifies a ref pointer,
  3472. // so we must pass in a valid pointer. Pass in a pointer to
  3473. // ReturnValue (this is just a dummy pointer).
  3474. //
  3475. if( !pData && !nSize ){
  3476. pData = (PBYTE)&ReturnValue;
  3477. }
  3478. if (!pType) {
  3479. pType = (PDWORD) &ReturnType;
  3480. }
  3481. //
  3482. // If pValueName is PrintProcCaps_datatype add the EMF version if necessary.
  3483. // This hardcoded EMF version number will have to be modified whenever GDI changes
  3484. // the version number. This change has been made for GetPrintProcessorCapabilities.
  3485. //
  3486. if (pValueName && !_wcsicmp(pValueName, szEMFDatatype)) {
  3487. pValueName = (LPWSTR) szEMFDatatypeWithVersion;
  3488. }
  3489. do {
  3490. RpcTryExcept {
  3491. ReturnValue = RpcGetPrinterData(pSpool->hPrinter, pValueName, pType,
  3492. pData, nSize, pcbNeeded);
  3493. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3494. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3495. } RpcEndExcept
  3496. } while( ReturnValue == ERROR_INVALID_HANDLE &&
  3497. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3498. RevalidateHandle( pSpool ));
  3499. vUnprotectHandle( hPrinter );
  3500. return ReturnValue;
  3501. }
  3502. DWORD
  3503. GetPrinterDataExW(
  3504. HANDLE hPrinter,
  3505. LPCWSTR pKeyName,
  3506. LPCWSTR pValueName,
  3507. LPDWORD pType,
  3508. LPBYTE pData,
  3509. DWORD nSize,
  3510. LPDWORD pcbNeeded
  3511. )
  3512. {
  3513. DWORD Key = 0;
  3514. DWORD ReturnValue = 0;
  3515. DWORD ReturnType = 0;
  3516. PSPOOL pSpool = (PSPOOL)hPrinter;
  3517. UINT cRetry = 0;
  3518. if( eProtectHandle( hPrinter, FALSE )){
  3519. return ERROR_INVALID_HANDLE;
  3520. }
  3521. //
  3522. // The user should be able to pass in NULL for buffer, and
  3523. // 0 for size. However, the RPC interface specifies a ref pointer,
  3524. // so we must pass in a valid pointer. Pass in a pointer to
  3525. // ReturnValue (this is just a dummy pointer).
  3526. //
  3527. if( !pData && !nSize ){
  3528. pData = (PBYTE)&ReturnValue;
  3529. }
  3530. if (!pType) {
  3531. pType = (PDWORD) &ReturnType;
  3532. }
  3533. if (!pKeyName) {
  3534. pKeyName = (PWSTR) &Key;
  3535. }
  3536. do
  3537. {
  3538. RpcTryExcept {
  3539. ReturnValue = RpcGetPrinterDataEx( pSpool->hPrinter,
  3540. pKeyName,
  3541. pValueName,
  3542. pType,
  3543. pData,
  3544. nSize,
  3545. pcbNeeded);
  3546. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3547. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3548. } RpcEndExcept
  3549. } while (ReturnValue == ERROR_INVALID_HANDLE &&
  3550. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3551. RevalidateHandle(pSpool));
  3552. vUnprotectHandle( hPrinter );
  3553. return ReturnValue;
  3554. }
  3555. HANDLE
  3556. GetSpoolFileHandle(
  3557. HANDLE hPrinter
  3558. )
  3559. /*++
  3560. Function Description: Gets spool file handle which is used by GDI in recording EMF
  3561. data.
  3562. Parameters: hPrinter - Printer handle
  3563. Return Values: Handle to the spool file if successful
  3564. INVALID_HANDLE_VALUE otherwise
  3565. --*/
  3566. {
  3567. HANDLE hReturn = INVALID_HANDLE_VALUE;
  3568. DWORD dwAppProcessId, cbBuf, dwNeeded, dwRpcReturn;
  3569. FILE_INFO_CONTAINER FileInfoContainer;
  3570. SPOOL_FILE_INFO_1 SpoolFileInfo;
  3571. PSPOOL pSpool = (PSPOOL) hPrinter;
  3572. if (eProtectHandle(hPrinter, FALSE)) {
  3573. return hReturn;
  3574. }
  3575. if (pSpool->hSpoolFile != INVALID_HANDLE_VALUE) {
  3576. // GetSpoolFileHandle has already been called; return old handles
  3577. hReturn = pSpool->hSpoolFile;
  3578. goto CleanUp;
  3579. }
  3580. dwAppProcessId = GetCurrentProcessId();
  3581. FileInfoContainer.Level = 1;
  3582. FileInfoContainer.FileInfo.Level1 = &SpoolFileInfo;
  3583. RpcTryExcept {
  3584. dwRpcReturn = RpcGetSpoolFileInfo2(pSpool->hPrinter,
  3585. dwAppProcessId,
  3586. 1,
  3587. &FileInfoContainer);
  3588. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3589. dwRpcReturn = TranslateExceptionCode(RpcExceptionCode());
  3590. } RpcEndExcept
  3591. if (dwRpcReturn) {
  3592. SetLastError(dwRpcReturn);
  3593. } else {
  3594. pSpool->hSpoolFile = FileInfoContainer.FileInfo.Level1->hSpoolFile;
  3595. pSpool->dwSpoolFileAttributes = FileInfoContainer.FileInfo.Level1->dwAttributes;
  3596. hReturn = pSpool->hSpoolFile;
  3597. }
  3598. CleanUp:
  3599. vUnprotectHandle(hPrinter);
  3600. return hReturn;
  3601. }
  3602. HANDLE
  3603. CommitSpoolData(
  3604. HANDLE hPrinter,
  3605. HANDLE hSpoolFile,
  3606. DWORD cbCommit
  3607. )
  3608. /*++
  3609. Function Description: Commits cbCommit bytes in the spool file. For temporary files, a new
  3610. spool file handle is returned.
  3611. Parameters: hPrinter -- printer handle
  3612. hSpoolFile -- spool file handle (from GetSpoolFileHandle)
  3613. cbCommit -- number of bytes to commit (incremental count)
  3614. Return Values: New spool file handle for temporary spool files and
  3615. old handle for persistent files
  3616. --*/
  3617. {
  3618. HANDLE hReturn = INVALID_HANDLE_VALUE;
  3619. DWORD dwAppProcessId, dwRpcReturn;
  3620. DWORD dwNeeded, cbBuf;
  3621. HANDLE hNewSpoolFile;
  3622. FILE_INFO_CONTAINER FileInfoContainer;
  3623. SPOOL_FILE_INFO_1 SpoolFileInfo;
  3624. PSPOOL pSpool = (PSPOOL) hPrinter;
  3625. if (eProtectHandle(hPrinter, FALSE)) {
  3626. return hReturn;
  3627. }
  3628. if ((pSpool->hSpoolFile == INVALID_HANDLE_VALUE) ||
  3629. (pSpool->hSpoolFile != hSpoolFile)) {
  3630. SetLastError(ERROR_INVALID_HANDLE);
  3631. goto CleanUp;
  3632. }
  3633. dwAppProcessId = GetCurrentProcessId();
  3634. FileInfoContainer.Level = 1;
  3635. FileInfoContainer.FileInfo.Level1 = &SpoolFileInfo;
  3636. RpcTryExcept {
  3637. dwRpcReturn = RpcCommitSpoolData2(pSpool->hPrinter,
  3638. dwAppProcessId,
  3639. cbCommit,
  3640. 1,
  3641. &FileInfoContainer);
  3642. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3643. dwRpcReturn = TranslateExceptionCode(RpcExceptionCode());
  3644. } RpcEndExcept
  3645. if (dwRpcReturn) {
  3646. SetLastError(dwRpcReturn);
  3647. } else {
  3648. hNewSpoolFile = FileInfoContainer.FileInfo.Level1->hSpoolFile;
  3649. if (hNewSpoolFile != SPOOL_INVALID_HANDLE_VALUE_32BIT &&
  3650. hNewSpoolFile != INVALID_HANDLE_VALUE) {
  3651. CloseHandle(pSpool->hSpoolFile);
  3652. pSpool->hSpoolFile = hNewSpoolFile;
  3653. }
  3654. hReturn = pSpool->hSpoolFile;
  3655. }
  3656. CleanUp:
  3657. vUnprotectHandle(hPrinter);
  3658. return hReturn;
  3659. }
  3660. BOOL
  3661. CloseSpoolFileHandle(
  3662. HANDLE hPrinter,
  3663. HANDLE hSpoolFile
  3664. )
  3665. /*++
  3666. Function Description: Closes the client and server handles for the spool file.
  3667. Parameters: hPrinter - printer handle
  3668. hSpoolFile - spool file handle (used for consistency across APIs)
  3669. Return Values: TRUE if sucessfule; FALSE otherwise
  3670. --*/
  3671. {
  3672. BOOL bReturn = FALSE;
  3673. DWORD dwLastError = ERROR_SUCCESS;
  3674. PSPOOL pSpool = (PSPOOL) hPrinter;
  3675. if (eProtectHandle(hPrinter, FALSE)) {
  3676. return FALSE;
  3677. }
  3678. if (pSpool->hSpoolFile != hSpoolFile) {
  3679. SetLastError(ERROR_INVALID_HANDLE);
  3680. goto Done;
  3681. }
  3682. if (pSpool->hSpoolFile != INVALID_HANDLE_VALUE) {
  3683. CloseHandle(pSpool->hSpoolFile);
  3684. pSpool->hSpoolFile = INVALID_HANDLE_VALUE;
  3685. }
  3686. RpcTryExcept {
  3687. dwLastError = RpcCloseSpoolFileHandle(pSpool->hPrinter);
  3688. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3689. dwLastError = TranslateExceptionCode(RpcExceptionCode());
  3690. } RpcEndExcept
  3691. if (dwLastError != ERROR_SUCCESS) {
  3692. SetLastError(dwLastError);
  3693. } else {
  3694. bReturn = TRUE;
  3695. }
  3696. Done:
  3697. vUnprotectHandle(hPrinter);
  3698. return bReturn;
  3699. }
  3700. DWORD
  3701. EnumPrinterDataW(
  3702. HANDLE hPrinter,
  3703. DWORD dwIndex, // index of value to query
  3704. LPWSTR pValueName, // address of buffer for value string
  3705. DWORD cbValueName, // size of pValueName
  3706. LPDWORD pcbValueName, // address for size of value buffer
  3707. LPDWORD pType, // address of buffer for type code
  3708. LPBYTE pData, // address of buffer for value data
  3709. DWORD cbData, // size of pData
  3710. LPDWORD pcbData // address for size of data buffer
  3711. )
  3712. {
  3713. DWORD ReturnValue = 0;
  3714. DWORD ReturnType = 0;
  3715. PSPOOL pSpool = (PSPOOL)hPrinter;
  3716. UINT cRetry = 0;
  3717. if( eProtectHandle( hPrinter, FALSE )){
  3718. return ERROR_INVALID_HANDLE;
  3719. }
  3720. //
  3721. // The user should be able to pass in NULL for buffer, and
  3722. // 0 for size. However, the RPC interface specifies a ref pointer,
  3723. // so we must pass in a valid pointer. Pass in a pointer to
  3724. // a dummy pointer.
  3725. //
  3726. if (!pValueName && !cbValueName)
  3727. pValueName = (LPWSTR) &ReturnValue;
  3728. if( !pData && !cbData )
  3729. pData = (PBYTE)&ReturnValue;
  3730. if (!pType)
  3731. pType = (PDWORD) &ReturnType;
  3732. do {
  3733. RpcTryExcept {
  3734. ReturnValue = RpcEnumPrinterData( pSpool->hPrinter,
  3735. dwIndex,
  3736. pValueName,
  3737. cbValueName,
  3738. pcbValueName,
  3739. pType,
  3740. pData,
  3741. cbData,
  3742. pcbData);
  3743. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3744. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3745. } RpcEndExcept
  3746. } while( ReturnValue == ERROR_INVALID_HANDLE &&
  3747. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3748. RevalidateHandle( pSpool ));
  3749. vUnprotectHandle( hPrinter );
  3750. return ReturnValue;
  3751. }
  3752. DWORD
  3753. EnumPrinterDataExW(
  3754. HANDLE hPrinter,
  3755. LPCWSTR pKeyName, // address of key name
  3756. LPBYTE pEnumValues,
  3757. DWORD cbEnumValues,
  3758. LPDWORD pcbEnumValues,
  3759. LPDWORD pnEnumValues
  3760. )
  3761. {
  3762. DWORD ReturnValue = 0;
  3763. DWORD ReturnType = 0;
  3764. PSPOOL pSpool = (PSPOOL)hPrinter;
  3765. DWORD i;
  3766. PPRINTER_ENUM_VALUES pEnumValue = (PPRINTER_ENUM_VALUES) pEnumValues;
  3767. UINT cRetry = 0;
  3768. if( eProtectHandle( hPrinter, FALSE )){
  3769. return ERROR_INVALID_HANDLE;
  3770. }
  3771. //
  3772. // The user should be able to pass in NULL for buffer, and
  3773. // 0 for size. However, the RPC interface specifies a ref pointer,
  3774. // so we must pass in a valid pointer. Pass in a pointer to
  3775. // a dummy pointer.
  3776. //
  3777. if (!pEnumValues && !cbEnumValues)
  3778. pEnumValues = (LPBYTE) &ReturnValue;
  3779. do {
  3780. RpcTryExcept {
  3781. ReturnValue = RpcEnumPrinterDataEx(pSpool->hPrinter,
  3782. pKeyName,
  3783. pEnumValues,
  3784. cbEnumValues,
  3785. pcbEnumValues,
  3786. pnEnumValues);
  3787. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3788. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3789. } RpcEndExcept
  3790. if (ReturnValue == ERROR_SUCCESS) {
  3791. if (pEnumValues) {
  3792. if (!MarshallUpStructuresArray((LPBYTE)pEnumValue, *pnEnumValues,PrinterEnumValuesFields,
  3793. sizeof(PRINTER_ENUM_VALUES), RPC_CALL) ) {
  3794. ReturnValue = GetLastError();
  3795. }
  3796. }
  3797. }
  3798. } while ( ReturnValue == ERROR_INVALID_HANDLE &&
  3799. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3800. RevalidateHandle( pSpool ));
  3801. vUnprotectHandle( hPrinter );
  3802. return ReturnValue;
  3803. }
  3804. DWORD
  3805. EnumPrinterKeyW(
  3806. HANDLE hPrinter,
  3807. LPCWSTR pKeyName, // address of key name
  3808. LPWSTR pSubkey, // address of buffer for value string
  3809. DWORD cbSubkey, // size of pValueName
  3810. LPDWORD pcbSubkey // address for size of value buffer
  3811. )
  3812. {
  3813. DWORD ReturnValue = 0;
  3814. DWORD ReturnType = 0;
  3815. PSPOOL pSpool = (PSPOOL)hPrinter;
  3816. UINT cRetry = 0;
  3817. if( eProtectHandle( hPrinter, FALSE )){
  3818. return ERROR_INVALID_HANDLE;
  3819. }
  3820. //
  3821. // The user should be able to pass in NULL for buffer, and
  3822. // 0 for size. However, the RPC interface specifies a ref pointer,
  3823. // so we must pass in a valid pointer. Pass in a pointer to
  3824. // a dummy pointer.
  3825. //
  3826. if (!pSubkey && !cbSubkey)
  3827. pSubkey = (LPWSTR) &ReturnValue;
  3828. do {
  3829. RpcTryExcept {
  3830. ReturnValue = RpcEnumPrinterKey(pSpool->hPrinter,
  3831. pKeyName,
  3832. pSubkey,
  3833. cbSubkey,
  3834. pcbSubkey);
  3835. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3836. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3837. } RpcEndExcept
  3838. } while ( ReturnValue == ERROR_INVALID_HANDLE &&
  3839. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3840. RevalidateHandle( pSpool ));
  3841. vUnprotectHandle( hPrinter );
  3842. return ReturnValue;
  3843. }
  3844. DWORD
  3845. DeletePrinterDataW(
  3846. HANDLE hPrinter,
  3847. LPWSTR pValueName
  3848. )
  3849. {
  3850. DWORD ReturnValue = 0;
  3851. PSPOOL pSpool = (PSPOOL)hPrinter;
  3852. UINT cRetry = 0;
  3853. if( eProtectHandle( hPrinter, FALSE )){
  3854. return ERROR_INVALID_HANDLE;
  3855. }
  3856. do {
  3857. RpcTryExcept {
  3858. ReturnValue = RpcDeletePrinterData(pSpool->hPrinter, pValueName);
  3859. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3860. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3861. } RpcEndExcept
  3862. } while( ReturnValue == ERROR_INVALID_HANDLE &&
  3863. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3864. RevalidateHandle( pSpool ));
  3865. vUnprotectHandle( hPrinter );
  3866. return ReturnValue;
  3867. }
  3868. DWORD
  3869. DeletePrinterDataExW(
  3870. HANDLE hPrinter,
  3871. LPCWSTR pKeyName,
  3872. LPCWSTR pValueName
  3873. )
  3874. {
  3875. DWORD ReturnValue = 0;
  3876. PSPOOL pSpool = (PSPOOL)hPrinter;
  3877. UINT cRetry = 0;
  3878. if( eProtectHandle( hPrinter, FALSE )){
  3879. return ERROR_INVALID_HANDLE;
  3880. }
  3881. do {
  3882. RpcTryExcept {
  3883. ReturnValue = RpcDeletePrinterDataEx(pSpool->hPrinter, pKeyName, pValueName);
  3884. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3885. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3886. } RpcEndExcept
  3887. } while( ReturnValue == ERROR_INVALID_HANDLE &&
  3888. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3889. RevalidateHandle( pSpool ));
  3890. vUnprotectHandle( hPrinter );
  3891. return ReturnValue;
  3892. }
  3893. DWORD
  3894. DeletePrinterKeyW(
  3895. HANDLE hPrinter,
  3896. LPCWSTR pKeyName
  3897. )
  3898. {
  3899. DWORD ReturnValue = 0;
  3900. PSPOOL pSpool = (PSPOOL)hPrinter;
  3901. UINT cRetry = 0;
  3902. if( eProtectHandle( hPrinter, FALSE )){
  3903. return ERROR_INVALID_HANDLE;
  3904. }
  3905. do {
  3906. RpcTryExcept {
  3907. ReturnValue = RpcDeletePrinterKey(pSpool->hPrinter, pKeyName);
  3908. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3909. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3910. } RpcEndExcept
  3911. } while( ReturnValue == ERROR_INVALID_HANDLE &&
  3912. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3913. RevalidateHandle( pSpool ));
  3914. vUnprotectHandle( hPrinter );
  3915. return ReturnValue;
  3916. }
  3917. DWORD
  3918. SetPrinterDataW(
  3919. HANDLE hPrinter,
  3920. LPWSTR pValueName,
  3921. DWORD Type,
  3922. LPBYTE pData,
  3923. DWORD cbData
  3924. )
  3925. {
  3926. DWORD ReturnValue = 0;
  3927. PSPOOL pSpool = (PSPOOL)hPrinter;
  3928. UINT cRetry = 0;
  3929. if( eProtectHandle( hPrinter, FALSE )){
  3930. return ERROR_INVALID_HANDLE;
  3931. }
  3932. do {
  3933. RpcTryExcept {
  3934. ReturnValue = RpcSetPrinterData(pSpool->hPrinter, pValueName, Type,
  3935. pData, cbData);
  3936. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3937. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3938. } RpcEndExcept
  3939. } while( ReturnValue == ERROR_INVALID_HANDLE &&
  3940. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3941. RevalidateHandle( pSpool ));
  3942. vUnprotectHandle( hPrinter );
  3943. return ReturnValue;
  3944. }
  3945. DWORD
  3946. SetPrinterDataExW(
  3947. HANDLE hPrinter,
  3948. LPCWSTR pKeyName,
  3949. LPCWSTR pValueName,
  3950. DWORD Type,
  3951. LPBYTE pData,
  3952. DWORD cbData
  3953. )
  3954. {
  3955. DWORD ReturnValue = 0;
  3956. PSPOOL pSpool = (PSPOOL)hPrinter;
  3957. UINT cRetry = 0;
  3958. if( eProtectHandle( hPrinter, FALSE )){
  3959. return ERROR_INVALID_HANDLE;
  3960. }
  3961. if (!pKeyName)
  3962. pKeyName = L"";
  3963. do {
  3964. RpcTryExcept {
  3965. ReturnValue = RpcSetPrinterDataEx( pSpool->hPrinter,
  3966. pKeyName,
  3967. pValueName,
  3968. Type,
  3969. pData,
  3970. cbData);
  3971. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3972. ReturnValue = TranslateExceptionCode(RpcExceptionCode());
  3973. } RpcEndExcept
  3974. } while( ReturnValue == ERROR_INVALID_HANDLE &&
  3975. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  3976. RevalidateHandle( pSpool ));
  3977. vUnprotectHandle( hPrinter );
  3978. return ReturnValue;
  3979. }
  3980. VOID
  3981. SplDriverUnloadComplete(
  3982. LPWSTR pDriverFile
  3983. )
  3984. /*++
  3985. Function Description: The information on the driver unload is set to the spooler
  3986. so that it may continue any pending upgrades.
  3987. Parameters: pDriverFile -- driver file name which was unloaded
  3988. Return Value: NONE
  3989. --*/
  3990. {
  3991. if (bLoadedBySpooler && fpYDriverUnloadComplete) {
  3992. (*fpYDriverUnloadComplete)(pDriverFile);
  3993. }
  3994. }
  3995. HANDLE
  3996. LoadNewCopy(
  3997. LPWSTR pConfigFile,
  3998. DWORD dwFlags,
  3999. DWORD dwVersion
  4000. )
  4001. /*++
  4002. Function Description: This function loads the driver file and creates a node to
  4003. maintain its reference count. It is called inside ListAccessSem.
  4004. Parameters: pConfigFile -- driver config file path
  4005. dwFlags -- flags for loading
  4006. dwVersion -- version number of the driver since reboot
  4007. Return Value: handle to the library
  4008. --*/
  4009. {
  4010. HANDLE hReturn = NULL;
  4011. PDRVLIBNODE pTmpDrvLib, pNewDrvLib = NULL;
  4012. ULONG_PTR lActCtx = 0;
  4013. BOOL bDidActivate = FALSE;
  4014. //
  4015. // Activate the empty context
  4016. //
  4017. bDidActivate = ActivateActCtx( ACTCTX_EMPTY, &lActCtx );
  4018. // Inside ListAccessSem
  4019. hReturn = LoadLibraryEx(pConfigFile, NULL, dwFlags);
  4020. if (hReturn) {
  4021. // Create a new DRVLIBNODE
  4022. if (pNewDrvLib = (PDRVLIBNODE) AllocSplMem(sizeof(DRVLIBNODE))) {
  4023. pNewDrvLib->hLib = hReturn;
  4024. pNewDrvLib->dwVersion = dwVersion;
  4025. // Initialize ref cnt to 2. This ensures that the library remains loaded
  4026. // in the normal course.
  4027. pNewDrvLib->dwNumHandles = 2;
  4028. pNewDrvLib->bArtificialIncrement = TRUE;
  4029. if (!(pNewDrvLib->pConfigFile = AllocSplStr(pConfigFile)))
  4030. {
  4031. FreeSplMem(pNewDrvLib);
  4032. pNewDrvLib = NULL;
  4033. }
  4034. }
  4035. if (!pNewDrvLib) {
  4036. // Free the library
  4037. FreeLibrary(hReturn);
  4038. hReturn = NULL;
  4039. } else {
  4040. // Add the node to the list
  4041. pNewDrvLib->pNext = pStartDrvLib;
  4042. pStartDrvLib = pNewDrvLib;
  4043. }
  4044. }
  4045. //
  4046. // Deactivate the context
  4047. //
  4048. if( bDidActivate ){
  4049. DeactivateActCtx( 0, lActCtx );
  4050. }
  4051. return hReturn;
  4052. }
  4053. PDRVLIBNODE
  4054. FindDriverNode(
  4055. LPWSTR pConfigFile,
  4056. DWORD dwVersion,
  4057. BOOL bUseVersion
  4058. )
  4059. /*++
  4060. Function Description: Searches thru the list of driver nodes to get the
  4061. required driver information. In case of version mismatch the
  4062. artificial increment on the old driver is removed.
  4063. This function is called inside the ListAccessSem
  4064. Parameters: pConfigFile -- driver config file name
  4065. dwVersion -- version number of the driver since reboot
  4066. bUseVersion -- flag to use the version number
  4067. Return Values: pDrvLibNode for the required driver, if present
  4068. --*/
  4069. {
  4070. PDRVLIBNODE pTmpDrvLib;
  4071. for (pTmpDrvLib = pStartDrvLib; pTmpDrvLib; pTmpDrvLib = pTmpDrvLib->pNext) {
  4072. if (!_wcsicmp(pConfigFile, pTmpDrvLib->pConfigFile)) {
  4073. break;
  4074. }
  4075. }
  4076. if (pTmpDrvLib && bUseVersion && (pTmpDrvLib->dwVersion != dwVersion)) {
  4077. if (pTmpDrvLib->bArtificialIncrement) {
  4078. pTmpDrvLib->bArtificialIncrement = FALSE;
  4079. if (RefCntUnloadDriver(pTmpDrvLib->hLib, FALSE)) {
  4080. pTmpDrvLib = NULL;
  4081. }
  4082. }
  4083. }
  4084. return pTmpDrvLib;
  4085. }
  4086. HANDLE
  4087. RefCntLoadDriver(
  4088. LPWSTR pConfigFile,
  4089. DWORD dwFlags,
  4090. DWORD dwVersion,
  4091. BOOL bUseVersion
  4092. )
  4093. /*++
  4094. Function Description: This function loads the driver config file. It reuses existing handles
  4095. to avoid expensive Loads and Frees. In case of a version mismatch the
  4096. original handle is freed and we load the driver again.
  4097. Parameters: pConfigFile -- driver config file name
  4098. dwFlags -- flags for loading (ignored if existing handle is returned)
  4099. dwVersion -- version of the driver file since reboot
  4100. bUseVersion -- flag to use the version number check
  4101. Return Value: handle to the library
  4102. --*/
  4103. {
  4104. HANDLE hReturn = NULL;
  4105. PDRVLIBNODE pTmpDrvLib;
  4106. if (!pConfigFile || !*pConfigFile) {
  4107. // nothing to load
  4108. return hReturn;
  4109. }
  4110. EnterCriticalSection( &ListAccessSem );
  4111. pTmpDrvLib = FindDriverNode(pConfigFile, dwVersion, bUseVersion);
  4112. // Use existing handle, if any.
  4113. if (pTmpDrvLib) {
  4114. // Increment the ref cnt for library usage;
  4115. pTmpDrvLib->dwNumHandles += 1;
  4116. hReturn = pTmpDrvLib->hLib;
  4117. } else {
  4118. // Reload the library
  4119. hReturn = LoadNewCopy(pConfigFile, dwFlags, dwVersion);
  4120. }
  4121. LeaveCriticalSection( &ListAccessSem );
  4122. return hReturn;
  4123. }
  4124. BOOL
  4125. RefCntUnloadDriver(
  4126. HANDLE hLib,
  4127. BOOL bNotifySpooler
  4128. )
  4129. /*++
  4130. Function Description: This function decrements the reference count for the library usage.
  4131. It also frees the library if the reference count falls to zero.
  4132. Parameters: hLib -- handle of the library to free
  4133. bNotifySpooler -- flag to notify the spooler of the unload
  4134. Return Value: TRUE if the driver library was freed
  4135. FALSE otherwise
  4136. --*/
  4137. {
  4138. BOOL bReturn = FALSE;
  4139. PDRVLIBNODE *ppTmpDrvLib, pTmpDrvLib;
  4140. LPWSTR pConfigFile = NULL;
  4141. EnterCriticalSection( &ListAccessSem );
  4142. for (ppTmpDrvLib = &pStartDrvLib;
  4143. pTmpDrvLib = *ppTmpDrvLib;
  4144. ppTmpDrvLib = &(pTmpDrvLib->pNext)) {
  4145. if (pTmpDrvLib->hLib == hLib) {
  4146. // Reduce the ref cnt
  4147. SPLASSERT(pTmpDrvLib->dwNumHandles > 0);
  4148. pTmpDrvLib->dwNumHandles -= 1;
  4149. // Free the library and the node if ref cnt is zero
  4150. if (pTmpDrvLib->dwNumHandles == 0) {
  4151. FreeLibrary(hLib);
  4152. *ppTmpDrvLib = pTmpDrvLib->pNext;
  4153. pConfigFile = AllocSplStr(pTmpDrvLib->pConfigFile);
  4154. FreeSplStr(pTmpDrvLib->pConfigFile);
  4155. FreeSplMem(pTmpDrvLib);
  4156. bReturn = TRUE;
  4157. }
  4158. break;
  4159. }
  4160. }
  4161. LeaveCriticalSection( &ListAccessSem );
  4162. if (bNotifySpooler && bReturn) {
  4163. SplDriverUnloadComplete(pConfigFile);
  4164. }
  4165. FreeSplStr(pConfigFile);
  4166. return bReturn;
  4167. }
  4168. BOOL
  4169. ForceUnloadDriver(
  4170. LPWSTR pConfigFile
  4171. )
  4172. /*++
  4173. Function Description: This function will remove any artificial increment on the
  4174. config file.
  4175. Parameters: pConfigFile -- driver config file name
  4176. Return Values: TRUE if the config file no longer loaded;
  4177. FALSE otherwise
  4178. --*/
  4179. {
  4180. BOOL bReturn = TRUE;
  4181. PDRVLIBNODE *ppTmpDrvLib, pTmpDrvLib;
  4182. if (!pConfigFile || !*pConfigFile) {
  4183. // nothing to unload
  4184. return bReturn;
  4185. }
  4186. EnterCriticalSection( &ListAccessSem );
  4187. pTmpDrvLib = FindDriverNode(pConfigFile, 0, FALSE);
  4188. if (pTmpDrvLib) {
  4189. if (pTmpDrvLib->bArtificialIncrement) {
  4190. pTmpDrvLib->bArtificialIncrement = FALSE;
  4191. bReturn = RefCntUnloadDriver(pTmpDrvLib->hLib, FALSE);
  4192. } else {
  4193. bReturn = FALSE;
  4194. }
  4195. } else {
  4196. bReturn = TRUE;
  4197. }
  4198. LeaveCriticalSection( &ListAccessSem );
  4199. return bReturn;
  4200. }
  4201. HANDLE
  4202. LoadPrinterDriver(
  4203. HANDLE hPrinter
  4204. )
  4205. {
  4206. PDRIVER_INFO_5 pDriverInfo;
  4207. DWORD cbNeeded, dwVersion;
  4208. HANDLE hModule=FALSE;
  4209. BYTE btBuffer[MAX_STATIC_ALLOC];
  4210. BOOL bAllocBuffer = FALSE, bReturn;
  4211. pDriverInfo = (PDRIVER_INFO_5) btBuffer;
  4212. bReturn = GetPrinterDriverW(hPrinter, NULL, 5, (LPBYTE)pDriverInfo,
  4213. MAX_STATIC_ALLOC, &cbNeeded);
  4214. if (!bReturn &&
  4215. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  4216. (pDriverInfo = (PDRIVER_INFO_5)LocalAlloc(LMEM_FIXED, cbNeeded))) {
  4217. bAllocBuffer = TRUE;
  4218. bReturn = GetPrinterDriverW(hPrinter, NULL, 5, (LPBYTE)pDriverInfo,
  4219. cbNeeded, &cbNeeded);
  4220. }
  4221. if (bReturn) {
  4222. hModule = RefCntLoadDriver(pDriverInfo->pConfigFile,
  4223. LOAD_WITH_ALTERED_SEARCH_PATH,
  4224. pDriverInfo->dwConfigVersion,
  4225. TRUE);
  4226. }
  4227. if (bAllocBuffer) {
  4228. LocalFree(pDriverInfo);
  4229. }
  4230. return hModule;
  4231. }
  4232. DWORD WINAPI
  4233. AsyncDocumentPropertiesW(
  4234. PVOID pData
  4235. )
  4236. {
  4237. PumpThrdData *ThrdData = (PumpThrdData *)pData;
  4238. RpcTryExcept
  4239. {
  4240. *ThrdData->Result = RPCSplWOW64DocumentProperties(ThrdData->hWnd,
  4241. ThrdData->PrinterName,
  4242. ThrdData->TouchedDevModeSize,
  4243. ThrdData->ClonedDevModeOutSize,
  4244. ThrdData->ClonedDevModeOut,
  4245. ThrdData->DevModeInSize,
  4246. ThrdData->pDevModeInput,
  4247. ThrdData->ClonedDevModeFill,
  4248. ThrdData->fMode,
  4249. ThrdData->dwRet);
  4250. }
  4251. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  4252. {
  4253. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4254. }
  4255. RpcEndExcept
  4256. return(0);
  4257. }
  4258. LONG
  4259. DocumentPropertiesWNative(
  4260. HWND hWnd,
  4261. HANDLE hPrinter,
  4262. LPWSTR pDeviceName,
  4263. PDEVMODE pDevModeOutput,
  4264. PDEVMODE pDevModeInput,
  4265. DWORD fMode
  4266. )
  4267. /*++
  4268. Routine Description:
  4269. DocumentProperties entry point to call DocumentPropertySheets() depends on
  4270. the DM_PROMPT
  4271. Arguments:
  4272. Return Value:
  4273. Author:
  4274. 13-Jun-1996 Thu 15:35:25 created -by- Daniel Chou (danielc)
  4275. Revision History:
  4276. --*/
  4277. {
  4278. DOCUMENTPROPERTYHEADER DPHdr;
  4279. PDEVMODE pDM;
  4280. LONG Result = -1;
  4281. HANDLE hTmpPrinter = NULL;
  4282. //
  4283. // Compatibility with Win95
  4284. // Win95 allows for hPrinter to be NULL
  4285. //
  4286. if (hPrinter == NULL) {
  4287. //
  4288. // Open the printer for default access.
  4289. //
  4290. if (!OpenPrinter( pDeviceName, &hTmpPrinter, NULL )) {
  4291. hTmpPrinter = NULL;
  4292. }
  4293. } else {
  4294. hTmpPrinter = hPrinter;
  4295. }
  4296. //
  4297. // Ensure the printer handle is valid
  4298. //
  4299. if( !eProtectHandle( hTmpPrinter, FALSE )){
  4300. //
  4301. // If fMode doesn't specify DM_IN_BUFFER, then zero out
  4302. // pDevModeInput.
  4303. //
  4304. // Old 3.51 (version 1-0) drivers used to ignore the absence of
  4305. // DM_IN_BUFFER and use pDevModeInput if it was not NULL. It
  4306. // probably did this because Printman.exe was broken.
  4307. //
  4308. // If the devmode is invalid, then don't pass one in.
  4309. // This fixes MS Imager32 (which passes dmSize == 0) and
  4310. // Milestones etc. 4.5.
  4311. //
  4312. // Note: this assumes that pDevModeOutput is still the
  4313. // correct size!
  4314. //
  4315. if( !(fMode & DM_IN_BUFFER) || !bValidDevModeW( pDevModeInput )){
  4316. //
  4317. // If either are not set, make sure both are not set.
  4318. //
  4319. pDevModeInput = NULL;
  4320. fMode &= ~DM_IN_BUFFER;
  4321. }
  4322. DPHdr.cbSize = sizeof(DPHdr);
  4323. DPHdr.Reserved = 0;
  4324. DPHdr.hPrinter = hTmpPrinter;
  4325. DPHdr.pszPrinterName = pDeviceName;
  4326. if (pDevModeOutput) {
  4327. //
  4328. // Get the driver devmode size at here
  4329. //
  4330. DPHdr.pdmIn = NULL;
  4331. DPHdr.pdmOut = NULL;
  4332. DPHdr.fMode = 0;
  4333. DPHdr.cbOut = (LONG)DocumentPropertySheets(NULL, (LPARAM)&DPHdr);
  4334. } else {
  4335. DPHdr.cbOut = 0;
  4336. }
  4337. DPHdr.pdmIn = (PDEVMODE)pDevModeInput;
  4338. DPHdr.pdmOut = (PDEVMODE)pDevModeOutput;
  4339. DPHdr.fMode = fMode;
  4340. if (fMode & DM_PROMPT) {
  4341. Result = CPSUI_CANCEL;
  4342. if ((CallCommonPropertySheetUI(hWnd,
  4343. (PFNPROPSHEETUI)DocumentPropertySheets,
  4344. (LPARAM)&DPHdr,
  4345. (LPDWORD)&Result)) < 0) {
  4346. Result = -1;
  4347. } else {
  4348. Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL;
  4349. }
  4350. } else {
  4351. Result = (LONG)DocumentPropertySheets(NULL, (LPARAM)&DPHdr);
  4352. }
  4353. vUnprotectHandle( hTmpPrinter );
  4354. }
  4355. if (hPrinter == NULL) {
  4356. if( hTmpPrinter ){
  4357. ClosePrinter(hTmpPrinter);
  4358. }
  4359. }
  4360. return Result;
  4361. }
  4362. LONG
  4363. DocumentPropertiesWThunk(
  4364. HWND hWnd,
  4365. HANDLE hPrinter,
  4366. LPWSTR pDeviceName,
  4367. PDEVMODE pDevModeOutput,
  4368. PDEVMODE pDevModeInput,
  4369. DWORD fMode
  4370. )
  4371. /*++
  4372. Routine Description:
  4373. DocumentProperties entry point to call DocumentPropertySheets() depends on
  4374. the DM_PROMPT
  4375. --*/
  4376. {
  4377. DOCUMENTPROPERTYHEADER DPHdr;
  4378. PDEVMODE pDM;
  4379. LONG Result = -1;
  4380. HANDLE hTmpPrinter = NULL;
  4381. PSPOOL pSpool = (PSPOOL)hPrinter;
  4382. if (hPrinter == NULL)
  4383. {
  4384. if (!OpenPrinter( pDeviceName, &hTmpPrinter, NULL ))
  4385. {
  4386. hTmpPrinter = NULL;
  4387. }
  4388. }
  4389. else
  4390. {
  4391. hTmpPrinter = hPrinter;
  4392. }
  4393. if( !eProtectHandle( hTmpPrinter, FALSE ))
  4394. {
  4395. LPWSTR PrinterName;
  4396. MSG msg;
  4397. LONG RetVal;
  4398. DWORD dwRet = ERROR_SUCCESS;
  4399. DWORD ClonedDevModeOutSize = 0;
  4400. DWORD TouchedDevModeSize = 0;
  4401. BOOL ClonedDevModeFill = (!!(fMode & DM_OUT_BUFFER) && pDevModeOutput);
  4402. DWORD DevModeInSize = pDevModeInput ? (pDevModeInput->dmSize + pDevModeInput->dmDriverExtra) : 0;
  4403. byte **ClonedDevModeOut = NULL;
  4404. if(ClonedDevModeOut = (byte **)LocalAlloc(LPTR,sizeof(byte *)))
  4405. {
  4406. *ClonedDevModeOut = NULL;
  4407. if(pSpool)
  4408. {
  4409. PrinterName = pSpool->pszPrinter;
  4410. }
  4411. else
  4412. {
  4413. PrinterName = pDeviceName;
  4414. }
  4415. //
  4416. // If fMode doesn't specify DM_IN_BUFFER, then zero out
  4417. // pDevModeInput.
  4418. //
  4419. // Old 3.51 (version 1-0) drivers used to ignore the absence of
  4420. // DM_IN_BUFFER and use pDevModeInput if it was not NULL. It
  4421. // probably did this because Printman.exe was broken.
  4422. //
  4423. // If the devmode is invalid, then don't pass one in.
  4424. // This fixes MS Imager32 (which passes dmSize == 0) and
  4425. // Milestones etc. 4.5.
  4426. //
  4427. // Note: this assumes that pDevModeOutput is still the
  4428. // correct size!
  4429. //
  4430. if( !(fMode & DM_IN_BUFFER) || !bValidDevModeW( pDevModeInput ))
  4431. {
  4432. //
  4433. // If either are not set, make sure both are not set.
  4434. //
  4435. pDevModeInput = NULL;
  4436. DevModeInSize = 0;
  4437. fMode &= ~DM_IN_BUFFER;
  4438. }
  4439. RpcTryExcept
  4440. {
  4441. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  4442. (!hWnd ||
  4443. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS)))
  4444. {
  4445. HANDLE hUIMsgThrd = NULL;
  4446. DWORD UIMsgThrdId = 0;
  4447. PumpThrdData ThrdData;
  4448. ThrdData.hWnd = (ULONG_PTR)hWnd;
  4449. ThrdData.PrinterName=PrinterName;
  4450. ThrdData.TouchedDevModeSize = &TouchedDevModeSize;
  4451. ThrdData.ClonedDevModeOutSize = &ClonedDevModeOutSize;
  4452. ThrdData.ClonedDevModeOut = (byte**)ClonedDevModeOut;
  4453. ThrdData.DevModeInSize = DevModeInSize;
  4454. ThrdData.pDevModeInput = (byte*)pDevModeInput;
  4455. ThrdData.fMode = fMode;
  4456. ThrdData.fExclusionFlags = 0;
  4457. ThrdData.dwRet = &dwRet;
  4458. ThrdData.ClonedDevModeFill = ClonedDevModeFill;
  4459. ThrdData.Result = &Result;
  4460. //
  4461. // If we have a window handle , the following functions cann't
  4462. // proceed synchronasly. The reason for that is in order to show
  4463. // the UI of the driver property sheets we need to be able to dispatch
  4464. // incomming messages and process them.For this reason the following
  4465. // call would be asynchronous call and the success or failure doesn't
  4466. // in reality tell us anything more than than the async process started
  4467. // or not. We get the success of failure from the termination message.
  4468. // If we don't have a window handle, then the call is synchronous.
  4469. //
  4470. if(!(hUIMsgThrd = CreateThread(NULL,
  4471. INITIAL_STACK_COMMIT,
  4472. AsyncDocumentPropertiesW,
  4473. (PVOID)&ThrdData,
  4474. 0,
  4475. &UIMsgThrdId)))
  4476. {
  4477. dwRet = GetLastError();
  4478. }
  4479. //
  4480. // The following is the required message loop for processing messages
  4481. // from the UI in case we have a window handle.
  4482. //
  4483. //
  4484. if(hUIMsgThrd && hWnd && (fMode & DM_PROMPT))
  4485. {
  4486. while (GetMessage(&msg, NULL, 0, 0))
  4487. {
  4488. //
  4489. // In This message loop We should trap a User defined message
  4490. // which indicates the success or the failure of the operation
  4491. //
  4492. if(msg.message == WM_ENDDOCUMENTPROPERTIES)
  4493. {
  4494. Result = (LONG)msg.wParam;
  4495. if(Result == -1)
  4496. SetLastError((DWORD)msg.lParam);
  4497. DelHandleFromList(hWnd);
  4498. break;
  4499. }
  4500. else if(msg.message == WM_SURROGATEFAILURE)
  4501. {
  4502. //
  4503. // This means that the server process died and we have
  4504. // break from the message loop
  4505. //
  4506. Result = -1;
  4507. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  4508. break;
  4509. }
  4510. TranslateMessage(&msg);
  4511. DispatchMessage(&msg);
  4512. }
  4513. }
  4514. if(hUIMsgThrd)
  4515. {
  4516. WaitForSingleObject(hUIMsgThrd,INFINITE);
  4517. CloseHandle(hUIMsgThrd);
  4518. }
  4519. if(Result!=-1 && pDevModeOutput)
  4520. {
  4521. memcpy((PVOID)pDevModeOutput,(PVOID)*ClonedDevModeOut,TouchedDevModeSize);
  4522. }
  4523. if(*ClonedDevModeOut)
  4524. {
  4525. MIDL_user_free((PVOID)*ClonedDevModeOut);
  4526. }
  4527. if(ClonedDevModeOut)
  4528. {
  4529. LocalFree((PVOID) ClonedDevModeOut);
  4530. }
  4531. }
  4532. else
  4533. {
  4534. SetLastError(dwRet);
  4535. }
  4536. }
  4537. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  4538. {
  4539. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4540. }
  4541. RpcEndExcept
  4542. vUnprotectHandle( hTmpPrinter );
  4543. }
  4544. else
  4545. {
  4546. SetLastError(ERROR_OUTOFMEMORY);
  4547. }
  4548. }
  4549. if (hPrinter == NULL)
  4550. {
  4551. if( hTmpPrinter )
  4552. {
  4553. ClosePrinter(hTmpPrinter);
  4554. }
  4555. }
  4556. return(Result);
  4557. }
  4558. LONG
  4559. DocumentPropertiesW(
  4560. HWND hWnd,
  4561. HANDLE hPrinter,
  4562. LPWSTR pDeviceName,
  4563. PDEVMODE pDevModeOutput,
  4564. PDEVMODE pDevModeInput,
  4565. DWORD fMode
  4566. )
  4567. {
  4568. if(RunInWOW64())
  4569. {
  4570. return(DocumentPropertiesWThunk(hWnd,
  4571. hPrinter,
  4572. pDeviceName,
  4573. pDevModeOutput,
  4574. pDevModeInput,
  4575. fMode));
  4576. }
  4577. else
  4578. {
  4579. return(DocumentPropertiesWNative(hWnd,
  4580. hPrinter,
  4581. pDeviceName,
  4582. pDevModeOutput,
  4583. pDevModeInput,
  4584. fMode));
  4585. }
  4586. }
  4587. LONG
  4588. AdvancedDocumentPropertiesW(
  4589. HWND hWnd,
  4590. HANDLE hPrinter,
  4591. LPWSTR pDeviceName,
  4592. PDEVMODE pDevModeOutput,
  4593. PDEVMODE pDevModeInput
  4594. )
  4595. /*++
  4596. Routine Description:
  4597. AdvanceDocumentProperties() will call DocumentProperties() with DM_ADVANCED
  4598. flag mode set
  4599. Arguments:
  4600. Return Value:
  4601. TRUE/FALSE
  4602. Author:
  4603. 13-Jun-1996 Thu 16:00:13 created -by- Daniel Chou (danielc)
  4604. Revision History:
  4605. --*/
  4606. {
  4607. return((DocumentPropertiesW(hWnd,
  4608. hPrinter,
  4609. pDeviceName,
  4610. pDevModeOutput,
  4611. pDevModeInput,
  4612. DM_PROMPT |
  4613. DM_MODIFY |
  4614. DM_COPY |
  4615. DM_ADVANCED) == CPSUI_OK) ? 1 : 0);
  4616. }
  4617. LONG
  4618. AdvancedSetupDialogW(
  4619. HWND hWnd,
  4620. HANDLE hInst,
  4621. LPDEVMODE pDevModeInput,
  4622. LPDEVMODE pDevModeOutput
  4623. )
  4624. {
  4625. HANDLE hPrinter;
  4626. LONG ReturnValue = -1;
  4627. if (OpenPrinterW(pDevModeInput->dmDeviceName, &hPrinter, NULL)) {
  4628. ReturnValue = AdvancedDocumentPropertiesW(hWnd, hPrinter,
  4629. pDevModeInput->dmDeviceName,
  4630. pDevModeOutput,
  4631. pDevModeInput);
  4632. ClosePrinter(hPrinter);
  4633. }
  4634. return ReturnValue;
  4635. }
  4636. int
  4637. WINAPI
  4638. DeviceCapabilitiesWNative(
  4639. LPCWSTR pDevice,
  4640. LPCWSTR pPort,
  4641. WORD fwCapability,
  4642. LPWSTR pOutput,
  4643. CONST DEVMODEW *pDevMode
  4644. )
  4645. {
  4646. HANDLE hPrinter, hModule;
  4647. int ReturnValue=-1;
  4648. INT_FARPROC pfn;
  4649. if (OpenPrinter((LPWSTR)pDevice, &hPrinter, NULL)) {
  4650. if (hModule = LoadPrinterDriver(hPrinter)) {
  4651. if (pfn = (INT_FARPROC)GetProcAddress(hModule, "DrvDeviceCapabilities")) {
  4652. try {
  4653. ReturnValue = (*pfn)(hPrinter, pDevice, fwCapability,
  4654. pOutput, pDevMode);
  4655. } except(1) {
  4656. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4657. ReturnValue = -1;
  4658. }
  4659. }
  4660. RefCntUnloadDriver(hModule, TRUE);
  4661. }
  4662. ClosePrinter(hPrinter);
  4663. }
  4664. return ReturnValue;
  4665. }
  4666. int
  4667. WINAPI
  4668. DeviceCapabilitiesWThunk(
  4669. LPCWSTR pDevice,
  4670. LPCWSTR pPort,
  4671. WORD fwCapability,
  4672. LPWSTR pOutput,
  4673. CONST DEVMODEW *pDevMode
  4674. )
  4675. {
  4676. HANDLE hPrinter, hModule;
  4677. int ReturnValue = -1;
  4678. INT_FARPROC pfn;
  4679. LPWSTR DriverFileName;
  4680. DWORD DevModeSize;
  4681. DWORD ClonedOutputSize = 0;
  4682. BOOL ClonedOutputFill = FALSE;
  4683. DWORD dwRet = ERROR_SUCCESS;
  4684. byte **ClonedOutput = NULL;
  4685. DevModeSize = pDevMode ? (pDevMode->dmSize + pDevMode->dmDriverExtra) : 0;
  4686. ClonedOutputFill = (pOutput != NULL);
  4687. if(ClonedOutput = (byte **)LocalAlloc(LPTR,sizeof(byte *)))
  4688. {
  4689. *ClonedOutput = NULL;
  4690. RpcTryExcept
  4691. {
  4692. if((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS)
  4693. {
  4694. ReturnValue = RPCSplWOW64DeviceCapabilities((LPWSTR)pDevice,
  4695. (LPWSTR)pPort,
  4696. fwCapability,
  4697. DevModeSize,
  4698. (byte*)pDevMode,
  4699. ClonedOutputFill,
  4700. &ClonedOutputSize,
  4701. (byte**)ClonedOutput,
  4702. &dwRet);
  4703. if(ReturnValue!=-1 &&
  4704. pOutput &&
  4705. *ClonedOutput)
  4706. {
  4707. memcpy((PVOID)pOutput,(PVOID)*ClonedOutput,ClonedOutputSize);
  4708. }
  4709. if(*ClonedOutput)
  4710. {
  4711. MIDL_user_free((PVOID)*ClonedOutput);
  4712. }
  4713. }
  4714. else
  4715. {
  4716. SetLastError(dwRet);
  4717. }
  4718. if(ClonedOutput)
  4719. {
  4720. LocalFree((PVOID) ClonedOutput);
  4721. }
  4722. }
  4723. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  4724. {
  4725. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4726. ReturnValue = -1;
  4727. }
  4728. RpcEndExcept
  4729. }
  4730. else
  4731. {
  4732. SetLastError(ERROR_OUTOFMEMORY);
  4733. }
  4734. return(ReturnValue);
  4735. }
  4736. int
  4737. WINAPI
  4738. DeviceCapabilitiesW(
  4739. LPCWSTR pDevice,
  4740. LPCWSTR pPort,
  4741. WORD fwCapability,
  4742. LPWSTR pOutput,
  4743. CONST DEVMODEW *pDevMode
  4744. )
  4745. {
  4746. if(RunInWOW64())
  4747. {
  4748. return(DeviceCapabilitiesWThunk(pDevice,
  4749. pPort,
  4750. fwCapability,
  4751. pOutput,
  4752. pDevMode));
  4753. }
  4754. else
  4755. {
  4756. return(DeviceCapabilitiesWNative(pDevice,
  4757. pPort,
  4758. fwCapability,
  4759. pOutput,
  4760. pDevMode));
  4761. }
  4762. }
  4763. BOOL
  4764. AddFormW(
  4765. HANDLE hPrinter,
  4766. DWORD Level,
  4767. LPBYTE pForm
  4768. )
  4769. {
  4770. BOOL ReturnValue;
  4771. GENERIC_CONTAINER FormContainer;
  4772. PSPOOL pSpool = (PSPOOL)hPrinter;
  4773. UINT cRetry = 0;
  4774. switch (Level) {
  4775. case 1:
  4776. break;
  4777. default:
  4778. SetLastError(ERROR_INVALID_LEVEL);
  4779. return FALSE;
  4780. }
  4781. if( eProtectHandle( hPrinter, FALSE )){
  4782. return FALSE;
  4783. }
  4784. FormContainer.Level = Level;
  4785. FormContainer.pData = pForm;
  4786. do {
  4787. RpcTryExcept {
  4788. if (ReturnValue = RpcAddForm(pSpool->hPrinter,
  4789. (PFORM_CONTAINER)&FormContainer)) {
  4790. SetLastError(ReturnValue);
  4791. ReturnValue = FALSE;
  4792. } else
  4793. ReturnValue = TRUE;
  4794. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  4795. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4796. ReturnValue = FALSE;
  4797. } RpcEndExcept
  4798. } while( !ReturnValue &&
  4799. GetLastError() == ERROR_INVALID_HANDLE &&
  4800. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  4801. RevalidateHandle( pSpool ));
  4802. vUnprotectHandle( hPrinter );
  4803. return ReturnValue;
  4804. }
  4805. BOOL
  4806. DeleteFormW(
  4807. HANDLE hPrinter,
  4808. LPWSTR pFormName
  4809. )
  4810. {
  4811. BOOL ReturnValue;
  4812. PSPOOL pSpool = (PSPOOL)hPrinter;
  4813. UINT cRetry = 0;
  4814. if( eProtectHandle( hPrinter, FALSE )){
  4815. return FALSE;
  4816. }
  4817. do {
  4818. RpcTryExcept {
  4819. if (ReturnValue = RpcDeleteForm(pSpool->hPrinter, pFormName)) {
  4820. SetLastError(ReturnValue);
  4821. ReturnValue = FALSE;
  4822. } else
  4823. ReturnValue = TRUE;
  4824. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  4825. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4826. ReturnValue = FALSE;
  4827. } RpcEndExcept
  4828. } while( !ReturnValue &&
  4829. GetLastError() == ERROR_INVALID_HANDLE &&
  4830. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  4831. RevalidateHandle( pSpool ));
  4832. vUnprotectHandle( hPrinter );
  4833. return ReturnValue;
  4834. }
  4835. BOOL
  4836. GetFormW(
  4837. HANDLE hPrinter,
  4838. LPWSTR pFormName,
  4839. DWORD Level,
  4840. LPBYTE pForm,
  4841. DWORD cbBuf,
  4842. LPDWORD pcbNeeded
  4843. )
  4844. {
  4845. BOOL ReturnValue;
  4846. FieldInfo *pFieldInfo;
  4847. PSPOOL pSpool = (PSPOOL)hPrinter;
  4848. UINT cRetry = 0;
  4849. SIZE_T cbStruct;
  4850. switch (Level) {
  4851. case 1:
  4852. pFieldInfo = FormInfo1Fields;
  4853. cbStruct = sizeof(FORM_INFO_1);
  4854. break;
  4855. default:
  4856. SetLastError(ERROR_INVALID_LEVEL);
  4857. return FALSE;
  4858. }
  4859. if( eProtectHandle( hPrinter, FALSE )){
  4860. return FALSE;
  4861. }
  4862. do {
  4863. RpcTryExcept {
  4864. if (pForm)
  4865. memset(pForm, 0, cbBuf);
  4866. if (ReturnValue = RpcGetForm(pSpool->hPrinter, pFormName, Level, pForm,
  4867. cbBuf, pcbNeeded)) {
  4868. SetLastError(ReturnValue);
  4869. ReturnValue = FALSE;
  4870. } else {
  4871. ReturnValue = TRUE;
  4872. if (pForm) {
  4873. ReturnValue = MarshallUpStructure(pForm, pFieldInfo, cbStruct, RPC_CALL);
  4874. }
  4875. }
  4876. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  4877. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4878. ReturnValue = FALSE;
  4879. } RpcEndExcept
  4880. } while( !ReturnValue &&
  4881. GetLastError() == ERROR_INVALID_HANDLE &&
  4882. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  4883. RevalidateHandle( pSpool ));
  4884. vUnprotectHandle( hPrinter );
  4885. return ReturnValue;
  4886. }
  4887. BOOL
  4888. SetFormW(
  4889. HANDLE hPrinter,
  4890. LPWSTR pFormName,
  4891. DWORD Level,
  4892. LPBYTE pForm
  4893. )
  4894. {
  4895. BOOL ReturnValue;
  4896. GENERIC_CONTAINER FormContainer;
  4897. PSPOOL pSpool = (PSPOOL)hPrinter;
  4898. UINT cRetry = 0;
  4899. switch (Level) {
  4900. case 1:
  4901. break;
  4902. default:
  4903. SetLastError(ERROR_INVALID_LEVEL);
  4904. return FALSE;
  4905. }
  4906. if( eProtectHandle( hPrinter, FALSE )){
  4907. return FALSE;
  4908. }
  4909. FormContainer.Level = Level;
  4910. FormContainer.pData = pForm;
  4911. do {
  4912. RpcTryExcept {
  4913. if (ReturnValue = RpcSetForm(pSpool->hPrinter, pFormName,
  4914. (PFORM_CONTAINER)&FormContainer)) {
  4915. SetLastError(ReturnValue);
  4916. ReturnValue = FALSE;
  4917. } else
  4918. ReturnValue = TRUE;
  4919. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  4920. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4921. ReturnValue = FALSE;
  4922. } RpcEndExcept
  4923. } while( !ReturnValue &&
  4924. GetLastError() == ERROR_INVALID_HANDLE &&
  4925. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  4926. RevalidateHandle( pSpool ));
  4927. vUnprotectHandle( hPrinter );
  4928. return ReturnValue;
  4929. }
  4930. BOOL
  4931. EnumFormsW(
  4932. HANDLE hPrinter,
  4933. DWORD Level,
  4934. LPBYTE pForm,
  4935. DWORD cbBuf,
  4936. LPDWORD pcbNeeded,
  4937. LPDWORD pcReturned
  4938. )
  4939. {
  4940. BOOL ReturnValue;
  4941. DWORD cbStruct, cbStruct32;
  4942. FieldInfo *pFieldInfo;
  4943. PSPOOL pSpool = (PSPOOL)hPrinter;
  4944. UINT cRetry = 0;
  4945. switch (Level) {
  4946. case 1:
  4947. pFieldInfo = FormInfo1Fields;
  4948. cbStruct = sizeof(FORM_INFO_1);
  4949. break;
  4950. default:
  4951. SetLastError(ERROR_INVALID_LEVEL);
  4952. return FALSE;
  4953. }
  4954. if( eProtectHandle( hPrinter, FALSE )){
  4955. return FALSE;
  4956. }
  4957. do {
  4958. RpcTryExcept {
  4959. if (pForm)
  4960. memset(pForm, 0, cbBuf);
  4961. if (ReturnValue = RpcEnumForms(pSpool->hPrinter, Level, pForm, cbBuf,
  4962. pcbNeeded, pcReturned)) {
  4963. SetLastError(ReturnValue);
  4964. ReturnValue = FALSE;
  4965. } else {
  4966. ReturnValue = TRUE;
  4967. if (pForm) {
  4968. ReturnValue = MarshallUpStructuresArray(pForm, *pcReturned, pFieldInfo,
  4969. cbStruct, RPC_CALL);
  4970. }
  4971. }
  4972. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  4973. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  4974. ReturnValue = FALSE;
  4975. } RpcEndExcept
  4976. } while( !ReturnValue &&
  4977. GetLastError() == ERROR_INVALID_HANDLE &&
  4978. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  4979. RevalidateHandle( pSpool ));
  4980. vUnprotectHandle( hPrinter );
  4981. return ReturnValue;
  4982. }
  4983. BOOL
  4984. EnumPortsW(
  4985. LPWSTR pName,
  4986. DWORD Level,
  4987. LPBYTE pPort,
  4988. DWORD cbBuf,
  4989. LPDWORD pcbNeeded,
  4990. LPDWORD pcReturned
  4991. )
  4992. {
  4993. BOOL ReturnValue;
  4994. DWORD cbStruct;
  4995. FieldInfo *pFieldInfo;
  4996. switch (Level) {
  4997. case 1:
  4998. pFieldInfo = PortInfo1Fields;
  4999. cbStruct = sizeof(PORT_INFO_1);
  5000. break;
  5001. case 2:
  5002. pFieldInfo = PortInfo2Fields;
  5003. cbStruct = sizeof(PORT_INFO_2);
  5004. break;
  5005. default:
  5006. SetLastError(ERROR_INVALID_LEVEL);
  5007. return FALSE;
  5008. }
  5009. RpcTryExcept {
  5010. if (pPort)
  5011. memset(pPort, 0, cbBuf);
  5012. if (ReturnValue = RpcEnumPorts(pName, Level, pPort, cbBuf,
  5013. pcbNeeded, pcReturned)) {
  5014. SetLastError(ReturnValue);
  5015. ReturnValue = FALSE;
  5016. } else {
  5017. ReturnValue = TRUE;
  5018. if (pPort) {
  5019. ReturnValue = MarshallUpStructuresArray(pPort, *pcReturned, pFieldInfo,
  5020. cbStruct, RPC_CALL);
  5021. }
  5022. }
  5023. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  5024. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  5025. ReturnValue = FALSE;
  5026. } RpcEndExcept
  5027. return ReturnValue;
  5028. }
  5029. BOOL
  5030. EnumMonitorsW(
  5031. LPWSTR pName,
  5032. DWORD Level,
  5033. LPBYTE pMonitor,
  5034. DWORD cbBuf,
  5035. LPDWORD pcbNeeded,
  5036. LPDWORD pcReturned
  5037. )
  5038. {
  5039. BOOL ReturnValue;
  5040. DWORD cbStruct;
  5041. FieldInfo *pFieldInfo;
  5042. switch (Level) {
  5043. case 1:
  5044. pFieldInfo = MonitorInfo1Fields;
  5045. cbStruct = sizeof(MONITOR_INFO_1);
  5046. break;
  5047. case 2:
  5048. pFieldInfo = MonitorInfo2Fields;
  5049. cbStruct = sizeof(MONITOR_INFO_2);
  5050. break;
  5051. default:
  5052. SetLastError(ERROR_INVALID_LEVEL);
  5053. return FALSE;
  5054. }
  5055. RpcTryExcept {
  5056. if (pMonitor)
  5057. memset(pMonitor, 0, cbBuf);
  5058. if (ReturnValue = RpcEnumMonitors(pName, Level, pMonitor, cbBuf,
  5059. pcbNeeded, pcReturned)) {
  5060. SetLastError(ReturnValue);
  5061. ReturnValue = FALSE;
  5062. } else {
  5063. ReturnValue = TRUE;
  5064. if (pMonitor) {
  5065. ReturnValue = MarshallUpStructuresArray(pMonitor, *pcReturned, pFieldInfo,
  5066. cbStruct, RPC_CALL);
  5067. }
  5068. }
  5069. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  5070. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  5071. ReturnValue = FALSE;
  5072. } RpcEndExcept
  5073. return ReturnValue;
  5074. }
  5075. typedef struct {
  5076. LPWSTR pName;
  5077. HWND hWnd;
  5078. LPWSTR pPortName;
  5079. HANDLE Complete;
  5080. DWORD ReturnValue;
  5081. DWORD Error;
  5082. INT_FARPROC pfn;
  5083. } CONFIGUREPORT_PARAMETERS;
  5084. void
  5085. PortThread(
  5086. CONFIGUREPORT_PARAMETERS *pParam
  5087. )
  5088. {
  5089. DWORD ReturnValue;
  5090. /* It's no use setting errors here, because they're kept on a per-thread
  5091. * basis. Instead we have to pass any error code back to the calling
  5092. * thread and let him set it.
  5093. */
  5094. RpcTryExcept {
  5095. if (ReturnValue = (*pParam->pfn)(pParam->pName, pParam->hWnd,
  5096. pParam->pPortName)) {
  5097. pParam->Error = ReturnValue;
  5098. ReturnValue = FALSE;
  5099. } else
  5100. ReturnValue = TRUE;
  5101. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  5102. pParam->Error = TranslateExceptionCode(RpcExceptionCode());
  5103. ReturnValue = FALSE;
  5104. } RpcEndExcept
  5105. pParam->ReturnValue = ReturnValue;
  5106. SetEvent(pParam->Complete);
  5107. }
  5108. BOOL
  5109. KickoffThread(
  5110. LPWSTR pName,
  5111. HWND hWnd,
  5112. LPWSTR pPortName,
  5113. INT_FARPROC pfn
  5114. )
  5115. {
  5116. CONFIGUREPORT_PARAMETERS Parameters;
  5117. HANDLE ThreadHandle;
  5118. MSG msg;
  5119. DWORD ThreadId;
  5120. if( hWnd ){
  5121. EnableWindow(hWnd, FALSE);
  5122. }
  5123. Parameters.pName = pName;
  5124. Parameters.hWnd = hWnd;
  5125. Parameters.pPortName = pPortName;
  5126. Parameters.Complete = CreateEvent(NULL, TRUE, FALSE, NULL);
  5127. Parameters.pfn = pfn;
  5128. ThreadHandle = CreateThread(NULL, INITIAL_STACK_COMMIT,
  5129. (LPTHREAD_START_ROUTINE)PortThread,
  5130. &Parameters, 0, &ThreadId);
  5131. if( ThreadHandle ){
  5132. CloseHandle(ThreadHandle);
  5133. while (MsgWaitForMultipleObjects(1, &Parameters.Complete, FALSE, INFINITE,
  5134. QS_ALLEVENTS | QS_SENDMESSAGE) == 1) {
  5135. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  5136. TranslateMessage(&msg);
  5137. DispatchMessage(&msg);
  5138. }
  5139. }
  5140. CloseHandle(Parameters.Complete);
  5141. if( hWnd ){
  5142. EnableWindow(hWnd, TRUE);
  5143. SetForegroundWindow(hWnd);
  5144. SetFocus(hWnd);
  5145. }
  5146. if(!Parameters.ReturnValue)
  5147. SetLastError(Parameters.Error);
  5148. return Parameters.ReturnValue;
  5149. }
  5150. return FALSE;
  5151. }
  5152. BOOL
  5153. AddPortWNative(
  5154. LPWSTR pName,
  5155. HWND hWnd,
  5156. LPWSTR pMonitorName
  5157. )
  5158. {
  5159. DWORD dwRet;
  5160. DWORD dwSessionId;
  5161. BOOL bRet;
  5162. PMONITORUI pMonitorUI;
  5163. PMONITORUIDATA pMonitorUIData = NULL;
  5164. dwRet = GetMonitorUI(pName, pMonitorName, L"XcvMonitor", &pMonitorUI, &pMonitorUIData);
  5165. if (dwRet == ERROR_SUCCESS ||
  5166. dwRet == ERROR_INVALID_PRINT_MONITOR ||
  5167. dwRet == ERROR_INVALID_PRINTER_NAME ||
  5168. dwRet == ERROR_NOT_SUPPORTED ||
  5169. dwRet == ERROR_MOD_NOT_FOUND ||
  5170. dwRet == ERROR_UNKNOWN_PORT) {
  5171. if (dwRet == ERROR_SUCCESS) {
  5172. bRet = (*pMonitorUI->pfnAddPortUI)(pName, hWnd, pMonitorName, NULL);
  5173. dwRet = GetLastError();
  5174. } else if ((bRet = ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId)) && dwSessionId) {
  5175. bRet = FALSE;
  5176. dwRet = ERROR_NOT_SUPPORTED;
  5177. } else {
  5178. bRet = KickoffThread(pName, hWnd, pMonitorName, RpcAddPort);
  5179. dwRet = GetLastError();
  5180. }
  5181. SetLastError(dwRet);
  5182. } else {
  5183. SetLastError(dwRet);
  5184. bRet = FALSE;
  5185. }
  5186. FreeMonitorUI(pMonitorUIData);
  5187. return bRet;
  5188. }
  5189. BOOL
  5190. AddPortWThunk(
  5191. LPWSTR pName,
  5192. HWND hWnd,
  5193. LPWSTR pMonitorName
  5194. )
  5195. {
  5196. DWORD dwRet;
  5197. DWORD dwSessionId;
  5198. BOOL bRet;
  5199. PMONITORUI pMonitorUI;
  5200. LPWSTR pMonitorUIDll = NULL;
  5201. dwRet = GetMonitorUIDll(pName,pMonitorName,L"XcvMonitor",&pMonitorUIDll);
  5202. RpcTryExcept
  5203. {
  5204. if (dwRet == ERROR_SUCCESS ||
  5205. dwRet == ERROR_INVALID_PRINT_MONITOR ||
  5206. dwRet == ERROR_INVALID_PRINTER_NAME ||
  5207. dwRet == ERROR_NOT_SUPPORTED ||
  5208. dwRet == ERROR_MOD_NOT_FOUND ||
  5209. dwRet == ERROR_UNKNOWN_PORT) {
  5210. if (dwRet == ERROR_SUCCESS)
  5211. {
  5212. MSG msg;
  5213. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  5214. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  5215. {
  5216. //
  5217. // The following functions cann't proceed synchronasly. The reason
  5218. // for that is in order to show the UI of the port monitor we need
  5219. // to be able to dispatch incomming messages and process them.
  5220. // For this reason the following call is an asynchronous call and the
  5221. // success or failure doesn't in reality tell us anything more than
  5222. // than the async process started or not
  5223. //
  5224. if(bRet = RPCSplWOW64AddPort((ULONG_PTR)hWnd,
  5225. pName,
  5226. pMonitorUIDll,
  5227. pMonitorName,
  5228. &dwRet))
  5229. {
  5230. //
  5231. // The following is the required message loop for processing messages
  5232. // from the UI. The window handle has to be NULL in order to process
  5233. // messages from all windows in the calling Thread , otherwise we would
  5234. // have message dispatching problems
  5235. //
  5236. while (GetMessage(&msg, NULL, 0, 0))
  5237. {
  5238. //
  5239. // In This message loop We should trap a User defined message
  5240. // which indicates the success or the failure of the operation
  5241. //
  5242. if(msg.message == WM_ENDADDPORT)
  5243. {
  5244. bRet = (BOOL)msg.wParam;
  5245. if(!bRet)
  5246. dwRet = (DWORD)msg.lParam;
  5247. else
  5248. dwRet = ERROR_SUCCESS;
  5249. DelHandleFromList(hWnd);
  5250. break;
  5251. }
  5252. else if(msg.message == WM_SURROGATEFAILURE)
  5253. {
  5254. //
  5255. // This means that the server process died and we have
  5256. // break from the message loop
  5257. //
  5258. bRet = FALSE;
  5259. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  5260. PostMessage(hWnd,WM_ACTIVATEAPP,TRUE,0);
  5261. break;
  5262. }
  5263. TranslateMessage(&msg);
  5264. DispatchMessage(&msg);
  5265. }
  5266. }
  5267. }
  5268. else
  5269. {
  5270. bRet = FALSE;
  5271. }
  5272. SetLastError(dwRet);
  5273. }
  5274. else if ((bRet = ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId)) && dwSessionId)
  5275. {
  5276. bRet = FALSE;
  5277. dwRet = ERROR_NOT_SUPPORTED;
  5278. }
  5279. else
  5280. {
  5281. bRet = KickoffThread(pName, hWnd, pMonitorName, RpcAddPort);
  5282. dwRet = GetLastError();
  5283. }
  5284. if(pMonitorUIDll)
  5285. {
  5286. FreeSplMem(pMonitorUIDll);
  5287. }
  5288. /* FreeLibrary is busting the last error, so we need to set it here
  5289. */
  5290. SetLastError(dwRet);
  5291. }
  5292. else
  5293. {
  5294. SetLastError(dwRet);
  5295. bRet = FALSE;
  5296. }
  5297. }
  5298. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  5299. {
  5300. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  5301. bRet = FALSE;
  5302. }
  5303. RpcEndExcept
  5304. return(bRet);
  5305. }
  5306. BOOL
  5307. AddPortW(
  5308. LPWSTR pName,
  5309. HWND hWnd,
  5310. LPWSTR pMonitorName
  5311. )
  5312. {
  5313. if(RunInWOW64())
  5314. {
  5315. return(AddPortWThunk(pName,
  5316. hWnd,
  5317. pMonitorName));
  5318. }
  5319. else
  5320. {
  5321. return(AddPortWNative(pName,
  5322. hWnd,
  5323. pMonitorName));
  5324. }
  5325. }
  5326. BOOL
  5327. ConfigurePortWNative(
  5328. LPWSTR pName,
  5329. HWND hWnd,
  5330. LPWSTR pPortName
  5331. )
  5332. {
  5333. DWORD dwRet;
  5334. DWORD dwSessionId;
  5335. BOOL bRet;
  5336. PMONITORUI pMonitorUI;
  5337. PMONITORUIDATA pMonitorUIData = NULL;
  5338. dwRet = GetMonitorUI(pName, pPortName, L"XcvPort", &pMonitorUI, &pMonitorUIData);
  5339. if (dwRet == ERROR_SUCCESS ||
  5340. dwRet == ERROR_INVALID_PRINT_MONITOR ||
  5341. dwRet == ERROR_INVALID_PRINTER_NAME ||
  5342. dwRet == ERROR_NOT_SUPPORTED ||
  5343. dwRet == ERROR_MOD_NOT_FOUND ||
  5344. dwRet == ERROR_UNKNOWN_PORT) {
  5345. if (dwRet == ERROR_SUCCESS) {
  5346. bRet = (*pMonitorUI->pfnConfigurePortUI)(pName, hWnd, pPortName);
  5347. } else if ((bRet = ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId)) && dwSessionId) {
  5348. bRet = FALSE;
  5349. SetLastError(ERROR_NOT_SUPPORTED);
  5350. } else {
  5351. bRet = KickoffThread(pName, hWnd, pPortName, RpcConfigurePort);
  5352. }
  5353. } else {
  5354. SetLastError(dwRet);
  5355. bRet = FALSE;
  5356. }
  5357. FreeMonitorUI(pMonitorUIData);
  5358. return bRet;
  5359. }
  5360. BOOL
  5361. ConfigurePortWThunk(
  5362. LPWSTR pName,
  5363. HWND hWnd,
  5364. LPWSTR pPortName
  5365. )
  5366. {
  5367. DWORD dwRet;
  5368. DWORD dwSessionId;
  5369. BOOL bRet;
  5370. PMONITORUI pMonitorUI;
  5371. LPWSTR pMonitorUIDll = NULL;
  5372. dwRet = GetMonitorUIDll(pName,pPortName,L"XcvPort",&pMonitorUIDll);
  5373. if (dwRet == ERROR_SUCCESS ||
  5374. dwRet == ERROR_INVALID_PRINT_MONITOR ||
  5375. dwRet == ERROR_INVALID_PRINTER_NAME ||
  5376. dwRet == ERROR_NOT_SUPPORTED ||
  5377. dwRet == ERROR_MOD_NOT_FOUND ||
  5378. dwRet == ERROR_UNKNOWN_PORT) {
  5379. if (dwRet == ERROR_SUCCESS)
  5380. {
  5381. RpcTryExcept
  5382. {
  5383. MSG msg;
  5384. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  5385. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  5386. {
  5387. //
  5388. // The following functions cann't proceed synchronasly. The reason
  5389. // for that is in order to show the UI of the port monitor we need
  5390. // to be able to dispatch incomming messages and process them.
  5391. // For this reason the following call is an asynchronous call and the
  5392. // success or failure doesn't in reality tell us anything more than
  5393. // than the async process started or not
  5394. //
  5395. if(bRet = RPCSplWOW64ConfigurePort((ULONG_PTR)hWnd,
  5396. pName,
  5397. pMonitorUIDll,
  5398. pPortName,
  5399. &dwRet))
  5400. {
  5401. //
  5402. // The following is the required message loop for processing messages
  5403. // from the UI. The window handle has to be NULL in order to process
  5404. // messages from all windows in the calling Thread , otherwise we would
  5405. // have message dispatching problems
  5406. //
  5407. while (GetMessage(&msg, NULL, 0, 0))
  5408. {
  5409. //
  5410. // In This message loop We should trap a User defined message
  5411. // which indicates the success or the failure of the operation
  5412. //
  5413. if(msg.message == WM_ENDCFGPORT)
  5414. {
  5415. bRet = (BOOL)msg.wParam;
  5416. if(!bRet)
  5417. dwRet = (DWORD)msg.lParam;
  5418. else
  5419. dwRet = ERROR_SUCCESS;
  5420. DelHandleFromList(hWnd);
  5421. break;
  5422. }
  5423. else if(msg.message == WM_SURROGATEFAILURE)
  5424. {
  5425. //
  5426. // This means that the server process died and we have
  5427. // break from the message loop
  5428. //
  5429. bRet = FALSE;
  5430. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  5431. break;
  5432. }
  5433. TranslateMessage(&msg);
  5434. DispatchMessage(&msg);
  5435. }
  5436. }
  5437. }
  5438. else
  5439. {
  5440. bRet = FALSE;
  5441. }
  5442. SetLastError(dwRet);
  5443. }
  5444. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  5445. {
  5446. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  5447. bRet = FALSE;
  5448. }
  5449. RpcEndExcept
  5450. }
  5451. else if ((bRet = ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId)) && dwSessionId) {
  5452. bRet = FALSE;
  5453. SetLastError(ERROR_NOT_SUPPORTED);
  5454. } else {
  5455. bRet = KickoffThread(pName, hWnd, pPortName, RpcConfigurePort);
  5456. }
  5457. if(pMonitorUIDll)
  5458. {
  5459. FreeSplMem(pMonitorUIDll);
  5460. }
  5461. }
  5462. else
  5463. {
  5464. SetLastError(dwRet);
  5465. bRet = FALSE;
  5466. }
  5467. return(bRet);
  5468. }
  5469. BOOL
  5470. ConfigurePortW(
  5471. LPWSTR pName,
  5472. HWND hWnd,
  5473. LPWSTR pPortName
  5474. )
  5475. {
  5476. if(RunInWOW64())
  5477. {
  5478. return(ConfigurePortWThunk(pName,
  5479. hWnd,
  5480. pPortName));
  5481. }
  5482. else
  5483. {
  5484. return(ConfigurePortWNative(pName,
  5485. hWnd,
  5486. pPortName));
  5487. }
  5488. }
  5489. BOOL
  5490. DeletePortWNative(
  5491. LPWSTR pName,
  5492. HWND hWnd,
  5493. LPWSTR pPortName
  5494. )
  5495. {
  5496. DWORD dwRet;
  5497. BOOL bRet;
  5498. PMONITORUI pMonitorUI;
  5499. PMONITORUIDATA pMonitorUIData = NULL;
  5500. dwRet = GetMonitorUI(pName, pPortName, L"XcvPort", &pMonitorUI, &pMonitorUIData);
  5501. if (dwRet == ERROR_SUCCESS ||
  5502. dwRet == ERROR_INVALID_PRINT_MONITOR ||
  5503. dwRet == ERROR_INVALID_PRINTER_NAME ||
  5504. dwRet == ERROR_NOT_SUPPORTED ||
  5505. dwRet == ERROR_MOD_NOT_FOUND ||
  5506. dwRet == ERROR_UNKNOWN_PORT) {
  5507. if (dwRet == ERROR_SUCCESS)
  5508. bRet = (*pMonitorUI->pfnDeletePortUI)(pName, hWnd, pPortName);
  5509. else
  5510. bRet = KickoffThread(pName, hWnd, pPortName, RpcDeletePort);
  5511. } else {
  5512. SetLastError(dwRet);
  5513. bRet = FALSE;
  5514. }
  5515. FreeMonitorUI(pMonitorUIData);
  5516. return bRet;
  5517. }
  5518. BOOL
  5519. DeletePortWThunk(
  5520. LPWSTR pName,
  5521. HWND hWnd,
  5522. LPWSTR pPortName
  5523. )
  5524. {
  5525. DWORD dwRet;
  5526. BOOL bRet;
  5527. PMONITORUI pMonitorUI;
  5528. LPWSTR pMonitorUIDll = NULL;
  5529. dwRet = GetMonitorUIDll(pName,pPortName,L"XcvPort",&pMonitorUIDll);
  5530. if (dwRet == ERROR_SUCCESS ||
  5531. dwRet == ERROR_INVALID_PRINT_MONITOR ||
  5532. dwRet == ERROR_INVALID_PRINTER_NAME ||
  5533. dwRet == ERROR_NOT_SUPPORTED ||
  5534. dwRet == ERROR_MOD_NOT_FOUND ||
  5535. dwRet == ERROR_UNKNOWN_PORT) {
  5536. if (dwRet == ERROR_SUCCESS)
  5537. {
  5538. RpcTryExcept
  5539. {
  5540. MSG msg;
  5541. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  5542. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  5543. {
  5544. //
  5545. // The following functions cann't proceed synchronasly. The reason
  5546. // for that is in order to show the UI of the port monitor we need
  5547. // to be able to dispatch incomming messages and process them.
  5548. // For this reason the following call is an asynchronous call and the
  5549. // success or failure doesn't in reality tell us anything more than
  5550. // than the async process started or not
  5551. //
  5552. if(bRet = RPCSplWOW64DeletePort((ULONG_PTR)hWnd,
  5553. pName,
  5554. pMonitorUIDll,
  5555. pPortName,
  5556. &dwRet))
  5557. {
  5558. //
  5559. // The following is the required message loop for processing messages
  5560. // from the UI. The window handle has to be NULL in order to process
  5561. // messages from all windows in the calling Thread , otherwise we would
  5562. // have message dispatching problems
  5563. //
  5564. while (GetMessage(&msg, NULL, 0, 0))
  5565. {
  5566. //
  5567. // In This message loop We should trap a User defined message
  5568. // which indicates the success or the failure of the operation
  5569. //
  5570. if(msg.message == WM_ENDDELPORT)
  5571. {
  5572. bRet = (BOOL)msg.wParam;
  5573. if(!bRet)
  5574. dwRet = (DWORD)msg.lParam;
  5575. else
  5576. dwRet = ERROR_SUCCESS;
  5577. DelHandleFromList(hWnd);
  5578. break;
  5579. }
  5580. else if(msg.message == WM_SURROGATEFAILURE)
  5581. {
  5582. //
  5583. // This means that the server process died and we have
  5584. // break from the message loop
  5585. //
  5586. bRet = FALSE;
  5587. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  5588. break;
  5589. }
  5590. TranslateMessage(&msg);
  5591. DispatchMessage(&msg);
  5592. }
  5593. }
  5594. }
  5595. else
  5596. {
  5597. bRet = FALSE;
  5598. }
  5599. SetLastError(dwRet);
  5600. }
  5601. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  5602. {
  5603. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  5604. bRet = FALSE;
  5605. }
  5606. RpcEndExcept
  5607. }
  5608. else
  5609. bRet = KickoffThread(pName, hWnd, pPortName, RpcDeletePort);
  5610. if(pMonitorUIDll)
  5611. {
  5612. FreeSplMem(pMonitorUIDll);
  5613. }
  5614. }
  5615. else
  5616. {
  5617. SetLastError(dwRet);
  5618. bRet = FALSE;
  5619. }
  5620. return(bRet);
  5621. }
  5622. BOOL
  5623. DeletePortW(
  5624. LPWSTR pName,
  5625. HWND hWnd,
  5626. LPWSTR pPortName
  5627. )
  5628. {
  5629. if(RunInWOW64())
  5630. {
  5631. return(DeletePortWThunk(pName,
  5632. hWnd,
  5633. pPortName));
  5634. }
  5635. else
  5636. {
  5637. return(DeletePortWNative(pName,
  5638. hWnd,
  5639. pPortName));
  5640. }
  5641. }
  5642. DWORD
  5643. GetMonitorUI(
  5644. IN PCWSTR pszMachineName,
  5645. IN PCWSTR pszObjectName,
  5646. IN PCWSTR pszObjectType,
  5647. OUT PMONITORUI *ppMonitorUI,
  5648. OUT PMONITORUIDATA *ppMonitorUIData
  5649. )
  5650. {
  5651. DWORD ReturnValue;
  5652. DWORD dwDummy; // RPC needs an address for 'out' parameters
  5653. HANDLE hXcv = NULL;
  5654. PBYTE pOutputData = NULL;
  5655. DWORD cbOutput;
  5656. PWSTR pszServerName = NULL;
  5657. PRINTER_DEFAULTS Default;
  5658. PMONITORUI (*pfnInitializePrintMonitorUI)(VOID) = NULL;
  5659. DWORD dwStatus;
  5660. BOOL bAllocBuffer = FALSE;
  5661. BYTE btBuffer[MAX_STATIC_ALLOC];
  5662. PMONITORUIDATA pMonitorUIData = NULL;
  5663. HRESULT hRetval;
  5664. Default.pDatatype = NULL;
  5665. Default.pDevMode = NULL;
  5666. Default.DesiredAccess = SERVER_ACCESS_ADMINISTER;
  5667. *ppMonitorUI = NULL;
  5668. *ppMonitorUIData = NULL;
  5669. if (!(pszServerName = ConstructXcvName(pszMachineName, pszObjectName, pszObjectType))) {
  5670. ReturnValue = GetLastError();
  5671. goto Done;
  5672. }
  5673. RpcTryExcept {
  5674. ReturnValue = OpenPrinter( pszServerName,
  5675. &hXcv,
  5676. &Default);
  5677. if (!ReturnValue) {
  5678. ReturnValue = GetLastError();
  5679. goto Done;
  5680. }
  5681. pOutputData = (PBYTE) btBuffer;
  5682. ZeroMemory(pOutputData, MAX_STATIC_ALLOC);
  5683. ReturnValue = RpcXcvData( ((PSPOOL)hXcv)->hPrinter,
  5684. L"MonitorUI",
  5685. (PBYTE) &dwDummy,
  5686. 0,
  5687. pOutputData,
  5688. MAX_STATIC_ALLOC,
  5689. &cbOutput,
  5690. &dwStatus);
  5691. if (ReturnValue != ERROR_SUCCESS)
  5692. goto Done;
  5693. if (dwStatus != ERROR_SUCCESS) {
  5694. if (dwStatus != ERROR_INSUFFICIENT_BUFFER) {
  5695. ReturnValue = dwStatus;
  5696. goto Done;
  5697. }
  5698. if (!(pOutputData = AllocSplMem(cbOutput))) {
  5699. ReturnValue = GetLastError();
  5700. goto Done;
  5701. }
  5702. bAllocBuffer = TRUE;
  5703. ReturnValue = RpcXcvData( ((PSPOOL)hXcv)->hPrinter,
  5704. L"MonitorUI",
  5705. (PBYTE) &dwDummy,
  5706. 0,
  5707. pOutputData,
  5708. cbOutput,
  5709. &cbOutput,
  5710. &dwStatus);
  5711. }
  5712. if (ReturnValue != ERROR_SUCCESS)
  5713. goto Done;
  5714. if (dwStatus != ERROR_SUCCESS) {
  5715. ReturnValue = dwStatus;
  5716. goto Done;
  5717. }
  5718. //
  5719. // Create and initialize the monitor UI data.
  5720. //
  5721. hRetval = CreateMonitorUIData(&pMonitorUIData);
  5722. if (FAILED(hRetval)) {
  5723. ReturnValue = HRESULT_CODE(hRetval);
  5724. goto Done;
  5725. }
  5726. //
  5727. // Get and activate the monitor UI context.
  5728. //
  5729. hRetval = GetMonitorUIActivationContext((PCWSTR)pOutputData, pMonitorUIData);
  5730. if (FAILED(hRetval)) {
  5731. ReturnValue = HRESULT_CODE(hRetval);
  5732. goto Done;
  5733. }
  5734. if (!(pMonitorUIData->hLibrary = LoadLibrary(pMonitorUIData->pszMonitorName))) {
  5735. ReturnValue = GetLastError();
  5736. goto Done;
  5737. }
  5738. pfnInitializePrintMonitorUI = (PMONITORUI (*)(VOID))
  5739. GetProcAddress(pMonitorUIData->hLibrary, "InitializePrintMonitorUI");
  5740. if (!pfnInitializePrintMonitorUI) {
  5741. ReturnValue = GetLastError();
  5742. goto Done;
  5743. }
  5744. *ppMonitorUI = (*pfnInitializePrintMonitorUI)();
  5745. *ppMonitorUIData = pMonitorUIData;
  5746. pMonitorUIData = NULL;
  5747. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  5748. SetLastError(ReturnValue = TranslateExceptionCode(RpcExceptionCode()));
  5749. } RpcEndExcept
  5750. Done:
  5751. if (bAllocBuffer) {
  5752. FreeSplMem(pOutputData);
  5753. }
  5754. if (hXcv) {
  5755. ClosePrinter(hXcv);
  5756. }
  5757. FreeSplMem(pszServerName);
  5758. FreeMonitorUI(pMonitorUIData);
  5759. return ReturnValue;
  5760. }
  5761. /*++
  5762. Routine Name:
  5763. CreateMonitorUIData
  5764. Routine Description:
  5765. This function creates and initialize the monitor UI data.
  5766. Arguments:
  5767. ppMonitorUIData - pointer where to return the monitor UI data
  5768. Returns:
  5769. An HRESULT
  5770. --*/
  5771. HRESULT
  5772. CreateMonitorUIData(
  5773. OUT MONITORUIDATA **ppMonitorUIData
  5774. )
  5775. {
  5776. HRESULT hRetval = E_FAIL;
  5777. MONITORUIDATA *pMonitorUIData = NULL;
  5778. hRetval = ppMonitorUIData ? S_OK : E_POINTER;
  5779. if (SUCCEEDED(hRetval))
  5780. {
  5781. *ppMonitorUIData = NULL;
  5782. }
  5783. if (SUCCEEDED(hRetval))
  5784. {
  5785. pMonitorUIData = AllocSplMem(sizeof(MONITORUIDATA));
  5786. hRetval = pMonitorUIData ? S_OK : E_OUTOFMEMORY;
  5787. }
  5788. //
  5789. // Initialize the monitor UI data.
  5790. //
  5791. if (SUCCEEDED(hRetval))
  5792. {
  5793. ZeroMemory(pMonitorUIData, sizeof(MONITORUIDATA));
  5794. pMonitorUIData->hActCtx = INVALID_HANDLE_VALUE;
  5795. }
  5796. //
  5797. // Everything succeeded, copy back the pointer.
  5798. //
  5799. if (SUCCEEDED(hRetval))
  5800. {
  5801. *ppMonitorUIData = pMonitorUIData;
  5802. }
  5803. return hRetval;
  5804. }
  5805. /*++
  5806. Routine Name:
  5807. FreeMonitorUI
  5808. Routine Description:
  5809. This function releases the monitor UI data. It is responsible
  5810. for releasing the monitor library as well the monitor fusion
  5811. activation context. Note this function is called in error cases
  5812. when GetMonitorUI fails so all the parameters must be checked
  5813. for validity before use.
  5814. Arguments:
  5815. pMonitorUIData - pointer to the monitor UI data created in GetMonitorUI
  5816. Returns:
  5817. Nothing.
  5818. --*/
  5819. VOID
  5820. FreeMonitorUI(
  5821. IN PMONITORUIDATA pMonitorUIData
  5822. )
  5823. {
  5824. //
  5825. // Preserve the last error.
  5826. //
  5827. DWORD dwLastError = GetLastError();
  5828. if (pMonitorUIData)
  5829. {
  5830. //
  5831. // Release the monitor library.
  5832. //
  5833. if (pMonitorUIData->hLibrary)
  5834. {
  5835. FreeLibrary(pMonitorUIData->hLibrary);
  5836. }
  5837. //
  5838. // If we have an activation cookie then deactivate this context
  5839. //
  5840. if (pMonitorUIData->bDidActivate)
  5841. {
  5842. DeactivateActCtx(0, pMonitorUIData->lActCtx);
  5843. }
  5844. //
  5845. // If we have created an activation context then release it.
  5846. //
  5847. if (pMonitorUIData->hActCtx != INVALID_HANDLE_VALUE && pMonitorUIData->hActCtx != ACTCTX_EMPTY)
  5848. {
  5849. ReleaseActCtx(pMonitorUIData->hActCtx);
  5850. }
  5851. //
  5852. // Release the monitor name
  5853. //
  5854. if (pMonitorUIData->pszMonitorName)
  5855. {
  5856. FreeSplMem(pMonitorUIData->pszMonitorName);
  5857. }
  5858. //
  5859. // Release the monitor UI data back to the heap.
  5860. //
  5861. FreeSplMem(pMonitorUIData);
  5862. }
  5863. SetLastError(dwLastError);
  5864. }
  5865. /*++
  5866. Routine Name:
  5867. GetMonitorUIActivationContext
  5868. Routine Description:
  5869. This routine gets the monitor UI activation context and then
  5870. activates the context. If the monitor does not have an activation
  5871. context in it's resource file it will activate the empty context
  5872. for compatiblity with previous version of common control.
  5873. Arguments:
  5874. pszMonitorName - pointer to the monitor name.
  5875. pMonitorUIData - pointer to the monitor UI data created in GetMonitorUI
  5876. Returns:
  5877. An HRESULT
  5878. --*/
  5879. HRESULT
  5880. GetMonitorUIActivationContext(
  5881. IN PCWSTR pszMonitorName,
  5882. IN MONITORUIDATA *pMonitorUIData
  5883. )
  5884. {
  5885. HRESULT hRetval = E_FAIL;
  5886. hRetval = pszMonitorName && pMonitorUIData ? S_OK : E_INVALIDARG;
  5887. //
  5888. // Get the monitor full name.
  5889. //
  5890. if (SUCCEEDED(hRetval))
  5891. {
  5892. hRetval = GetMonitorUIFullName(pszMonitorName, &pMonitorUIData->pszMonitorName);
  5893. }
  5894. //
  5895. // See if there is an activation context in the resouce of this
  5896. // monitor UI binary. If there is we will create this context
  5897. // else we will create the empty context for backward compatibility.
  5898. //
  5899. if (SUCCEEDED(hRetval))
  5900. {
  5901. ACTCTX act;
  5902. ZeroMemory(&act, sizeof(act));
  5903. act.cbSize = sizeof(act);
  5904. act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
  5905. act.lpSource = pMonitorUIData->pszMonitorName;
  5906. act.lpResourceName = MAKEINTRESOURCE(ACTIVATION_CONTEXT_RESOURCE_ID);
  5907. pMonitorUIData->hActCtx = CreateActCtx(&act);
  5908. if (pMonitorUIData->hActCtx == INVALID_HANDLE_VALUE)
  5909. {
  5910. pMonitorUIData->hActCtx = ACTCTX_EMPTY;
  5911. }
  5912. hRetval = pMonitorUIData->hActCtx ? S_OK : E_FAIL;
  5913. }
  5914. //
  5915. // Activate this context.
  5916. //
  5917. if (SUCCEEDED(hRetval))
  5918. {
  5919. hRetval = ActivateActCtx(pMonitorUIData->hActCtx,
  5920. &pMonitorUIData->lActCtx) ? S_OK : GetLastErrorAsHResult();
  5921. pMonitorUIData->bDidActivate = SUCCEEDED(hRetval);
  5922. }
  5923. return hRetval;
  5924. }
  5925. /*++
  5926. Routine Name:
  5927. GetMonitorUIFullName
  5928. Routine Description:
  5929. Get's the full monitor name. XCV is currently returning just the file name
  5930. not fully qualified. However the ddk does not indicate whether a monitor
  5931. should or should not return the monitor name fully qualified or not. Hence
  5932. this routine was written. It first builds a full name then it checkes if the
  5933. name is valid and if it is not then the orginal name is assumed fully
  5934. qualified and returned to the caller.
  5935. Arguments:
  5936. pszMonitorName - pointer to the monitor name.
  5937. ppszMonitorName - pointer where to return a monitor name pointer
  5938. Returns:
  5939. An HRESULT
  5940. --*/
  5941. HRESULT
  5942. GetMonitorUIFullName(
  5943. IN PCWSTR pszMonitorName,
  5944. IN PWSTR *ppszMonitorName
  5945. )
  5946. {
  5947. HRESULT hRetval = E_FAIL;
  5948. PWSTR pszTempMonitorName = NULL;
  5949. PWSTR pszBuff = NULL;
  5950. DWORD dwRetval = ERROR_SUCCESS;
  5951. hRetval = pszMonitorName && ppszMonitorName ? S_OK : E_INVALIDARG;
  5952. if (SUCCEEDED(hRetval))
  5953. {
  5954. *ppszMonitorName = NULL;
  5955. }
  5956. //
  5957. // Allocate a temp buffer, use the heap. Too much stack usage
  5958. // will cause stress failures.
  5959. //
  5960. if (SUCCEEDED(hRetval))
  5961. {
  5962. pszBuff = (PWSTR)AllocSplMem(MAX_PATH * sizeof(WCHAR));
  5963. hRetval = pszBuff ? S_OK : E_OUTOFMEMORY;
  5964. }
  5965. //
  5966. // We need a full path to create an activation context. Xcv
  5967. // is only returning the monitor name not the full path.
  5968. //
  5969. if (SUCCEEDED(hRetval))
  5970. {
  5971. hRetval = GetSystemDirectory(pszBuff, MAX_PATH) ? S_OK : GetLastErrorAsHResult();
  5972. }
  5973. //
  5974. // Append the monitor name to the system directory.
  5975. //
  5976. if (SUCCEEDED(hRetval))
  5977. {
  5978. dwRetval = StrCatAlloc(&pszTempMonitorName,
  5979. pszBuff,
  5980. szSlash,
  5981. pszMonitorName,
  5982. NULL);
  5983. hRetval = HRESULT_FROM_WIN32(dwRetval);
  5984. }
  5985. //
  5986. // Check to see if this is a valid name.
  5987. //
  5988. if (SUCCEEDED(hRetval))
  5989. {
  5990. hRetval = GetFileAttributes(pszTempMonitorName) != -1 ? S_OK : GetLastErrorAsHResult();
  5991. //
  5992. // Name is not valid, release the current name and
  5993. // make a copy of the name passed to us and return this
  5994. // and the full monitor name.
  5995. //
  5996. if (FAILED(hRetval))
  5997. {
  5998. FreeSplMem(pszTempMonitorName);
  5999. dwRetval = StrCatAlloc(&pszTempMonitorName,
  6000. pszMonitorName,
  6001. NULL);
  6002. hRetval = HRESULT_FROM_WIN32(dwRetval);
  6003. }
  6004. }
  6005. //
  6006. // We have a valid name return it to the caller.
  6007. //
  6008. if (SUCCEEDED(hRetval))
  6009. {
  6010. *ppszMonitorName = pszTempMonitorName;
  6011. pszTempMonitorName = NULL;
  6012. }
  6013. FreeSplMem(pszBuff);
  6014. FreeSplMem(pszTempMonitorName);
  6015. return hRetval;
  6016. }
  6017. DWORD
  6018. GetMonitorUIDll(
  6019. PCWSTR pszMachineName,
  6020. PCWSTR pszObjectName,
  6021. PCWSTR pszObjectType,
  6022. PWSTR *pMonitorUIDll
  6023. )
  6024. {
  6025. DWORD ReturnValue;
  6026. DWORD dwDummy; // RPC needs an address for 'out' parameters
  6027. HANDLE hXcv = NULL;
  6028. PBYTE pOutputData = NULL;
  6029. DWORD cbOutput;
  6030. PWSTR pszServerName = NULL;
  6031. PRINTER_DEFAULTS Default;
  6032. PMONITORUI (*pfnInitializePrintMonitorUI)(VOID) = NULL;
  6033. DWORD dwStatus;
  6034. BOOL bAllocBuffer = FALSE;
  6035. BYTE btBuffer[MAX_STATIC_ALLOC];
  6036. Default.pDatatype = NULL;
  6037. Default.pDevMode = NULL;
  6038. Default.DesiredAccess = SERVER_ACCESS_ADMINISTER;
  6039. *pMonitorUIDll = NULL;
  6040. if (!(pszServerName = ConstructXcvName(pszMachineName, pszObjectName, pszObjectType))) {
  6041. ReturnValue = GetLastError();
  6042. goto Done;
  6043. }
  6044. RpcTryExcept {
  6045. ReturnValue = OpenPrinter( pszServerName,
  6046. &hXcv,
  6047. &Default);
  6048. if (!ReturnValue) {
  6049. ReturnValue = GetLastError();
  6050. goto Done;
  6051. }
  6052. pOutputData = (PBYTE) btBuffer;
  6053. ZeroMemory(pOutputData, MAX_STATIC_ALLOC);
  6054. ReturnValue = RpcXcvData( ((PSPOOL)hXcv)->hPrinter,
  6055. L"MonitorUI",
  6056. (PBYTE) &dwDummy,
  6057. 0,
  6058. pOutputData,
  6059. MAX_STATIC_ALLOC,
  6060. &cbOutput,
  6061. &dwStatus);
  6062. if (ReturnValue != ERROR_SUCCESS)
  6063. goto Done;
  6064. if (dwStatus != ERROR_SUCCESS) {
  6065. if (dwStatus != ERROR_INSUFFICIENT_BUFFER) {
  6066. ReturnValue = dwStatus;
  6067. goto Done;
  6068. }
  6069. if (!(pOutputData = AllocSplMem(cbOutput))) {
  6070. ReturnValue = GetLastError();
  6071. goto Done;
  6072. }
  6073. bAllocBuffer = TRUE;
  6074. ReturnValue = RpcXcvData( ((PSPOOL)hXcv)->hPrinter,
  6075. L"MonitorUI",
  6076. (PBYTE) &dwDummy,
  6077. 0,
  6078. pOutputData,
  6079. cbOutput,
  6080. &cbOutput,
  6081. &dwStatus);
  6082. }
  6083. else
  6084. {
  6085. cbOutput = MAX_STATIC_ALLOC;
  6086. }
  6087. if (ReturnValue != ERROR_SUCCESS)
  6088. goto Done;
  6089. if (dwStatus != ERROR_SUCCESS) {
  6090. ReturnValue = dwStatus;
  6091. goto Done;
  6092. }
  6093. if (!(*pMonitorUIDll = AllocSplMem(cbOutput))) {
  6094. ReturnValue = GetLastError();
  6095. goto Done;
  6096. }
  6097. wcscpy(*pMonitorUIDll,(LPWSTR)pOutputData);
  6098. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6099. SetLastError(ReturnValue = TranslateExceptionCode(RpcExceptionCode()));
  6100. } RpcEndExcept
  6101. Done:
  6102. if (bAllocBuffer) {
  6103. FreeSplMem(pOutputData);
  6104. }
  6105. FreeSplMem(pszServerName);
  6106. if (hXcv) {
  6107. ClosePrinter(hXcv);
  6108. }
  6109. return ReturnValue;
  6110. }
  6111. HANDLE
  6112. CreatePrinterIC(
  6113. HANDLE hPrinter,
  6114. LPDEVMODEW pDevMode
  6115. )
  6116. {
  6117. HANDLE ReturnValue;
  6118. DWORD Error;
  6119. DEVMODE_CONTAINER DevModeContainer;
  6120. HANDLE hGdi;
  6121. PSPOOL pSpool = (PSPOOL)hPrinter;
  6122. UINT cRetry = 0;
  6123. if( eProtectHandle( hPrinter, FALSE )){
  6124. return FALSE;
  6125. }
  6126. if( bValidDevModeW( pDevMode )){
  6127. DevModeContainer.cbBuf = pDevMode->dmSize + pDevMode->dmDriverExtra;
  6128. DevModeContainer.pDevMode = (LPBYTE)pDevMode;
  6129. } else {
  6130. DevModeContainer.cbBuf = 0;
  6131. DevModeContainer.pDevMode = (LPBYTE)pDevMode;
  6132. }
  6133. do {
  6134. RpcTryExcept {
  6135. if (Error = RpcCreatePrinterIC( pSpool->hPrinter,
  6136. &hGdi,
  6137. &DevModeContainer )){
  6138. SetLastError(Error);
  6139. ReturnValue = FALSE;
  6140. } else {
  6141. ReturnValue = hGdi;
  6142. InterlockedIncrement( &gcClientICHandle );
  6143. }
  6144. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6145. SetLastError(RpcExceptionCode());
  6146. ReturnValue = FALSE;
  6147. } RpcEndExcept
  6148. } while( !ReturnValue &&
  6149. GetLastError() == ERROR_INVALID_HANDLE &&
  6150. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  6151. RevalidateHandle( pSpool ));
  6152. vUnprotectHandle( hPrinter );
  6153. return ReturnValue;
  6154. }
  6155. BOOL
  6156. PlayGdiScriptOnPrinterIC(
  6157. HANDLE hPrinterIC,
  6158. LPBYTE pIn,
  6159. DWORD cIn,
  6160. LPBYTE pOut,
  6161. DWORD cOut,
  6162. DWORD ul
  6163. )
  6164. {
  6165. BOOL ReturnValue;
  6166. RpcTryExcept {
  6167. if (ReturnValue = RpcPlayGdiScriptOnPrinterIC(hPrinterIC, pIn, cIn,
  6168. pOut, cOut, ul)) {
  6169. SetLastError(ReturnValue);
  6170. ReturnValue = FALSE;
  6171. } else
  6172. ReturnValue = TRUE;
  6173. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6174. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6175. ReturnValue = FALSE;
  6176. } RpcEndExcept
  6177. return ReturnValue;
  6178. }
  6179. BOOL
  6180. DeletePrinterIC(
  6181. HANDLE hPrinterIC
  6182. )
  6183. {
  6184. BOOL ReturnValue;
  6185. RpcTryExcept {
  6186. if (ReturnValue = RpcDeletePrinterIC(&hPrinterIC)) {
  6187. SetLastError(ReturnValue);
  6188. ReturnValue = FALSE;
  6189. } else {
  6190. ReturnValue = TRUE;
  6191. InterlockedDecrement( &gcClientICHandle );
  6192. }
  6193. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6194. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6195. ReturnValue = FALSE;
  6196. } RpcEndExcept
  6197. return ReturnValue;
  6198. }
  6199. /****************************************************************************
  6200. * INT QueryRemoteFonts( HANDLE, PUNIVERSAL_FONT_ID, ULONG )
  6201. *
  6202. * This is a hacky version of QueryRemoteFonts that doesn't do any
  6203. * caching based on the time stamp returned by QueryFonts. Additionally,
  6204. * it uses the CreatePrinterIC/PlayGdiScriptOnDC mechanism since it was
  6205. * already in place. It may be better to eliminate CreatePrinterIC and use
  6206. * an HPRINTER instead.
  6207. *
  6208. * Note that if the user doesn't pass in a buffer large enough to hold all
  6209. * the fonts we truncate the list and copy only enough fonts for which there
  6210. * is room but will still return success. This is okay because the worst
  6211. * that can happen in this case is that we may download unecessary fonts in
  6212. * the spool stream.
  6213. *
  6214. *
  6215. * History:
  6216. * 5/25/1995 by Gerrit van Wingerden [gerritv]
  6217. * Wrote it.
  6218. *****************************************************************************/
  6219. INT QueryRemoteFonts(
  6220. HANDLE hPrinter,
  6221. PUNIVERSAL_FONT_ID pufi,
  6222. ULONG nBufferSize
  6223. )
  6224. {
  6225. HANDLE hPrinterIC;
  6226. PBYTE pBuf;
  6227. DWORD dwDummy,cOut;
  6228. INT iRet = -1;
  6229. hPrinterIC = CreatePrinterIC( hPrinter, NULL );
  6230. if( hPrinterIC )
  6231. {
  6232. cOut = (nBufferSize * sizeof(UNIVERSAL_FONT_ID)) + sizeof(INT);
  6233. pBuf = LocalAlloc( LMEM_FIXED, cOut );
  6234. if( pBuf )
  6235. {
  6236. // Just call PlayGdiScriptOnPrinterIC for now since the piping is in place.
  6237. // For some reason the RPC stuff doesn't like NULL pointers for pIn so we
  6238. // use &dwDummy instead;
  6239. if(PlayGdiScriptOnPrinterIC(hPrinterIC,(PBYTE) &dwDummy,
  6240. sizeof(dwDummy),pBuf,cOut, 0))
  6241. {
  6242. DWORD dwSize = *((DWORD*) pBuf );
  6243. iRet = (INT) dwSize;
  6244. SPLASSERT( iRet >= 0 );
  6245. //
  6246. // If the supplied buffer is not large enough, we truncate the data
  6247. // The caller needs to check if he needs to call again this function
  6248. // with a larger buffer
  6249. //
  6250. if( dwSize > nBufferSize )
  6251. {
  6252. dwSize = nBufferSize;
  6253. }
  6254. memcpy(pufi,pBuf+sizeof(DWORD),dwSize * sizeof(UNIVERSAL_FONT_ID));
  6255. }
  6256. LocalFree( pBuf );
  6257. }
  6258. DeletePrinterIC( hPrinterIC );
  6259. }
  6260. return(iRet);
  6261. }
  6262. DWORD
  6263. PrinterMessageBoxW(
  6264. HANDLE hPrinter,
  6265. DWORD Error,
  6266. HWND hWnd,
  6267. LPWSTR pText,
  6268. LPWSTR pCaption,
  6269. DWORD dwType
  6270. )
  6271. {
  6272. return ERROR_NOT_SUPPORTED;
  6273. }
  6274. BOOL
  6275. AddMonitorW(
  6276. LPWSTR pName,
  6277. DWORD Level,
  6278. LPBYTE pMonitorInfo
  6279. )
  6280. {
  6281. BOOL ReturnValue;
  6282. MONITOR_CONTAINER MonitorContainer;
  6283. MONITOR_INFO_2 MonitorInfo2;
  6284. switch (Level) {
  6285. case 2:
  6286. break;
  6287. default:
  6288. SetLastError(ERROR_INVALID_LEVEL);
  6289. return FALSE;
  6290. }
  6291. if (pMonitorInfo)
  6292. MonitorInfo2 = *(PMONITOR_INFO_2)pMonitorInfo;
  6293. else
  6294. memset(&MonitorInfo2, 0, sizeof(MonitorInfo2));
  6295. if (!MonitorInfo2.pEnvironment || !*MonitorInfo2.pEnvironment) {
  6296. if(RunInWOW64()) {
  6297. MonitorInfo2.pEnvironment = szIA64Environment;
  6298. }
  6299. else {
  6300. MonitorInfo2.pEnvironment = szEnvironment;
  6301. }
  6302. }
  6303. MonitorContainer.Level = Level;
  6304. MonitorContainer.MonitorInfo.pMonitorInfo2 = (MONITOR_INFO_2 *)&MonitorInfo2;
  6305. RpcTryExcept {
  6306. if (ReturnValue = RpcAddMonitor(pName, &MonitorContainer)) {
  6307. SetLastError(ReturnValue);
  6308. ReturnValue = FALSE;
  6309. } else
  6310. ReturnValue = TRUE;
  6311. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6312. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6313. ReturnValue = FALSE;
  6314. } RpcEndExcept
  6315. return ReturnValue;
  6316. }
  6317. BOOL
  6318. DeleteMonitorW(
  6319. LPWSTR pName,
  6320. LPWSTR pEnvironment,
  6321. LPWSTR pMonitorName
  6322. )
  6323. {
  6324. BOOL ReturnValue;
  6325. if (!pMonitorName || !*pMonitorName) {
  6326. SetLastError(ERROR_INVALID_PARAMETER);
  6327. return (FALSE);
  6328. }
  6329. RpcTryExcept {
  6330. if (!pEnvironment || !*pEnvironment)
  6331. pEnvironment = szEnvironment;
  6332. if (ReturnValue = RpcDeleteMonitor(pName,
  6333. pEnvironment,
  6334. pMonitorName)) {
  6335. SetLastError(ReturnValue);
  6336. ReturnValue = FALSE;
  6337. } else
  6338. ReturnValue = TRUE;
  6339. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6340. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6341. ReturnValue = FALSE;
  6342. } RpcEndExcept
  6343. return ReturnValue;
  6344. }
  6345. BOOL
  6346. DeletePrintProcessorW(
  6347. LPWSTR pName,
  6348. LPWSTR pEnvironment,
  6349. LPWSTR pPrintProcessorName
  6350. )
  6351. {
  6352. BOOL ReturnValue;
  6353. if (!pPrintProcessorName || !*pPrintProcessorName) {
  6354. SetLastError(ERROR_INVALID_PARAMETER);
  6355. return FALSE;
  6356. }
  6357. RpcTryExcept {
  6358. if (!pEnvironment || !*pEnvironment)
  6359. pEnvironment = szEnvironment;
  6360. if (ReturnValue = RpcDeletePrintProcessor(pName,
  6361. pEnvironment,
  6362. pPrintProcessorName)) {
  6363. SetLastError(ReturnValue);
  6364. ReturnValue = FALSE;
  6365. } else
  6366. ReturnValue = TRUE;
  6367. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6368. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6369. ReturnValue = FALSE;
  6370. } RpcEndExcept
  6371. return ReturnValue;
  6372. }
  6373. BOOL
  6374. AddPrintProvidorW(
  6375. LPWSTR pName,
  6376. DWORD Level,
  6377. LPBYTE pProvidorInfo
  6378. )
  6379. {
  6380. BOOL ReturnValue;
  6381. LPWSTR pStr;
  6382. PROVIDOR_CONTAINER ProvidorContainer;
  6383. RPC_PROVIDOR_INFO_2W RpcProvidorInfo;
  6384. ProvidorContainer.Level = Level;
  6385. switch (Level) {
  6386. case 1:
  6387. ProvidorContainer.ProvidorInfo.pProvidorInfo1 = (PROVIDOR_INFO_1 *)pProvidorInfo;
  6388. break;
  6389. case 2:
  6390. RpcProvidorInfo.pOrder = ((PROVIDOR_INFO_2 *) pProvidorInfo)->pOrder;
  6391. for (pStr = RpcProvidorInfo.pOrder;
  6392. pStr && *pStr;
  6393. pStr += (wcslen(pStr) + 1)) ;
  6394. // Set the character count for the multisz string
  6395. RpcProvidorInfo.cchOrder = (DWORD) ((ULONG_PTR) (pStr - RpcProvidorInfo.pOrder + 1));
  6396. ProvidorContainer.ProvidorInfo.pRpcProvidorInfo2 = &RpcProvidorInfo;
  6397. break;
  6398. default:
  6399. SetLastError(ERROR_INVALID_LEVEL);
  6400. return FALSE;
  6401. }
  6402. RpcTryExcept {
  6403. if (ReturnValue = RpcAddPrintProvidor(pName, &ProvidorContainer)) {
  6404. SetLastError(ReturnValue);
  6405. ReturnValue = FALSE;
  6406. } else
  6407. ReturnValue = TRUE;
  6408. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6409. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6410. ReturnValue = FALSE;
  6411. } RpcEndExcept
  6412. return ReturnValue;
  6413. }
  6414. BOOL
  6415. DeletePrintProvidorW(
  6416. LPWSTR pName,
  6417. LPWSTR pEnvironment,
  6418. LPWSTR pPrintProvidorName
  6419. )
  6420. {
  6421. BOOL ReturnValue;
  6422. RpcTryExcept {
  6423. if (!pEnvironment || !*pEnvironment)
  6424. pEnvironment = szEnvironment;
  6425. if (ReturnValue = RpcDeletePrintProvidor(pName,
  6426. pEnvironment,
  6427. pPrintProvidorName)) {
  6428. SetLastError(ReturnValue);
  6429. ReturnValue = FALSE;
  6430. } else
  6431. ReturnValue = TRUE;
  6432. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6433. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6434. ReturnValue = FALSE;
  6435. } RpcEndExcept
  6436. return ReturnValue;
  6437. }
  6438. LPWSTR
  6439. IsaFileName(
  6440. LPWSTR pOutputFile,
  6441. LPWSTR FullPathName,
  6442. DWORD cchFullPathName
  6443. )
  6444. {
  6445. HANDLE hFile = INVALID_HANDLE_VALUE;
  6446. LPWSTR pFileName=NULL;
  6447. LPWSTR pFullPathName=NULL;
  6448. //
  6449. // Hack for Word20c.Win
  6450. //
  6451. if (!_wcsicmp(pOutputFile, L"FILE")) {
  6452. return NULL;
  6453. }
  6454. //
  6455. // cchFullPathName needs to be at least MAX_PATH
  6456. //
  6457. if (GetFullPathName(pOutputFile, cchFullPathName, FullPathName, &pFileName)) {
  6458. DBGMSG(DBG_TRACE, ("Fully qualified filename is %ws\n", FullPathName));
  6459. //
  6460. // Filenames containing ":" create a stream and a file on NTFS. When the file is closed,
  6461. // the stream is deleted (if DELETE_ON_CLOSE is specified) but the file remains. Not only
  6462. // that, but GetFileType will return FILE_TYPE_DISK. You can see this by printing from IE
  6463. // to a network printer. The incoming name will be something like "157.55.3.5:PASSTHRU".
  6464. // Therefore, we need to catch this case here.
  6465. //
  6466. if (pFileName && wcschr(pFileName, L':')) {
  6467. return NULL;
  6468. }
  6469. hFile = CreateFile(pOutputFile,
  6470. GENERIC_READ,
  6471. 0,
  6472. NULL,
  6473. OPEN_EXISTING,
  6474. FILE_ATTRIBUTE_NORMAL,
  6475. NULL);
  6476. if (hFile == INVALID_HANDLE_VALUE) {
  6477. hFile = CreateFile(pOutputFile,
  6478. GENERIC_WRITE,
  6479. FILE_SHARE_READ | FILE_SHARE_WRITE,
  6480. NULL,
  6481. OPEN_ALWAYS,
  6482. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
  6483. NULL);
  6484. }
  6485. if (hFile != INVALID_HANDLE_VALUE) {
  6486. if (GetFileType(hFile) == FILE_TYPE_DISK) {
  6487. pFullPathName = FullPathName;
  6488. }
  6489. CloseHandle(hFile);
  6490. }
  6491. }
  6492. return pFullPathName;
  6493. }
  6494. BOOL IsaPortName(
  6495. PKEYDATA pKeyData,
  6496. LPWSTR pOutputFile
  6497. )
  6498. {
  6499. DWORD i = 0;
  6500. UINT uStrLen;
  6501. if (!pKeyData) {
  6502. return(FALSE);
  6503. }
  6504. for (i=0; i < pKeyData->cTokens; i++) {
  6505. //
  6506. // If FILE: is one of the ports, and the app got the port
  6507. // name from win.in (e.g., Nexx:), then we will put up the
  6508. // print to file dialog, so we're not really printing to a port.
  6509. //
  6510. if (!lstrcmpi(pKeyData->pTokens[i], szFilePort)) {
  6511. if ((!wcsncmp(pOutputFile, L"Ne", 2)) &&
  6512. (*(pOutputFile + 4) == L':')) {
  6513. return(FALSE);
  6514. } else {
  6515. continue;
  6516. }
  6517. }
  6518. if (!lstrcmpi(pKeyData->pTokens[i], pOutputFile)) {
  6519. return(TRUE);
  6520. }
  6521. }
  6522. //
  6523. // Hack for NeXY: ports
  6524. //
  6525. if (!_wcsnicmp(pOutputFile, L"Ne", 2)) {
  6526. uStrLen = wcslen( pOutputFile );
  6527. //
  6528. // Ne00: or Ne00 if app truncates it
  6529. //
  6530. if (( uStrLen == 5 ) || ( uStrLen == 4 ) ) {
  6531. // Check for two Digits
  6532. if (( pOutputFile[2] >= L'0' ) && ( pOutputFile[2] <= L'9' ) &&
  6533. ( pOutputFile[3] >= L'0' ) && ( pOutputFile[3] <= L'9' )) {
  6534. //
  6535. // Check for the final : as in Ne01:,
  6536. // note some apps will truncate it.
  6537. //
  6538. if (( uStrLen == 5 ) && (pOutputFile[4] != L':')) {
  6539. return FALSE;
  6540. }
  6541. return TRUE;
  6542. }
  6543. }
  6544. }
  6545. return(FALSE);
  6546. }
  6547. BOOL HasAFilePort(PKEYDATA pKeyData)
  6548. {
  6549. DWORD i = 0;
  6550. if (!pKeyData) {
  6551. return(FALSE);
  6552. }
  6553. for (i=0; i < pKeyData->cTokens; i++) {
  6554. if (!lstrcmpi(pKeyData->pTokens[i], szFilePort)) {
  6555. return(TRUE);
  6556. }
  6557. }
  6558. return(FALSE);
  6559. }
  6560. //
  6561. // This function is trying to get the last active popup of the top
  6562. // level owner of the current thread active window.
  6563. //
  6564. HRESULT
  6565. GetCurrentThreadLastPopup(
  6566. OUT HWND *phwnd
  6567. )
  6568. {
  6569. HWND hwndOwner, hwndParent;
  6570. HRESULT hr = E_INVALIDARG;
  6571. GUITHREADINFO ti = {0};
  6572. if( phwnd )
  6573. {
  6574. hr = E_FAIL;
  6575. *phwnd = NULL;
  6576. ti.cbSize = sizeof(ti);
  6577. if( GetGUIThreadInfo(0, &ti) && ti.hwndActive )
  6578. {
  6579. *phwnd = ti.hwndActive;
  6580. // climb up to the top parent in case it's a child window...
  6581. while( hwndParent = GetParent(*phwnd) )
  6582. {
  6583. *phwnd = hwndParent;
  6584. }
  6585. // get the owner in case the top parent is owned
  6586. hwndOwner = GetWindow(*phwnd, GW_OWNER);
  6587. if( hwndOwner )
  6588. {
  6589. *phwnd = hwndOwner;
  6590. }
  6591. // get the last popup of the owner window
  6592. *phwnd = GetLastActivePopup(*phwnd);
  6593. hr = (*phwnd) ? S_OK : E_FAIL;
  6594. }
  6595. }
  6596. return hr;
  6597. }
  6598. LPWSTR
  6599. StartDocDlgW(
  6600. HANDLE hPrinter,
  6601. DOCINFO *pDocInfo
  6602. )
  6603. {
  6604. DWORD dwError = 0;
  6605. DWORD dwStatus = FALSE;
  6606. LPWSTR lpFileName = NULL;
  6607. DWORD rc = 0;
  6608. PKEYDATA pKeyData = NULL;
  6609. LPWSTR pPortNames = NULL;
  6610. WCHAR FullPathName[MAX_PATH];
  6611. WCHAR CurrentDirectory[MAX_PATH];
  6612. PKEYDATA pOutputList = NULL;
  6613. WCHAR PortNames[MAX_PATH];
  6614. DWORD i = 0;
  6615. HWND hwndParent = NULL;
  6616. #if DBG
  6617. GetCurrentDirectory(MAX_PATH, CurrentDirectory);
  6618. DBGMSG(DBG_TRACE, ("The Current Directory is %ws\n", CurrentDirectory));
  6619. #endif
  6620. if (pDocInfo) {
  6621. DBGMSG(DBG_TRACE, ("lpOutputFile is %ws\n", pDocInfo->lpszOutput ? pDocInfo->lpszOutput: L""));
  6622. }
  6623. memset(FullPathName, 0, sizeof(WCHAR)*MAX_PATH);
  6624. pPortNames = GetPrinterPortList(hPrinter);
  6625. pKeyData = CreateTokenList(pPortNames);
  6626. //
  6627. // Check for the presence of multiple ports in the lpszOutput field
  6628. // the assumed delimiter is the comma. Thus there can be no files with commas
  6629. //
  6630. if (pDocInfo && pDocInfo->lpszOutput && pDocInfo->lpszOutput[0]) {
  6631. //
  6632. // Make a copy of the pDocInfo->lpszOutput because CreateTokenList is destructive
  6633. //
  6634. wcsncpy(PortNames, pDocInfo->lpszOutput, COUNTOF(PortNames)-1);
  6635. PortNames[COUNTOF(PortNames)-1] = 0;
  6636. pOutputList = CreateTokenList(PortNames);
  6637. if (pOutputList && (pOutputList->cTokens > 1) &&
  6638. !lstrcmpi(pPortNames, pDocInfo->lpszOutput))
  6639. {
  6640. for (i= 0; i < pOutputList->cTokens; i++) {
  6641. if (!lstrcmpi(pOutputList->pTokens[i], szFilePort)) {
  6642. wcscpy((LPWSTR)pDocInfo->lpszOutput, szFilePort);
  6643. break;
  6644. }
  6645. }
  6646. if (i == pOutputList->cTokens) {
  6647. wcscpy((LPWSTR)pDocInfo->lpszOutput, pOutputList->pTokens[0]);
  6648. }
  6649. }
  6650. FreeSplMem(pOutputList);
  6651. }
  6652. if (pDocInfo && pDocInfo->lpszOutput && pDocInfo->lpszOutput[0]) {
  6653. if (IsaPortName(pKeyData, (LPWSTR)pDocInfo->lpszOutput)) {
  6654. lpFileName = NULL;
  6655. goto StartDocDlgWReturn;
  6656. }
  6657. if (IsaFileName((LPWSTR)pDocInfo->lpszOutput, FullPathName, COUNTOF(FullPathName))) {
  6658. //
  6659. // Fully Qualify the pathname for Apps like PageMaker and QuatroPro
  6660. //
  6661. if (lpFileName = LocalAlloc(LPTR, (wcslen(FullPathName)+1)*sizeof(WCHAR))) {
  6662. wcscpy(lpFileName, FullPathName);
  6663. }
  6664. goto StartDocDlgWReturn;
  6665. }
  6666. }
  6667. if ((HasAFilePort(pKeyData)) ||
  6668. (pDocInfo && pDocInfo->lpszOutput
  6669. && (!_wcsicmp(pDocInfo->lpszOutput, L"FILE:") ||
  6670. !_wcsicmp(pDocInfo->lpszOutput, L"FILE"))))
  6671. {
  6672. //
  6673. // since we have no idea who is calling us and we want to show
  6674. // modal against the last active popup, we need to figure out
  6675. // who is the last active popup of the calling app and then specify
  6676. // as parent - GetCurrentThreadLastPopup does a little magic to
  6677. // find the appropriate window.
  6678. //
  6679. DBGMSG(DBG_TRACE, ("We returned True from has file\n"));
  6680. rc = (DWORD)DialogBoxParam( hInst,
  6681. MAKEINTRESOURCE( DLG_PRINTTOFILE ),
  6682. SUCCEEDED(GetCurrentThreadLastPopup(&hwndParent)) ? hwndParent : NULL, (DLGPROC)PrintToFileDlg,
  6683. (LPARAM)&lpFileName );
  6684. if (rc == -1) {
  6685. DBGMSG(DBG_TRACE, ("Error from DialogBoxParam- %d\n", GetLastError()));
  6686. lpFileName = (LPWSTR)-1;
  6687. goto StartDocDlgWReturn;
  6688. } else if (rc == 0) {
  6689. DBGMSG(DBG_TRACE, ("User cancelled the dialog\n"));
  6690. lpFileName = (LPWSTR)-2;
  6691. SetLastError( ERROR_CANCELLED );
  6692. goto StartDocDlgWReturn;
  6693. } else {
  6694. DBGMSG(DBG_TRACE, ("The string was successfully returned\n"));
  6695. DBGMSG(DBG_TRACE, ("The string is %ws\n", lpFileName? lpFileName: L"NULL"));
  6696. goto StartDocDlgWReturn;
  6697. }
  6698. } else {
  6699. lpFileName = (LPWSTR)NULL;
  6700. }
  6701. StartDocDlgWReturn:
  6702. FreeSplMem(pKeyData);
  6703. FreeSplStr(pPortNames);
  6704. return(lpFileName);
  6705. }
  6706. BOOL
  6707. AddPortExW(
  6708. LPWSTR pName,
  6709. DWORD Level,
  6710. LPBYTE lpBuffer,
  6711. LPWSTR lpMonitorName
  6712. )
  6713. {
  6714. DWORD ReturnValue;
  6715. PORT_CONTAINER PortContainer;
  6716. PORT_VAR_CONTAINER PortVarContainer;
  6717. PPORT_INFO_FF pPortInfoFF;
  6718. PPORT_INFO_1 pPortInfo1;
  6719. if (!lpBuffer) {
  6720. SetLastError(ERROR_INVALID_PARAMETER);
  6721. return(FALSE);
  6722. }
  6723. switch (Level) {
  6724. case (DWORD)-1:
  6725. pPortInfoFF = (PPORT_INFO_FF)lpBuffer;
  6726. PortContainer.Level = Level;
  6727. PortContainer.PortInfo.pPortInfoFF = (PPORT_INFO_FF)pPortInfoFF;
  6728. PortVarContainer.cbMonitorData = pPortInfoFF->cbMonitorData;
  6729. PortVarContainer.pMonitorData = pPortInfoFF->pMonitorData;
  6730. break;
  6731. case 1:
  6732. pPortInfo1 = (PPORT_INFO_1)lpBuffer;
  6733. PortContainer.Level = Level;
  6734. PortContainer.PortInfo.pPortInfo1 = (PPORT_INFO_1)pPortInfo1;
  6735. PortVarContainer.cbMonitorData = 0;
  6736. PortVarContainer.pMonitorData = NULL;
  6737. break;
  6738. default:
  6739. SetLastError(ERROR_INVALID_LEVEL);
  6740. return(FALSE);
  6741. }
  6742. RpcTryExcept {
  6743. if (ReturnValue = RpcAddPortEx(pName, (LPPORT_CONTAINER)&PortContainer,
  6744. (LPPORT_VAR_CONTAINER)&PortVarContainer,
  6745. lpMonitorName
  6746. )) {
  6747. SetLastError(ReturnValue);
  6748. ReturnValue = FALSE;
  6749. } else {
  6750. ReturnValue = TRUE;
  6751. }
  6752. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6753. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6754. ReturnValue = FALSE;
  6755. } RpcEndExcept
  6756. return ReturnValue;
  6757. }
  6758. BOOL
  6759. DevQueryPrint(
  6760. HANDLE hPrinter,
  6761. LPDEVMODE pDevMode,
  6762. DWORD *pResID
  6763. )
  6764. {
  6765. BOOL Ok = FALSE;
  6766. HANDLE hModule;
  6767. INT_FARPROC pfn;
  6768. if (hModule = LoadPrinterDriver(hPrinter)) {
  6769. if (pfn = (INT_FARPROC)GetProcAddress(hModule, "DevQueryPrint")) {
  6770. try {
  6771. Ok = (*pfn)(hPrinter, pDevMode, pResID);
  6772. } except(1) {
  6773. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6774. Ok = FALSE;
  6775. }
  6776. }
  6777. RefCntUnloadDriver(hModule, TRUE);
  6778. }
  6779. return(Ok);
  6780. }
  6781. BOOL
  6782. DevQueryPrintEx(
  6783. PDEVQUERYPRINT_INFO pDQPInfo
  6784. )
  6785. {
  6786. BOOL Ok = FALSE;
  6787. HANDLE hModule;
  6788. INT_FARPROC pfn;
  6789. if (hModule = LoadPrinterDriver(pDQPInfo->hPrinter)) {
  6790. if (pfn = (INT_FARPROC)GetProcAddress(hModule, "DevQueryPrintEx")) {
  6791. try {
  6792. Ok = (*pfn)(pDQPInfo);
  6793. } except(1) {
  6794. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6795. Ok = FALSE;
  6796. }
  6797. }
  6798. RefCntUnloadDriver(hModule, TRUE);
  6799. }
  6800. return(Ok);
  6801. }
  6802. BOOL
  6803. SpoolerDevQueryPrintW(
  6804. HANDLE hPrinter,
  6805. LPDEVMODE pDevMode,
  6806. DWORD *pResID,
  6807. LPWSTR pszBuffer,
  6808. DWORD cchBuffer
  6809. )
  6810. {
  6811. BOOL Ok = FALSE;
  6812. HANDLE hModule;
  6813. INT_FARPROC pfn;
  6814. if (hModule = LoadPrinterDriver(hPrinter)) {
  6815. if (pfn = (INT_FARPROC)GetProcAddress(hModule, "DevQueryPrintEx")) {
  6816. DEVQUERYPRINT_INFO DQPInfo;
  6817. DQPInfo.cbSize = sizeof(DQPInfo);
  6818. DQPInfo.Level = 1;
  6819. DQPInfo.hPrinter = hPrinter;
  6820. DQPInfo.pDevMode = pDevMode;
  6821. DQPInfo.pszErrorStr = (LPTSTR)pszBuffer;
  6822. DQPInfo.cchErrorStr = (WORD)cchBuffer;
  6823. DQPInfo.cchNeeded = 0;
  6824. try {
  6825. *pResID = (Ok = (*pfn)(&DQPInfo)) ? 0 : 0xDCDCDCDC;
  6826. } except(1) {
  6827. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6828. Ok = FALSE;
  6829. }
  6830. } else if (pfn = (INT_FARPROC)GetProcAddress(hModule, "DevQueryPrint")) {
  6831. try {
  6832. if ((Ok = (*pfn)(hPrinter, pDevMode, pResID)) &&
  6833. (*pResID)) {
  6834. UINT cch;
  6835. *pszBuffer = L'\0';
  6836. SelectFormNameFromDevMode(hPrinter, pDevMode, pszBuffer);
  6837. if (cch = lstrlen(pszBuffer)) {
  6838. pszBuffer += cch;
  6839. *pszBuffer++ = L' ';
  6840. *pszBuffer++ = L'-';
  6841. *pszBuffer++ = L' ';
  6842. cchBuffer -= (cch + 3);
  6843. }
  6844. LoadString(hModule, *pResID, pszBuffer, cchBuffer);
  6845. }
  6846. } except(1) {
  6847. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6848. Ok = FALSE;
  6849. }
  6850. }
  6851. RefCntUnloadDriver(hModule, TRUE);
  6852. }
  6853. return(Ok);
  6854. }
  6855. LPWSTR
  6856. SelectFormNameFromDevMode(
  6857. HANDLE hPrinter,
  6858. PDEVMODEW pDevModeW,
  6859. LPWSTR pFormName
  6860. )
  6861. /*++
  6862. Routine Description:
  6863. This function pick the current form associated with current devmode and
  6864. return a form name pointer
  6865. Arguments:
  6866. hPrinter - Handle to the printer object
  6867. pDevModeW - Pointer to the unicode devmode for this printer
  6868. FormName - Pointer to the formname to be filled
  6869. Return Value:
  6870. Either a pointer to the FormName passed in if we do found one form,
  6871. otherwise it return NULL to signal a failue
  6872. Author:
  6873. 21-Mar-1995 Tue 16:57:51 created -by- Daniel Chou (danielc)
  6874. Revision History:
  6875. --*/
  6876. {
  6877. DWORD cb;
  6878. DWORD cRet;
  6879. LPFORM_INFO_1 pFIBase;
  6880. LPFORM_INFO_1 pFI;
  6881. BYTE btBuffer[MAX_STATIC_ALLOC];
  6882. BOOL bAllocBuffer = FALSE, bReturn;
  6883. //
  6884. // 1. If the DM_FORMNAME is turned on, then we want to check this bit first
  6885. // because it only specific to the NT which using form. The form name
  6886. // supposed set by any NT driver but not win31 or Win95.Use the
  6887. // dmFormName only if dmPaperSize, dmPaperLength and dmPaperWidth fields
  6888. // are not set. If any of them is set then we have to find a form using
  6889. // the value in these fields.
  6890. //
  6891. if ( (pDevModeW->dmFields & DM_FORMNAME)
  6892. && (!(pDevModeW->dmFields & (DM_PAPERSIZE |
  6893. DM_PAPERLENGTH |
  6894. DM_PAPERWIDTH))) ) {
  6895. wcscpy(pFormName, pDevModeW->dmFormName);
  6896. return(pFormName);
  6897. }
  6898. //
  6899. // For all other cases we need to get forms data base first, but we want
  6900. // to set the form name to NULL so that we can check if we found one
  6901. //
  6902. cb =
  6903. cRet = 0;
  6904. pFIBase =
  6905. pFI = NULL;
  6906. pFIBase = (LPFORM_INFO_1) btBuffer;
  6907. ZeroMemory(pFIBase, MAX_STATIC_ALLOC);
  6908. bReturn = EnumForms(hPrinter, 1, (LPBYTE)pFIBase, MAX_STATIC_ALLOC,
  6909. &cb, &cRet);
  6910. if (!bReturn &&
  6911. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  6912. (pFIBase = (LPFORM_INFO_1)LocalAlloc(LPTR, cb))) {
  6913. bAllocBuffer = TRUE;
  6914. bReturn = EnumForms(hPrinter, 1, (LPBYTE)pFIBase, cb, &cb, &cRet);
  6915. }
  6916. if (bReturn) {
  6917. //
  6918. // 2. If user specified dmPaperSize then honor it, otherwise, it must
  6919. // be a custom form, and we will check to see if it match one of
  6920. // in the database
  6921. //
  6922. if ((pDevModeW->dmFields & DM_PAPERSIZE) &&
  6923. (pDevModeW->dmPaperSize >= DMPAPER_FIRST) &&
  6924. (pDevModeW->dmPaperSize <= (SHORT)cRet)) {
  6925. //
  6926. // We go the valid index now
  6927. //
  6928. pFI = pFIBase + (pDevModeW->dmPaperSize - DMPAPER_FIRST);
  6929. } else if ((pDevModeW->dmFields & DM_PAPER_WL) == DM_PAPER_WL) {
  6930. LPFORM_INFO_1 pFICur = pFIBase;
  6931. while (cRet--) {
  6932. if ((DM_MATCH(pDevModeW->dmPaperWidth, pFICur->Size.cx)) &&
  6933. (DM_MATCH(pDevModeW->dmPaperLength, pFICur->Size.cy))) {
  6934. //
  6935. // We found the match which has discern size differences
  6936. //
  6937. pFI = pFICur;
  6938. break;
  6939. }
  6940. pFICur++;
  6941. }
  6942. }
  6943. }
  6944. //
  6945. // If we found the form then copy the name down, otherwise set the
  6946. // formname to be NULL
  6947. //
  6948. if (pFI) {
  6949. wcscpy(pFormName, pFI->pName);
  6950. } else {
  6951. *pFormName = L'\0';
  6952. pFormName = NULL;
  6953. }
  6954. if (bAllocBuffer) {
  6955. LocalFree((HLOCAL)pFIBase);
  6956. }
  6957. return(pFormName);
  6958. }
  6959. BOOL
  6960. SetAllocFailCount(
  6961. HANDLE hPrinter,
  6962. DWORD dwFailCount,
  6963. LPDWORD lpdwAllocCount,
  6964. LPDWORD lpdwFreeCount,
  6965. LPDWORD lpdwFailCountHit
  6966. )
  6967. {
  6968. BOOL ReturnValue;
  6969. PSPOOL pSpool = hPrinter;
  6970. UINT cRetry = 0;
  6971. if( eProtectHandle( hPrinter, FALSE )){
  6972. return FALSE;
  6973. }
  6974. do {
  6975. RpcTryExcept {
  6976. if (ReturnValue = RpcSetAllocFailCount( pSpool->hPrinter,
  6977. dwFailCount,
  6978. lpdwAllocCount,
  6979. lpdwFreeCount,
  6980. lpdwFailCountHit )) {
  6981. SetLastError(ReturnValue);
  6982. ReturnValue = FALSE;
  6983. } else
  6984. ReturnValue = TRUE;
  6985. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  6986. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  6987. ReturnValue = FALSE;
  6988. } RpcEndExcept
  6989. } while( !ReturnValue &&
  6990. GetLastError() == ERROR_INVALID_HANDLE &&
  6991. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  6992. RevalidateHandle( pSpool ));
  6993. vUnprotectHandle( hPrinter );
  6994. return ReturnValue;
  6995. }
  6996. BOOL
  6997. WINAPI
  6998. EnumPrinterPropertySheets(
  6999. HANDLE hPrinter,
  7000. HWND hWnd,
  7001. LPFNADDPROPSHEETPAGE lpfnAdd,
  7002. LPARAM lParam
  7003. )
  7004. {
  7005. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  7006. return FALSE;
  7007. }
  7008. VOID
  7009. vUpdateTrayIcon(
  7010. IN HANDLE hPrinter,
  7011. IN DWORD JobId
  7012. )
  7013. {
  7014. SHCNF_PRINTJOB_DATA JobData;
  7015. LPPRINTER_INFO_1 pPrinterInfo1;
  7016. FARPROC pfnSHChangeNotify;
  7017. PSPOOL pSpool = (PSPOOL)hPrinter;
  7018. BYTE btBuffer[MAX_PRINTER_INFO1];
  7019. SPLASSERT( JobId );
  7020. //
  7021. // Avoid sending multiple notifications by setting this flag.
  7022. // When other calls (notably StartDocPrinter) see this,
  7023. // they will avoid sending a notification.
  7024. //
  7025. pSpool->Status |= SPOOL_STATUS_TRAYICON_NOTIFIED;
  7026. if (InCSRProcess()) {
  7027. //
  7028. // We are running in CSR, don't load up shell.
  7029. //
  7030. return;
  7031. }
  7032. ZeroMemory( &JobData, sizeof( JobData ));
  7033. JobData.JobId = JobId;
  7034. //
  7035. // Get a copy of the real printer name
  7036. //
  7037. pPrinterInfo1 = (LPPRINTER_INFO_1) btBuffer;
  7038. ZeroMemory(pPrinterInfo1, MAX_PRINTER_INFO1);
  7039. if( pPrinterInfo1 ){
  7040. DWORD dwNeeded;
  7041. if( GetPrinter( hPrinter,
  7042. 1,
  7043. (PBYTE)pPrinterInfo1,
  7044. MAX_PRINTER_INFO1,
  7045. &dwNeeded )){
  7046. if (hShell32 == INVALID_HANDLE_VALUE)
  7047. hShell32 = LoadLibrary( gszShell32 );
  7048. if (hShell32) {
  7049. pfnSHChangeNotify = GetProcAddress( hShell32,
  7050. "SHChangeNotify" );
  7051. if( pfnSHChangeNotify ){
  7052. (*pfnSHChangeNotify)(
  7053. SHCNE_CREATE,
  7054. SHCNF_PRINTJOB | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT,
  7055. pPrinterInfo1->pName,
  7056. &JobData );
  7057. }
  7058. }
  7059. }
  7060. }
  7061. }
  7062. INT
  7063. CallDrvDocumentEventNative(
  7064. HANDLE hPrinter,
  7065. HDC hdc,
  7066. INT iEsc,
  7067. ULONG cbIn,
  7068. PVOID pulIn,
  7069. ULONG cbOut,
  7070. PVOID pulOut
  7071. )
  7072. /*++
  7073. Routine Description:
  7074. Call DrvDocumentEvent on driver UI
  7075. Arguments:
  7076. Return Value:
  7077. -1 : DOCUMENTEVENT_FAILURE
  7078. 0 : DOCUMENTEVENT_UNSUPPORTED
  7079. 1 : DOCUMENTEVENT_SUCCESS
  7080. --*/
  7081. {
  7082. HANDLE hLibrary;
  7083. INT_FARPROC pfn;
  7084. INT ReturnValue=DOCUMENTEVENT_UNSUPPORTED;
  7085. PSPOOL pSpool = (PSPOOL)hPrinter;
  7086. ULONG_PTR lActCtx = 0;
  7087. BOOL bDidActivate = FALSE;
  7088. if ( hLibrary = LoadPrinterDriver( hPrinter )) {
  7089. //
  7090. // Activate the empty context, we do not check the return value.
  7091. // because this may be called for non UI document events.
  7092. //
  7093. bDidActivate = ActivateActCtx( ACTCTX_EMPTY, &lActCtx );
  7094. //
  7095. // Disable the call so we don't recurse if the
  7096. // callback calls StartPage, etc.
  7097. //
  7098. pSpool->Status &= ~SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
  7099. if( pfn = (INT_FARPROC)GetProcAddress( hLibrary, "DrvDocumentEvent")){
  7100. try {
  7101. ReturnValue = (*pfn)( hPrinter,
  7102. hdc,
  7103. iEsc,
  7104. cbIn,
  7105. pulIn,
  7106. cbOut,
  7107. pulOut);
  7108. } except(1) {
  7109. SetLastError(TranslateExceptionCode(GetExceptionCode()));
  7110. ReturnValue = DOCUMENTEVENT_FAILURE;
  7111. }
  7112. //
  7113. // When driver does not export DrvDocumentEvent we leave
  7114. // this bit disabled so we will not try to load the DLL
  7115. // for future calls
  7116. //
  7117. pSpool->Status |= SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
  7118. }
  7119. //
  7120. // Deactivate the context
  7121. //
  7122. if( bDidActivate ){
  7123. DeactivateActCtx( 0, lActCtx );
  7124. }
  7125. RefCntUnloadDriver(hLibrary, TRUE);
  7126. }
  7127. return ReturnValue;
  7128. }
  7129. INT
  7130. CallDrvDocumentEventThunk(
  7131. HANDLE hPrinter,
  7132. HDC hdc,
  7133. INT iEsc,
  7134. ULONG cbIn,
  7135. PVOID pulIn,
  7136. ULONG cbOut,
  7137. PVOID pulOut
  7138. )
  7139. /*++
  7140. Routine Description:
  7141. Call DrvDocumentEvent on driver UI
  7142. Arguments:
  7143. Return Value:
  7144. -1 : DOCUMENTEVENT_FAILURE
  7145. 0 : DOCUMENTEVENT_UNSUPPORTED
  7146. 1 : DOCUMENTEVENT_SUCCESS
  7147. --*/
  7148. {
  7149. HANDLE hLibrary;
  7150. INT_FARPROC pfn;
  7151. INT ReturnValue=DOCUMENTEVENT_UNSUPPORTED;
  7152. DWORD dwRet = ERROR_SUCCESS;
  7153. PSPOOL pSpool = (PSPOOL)hPrinter;
  7154. LPWSTR PrinterName = pSpool->pszPrinter;
  7155. pSpool->Status &= ~SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
  7156. RpcTryExcept
  7157. {
  7158. *((PULONG_PTR)pulOut) = (ULONG_PTR)0L;
  7159. if((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS)
  7160. {
  7161. ReturnValue = RPCSplWOW64DocumentEvent(PrinterName,
  7162. (ULONG_PTR)hdc,
  7163. iEsc,
  7164. cbIn,
  7165. (LPBYTE) pulIn,
  7166. &cbOut,
  7167. (LPBYTE*) pulOut,
  7168. &dwRet);
  7169. }
  7170. else
  7171. {
  7172. SetLastError(dwRet);
  7173. }
  7174. }
  7175. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  7176. {
  7177. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7178. ReturnValue = -1;
  7179. }
  7180. RpcEndExcept
  7181. pSpool->Status |= SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
  7182. return ReturnValue;
  7183. }
  7184. INT
  7185. CallDrvDocumentEvent(
  7186. HANDLE hPrinter,
  7187. HDC hdc,
  7188. INT iEsc,
  7189. ULONG cbIn,
  7190. PVOID pulIn,
  7191. ULONG cbOut,
  7192. PVOID pulOut
  7193. )
  7194. {
  7195. if(RunInWOW64())
  7196. {
  7197. return(CallDrvDocumentEventThunk(hPrinter,
  7198. hdc,
  7199. iEsc,
  7200. cbIn,
  7201. pulIn,
  7202. cbOut,
  7203. pulOut));
  7204. }
  7205. else
  7206. {
  7207. return(CallDrvDocumentEventNative(hPrinter,
  7208. hdc,
  7209. iEsc,
  7210. cbIn,
  7211. pulIn,
  7212. cbOut,
  7213. pulOut));
  7214. }
  7215. }
  7216. INT
  7217. DocumentEvent(
  7218. HANDLE hPrinter,
  7219. HDC hdc,
  7220. INT iEsc,
  7221. ULONG cbIn,
  7222. PVOID pulIn,
  7223. ULONG cbOut,
  7224. PVOID pulOut
  7225. )
  7226. /*++
  7227. Routine Description:
  7228. Allow the driver UI dll to hook specific print events.
  7229. Arguments:
  7230. Return Value:
  7231. -1 : DOCUMENTEVENT_FAILURE
  7232. 0 : DOCUMENTEVENT_UNSUPPORTED
  7233. 1 : DOCUMENTEVENT_SUCCESS
  7234. --*/
  7235. {
  7236. DWORD cbNeeded;
  7237. INT ReturnValue = DOCUMENTEVENT_FAILURE;
  7238. PSPOOL pSpool = (PSPOOL)hPrinter;
  7239. PDOCEVENT_FILTER pDoceventFilter = NULL;
  7240. BOOL bDocEventFilter = FALSE;
  7241. BOOL bCallDriver = TRUE;
  7242. UINT uIndex;
  7243. if( eProtectHandle( hPrinter, FALSE )){
  7244. return DOCUMENTEVENT_FAILURE;
  7245. }
  7246. if( DOCUMENTEVENT_EVENT( iEsc ) == DOCUMENTEVENT_CREATEDCPRE ){
  7247. if ( pSpool->pDoceventFilter ) {
  7248. FreeSplMem(pSpool->pDoceventFilter);
  7249. pSpool->pDoceventFilter = NULL;
  7250. }
  7251. //
  7252. // First we will check if the driver wants to filter the events
  7253. //
  7254. cbNeeded = sizeof(DOCEVENT_FILTER) + sizeof(DWORD) * (DOCUMENTEVENT_LAST-2);
  7255. pDoceventFilter = AllocSplMem(cbNeeded);
  7256. if ( pDoceventFilter == NULL )
  7257. goto Fail;
  7258. pDoceventFilter->cbSize = sizeof(DOCEVENT_FILTER);
  7259. pDoceventFilter->cElementsAllocated = DOCUMENTEVENT_LAST-1;
  7260. pDoceventFilter->cElementsReturned = (UINT)-1;
  7261. pDoceventFilter->cElementsNeeded = (UINT)-1;
  7262. //
  7263. // Before every CreateDC, re-enable DocumentEvent.
  7264. // If it fails on the first try, then don't try again
  7265. // until the next CreateDC.
  7266. //
  7267. pSpool->Status |= SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
  7268. ReturnValue = CallDrvDocumentEvent( hPrinter,
  7269. hdc,
  7270. DOCUMENTEVENT_QUERYFILTER,
  7271. cbIn,
  7272. pulIn,
  7273. cbNeeded,
  7274. (PVOID)pDoceventFilter);
  7275. //
  7276. // We only regard the call to be successful if the driver returned
  7277. // success _and_ modified aither cElementsReturned or cElementsNeeded.
  7278. // This is to handle the case where a driver returns success, but in
  7279. // fact does not know how to handle the call.
  7280. //
  7281. bDocEventFilter = ReturnValue == DOCUMENTEVENT_SUCCESS &&
  7282. (pDoceventFilter->cElementsReturned != (UINT)-1 ||
  7283. pDoceventFilter->cElementsNeeded != (UINT)-1);
  7284. if (pDoceventFilter->cElementsReturned == (UINT)-1)
  7285. {
  7286. pDoceventFilter->cElementsReturned = 0;
  7287. }
  7288. if (pDoceventFilter->cElementsNeeded == (UINT)-1)
  7289. {
  7290. pDoceventFilter->cElementsNeeded = 0;
  7291. }
  7292. if (bDocEventFilter) {
  7293. //
  7294. // Validity check
  7295. //
  7296. if ( pDoceventFilter->cElementsReturned > pDoceventFilter->cElementsAllocated ) {
  7297. SPLASSERT(pDoceventFilter->cElementsReturned <= pDoceventFilter->cElementsAllocated);
  7298. ReturnValue = DOCUMENTEVENT_FAILURE;
  7299. goto Fail;
  7300. //
  7301. // For drivers that are written for future OS (with new doc events)
  7302. // we still want to filter and send the doc events we support
  7303. //
  7304. // So we realloc and query
  7305. //
  7306. } else if ( pDoceventFilter->cElementsNeeded > pDoceventFilter->cElementsAllocated ) {
  7307. uIndex = pDoceventFilter->cElementsNeeded;
  7308. cbNeeded = sizeof(DOCEVENT_FILTER) + sizeof(DWORD) * (uIndex - 1);
  7309. FreeSplMem(pDoceventFilter);
  7310. ReturnValue = DOCUMENTEVENT_FAILURE;
  7311. pDoceventFilter = AllocSplMem(cbNeeded);
  7312. if ( pDoceventFilter == NULL )
  7313. goto Fail;
  7314. pDoceventFilter->cbSize = sizeof(DOCEVENT_FILTER);
  7315. pDoceventFilter->cElementsAllocated = uIndex;
  7316. ReturnValue = CallDrvDocumentEvent( hPrinter,
  7317. hdc,
  7318. DOCUMENTEVENT_QUERYFILTER,
  7319. cbIn,
  7320. pulIn,
  7321. cbNeeded,
  7322. (PVOID)pDoceventFilter);
  7323. //
  7324. // Validity check for second call
  7325. //
  7326. if ( ReturnValue == DOCUMENTEVENT_SUCCESS ) {
  7327. if ( pDoceventFilter->cElementsReturned > pDoceventFilter->cElementsAllocated ) {
  7328. SPLASSERT(pDoceventFilter->cElementsReturned <= pDoceventFilter->cElementsAllocated);
  7329. ReturnValue = DOCUMENTEVENT_FAILURE;;
  7330. goto Fail;
  7331. }
  7332. }
  7333. }
  7334. }
  7335. //
  7336. // Not supported we go to old behavior (no filtering)
  7337. //
  7338. if ( bDocEventFilter && ReturnValue == DOCUMENTEVENT_SUCCESS ) {
  7339. pSpool->pDoceventFilter = pDoceventFilter;
  7340. } else {
  7341. FreeSplMem(pDoceventFilter);
  7342. pDoceventFilter = NULL;
  7343. }
  7344. }
  7345. ReturnValue = DOCUMENTEVENT_UNSUPPORTED;
  7346. if( pSpool->Status & SPOOL_STATUS_DOCUMENTEVENT_ENABLED ){
  7347. //
  7348. // When driver supports DOCUMENTEVENT_QUERYFILTER we will
  7349. // only call events in the filter with
  7350. // DOCUMENTEVENT_CREATEDCPRE being an exception
  7351. //
  7352. // When driver does not support it (or fails it) we revert to old
  7353. // behavior and make all callbacks
  7354. //
  7355. if ( DOCUMENTEVENT_EVENT( iEsc ) != DOCUMENTEVENT_CREATEDCPRE &&
  7356. (pDoceventFilter = pSpool->pDoceventFilter) != NULL ) {
  7357. for ( uIndex = 0, bCallDriver = FALSE ;
  7358. uIndex < pDoceventFilter->cElementsReturned && !bCallDriver ;
  7359. ++uIndex ) {
  7360. if ( pDoceventFilter->aDocEventCall[uIndex] == DOCUMENTEVENT_EVENT(iEsc) )
  7361. bCallDriver = TRUE;
  7362. }
  7363. }
  7364. if ( bCallDriver ) {
  7365. ReturnValue = CallDrvDocumentEvent( hPrinter,
  7366. hdc,
  7367. iEsc,
  7368. cbIn,
  7369. pulIn,
  7370. cbOut,
  7371. pulOut);
  7372. //
  7373. // Old (i.e. before DOCUMENTEVENT_QUERYFILTER) behavior is
  7374. // on DOCUMENTEVENT_CREATEDCPRE failure no more calls are made
  7375. // to the driver UI dll. We preserve the same behavior.
  7376. //
  7377. // Note that some drivers return a large positive value for a success
  7378. // code. So, ReturnValue <= DOCUMENTEVENT_UNSUPPORTED is the correct
  7379. // implementation.
  7380. //
  7381. if ( DOCUMENTEVENT_EVENT( iEsc ) == DOCUMENTEVENT_CREATEDCPRE &&
  7382. ReturnValue <= DOCUMENTEVENT_UNSUPPORTED )
  7383. pSpool->Status &= ~SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
  7384. }
  7385. }
  7386. //
  7387. // If it's a StartDocPost, a job was just added. Notify the
  7388. // tray icon if we haven't already.
  7389. //
  7390. if( DOCUMENTEVENT_EVENT( iEsc ) == DOCUMENTEVENT_STARTDOCPOST ){
  7391. if( !( pSpool->Status & SPOOL_STATUS_TRAYICON_NOTIFIED )){
  7392. //
  7393. // If we have a StartDocPost, then issue a notification so that
  7394. // the user's tray starts polling. pulIn[0] holds the JobId.
  7395. //
  7396. vUpdateTrayIcon( hPrinter, (DWORD)((PULONG_PTR)pulIn)[0] );
  7397. }
  7398. } else {
  7399. //
  7400. // If we have sent a notification, then by the next time we get a
  7401. // document event, we have completed any additional AddJobs or
  7402. // StartDocPrinters. Therefore we can reset the TRAYICON_NOTIFIED
  7403. // flag, since any more AddJobs/StartDocPrinters are really new
  7404. // jobs.
  7405. //
  7406. pSpool->Status &= ~SPOOL_STATUS_TRAYICON_NOTIFIED;
  7407. }
  7408. Fail:
  7409. if ( DOCUMENTEVENT_EVENT( iEsc ) == DOCUMENTEVENT_CREATEDCPRE &&
  7410. ReturnValue == DOCUMENTEVENT_FAILURE ) {
  7411. FreeSplMem(pDoceventFilter);
  7412. pSpool->Status &= ~SPOOL_STATUS_DOCUMENTEVENT_ENABLED;
  7413. pSpool->pDoceventFilter = NULL;
  7414. }
  7415. vUnprotectHandle( hPrinter );
  7416. return ReturnValue;
  7417. }
  7418. /****************************************************************************
  7419. * INT QueryColorProfile()
  7420. *
  7421. * Returns:
  7422. *
  7423. * -1 : Printer driver does not hook color profile.
  7424. * 0 : Error.
  7425. * 1 : Success.
  7426. *
  7427. * History:
  7428. * 8/Oct/1997 by Hideyuki Nagase [hideyukn]
  7429. * Wrote it.
  7430. *****************************************************************************/
  7431. INT
  7432. QueryColorProfile(
  7433. HANDLE hPrinter,
  7434. PDEVMODEW pdevmode,
  7435. ULONG ulQueryMode,
  7436. PVOID pvProfileData,
  7437. ULONG *pcbProfileData,
  7438. FLONG *pflProfileData
  7439. )
  7440. {
  7441. INT iRet = 0;
  7442. PSPOOL pSpool = (PSPOOL)hPrinter;
  7443. if( eProtectHandle( hPrinter, FALSE )){
  7444. return 0;
  7445. }
  7446. if (pSpool->Status & SPOOL_STATUS_NO_COLORPROFILE_HOOK) {
  7447. //
  7448. // DrvQueryColorProfile is not supported in Printer driver.
  7449. //
  7450. iRet = -1;
  7451. } else {
  7452. HANDLE hLibrary;
  7453. INT_FARPROC pfn;
  7454. if (hLibrary = LoadPrinterDriver( hPrinter )) {
  7455. if (pfn = (INT_FARPROC)GetProcAddress( hLibrary, "DrvQueryColorProfile" )) {
  7456. try {
  7457. //
  7458. // Call the Printer UI driver.
  7459. //
  7460. iRet = (*pfn)( hPrinter,
  7461. pdevmode,
  7462. ulQueryMode,
  7463. pvProfileData,
  7464. pcbProfileData,
  7465. pflProfileData );
  7466. } except(1) {
  7467. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7468. }
  7469. } else {
  7470. //
  7471. // Mark this driver does not export it, so later
  7472. // we can fail without load printer driver.
  7473. //
  7474. pSpool->Status |= SPOOL_STATUS_NO_COLORPROFILE_HOOK;
  7475. //
  7476. // Tell callee it is not supported.
  7477. //
  7478. iRet = -1;
  7479. }
  7480. RefCntUnloadDriver(hLibrary, TRUE);
  7481. }
  7482. }
  7483. vUnprotectHandle( hPrinter );
  7484. return (iRet);
  7485. }
  7486. /****************************************************************************
  7487. * BOOL QuerySpoolMode( hPrinter, pflSpoolMode, puVersion )
  7488. *
  7489. * This function is called by GDI at StartDoc time when printing to an EMF.
  7490. * It tell GDI whether to embed fonts in the job as well as what version of
  7491. * EMF to generate.
  7492. *
  7493. * For now I am doing something hacky: I'm calling GetPrinterInfo to determine
  7494. * if the target is a remote machine and if so always telling GDI to embed
  7495. * fonts which don't exist on the server into spool file. Eventually this
  7496. * call will be routed to the print processor on the target machine which
  7497. * will use some UI/registry setting to determine what to do with fonts and
  7498. * set the version number correctly.
  7499. *
  7500. * History:
  7501. * 5/13/1995 by Gerrit van Wingerden [gerritv]
  7502. * Wrote it.
  7503. *****************************************************************************/
  7504. // !!later move this define to the appropriate header file
  7505. #define QSM_DOWNLOADFONTS 0x00000001
  7506. BOOL
  7507. QuerySpoolMode(
  7508. HANDLE hPrinter,
  7509. LONG *pflSpoolMode,
  7510. ULONG *puVersion
  7511. )
  7512. {
  7513. DWORD dwPrinterInfoSize = 0;
  7514. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  7515. BOOL bRet = FALSE, bStatus, bAllocBuffer = FALSE;
  7516. BYTE btBuffer[MAX_STATIC_ALLOC];
  7517. pPrinterInfo2 = (PPRINTER_INFO_2) btBuffer;
  7518. ZeroMemory(pPrinterInfo2, MAX_STATIC_ALLOC);
  7519. bStatus = GetPrinter(hPrinter, 2, (LPBYTE) pPrinterInfo2,
  7520. MAX_STATIC_ALLOC, &dwPrinterInfoSize);
  7521. if (!bStatus &&
  7522. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  7523. (pPrinterInfo2 = (PRINTER_INFO_2*) LocalAlloc(LPTR,
  7524. dwPrinterInfoSize)))
  7525. {
  7526. bAllocBuffer = TRUE;
  7527. bStatus = GetPrinter(hPrinter, 2, (LPBYTE) pPrinterInfo2,
  7528. dwPrinterInfoSize, &dwPrinterInfoSize);
  7529. }
  7530. if (bStatus)
  7531. {
  7532. *puVersion = 0x00010000; // version 1.0
  7533. //
  7534. // No server means we are printing locally
  7535. //
  7536. *pflSpoolMode = ( pPrinterInfo2->pServerName == NULL ) ?
  7537. 0 :
  7538. QSM_DOWNLOADFONTS;
  7539. bRet = TRUE;
  7540. }
  7541. else
  7542. {
  7543. DBGMSG( DBG_WARNING, ( "QuerySpoolMode: GetPrinter failed %d.\n", GetLastError( )));
  7544. }
  7545. if (bAllocBuffer)
  7546. {
  7547. LocalFree( pPrinterInfo2 );
  7548. }
  7549. return bRet;
  7550. }
  7551. BOOL
  7552. SetPortW(
  7553. LPWSTR pszName,
  7554. LPWSTR pszPortName,
  7555. DWORD dwLevel,
  7556. LPBYTE pPortInfo
  7557. )
  7558. {
  7559. BOOL ReturnValue;
  7560. PORT_CONTAINER PortContainer;
  7561. switch (dwLevel) {
  7562. case 3:
  7563. if ( !pPortInfo ) {
  7564. SetLastError(ERROR_INVALID_PARAMETER);
  7565. return FALSE;
  7566. }
  7567. PortContainer.Level = dwLevel;
  7568. PortContainer.PortInfo.pPortInfo3 = (PPORT_INFO_3)pPortInfo;
  7569. break;
  7570. default:
  7571. SetLastError(ERROR_INVALID_LEVEL);
  7572. return FALSE;
  7573. }
  7574. RpcTryExcept {
  7575. if (bLoadedBySpooler && fpYSetPort) {
  7576. ReturnValue = (*fpYSetPort)(pszName, pszPortName, &PortContainer, NATIVE_CALL);
  7577. }
  7578. else {
  7579. ReturnValue = RpcSetPort(pszName, pszPortName, &PortContainer);
  7580. }
  7581. if (ReturnValue != ERROR_SUCCESS) {
  7582. SetLastError(ReturnValue);
  7583. ReturnValue = FALSE;
  7584. } else {
  7585. ReturnValue = TRUE;
  7586. }
  7587. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  7588. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7589. ReturnValue = FALSE;
  7590. } RpcEndExcept
  7591. return ReturnValue;
  7592. }
  7593. BOOL
  7594. bValidDevModeW(
  7595. const DEVMODE *pDevMode
  7596. )
  7597. /*++
  7598. Routine Description:
  7599. Check whether a devmode is valid to be RPC'd across to the spooler.
  7600. Arguments:
  7601. pDevMode - DevMode to check.
  7602. Return Value:
  7603. TRUE - Devmode can be RPC'd to spooler.
  7604. FALSE - Invalid Devmode.
  7605. --*/
  7606. {
  7607. if( !pDevMode || pDevMode == (PDEVMODE)-1 ){
  7608. return FALSE;
  7609. }
  7610. if( pDevMode->dmSize < MIN_DEVMODE_SIZEW ){
  7611. //
  7612. // The only valid case is if pDevModeW is NULL. If it's
  7613. // not NULL, then a bad devmode was passed in and the
  7614. // app should fix it's code.
  7615. //
  7616. SPLASSERT( pDevMode->dmSize >= MIN_DEVMODE_SIZEW );
  7617. return FALSE;
  7618. }
  7619. return TRUE;
  7620. }
  7621. BOOL
  7622. XcvDataW(
  7623. HANDLE hPrinter,
  7624. PCWSTR pszDataName,
  7625. PBYTE pInputData,
  7626. DWORD cbInputData,
  7627. PBYTE pOutputData,
  7628. DWORD cbOutputData,
  7629. PDWORD pcbOutputNeeded,
  7630. PDWORD pdwStatus
  7631. )
  7632. {
  7633. DWORD ReturnValue = 0;
  7634. DWORD ReturnType = 0;
  7635. PSPOOL pSpool = (PSPOOL)hPrinter;
  7636. UINT cRetry = 0;
  7637. if (!pcbOutputNeeded){
  7638. SetLastError( ERROR_INVALID_PARAMETER );
  7639. return FALSE;
  7640. }
  7641. if( eProtectHandle( hPrinter, FALSE )){
  7642. SetLastError( ERROR_INVALID_HANDLE );
  7643. return FALSE;
  7644. }
  7645. //
  7646. // The user should be able to pass in NULL for buffer, and
  7647. // 0 for size. However, the RPC interface specifies a ref pointer,
  7648. // so we must pass in a valid pointer. Pass in a pointer to
  7649. // a dummy pointer.
  7650. //
  7651. if (!pInputData && !cbInputData)
  7652. pInputData = (PBYTE) &ReturnValue;
  7653. if (!pOutputData && !cbOutputData)
  7654. pOutputData = (PBYTE) &ReturnValue;
  7655. do {
  7656. RpcTryExcept {
  7657. if (ReturnValue = RpcXcvData( pSpool->hPrinter,
  7658. pszDataName,
  7659. pInputData,
  7660. cbInputData,
  7661. pOutputData,
  7662. cbOutputData,
  7663. pcbOutputNeeded,
  7664. pdwStatus)) {
  7665. SetLastError(ReturnValue);
  7666. ReturnValue = FALSE;
  7667. } else {
  7668. ReturnValue = TRUE;
  7669. }
  7670. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  7671. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7672. ReturnValue = FALSE;
  7673. } RpcEndExcept
  7674. } while( !ReturnValue &&
  7675. GetLastError() == ERROR_INVALID_HANDLE &&
  7676. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  7677. RevalidateHandle( pSpool ));
  7678. if (!ReturnValue) {
  7679. DBGMSG(DBG_TRACE,("XcvData Exception: %d\n", GetLastError()));
  7680. }
  7681. vUnprotectHandle( hPrinter );
  7682. return ReturnValue;
  7683. }
  7684. PWSTR
  7685. ConstructXcvName(
  7686. PCWSTR pServerName,
  7687. PCWSTR pObjectName,
  7688. PCWSTR pObjectType
  7689. )
  7690. {
  7691. DWORD cbOutput;
  7692. PWSTR pOut;
  7693. cbOutput = pServerName ? (wcslen(pServerName) + 2)*sizeof(WCHAR) : sizeof(WCHAR); /* "\\Server\," */
  7694. cbOutput += (wcslen(pObjectType) + 2)*sizeof(WCHAR); /* "\\Server\,XcvPort _" */
  7695. cbOutput += pObjectName ? (wcslen(pObjectName))*sizeof(WCHAR) : 0; /* "\\Server\,XcvPort Object_" */
  7696. if (pOut = AllocSplMem(cbOutput)) {
  7697. if (pServerName) {
  7698. wcscpy(pOut,pServerName);
  7699. wcscat(pOut, L"\\");
  7700. }
  7701. wcscat(pOut,L",");
  7702. wcscat(pOut,pObjectType);
  7703. wcscat(pOut,L" ");
  7704. if (pObjectName)
  7705. wcscat(pOut,pObjectName);
  7706. }
  7707. return pOut;
  7708. }
  7709. HANDLE
  7710. ConnectToPrinterDlg(
  7711. IN HWND hwnd,
  7712. IN DWORD dwFlags
  7713. )
  7714. {
  7715. typedef HANDLE (WINAPI *PF_CONNECTTOPRINTERDLG)( HWND, DWORD );
  7716. PF_CONNECTTOPRINTERDLG pfConnectToPrinterDlg = NULL;
  7717. HANDLE hHandle = NULL;
  7718. HINSTANCE hLib = NULL;
  7719. hLib = LoadLibrary( szPrintUIDll );
  7720. if( hLib )
  7721. {
  7722. pfConnectToPrinterDlg = (PF_CONNECTTOPRINTERDLG)GetProcAddress( hLib, "ConnectToPrinterDlg" );
  7723. if( pfConnectToPrinterDlg )
  7724. {
  7725. hHandle = pfConnectToPrinterDlg( hwnd, dwFlags );
  7726. }
  7727. FreeLibrary( hLib );
  7728. }
  7729. return hHandle;
  7730. }
  7731. DWORD
  7732. SendRecvBidiData(
  7733. IN HANDLE hPrinter,
  7734. IN LPCWSTR pAction,
  7735. IN PBIDI_REQUEST_CONTAINER pReqData,
  7736. OUT PBIDI_RESPONSE_CONTAINER* ppResData
  7737. )
  7738. {
  7739. DWORD dwRet = ERROR_SUCCESS;
  7740. PSPOOL pSpool = (PSPOOL)hPrinter;
  7741. UINT cRetry = 0;
  7742. if( eProtectHandle( hPrinter, FALSE ))
  7743. {
  7744. dwRet = GetLastError();
  7745. }
  7746. else
  7747. {
  7748. do
  7749. {
  7750. RpcTryExcept
  7751. {
  7752. if(ppResData)
  7753. {
  7754. *ppResData = NULL;
  7755. }
  7756. dwRet = RpcSendRecvBidiData(pSpool->hPrinter,
  7757. pAction,
  7758. (PRPC_BIDI_REQUEST_CONTAINER)pReqData,
  7759. (PRPC_BIDI_RESPONSE_CONTAINER*)ppResData);
  7760. }
  7761. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  7762. {
  7763. dwRet = TranslateExceptionCode(RpcExceptionCode());
  7764. }
  7765. RpcEndExcept
  7766. } while (dwRet == ERROR_INVALID_HANDLE &&
  7767. cRetry++ < MAX_RETRY_INVALID_HANDLE &&
  7768. RevalidateHandle( pSpool ));
  7769. vUnprotectHandle( hPrinter );
  7770. }
  7771. //
  7772. // If we are trying to communicate with a downlevel router, that does
  7773. // not understand the meaning of SendRecvBidiData , we would get the
  7774. // error code: RPC_S_PROCNUM_OUT_OF_RANGE which might be converted to
  7775. // ERROR_NOT_SUPPORTED for better clearity and more consistency with
  7776. // the a genaral return error code if feature is not supported.
  7777. if(dwRet == RPC_S_PROCNUM_OUT_OF_RANGE)
  7778. {
  7779. dwRet = ERROR_NOT_SUPPORTED;
  7780. }
  7781. return (dwRet);
  7782. }
  7783. VOID
  7784. PrintUIQueueCreate(
  7785. IN HWND hWnd,
  7786. IN LPCWSTR PrinterName,
  7787. IN INT CmdShow,
  7788. IN LPARAM lParam
  7789. )
  7790. {
  7791. DWORD dwRet = ERROR_SUCCESS;
  7792. RpcTryExcept
  7793. {
  7794. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  7795. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  7796. {
  7797. AllowSetForegroundWindow(RPCSplWOW64GetProcessID());
  7798. if((dwRet = RPCSplWOW64PrintUIQueueCreate((ULONG_PTR)GetForeGroundWindow(),
  7799. PrinterName,
  7800. CmdShow,
  7801. lParam)) == ERROR_SUCCESS)
  7802. {
  7803. MSG msg;
  7804. while(GetMessage(&msg, NULL, 0, 0))
  7805. {
  7806. if(msg.message == WM_ENDQUEUECREATE)
  7807. {
  7808. DelHandleFromList(hWnd);
  7809. break;
  7810. }
  7811. else if(msg.message == WM_SURROGATEFAILURE)
  7812. {
  7813. //
  7814. // This means that the server process died and we have
  7815. // break from the message loop
  7816. //
  7817. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  7818. break;
  7819. }
  7820. TranslateMessage(&msg);
  7821. DispatchMessage(&msg);
  7822. }
  7823. }
  7824. else
  7825. {
  7826. SetLastError(dwRet);
  7827. }
  7828. }
  7829. }
  7830. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  7831. {
  7832. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7833. }
  7834. RpcEndExcept
  7835. }
  7836. VOID
  7837. PrintUIPrinterPropPages(
  7838. IN HWND hWnd,
  7839. IN LPCWSTR PrinterName,
  7840. IN INT CmdShow,
  7841. IN LPARAM lParam
  7842. )
  7843. {
  7844. DWORD dwRet = ERROR_SUCCESS;
  7845. RpcTryExcept
  7846. {
  7847. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  7848. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  7849. {
  7850. AllowSetForegroundWindow(RPCSplWOW64GetProcessID());
  7851. if((dwRet = RPCSplWOW64PrintUIPrinterPropPages((ULONG_PTR)GetForeGroundWindow(),
  7852. PrinterName,
  7853. CmdShow,
  7854. lParam)) == ERROR_SUCCESS)
  7855. {
  7856. MSG msg;
  7857. while(GetMessage(&msg, NULL, 0, 0))
  7858. {
  7859. if(msg.message == WM_ENDPRINTERPROPPAGES)
  7860. {
  7861. DelHandleFromList(hWnd);
  7862. break;
  7863. }
  7864. else if(msg.message == WM_SURROGATEFAILURE)
  7865. {
  7866. //
  7867. // This means that the server process died and we have
  7868. // break from the message loop
  7869. //
  7870. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  7871. break;
  7872. }
  7873. TranslateMessage(&msg);
  7874. DispatchMessage(&msg);
  7875. }
  7876. }
  7877. else
  7878. {
  7879. SetLastError(dwRet);
  7880. }
  7881. }
  7882. }
  7883. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  7884. {
  7885. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7886. }
  7887. RpcEndExcept
  7888. }
  7889. VOID
  7890. PrintUIDocumentDefaults(
  7891. IN HWND hWnd,
  7892. IN LPCWSTR PrinterName,
  7893. IN INT CmdShow,
  7894. IN LPARAM lParam
  7895. )
  7896. {
  7897. DWORD dwRet = ERROR_SUCCESS;
  7898. RpcTryExcept
  7899. {
  7900. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  7901. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  7902. {
  7903. AllowSetForegroundWindow(RPCSplWOW64GetProcessID());
  7904. if((dwRet = RPCSplWOW64PrintUIDocumentDefaults((ULONG_PTR)GetForeGroundWindow(),
  7905. PrinterName,
  7906. CmdShow,
  7907. lParam)) == ERROR_SUCCESS)
  7908. {
  7909. MSG msg;
  7910. while(GetMessage(&msg, NULL, 0, 0))
  7911. {
  7912. if(msg.message == WM_ENDDOCUMENTDEFAULTS)
  7913. {
  7914. DelHandleFromList(hWnd);
  7915. break;
  7916. }
  7917. else if(msg.message == WM_SURROGATEFAILURE)
  7918. {
  7919. //
  7920. // This means that the server process died and we have
  7921. // break from the message loop
  7922. //
  7923. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  7924. break;
  7925. }
  7926. TranslateMessage(&msg);
  7927. DispatchMessage(&msg);
  7928. }
  7929. }
  7930. else
  7931. {
  7932. SetLastError(dwRet);
  7933. }
  7934. }
  7935. }
  7936. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  7937. {
  7938. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7939. }
  7940. RpcEndExcept
  7941. }
  7942. DWORD WINAPI
  7943. AsyncPrinterSetup(
  7944. PVOID pData
  7945. )
  7946. {
  7947. PrinterSetupData *pThrdData = (PrinterSetupData *)pData;
  7948. RpcTryExcept
  7949. {
  7950. RPCSplWOW64PrintUIPrinterSetup((ULONG_PTR)GetForeGroundWindow(),
  7951. pThrdData->uAction,
  7952. pThrdData->cchPrinterName,
  7953. pThrdData->PrinterNameSize,
  7954. (byte *)pThrdData->pszPrinterName,
  7955. pThrdData->pcchPrinterName,
  7956. pThrdData->pszServerName);
  7957. }
  7958. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  7959. {
  7960. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  7961. }
  7962. RpcEndExcept
  7963. return(0);
  7964. }
  7965. BOOL
  7966. PrintUIPrinterSetup(
  7967. IN HWND hWnd,
  7968. IN UINT uAction,
  7969. IN UINT cchPrinterName,
  7970. IN OUT LPWSTR pszPrinterName,
  7971. OUT UINT *pcchPrinterName,
  7972. IN LPCWSTR pszServerName
  7973. )
  7974. {
  7975. BOOL bRet = FALSE;
  7976. DWORD dwRet = ERROR_SUCCESS;
  7977. RpcTryExcept
  7978. {
  7979. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  7980. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  7981. {
  7982. HANDLE hAsyncSetupThrd = NULL;
  7983. DWORD AsyncSetupThrdId = 0;
  7984. PrinterSetupData ThrdData;
  7985. AllowSetForegroundWindow(RPCSplWOW64GetProcessID());
  7986. ThrdData.hWnd = (ULONG_PTR)GetForeGroundWindow();
  7987. ThrdData.uAction = uAction;
  7988. ThrdData.cchPrinterName = cchPrinterName;
  7989. ThrdData.PrinterNameSize = cchPrinterName*2;
  7990. ThrdData.pszPrinterName = pszPrinterName;
  7991. ThrdData.pcchPrinterName = pcchPrinterName;
  7992. ThrdData.pszServerName = pszServerName;
  7993. if(!(hAsyncSetupThrd = CreateThread(NULL,
  7994. INITIAL_STACK_COMMIT,
  7995. AsyncPrinterSetup,
  7996. (PVOID)&ThrdData,
  7997. 0,
  7998. &AsyncSetupThrdId)))
  7999. {
  8000. dwRet = GetLastError();
  8001. }
  8002. else
  8003. {
  8004. MSG msg;
  8005. while(GetMessage(&msg, NULL, 0, 0))
  8006. {
  8007. if(msg.message == WM_ENDPRINTERSETUP)
  8008. {
  8009. bRet = (BOOL)msg.wParam;
  8010. SetLastError((DWORD)msg.lParam);
  8011. DelHandleFromList(hWnd);
  8012. break;
  8013. }
  8014. else if(msg.message == WM_SURROGATEFAILURE)
  8015. {
  8016. //
  8017. // This means that the server process died and we have
  8018. // break from the message loop
  8019. //
  8020. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  8021. break;
  8022. }
  8023. TranslateMessage(&msg);
  8024. DispatchMessage(&msg);
  8025. }
  8026. WaitForSingleObject(hAsyncSetupThrd,INFINITE);
  8027. CloseHandle(hAsyncSetupThrd);
  8028. }
  8029. }
  8030. }
  8031. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  8032. {
  8033. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  8034. }
  8035. RpcEndExcept
  8036. return bRet;
  8037. }
  8038. VOID
  8039. PrintUIServerPropPages(
  8040. IN HWND hWnd,
  8041. IN LPCWSTR ServerName,
  8042. IN INT CmdShow,
  8043. IN LPARAM lParam
  8044. )
  8045. {
  8046. DWORD dwRet = ERROR_SUCCESS;
  8047. RpcTryExcept
  8048. {
  8049. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  8050. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS))
  8051. {
  8052. AllowSetForegroundWindow(RPCSplWOW64GetProcessID());
  8053. if((dwRet = RPCSplWOW64PrintUIServerPropPages((ULONG_PTR)GetForeGroundWindow(),
  8054. ServerName,
  8055. CmdShow,
  8056. lParam)) == ERROR_SUCCESS)
  8057. {
  8058. MSG msg;
  8059. while(GetMessage(&msg, NULL, 0, 0))
  8060. {
  8061. if(msg.message == WM_ENDSERVERPROPPAGES)
  8062. {
  8063. DelHandleFromList(hWnd);
  8064. break;
  8065. }
  8066. else if(msg.message == WM_SURROGATEFAILURE)
  8067. {
  8068. //
  8069. // This means that the server process died and we have
  8070. // break from the message loop
  8071. //
  8072. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  8073. break;
  8074. }
  8075. TranslateMessage(&msg);
  8076. DispatchMessage(&msg);
  8077. }
  8078. }
  8079. else
  8080. {
  8081. SetLastError(dwRet);
  8082. }
  8083. }
  8084. }
  8085. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  8086. {
  8087. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  8088. }
  8089. RpcEndExcept
  8090. }
  8091. DWORD WINAPI
  8092. AsyncDocumentPropertiesWrap(
  8093. PVOID pData
  8094. )
  8095. {
  8096. PumpThrdData *ThrdData = (PumpThrdData *)pData;
  8097. RpcTryExcept
  8098. {
  8099. *ThrdData->Result = RPCSplWOW64PrintUIDocumentProperties(ThrdData->hWnd,
  8100. ThrdData->PrinterName,
  8101. ThrdData->TouchedDevModeSize,
  8102. ThrdData->ClonedDevModeOutSize,
  8103. ThrdData->ClonedDevModeOut,
  8104. ThrdData->DevModeInSize,
  8105. ThrdData->pDevModeInput,
  8106. ThrdData->ClonedDevModeFill,
  8107. ThrdData->fMode,
  8108. ThrdData->fExclusionFlags,
  8109. ThrdData->dwRet);
  8110. }
  8111. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  8112. {
  8113. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  8114. }
  8115. RpcEndExcept
  8116. return(0);
  8117. }
  8118. LONG
  8119. PrintUIDocumentPropertiesWrap(
  8120. HWND hWnd, // handle to parent window
  8121. HANDLE hPrinter, // handle to printer object
  8122. LPTSTR pDeviceName, // device name
  8123. PDEVMODE pDevModeOutput, // modified device mode
  8124. PDEVMODE pDevModeInput, // original device mode
  8125. DWORD fMode, // mode options
  8126. DWORD fExclusionFlags // exclusion flags
  8127. )
  8128. {
  8129. DOCUMENTPROPERTYHEADER DPHdr;
  8130. PDEVMODE pDM;
  8131. LONG Result = -1;
  8132. HANDLE hTmpPrinter = NULL;
  8133. PSPOOL pSpool = (PSPOOL)hPrinter;
  8134. if (hPrinter == NULL)
  8135. {
  8136. if (!OpenPrinter( pDeviceName, &hTmpPrinter, NULL ))
  8137. {
  8138. hTmpPrinter = NULL;
  8139. }
  8140. }
  8141. else
  8142. {
  8143. hTmpPrinter = hPrinter;
  8144. }
  8145. if( !eProtectHandle( hTmpPrinter, FALSE ))
  8146. {
  8147. LPWSTR PrinterName;
  8148. MSG msg;
  8149. LONG RetVal;
  8150. DWORD dwRet = ERROR_SUCCESS;
  8151. DWORD ClonedDevModeOutSize = 0;
  8152. DWORD TouchedDevModeSize = 0;
  8153. BOOL ClonedDevModeFill = (!!(fMode & DM_OUT_BUFFER) && pDevModeOutput);
  8154. DWORD DevModeInSize = pDevModeInput ? (pDevModeInput->dmSize + pDevModeInput->dmDriverExtra) : 0;
  8155. byte **ClonedDevModeOut = NULL;
  8156. if(ClonedDevModeOut = (byte **)LocalAlloc(LPTR,sizeof(byte *)))
  8157. {
  8158. *ClonedDevModeOut = NULL;
  8159. if(pSpool)
  8160. {
  8161. PrinterName = pSpool->pszPrinter;
  8162. }
  8163. else
  8164. {
  8165. PrinterName = pDeviceName;
  8166. }
  8167. //
  8168. // If fMode doesn't specify DM_IN_BUFFER, then zero out
  8169. // pDevModeInput.
  8170. //
  8171. // Old 3.51 (version 1-0) drivers used to ignore the absence of
  8172. // DM_IN_BUFFER and use pDevModeInput if it was not NULL. It
  8173. // probably did this because Printman.exe was broken.
  8174. //
  8175. // If the devmode is invalid, then don't pass one in.
  8176. // This fixes MS Imager32 (which passes dmSize == 0) and
  8177. // Milestones etc. 4.5.
  8178. //
  8179. // Note: this assumes that pDevModeOutput is still the
  8180. // correct size!
  8181. //
  8182. if( !(fMode & DM_IN_BUFFER) || !bValidDevModeW( pDevModeInput ))
  8183. {
  8184. //
  8185. // If either are not set, make sure both are not set.
  8186. //
  8187. pDevModeInput = NULL;
  8188. DevModeInSize = 0;
  8189. fMode &= ~DM_IN_BUFFER;
  8190. }
  8191. RpcTryExcept
  8192. {
  8193. if(((dwRet = ConnectToLd64In32Server(&hSurrogateProcess)) == ERROR_SUCCESS) &&
  8194. (!hWnd ||
  8195. ((dwRet = AddHandleToList(hWnd)) == ERROR_SUCCESS)))
  8196. {
  8197. HANDLE hUIMsgThrd = NULL;
  8198. DWORD UIMsgThrdId = 0;
  8199. PumpThrdData ThrdData;
  8200. ThrdData.hWnd = (ULONG_PTR)hWnd;
  8201. ThrdData.PrinterName=PrinterName;
  8202. ThrdData.TouchedDevModeSize = &TouchedDevModeSize;
  8203. ThrdData.ClonedDevModeOutSize = &ClonedDevModeOutSize;
  8204. ThrdData.ClonedDevModeOut = (byte**)ClonedDevModeOut;
  8205. ThrdData.DevModeInSize = DevModeInSize;
  8206. ThrdData.pDevModeInput = (byte*)pDevModeInput;
  8207. ThrdData.fMode = fMode;
  8208. ThrdData.fExclusionFlags = fExclusionFlags;
  8209. ThrdData.dwRet = &dwRet;
  8210. ThrdData.ClonedDevModeFill = ClonedDevModeFill;
  8211. ThrdData.Result = &Result;
  8212. //
  8213. // If we have a window handle , the following functions cann't
  8214. // proceed synchronasly. The reason for that is in order to show
  8215. // the UI of the driver property sheets we need to be able to dispatch
  8216. // incomming messages and process them.For this reason the following
  8217. // call would be asynchronous call and the success or failure doesn't
  8218. // in reality tell us anything more than than the async process started
  8219. // or not. We get the success of failure from the termination message.
  8220. // If we don't have a window handle, then the call is synchronous.
  8221. //
  8222. if(!(hUIMsgThrd = CreateThread(NULL,
  8223. INITIAL_STACK_COMMIT,
  8224. AsyncDocumentPropertiesWrap,
  8225. (PVOID)&ThrdData,
  8226. 0,
  8227. &UIMsgThrdId)))
  8228. {
  8229. dwRet = GetLastError();
  8230. }
  8231. //
  8232. // The following is the required message loop for processing messages
  8233. // from the UI in case we have a window handle.
  8234. //
  8235. //
  8236. if(hUIMsgThrd && hWnd)
  8237. {
  8238. while (GetMessage(&msg, NULL, 0, 0))
  8239. {
  8240. //
  8241. // In This message loop We should trap a User defined message
  8242. // which indicates the success or the failure of the operation
  8243. //
  8244. if(msg.message == WM_ENDPRINTUIDOCUMENTPROPERTIES)
  8245. {
  8246. Result = (LONG)msg.wParam;
  8247. if(Result == -1)
  8248. SetLastError((DWORD)msg.lParam);
  8249. DelHandleFromList(hWnd);
  8250. break;
  8251. }
  8252. else if(msg.message == WM_SURROGATEFAILURE)
  8253. {
  8254. //
  8255. // This means that the server process died and we have
  8256. // break from the message loop
  8257. //
  8258. Result = -1;
  8259. SetLastError(RPC_S_SERVER_UNAVAILABLE);
  8260. break;
  8261. }
  8262. TranslateMessage(&msg);
  8263. DispatchMessage(&msg);
  8264. }
  8265. }
  8266. if(hUIMsgThrd)
  8267. {
  8268. WaitForSingleObject(hUIMsgThrd,INFINITE);
  8269. CloseHandle(hUIMsgThrd);
  8270. }
  8271. if(Result!=-1 && pDevModeOutput)
  8272. {
  8273. memcpy((PVOID)pDevModeOutput,(PVOID)*ClonedDevModeOut,TouchedDevModeSize);
  8274. }
  8275. if(*ClonedDevModeOut)
  8276. {
  8277. MIDL_user_free((PVOID)*ClonedDevModeOut);
  8278. }
  8279. if(ClonedDevModeOut)
  8280. {
  8281. LocalFree((PVOID) ClonedDevModeOut);
  8282. }
  8283. }
  8284. else
  8285. {
  8286. SetLastError(dwRet);
  8287. }
  8288. }
  8289. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  8290. {
  8291. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  8292. }
  8293. RpcEndExcept
  8294. vUnprotectHandle( hTmpPrinter );
  8295. }
  8296. else
  8297. {
  8298. SetLastError(ERROR_OUTOFMEMORY);
  8299. }
  8300. }
  8301. if (hPrinter == NULL)
  8302. {
  8303. if( hTmpPrinter )
  8304. {
  8305. ClosePrinter(hTmpPrinter);
  8306. }
  8307. }
  8308. return(Result);
  8309. }
  8310. /*++
  8311. Function Name:
  8312. MonitorRPCServerProcess
  8313. Description:
  8314. This function monitors the status of the RPC surrogate
  8315. process. The one used in loading the required 64 dlls
  8316. in a 32 bit client.This function always run in a
  8317. separate thread
  8318. Parameters:
  8319. pData : Pointer to the process handle to monitor
  8320. Return Value
  8321. Always return 0
  8322. --*/
  8323. DWORD WINAPI
  8324. MonitorRPCServerProcess(
  8325. PVOID pData
  8326. )
  8327. {
  8328. WndHndlList ListObj;
  8329. HANDLE* phProcess;
  8330. HANDLE hEvent;
  8331. LPMonitorThrdData pThrdData = (LPMonitorThrdData)pData;
  8332. ListObj.Head = 0x00000000;
  8333. ListObj.Tail = 0x00000000;
  8334. ListObj.NumOfHndls = 0;
  8335. //
  8336. // reconstruct the Data for the thread
  8337. //
  8338. hEvent = pThrdData->hEvent;
  8339. phProcess = pThrdData->hProcess;
  8340. EnterCriticalSection(&ProcessHndlCS);
  8341. {
  8342. GWndHndlList = &ListObj;
  8343. }
  8344. LeaveCriticalSection(&ProcessHndlCS);
  8345. SetEvent(hEvent);
  8346. WaitForSingleObject(*phProcess,INFINITE);
  8347. EnterCriticalSection(&ProcessHndlCS);
  8348. {
  8349. CloseHandle(*((HANDLE *)phProcess));
  8350. *((HANDLE *)phProcess) = 0x00000000;
  8351. RpcBindingFree(&hSurrogate);
  8352. //
  8353. // Release any windows which might be
  8354. // locked on a surrogate process waiting
  8355. // for its completion
  8356. //
  8357. ReleaseAndCleanupWndList();
  8358. }
  8359. LeaveCriticalSection(&ProcessHndlCS);
  8360. return(0);
  8361. }
  8362. /*++
  8363. Function Name:
  8364. ConnectToLd64In32Server
  8365. Description:
  8366. This function make sure that we retry connection to the server
  8367. in case of a very slight window where the Server terminated between
  8368. our connection and the very first call.
  8369. Parameters:
  8370. hProcess : Pointer to the process handle that retrieves
  8371. the process handle of the server
  8372. Return Value
  8373. --*/
  8374. DWORD
  8375. ConnectToLd64In32Server(
  8376. HANDLE *hProcess
  8377. )
  8378. {
  8379. DWORD RetVal = ERROR_SUCCESS;
  8380. //
  8381. // As GDI would be using the same monitoring Thread, So we spin
  8382. // only one thread.
  8383. //
  8384. if(!hProcess)
  8385. {
  8386. hProcess = &hSurrogateProcess;
  8387. }
  8388. if( (RetVal = ConnectToLd64In32ServerWorker(hProcess)) != ERROR_SUCCESS)
  8389. {
  8390. if(RetVal == RPC_S_SERVER_UNAVAILABLE || RetVal == RPC_S_CALL_FAILED_DNE)
  8391. {
  8392. RetVal = ConnectToLd64In32ServerWorker(hProcess);
  8393. }
  8394. }
  8395. return(RetVal);
  8396. }
  8397. /*++
  8398. Function Name:
  8399. ConnectToLd64In32ServerWorker
  8400. Description:
  8401. This function handles the connectivity issues with
  8402. the RPC surrogate process (the one that loads 64 bit
  8403. dlls in a 32 bit process).
  8404. Parameters:
  8405. hProcess : Pointer to the process handle that retrieves
  8406. the process handle of the server
  8407. Return Value
  8408. --*/
  8409. DWORD
  8410. ConnectToLd64In32ServerWorker(
  8411. HANDLE *hProcess
  8412. )
  8413. {
  8414. DWORD RetVal = ERROR_SUCCESS;
  8415. RPC_STATUS RpcStatus;
  8416. EnterCriticalSection(&ProcessHndlCS);
  8417. {
  8418. if(!*hProcess)
  8419. {
  8420. WCHAR* StringBinding = NULL;
  8421. STARTUPINFO StartUPInfo;
  8422. PROCESS_INFORMATION ProcessInfo;
  8423. ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO));
  8424. ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION));
  8425. StartUPInfo.cb = sizeof(STARTUPINFO);
  8426. RpcTryExcept
  8427. {
  8428. HANDLE hOneProcessMutex = NULL;
  8429. WCHAR SessionEndPoint[50];
  8430. DWORD CurrSessionId;
  8431. DWORD CurrProcessId = GetCurrentProcessId();
  8432. if(ProcessIdToSessionId(CurrProcessId,&CurrSessionId))
  8433. {
  8434. wsprintf(SessionEndPoint,L"%s_%x",L"splwow64",CurrSessionId);
  8435. if(!(((RpcStatus = RpcStringBindingCompose(NULL,
  8436. L"ncalrpc",
  8437. NULL,
  8438. SessionEndPoint,
  8439. NULL,
  8440. &StringBinding))==RPC_S_OK) &&
  8441. ((RpcStatus = RpcBindingFromStringBinding(StringBinding,
  8442. &hSurrogate))==RPC_S_OK) &&
  8443. ((RpcStatus = RpcStringFree(&StringBinding)) == RPC_S_OK)))
  8444. {
  8445. RetVal = (DWORD)RpcStatus;
  8446. }
  8447. else
  8448. {
  8449. //
  8450. // This mutex is defined as Local to be different for
  8451. // each TS session
  8452. //
  8453. if(hOneProcessMutex = CreateMutex(NULL,
  8454. FALSE,
  8455. L"Local\\WinSpl64To32Mutex"))
  8456. {
  8457. HANDLE hThread;
  8458. HANDLE hMonitorStartedEvent;
  8459. DWORD ThreadId;
  8460. DWORD i=0;
  8461. DWORD RpcRetCode;
  8462. WaitForSingleObject(hOneProcessMutex,INFINITE);
  8463. {
  8464. if(RpcMgmtIsServerListening(hSurrogate) == RPC_S_NOT_LISTENING)
  8465. {
  8466. WCHAR ProcessName[MAX_PATH+1];
  8467. WCHAR WindowsDirectory[MAX_PATH+1];
  8468. //
  8469. // In the future this should work , but
  8470. // for the time being , wow64 redirects
  8471. // any CreateProcess initiated from a wow
  8472. // app and requesting an app from system32
  8473. // to syswow64. That is why I moving the exe
  8474. // out of the system32 directory.
  8475. //
  8476. GetSystemWindowsDirectory(WindowsDirectory,MAX_PATH);
  8477. wsprintf(ProcessName,L"%ws\\splwow64.exe",WindowsDirectory);
  8478. if(!CreateProcess(ProcessName,
  8479. L"splwow64",
  8480. NULL,
  8481. NULL,
  8482. FALSE,
  8483. CREATE_DEFAULT_ERROR_MODE |
  8484. CREATE_NO_WINDOW |
  8485. DETACHED_PROCESS,
  8486. NULL,
  8487. WindowsDirectory,
  8488. &StartUPInfo,
  8489. &ProcessInfo))
  8490. {
  8491. RetVal = GetLastError();
  8492. }
  8493. else
  8494. {
  8495. *hProcess = ProcessInfo.hProcess;
  8496. //
  8497. // A spinlock making sure that the process is really live and kicking.
  8498. // I also added to the spin lock a time out value in order not to enter
  8499. // in an endless loop. So, after a minute we just break.
  8500. //
  8501. for(i=0,
  8502. RpcRetCode = RpcMgmtIsServerListening(hSurrogate);
  8503. ((i<60) && (RpcRetCode == RPC_S_NOT_LISTENING));
  8504. Sleep(1000),
  8505. RpcRetCode = RpcMgmtIsServerListening(hSurrogate),
  8506. i++
  8507. );
  8508. }
  8509. }
  8510. else
  8511. {
  8512. *hProcess = (HANDLE) RPCSplWOW64GetProcessHndl((DWORD)GetCurrentProcessId(),&RetVal);
  8513. }
  8514. }
  8515. ReleaseMutex(hOneProcessMutex);
  8516. CloseHandle(hOneProcessMutex);
  8517. if(!(hMonitorStartedEvent=CreateEvent(NULL,FALSE,FALSE,NULL)))
  8518. {
  8519. RetVal = GetLastError();
  8520. }
  8521. else
  8522. {
  8523. MonitorThrdData ThrdData;
  8524. ThrdData.hEvent = hMonitorStartedEvent;
  8525. ThrdData.hProcess = hProcess;
  8526. if(!(hThread = CreateThread(NULL,
  8527. INITIAL_STACK_COMMIT,
  8528. MonitorRPCServerProcess,
  8529. (PVOID)&ThrdData,
  8530. 0,
  8531. &ThreadId)))
  8532. {
  8533. RetVal = GetLastError();
  8534. }
  8535. else
  8536. {
  8537. LeaveCriticalSection(&ProcessHndlCS);
  8538. {
  8539. WaitForSingleObject(hMonitorStartedEvent,INFINITE);
  8540. }
  8541. EnterCriticalSection(&ProcessHndlCS);
  8542. CloseHandle(hThread);
  8543. }
  8544. CloseHandle(hMonitorStartedEvent);
  8545. }
  8546. }
  8547. else
  8548. {
  8549. RetVal = GetLastError();
  8550. }
  8551. }
  8552. }
  8553. else
  8554. {
  8555. RetVal = GetLastError();
  8556. }
  8557. }
  8558. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  8559. {
  8560. RetVal = RpcExceptionCode();
  8561. }
  8562. RpcEndExcept
  8563. }
  8564. else
  8565. {
  8566. //
  8567. // Refresh the life of the server
  8568. //
  8569. RpcTryExcept
  8570. {
  8571. RPCSplWOW64RefreshLifeSpan();
  8572. }
  8573. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  8574. {
  8575. RetVal = RpcExceptionCode();
  8576. }
  8577. RpcEndExcept
  8578. }
  8579. }
  8580. LeaveCriticalSection(&ProcessHndlCS);
  8581. return(RetVal);
  8582. }
  8583. DWORD
  8584. AddHandleToList(
  8585. HWND hWnd
  8586. )
  8587. {
  8588. LPWndHndlNode NewNode = 0x00000000;
  8589. DWORD RetVal = ERROR_SUCCESS;
  8590. EnterCriticalSection(&ProcessHndlCS);
  8591. {
  8592. if(GWndHndlList)
  8593. {
  8594. if(NewNode = (LPWndHndlNode)LocalAlloc(LMEM_FIXED, sizeof(WndHndlNode)))
  8595. {
  8596. NewNode->PrevNode = 0x000000000;
  8597. NewNode->NextNode = 0x000000000;
  8598. NewNode->hWnd = hWnd;
  8599. if(!GWndHndlList->Head &&
  8600. !GWndHndlList->NumOfHndls)
  8601. {
  8602. GWndHndlList->Head = NewNode;
  8603. GWndHndlList->Tail = NewNode;
  8604. }
  8605. else
  8606. {
  8607. NewNode->PrevNode = GWndHndlList->Tail;
  8608. GWndHndlList->Tail->NextNode = NewNode;
  8609. GWndHndlList->Tail = NewNode;
  8610. }
  8611. GWndHndlList->NumOfHndls++;
  8612. }
  8613. else
  8614. {
  8615. RetVal = GetLastError();
  8616. }
  8617. }
  8618. else
  8619. {
  8620. RetVal = ERROR_INVALID_PARAMETER;
  8621. }
  8622. }
  8623. LeaveCriticalSection(&ProcessHndlCS);
  8624. return(RetVal);
  8625. }
  8626. BOOL
  8627. DelHandleFromList(
  8628. HWND hWnd
  8629. )
  8630. {
  8631. DWORD RetVal = ERROR_SUCCESS;
  8632. BOOL Found = FALSE;
  8633. EnterCriticalSection(&ProcessHndlCS);
  8634. {
  8635. LPWndHndlNode TempNode = 0x00000000;
  8636. if(GWndHndlList)
  8637. {
  8638. if(GWndHndlList->NumOfHndls)
  8639. {
  8640. //
  8641. // Is it last Element in list
  8642. //
  8643. if(GWndHndlList->Tail->hWnd == hWnd)
  8644. {
  8645. TempNode = GWndHndlList->Tail;
  8646. GWndHndlList->Tail = TempNode->PrevNode;
  8647. if(GWndHndlList->Tail)
  8648. {
  8649. GWndHndlList->Tail->NextNode = 0x00000000;
  8650. }
  8651. Found = TRUE;
  8652. }
  8653. //
  8654. // Is it first Element in list
  8655. //
  8656. else if(GWndHndlList->Head->hWnd == hWnd)
  8657. {
  8658. TempNode = GWndHndlList->Head;
  8659. GWndHndlList->Head = TempNode->NextNode;
  8660. if(GWndHndlList->Head)
  8661. GWndHndlList->Head->PrevNode = 0x00000000;
  8662. Found = TRUE;
  8663. }
  8664. //
  8665. // Is it an intermediate Element
  8666. //
  8667. else
  8668. {
  8669. TempNode = GWndHndlList->Head->NextNode;
  8670. while(TempNode &&
  8671. (TempNode->hWnd != hWnd) &&
  8672. TempNode != GWndHndlList->Tail)
  8673. {
  8674. TempNode = TempNode->NextNode;
  8675. }
  8676. if(TempNode && TempNode!=GWndHndlList->Tail)
  8677. {
  8678. Found = TRUE;
  8679. TempNode->PrevNode->NextNode = TempNode->NextNode;
  8680. TempNode->NextNode->PrevNode = TempNode->PrevNode;
  8681. }
  8682. }
  8683. if(Found)
  8684. {
  8685. if(!--GWndHndlList->NumOfHndls)
  8686. {
  8687. GWndHndlList->Head = GWndHndlList->Tail = 0x00000000;
  8688. }
  8689. LocalFree(TempNode);
  8690. }
  8691. }
  8692. }
  8693. else
  8694. {
  8695. RetVal = ERROR_INVALID_PARAMETER;
  8696. }
  8697. }
  8698. LeaveCriticalSection(&ProcessHndlCS);
  8699. return(RetVal);
  8700. }
  8701. VOID
  8702. ReleaseAndCleanupWndList(
  8703. VOID
  8704. )
  8705. {
  8706. LPWndHndlNode TempNode = (LPWndHndlNode)GWndHndlList->Head;
  8707. while(TempNode)
  8708. {
  8709. PostMessage(TempNode->hWnd,
  8710. WM_SURROGATEFAILURE,
  8711. 0,
  8712. 0);
  8713. GWndHndlList->Head = TempNode->NextNode;
  8714. LocalFree(TempNode);
  8715. TempNode = GWndHndlList->Head;
  8716. }
  8717. GWndHndlList->NumOfHndls = 0;
  8718. }
  8719. BOOL
  8720. JobCanceled(
  8721. IN PSJobCancelInfo pJobCancelInfo
  8722. )
  8723. {
  8724. if (!pJobCancelInfo->NumOfCmpltWrts && pJobCancelInfo->pSpool->cbFlushPending)
  8725. {
  8726. //
  8727. // Data to be flushed =
  8728. // pSpool->cbFlushPending
  8729. //
  8730. FlushPrinter(pJobCancelInfo->pSpool,
  8731. pJobCancelInfo->pSpool->pBuffer+pJobCancelInfo->cbFlushed,
  8732. pJobCancelInfo->pSpool->cbFlushPending,
  8733. pJobCancelInfo->pcbWritten,
  8734. 0);
  8735. pJobCancelInfo->pSpool->Flushed = 1;
  8736. }
  8737. else
  8738. {
  8739. DWORD WrittenDataSize = *pJobCancelInfo->pcTotalWritten + pJobCancelInfo->cbFlushed;
  8740. //
  8741. // Data to be flushed =
  8742. // I/P Data + Pending Data - Total Written
  8743. //
  8744. SPLASSERT(WrittenDataSize <= pJobCancelInfo->ReqTotalDataSize);
  8745. if (pJobCancelInfo->ReqTotalDataSize - WrittenDataSize)
  8746. {
  8747. LPBYTE pFlushBuffer;
  8748. //
  8749. // Location in pFlushBuffer where data from the
  8750. // i/p buffer starts
  8751. //
  8752. DWORD InitialBuffStart = 0;
  8753. if ((pFlushBuffer = VirtualAlloc(NULL,
  8754. (pJobCancelInfo->ReqTotalDataSize - WrittenDataSize),
  8755. MEM_COMMIT, PAGE_READWRITE)))
  8756. {
  8757. //
  8758. // Since this seems to be quite a complicated functionality
  8759. // I'll try explaining it in details here
  8760. // These are the Data Buffers we are dealing with and their
  8761. // initial states
  8762. //
  8763. // pSpool->pBuffer pBuf = pInitialBuf
  8764. // ____________________ _________________________________
  8765. // | | | | |
  8766. // | | | | |
  8767. // -------------------- ---------------------------------
  8768. // <-------> <-------------------------------->
  8769. // pending ReqToWriteDataSize
  8770. // | |
  8771. // | |
  8772. // ----------------+----------------
  8773. // |
  8774. // (RequiredTotalDataSize)
  8775. //
  8776. // At this stage of the function we could have the
  8777. // following conditions
  8778. // 1. Written < Pending -----> Then we have to
  8779. // count both Buffers for Flushing
  8780. // 2. Written > Pending -----> Then we count only pBuf for
  8781. // Flushing
  8782. // Based on these conditions we need to figure out which of the
  8783. // of the 2 buffers is used for flushing the data and what pointer
  8784. // in either is the starting point of this data
  8785. // For Condition 1 FlushBuffer would be the aggregation of :
  8786. // pSpool->pBuffer pBuf = pInitialBuf
  8787. // ____________________ _________________________________
  8788. // | | | | | |
  8789. // | | | | | |
  8790. // -------------------- ---------------------------------
  8791. // <---> <------------------------------->
  8792. // Pending-Written ReqToWriteDataSize
  8793. //
  8794. // FlushBuffer
  8795. // _____________________________________
  8796. // | | |
  8797. // | | |
  8798. // -------------------------------------
  8799. // |
  8800. // |
  8801. // InitialBuffStart(where pBuf starts in FlushBuffer)
  8802. // <---><------------------------------->
  8803. // Pending-Written ReqToWriteDataSize
  8804. //
  8805. // For Condition 2 FlushBuffer would be a portion of pBuf:
  8806. // pBuf = pInitialBuf
  8807. // _________________________________
  8808. // | | |
  8809. // | | |
  8810. // ---------------------------------
  8811. // <----------------------->
  8812. // ReqTotalDataSize - Written
  8813. //
  8814. // FlushBuffer
  8815. // _______________________
  8816. // | |
  8817. // | |
  8818. // -----------------------
  8819. // |
  8820. // |
  8821. // InitialBuffStart(at the very beginning)
  8822. // <--------------------->
  8823. // ReqTotalDataSize - Written
  8824. //
  8825. if (WrittenDataSize < pJobCancelInfo->FlushPendingDataSize)
  8826. {
  8827. InitialBuffStart = pJobCancelInfo->FlushPendingDataSize - WrittenDataSize;
  8828. CopyMemory( pFlushBuffer ,
  8829. pJobCancelInfo->pSpool->pBuffer + WrittenDataSize,
  8830. InitialBuffStart);
  8831. }
  8832. CopyMemory(pFlushBuffer + InitialBuffStart ,
  8833. pJobCancelInfo->pInitialBuf +
  8834. (InitialBuffStart ? 0 : WrittenDataSize - pJobCancelInfo->FlushPendingDataSize),
  8835. pJobCancelInfo->ReqTotalDataSize - WrittenDataSize - InitialBuffStart);
  8836. FlushPrinter(pJobCancelInfo->pSpool,
  8837. pFlushBuffer,
  8838. pJobCancelInfo->ReqTotalDataSize - WrittenDataSize,
  8839. pJobCancelInfo->pcbWritten,
  8840. 0);
  8841. VirtualFree(pFlushBuffer,
  8842. (pJobCancelInfo->ReqTotalDataSize - WrittenDataSize),
  8843. MEM_RELEASE);
  8844. pJobCancelInfo->ReturnValue = TRUE;
  8845. pJobCancelInfo->pSpool->Flushed = 1;
  8846. if (*pJobCancelInfo->pcbWritten == (pJobCancelInfo->ReqTotalDataSize - WrittenDataSize))
  8847. {
  8848. *pJobCancelInfo->pcTotalWritten+=pJobCancelInfo->ReqToWriteDataSize;
  8849. }
  8850. }
  8851. else
  8852. {
  8853. DBGMSG(DBG_WARNING, ("JObCanceled::VirtualAlloc Failed to allocate 4k buffer %d\n",GetLastError()));
  8854. }
  8855. }
  8856. }
  8857. if (pJobCancelInfo->pSpool->Flushed)
  8858. {
  8859. pJobCancelInfo->pSpool->cbFlushPending = 0;
  8860. pJobCancelInfo->pSpool->cbBuffer = 0;
  8861. }
  8862. return pJobCancelInfo->ReturnValue;
  8863. }