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

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