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.

1667 lines
39 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. driverui.c
  5. Abstract:
  6. This file contains utility functions for the UI and the
  7. interface to the parser.
  8. Environment:
  9. Win32 subsystem, DriverUI module, user mode
  10. Revision History:
  11. 02/09/97 -davidx-
  12. Rewrote it to consistently handle common printer info
  13. and to clean up parser interface code.
  14. 02/04/97 -davidx-
  15. Reorganize driver UI to separate ps and uni DLLs.
  16. 07/17/96 -amandan-
  17. Created it.
  18. --*/
  19. #include "precomp.h"
  20. HANDLE HCreateHeapForCI();
  21. PCOMMONINFO
  22. PLoadCommonInfo(
  23. HANDLE hPrinter,
  24. PTSTR pPrinterName,
  25. DWORD dwFlags
  26. )
  27. /*++
  28. Routine Description:
  29. Load basic information needed by the driver UI such as:
  30. printer driver info level 2
  31. load raw printer description data
  32. printer description data instance based on default settings
  33. get information about OEM plugins
  34. load OEM UI modules
  35. Arguments:
  36. hPrinter - Handle to the current printer
  37. pPrinterName - Points to the current printer name
  38. dwFlags - One of the following combinations:
  39. 0
  40. FLAG_ALLOCATE_UIDATA
  41. FLAG_OPENPRINTER_NORMAL [ | FLAG_OPEN_CONDITIONAL ]
  42. FLAG_OPENPRINTER_ADMIN [ | FLAG_INIT_PRINTER ]
  43. FLAG_OPENPRINTER_ADMIN [ | FLAG_PROCESS_INIFILE ]
  44. Return Value:
  45. Pointer to an allocated COMMONINFO structure if successful
  46. NULL if there is an error
  47. --*/
  48. {
  49. static PRINTER_DEFAULTS PrinterDefaults = { NULL, NULL, PRINTER_ALL_ACCESS };
  50. PCOMMONINFO pci;
  51. DWORD dwSize;
  52. //
  53. // Allocate memory for a COMMONINFO structure
  54. //
  55. dwSize = (dwFlags & FLAG_ALLOCATE_UIDATA) ? sizeof(UIDATA) : sizeof(COMMONINFO);
  56. if (! (pci = MemAllocZ(dwSize)) ||
  57. ! (pci->pPrinterName = DuplicateString(pPrinterName ? pPrinterName : TEXT("NULL"))))
  58. {
  59. ERR(("Memory allocation failed\n"));
  60. VFreeCommonInfo(pci);
  61. return NULL;
  62. }
  63. pci->pvStartSign = pci;
  64. pci->dwFlags = dwFlags;
  65. //
  66. // Check if we should open a handle to the current printer
  67. //
  68. if (dwFlags & (FLAG_OPENPRINTER_NORMAL | FLAG_OPENPRINTER_ADMIN))
  69. {
  70. ASSERT(hPrinter == NULL && pPrinterName != NULL);
  71. //
  72. // Open a printer handle with the specified access right
  73. //
  74. if (! OpenPrinter(pPrinterName,
  75. &hPrinter,
  76. (dwFlags & FLAG_OPENPRINTER_ADMIN) ? &PrinterDefaults : NULL))
  77. {
  78. ERR(("OpenPrinter failed for '%ws': %d\n", pPrinterName, GetLastError()));
  79. VFreeCommonInfo(pci);
  80. return NULL;
  81. }
  82. pci->hPrinter = hPrinter;
  83. }
  84. else
  85. {
  86. ASSERT(hPrinter != NULL);
  87. pci->hPrinter = hPrinter;
  88. }
  89. //
  90. // If the caller requires that the printer to be initialized,
  91. // check to make sure it is. If not, return error.
  92. //
  93. if (dwFlags & FLAG_OPEN_CONDITIONAL)
  94. {
  95. PPRINTER_INFO_2 pPrinterInfo2;
  96. DWORD dwInitData;
  97. //
  98. // NOTE: We're really like to use level 4 here. But due to bug in the
  99. // spooler, GetPrinter level 4 doesn't work for printer connections.
  100. //
  101. dwInitData = gwDriverVersion;
  102. #ifdef WINNT_40
  103. //
  104. // Hack around spooler bug where DrvConvertDevmode is called before
  105. // DrvPrinterEvent.Initialzed is called.
  106. //
  107. if (!BGetPrinterDataDWord(hPrinter, REGVAL_PRINTER_INITED, &dwInitData))
  108. DrvPrinterEvent(pPrinterName, PRINTER_EVENT_INITIALIZE, 0, 0);
  109. #endif
  110. if ((pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) == NULL ||
  111. (pPrinterInfo2->pServerName == NULL) &&
  112. !BGetPrinterDataDWord(hPrinter, REGVAL_PRINTER_INITED, &dwInitData))
  113. {
  114. dwInitData = 0;
  115. }
  116. MemFree(pPrinterInfo2);
  117. if (dwInitData != gwDriverVersion)
  118. {
  119. TERSE(("Printer not fully initialized yet: %d\n", GetLastError()));
  120. VFreeCommonInfo(pci);
  121. return NULL;
  122. }
  123. }
  124. //
  125. // Get information about the printer driver
  126. //
  127. if ((pci->pDriverInfo3 = MyGetPrinterDriver(hPrinter, NULL, 3)) == NULL)
  128. {
  129. ERR(("Cannot get printer driver info: %d\n", GetLastError()));
  130. VFreeCommonInfo(pci);
  131. return NULL;
  132. }
  133. //
  134. // If FLAG_INIT_PRINTER is set, we should initialize the printer here.
  135. //
  136. if (dwFlags & (FLAG_INIT_PRINTER | FLAG_PROCESS_INIFILE))
  137. {
  138. //
  139. // Parse OEM plugin configuration file and
  140. // save the resulting info into registry
  141. //
  142. if (!BProcessPrinterIniFile(hPrinter, pci->pDriverInfo3, NULL,
  143. (dwFlags & FLAG_UPGRADE_PRINTER) ? FLAG_INIPROCESS_UPGRADE : 0))
  144. {
  145. VERBOSE(("BProcessPrinterIniFile failed\n"));
  146. }
  147. //
  148. // If printer was successfully initialized and caller is not asking to process
  149. // ini file only, save a flag in the registry to indicate the fact.
  150. //
  151. if (dwFlags & FLAG_INIT_PRINTER)
  152. {
  153. (VOID) BSetPrinterDataDWord(hPrinter, REGVAL_PRINTER_INITED, gwDriverVersion);
  154. }
  155. }
  156. //
  157. // fix 317359. In case some part of the driver has changed refresh the .bpd
  158. // to update driver-language-specific strings in the .bpd. "Manual Feed" is
  159. // written by the parser and therefore the .bpd depends on the language the
  160. // parser was localized for. Checking the language would have to be done every time
  161. // something is printed, therefore we just delete the .bpd, then the it gets reparsed
  162. // always has the same language as the driver.
  163. //
  164. #ifdef PSCRIPT
  165. if (dwFlags & FLAG_REFRESH_PARSED_DATA)
  166. {
  167. DeleteRawBinaryData(pci->pDriverInfo3->pDataFile);
  168. }
  169. #endif
  170. //
  171. // Load raw binary printer description data, and
  172. // Get a printer description data instance using the default settings
  173. //
  174. // Notice that this is done inside a critical section (because
  175. // GPD parsers has lots of globals).
  176. //
  177. // ENTER_CRITICAL_SECTION();
  178. pci->pRawData = LoadRawBinaryData(pci->pDriverInfo3->pDataFile);
  179. if (pci->pRawData)
  180. pci->pInfoHeader = InitBinaryData(pci->pRawData, NULL, NULL);
  181. if (pci->pInfoHeader)
  182. pci->pUIInfo = OFFSET_TO_POINTER(pci->pInfoHeader, pci->pInfoHeader->loUIInfoOffset);
  183. // LEAVE_CRITICAL_SECTION();
  184. if (!pci->pRawData || !pci->pInfoHeader || !pci->pUIInfo)
  185. {
  186. ERR(("Cannot load printer description data: %d\n", GetLastError()));
  187. VFreeCommonInfo(pci);
  188. return NULL;
  189. }
  190. //
  191. // Get information about OEM plugins and load them
  192. //
  193. if (! (pci->pOemPlugins = PGetOemPluginInfo(hPrinter,
  194. pci->pDriverInfo3->pConfigFile,
  195. pci->pDriverInfo3)) ||
  196. ! BLoadOEMPluginModules(pci->pOemPlugins))
  197. {
  198. ERR(("Cannot load OEM plugins: %d\n", GetLastError()));
  199. VFreeCommonInfo(pci);
  200. return NULL;
  201. }
  202. pci->oemuiobj.cbSize = sizeof(OEMUIOBJ);
  203. pci->oemuiobj.pOemUIProcs = (POEMUIPROCS) &OemUIHelperFuncs;
  204. pci->pOemPlugins->pdriverobj = &pci->oemuiobj;
  205. return pci;
  206. }
  207. VOID
  208. VFreeCommonInfo(
  209. PCOMMONINFO pci
  210. )
  211. /*++
  212. Routine Description:
  213. Release common information used by the driver UI
  214. Arguments:
  215. pci - Common driver information to be released
  216. Return Value:
  217. NONE
  218. --*/
  219. {
  220. if (pci == NULL)
  221. return;
  222. //
  223. // Unload OEM UI modules and free OEM plugin info
  224. //
  225. if (pci->pOemPlugins)
  226. VFreeOemPluginInfo(pci->pOemPlugins);
  227. //
  228. // Unload raw binary printer description data
  229. // and/or any printer description data instance
  230. //
  231. if (pci->pInfoHeader)
  232. FreeBinaryData(pci->pInfoHeader);
  233. if (pci->pRawData)
  234. UnloadRawBinaryData(pci->pRawData);
  235. //
  236. // Close the printer handle if it was opened by us
  237. //
  238. if ((pci->dwFlags & (FLAG_OPENPRINTER_NORMAL|FLAG_OPENPRINTER_ADMIN)) &&
  239. (pci->hPrinter != NULL))
  240. {
  241. ClosePrinter(pci->hPrinter);
  242. }
  243. #ifdef UNIDRV
  244. if (pci->pWinResData)
  245. {
  246. VWinResClose(pci->pWinResData);
  247. MemFree(pci->pWinResData);
  248. }
  249. #endif
  250. if (pci->hHeap)
  251. HeapDestroy(pci->hHeap);
  252. MemFree(pci->pSplForms);
  253. MemFree(pci->pCombinedOptions);
  254. MemFree(pci->pPrinterData);
  255. MemFree(pci->pPrinterName);
  256. MemFree(pci->pDriverInfo3);
  257. MemFree(pci->pdm);
  258. MemFree(pci);
  259. }
  260. BOOL
  261. BFillCommonInfoDevmode(
  262. PCOMMONINFO pci,
  263. PDEVMODE pdmPrinter,
  264. PDEVMODE pdmInput
  265. )
  266. /*++
  267. Routine Description:
  268. Populate the devmode fields in the COMMONINFO structure.
  269. start out with the driver default devmode, and
  270. merge it with the printer default devmode, and
  271. merge it with the input devmode
  272. Arguments:
  273. pci - Points to a COMMONINFO structure
  274. pdmPrinter - Points to printer default devmode
  275. pdmInput - Points to input devmode
  276. Return Value:
  277. TRUE if successful, FALSE if there is an error
  278. Note:
  279. pdmPrinter and/or pdmInput can be NULL.
  280. --*/
  281. {
  282. //
  283. // Start with driver default devmode
  284. //
  285. ASSERT(pci->pdm == NULL);
  286. pci->pdm = PGetDefaultDevmodeWithOemPlugins(
  287. pci->pPrinterName,
  288. pci->pUIInfo,
  289. pci->pRawData,
  290. IsMetricCountry(),
  291. pci->pOemPlugins,
  292. pci->hPrinter);
  293. //
  294. // Merge with printer default and input devmode
  295. //
  296. if (! pci->pdm ||
  297. ! BValidateAndMergeDevmodeWithOemPlugins(
  298. pci->pdm,
  299. pci->pUIInfo,
  300. pci->pRawData,
  301. pdmPrinter,
  302. pci->pOemPlugins,
  303. pci->hPrinter) ||
  304. ! BValidateAndMergeDevmodeWithOemPlugins(
  305. pci->pdm,
  306. pci->pUIInfo,
  307. pci->pRawData,
  308. pdmInput,
  309. pci->pOemPlugins,
  310. pci->hPrinter))
  311. {
  312. ERR(("Cannot process devmode information: %d\n", GetLastError()));
  313. return FALSE;
  314. }
  315. pci->pdmPrivate = (PDRIVEREXTRA) GET_DRIVER_PRIVATE_DEVMODE(pci->pdm);
  316. return TRUE;
  317. }
  318. BOOL
  319. BFillCommonInfoPrinterData(
  320. PCOMMONINFO pci
  321. )
  322. /*++
  323. Routine Description:
  324. Populate the printer-sticky property data field
  325. Arguments:
  326. pci - Points to basic printer info
  327. Return Value:
  328. TRUE if successful, FALSE if there is an error
  329. --*/
  330. {
  331. ASSERT(pci->pPrinterData == NULL);
  332. if (pci->pPrinterData = MemAllocZ(sizeof(PRINTERDATA)))
  333. return BGetPrinterProperties(pci->hPrinter, pci->pRawData, pci->pPrinterData);
  334. ERR(("Memory allocation failed\n"));
  335. return FALSE;
  336. }
  337. BOOL
  338. BCombineCommonInfoOptionsArray(
  339. PCOMMONINFO pci
  340. )
  341. /*++
  342. Routine Description:
  343. Combined document-sticky feature selections and printer-sticky
  344. feature selection into a single options array
  345. Arguments:
  346. pci - Points to basic printer info
  347. Return Value:
  348. TRUE if successful, FALSE if there is an error
  349. --*/
  350. {
  351. POPTSELECT pDocOptions, pPrinterOptions;
  352. #ifdef UNIDRV
  353. OPTSELECT DocOptions[MAX_PRINTER_OPTIONS];
  354. OPTSELECT PrinterOptions[MAX_PRINTER_OPTIONS];
  355. #endif
  356. //
  357. // Allocate enough memory for the combined options array
  358. //
  359. pci->pCombinedOptions = MemAllocZ(sizeof(OPTSELECT) * MAX_COMBINED_OPTIONS);
  360. if (pci->pCombinedOptions == NULL)
  361. {
  362. ERR(("Memory allocation failed\n"));
  363. return FALSE;
  364. }
  365. pDocOptions = pci->pdm ? PGetDevmodeOptionsArray(pci->pdm) : NULL;
  366. pPrinterOptions = pci->pPrinterData ? pci->pPrinterData->aOptions : NULL;
  367. #ifdef UNIDRV
  368. //
  369. // GPD parser doesn't follow the current parser interface spec.
  370. // It AVs if either doc- or printer-sticky options array is NULL.
  371. // So we have to call it first to get appropriate default options first.
  372. //
  373. if (pDocOptions == NULL)
  374. {
  375. if (! InitDefaultOptions(pci->pRawData,
  376. DocOptions,
  377. MAX_PRINTER_OPTIONS,
  378. MODE_DOCUMENT_STICKY))
  379. {
  380. return FALSE;
  381. }
  382. pDocOptions = DocOptions;
  383. }
  384. if (pPrinterOptions == NULL)
  385. {
  386. if (! InitDefaultOptions(pci->pRawData,
  387. PrinterOptions,
  388. MAX_PRINTER_OPTIONS,
  389. MODE_PRINTER_STICKY))
  390. {
  391. return FALSE;
  392. }
  393. pPrinterOptions = PrinterOptions;
  394. }
  395. #endif // UNIDRV
  396. return CombineOptionArray(pci->pRawData,
  397. pci->pCombinedOptions,
  398. MAX_COMBINED_OPTIONS,
  399. pDocOptions,
  400. pPrinterOptions);
  401. }
  402. VOID
  403. VFixOptionsArrayWithPaperSizeID(
  404. PCOMMONINFO pci
  405. )
  406. /*++
  407. Routine Description:
  408. Fix up combined options array with paper size information from public devmode fields
  409. Arguments:
  410. pci - Points to basic printer info
  411. Return Value:
  412. NONE
  413. --*/
  414. {
  415. PFEATURE pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE);
  416. BOOL abEnabledOptions[MAX_PRINTER_OPTIONS];
  417. PDWORD pdwPaperIndex = (PDWORD)abEnabledOptions;
  418. DWORD dwCount, dwOptionIndex, i;
  419. WCHAR awchBuf[CCHPAPERNAME];
  420. if (pFeature == NULL)
  421. return;
  422. dwCount = MapToDeviceOptIndex(pci->pInfoHeader,
  423. GID_PAGESIZE,
  424. pci->pdm->dmPaperWidth * DEVMODE_PAPER_UNIT,
  425. pci->pdm->dmPaperLength * DEVMODE_PAPER_UNIT,
  426. pdwPaperIndex);
  427. if (dwCount == 0 )
  428. return;
  429. if (dwCount > 1 )
  430. {
  431. PPAGESIZE pPageSize;
  432. for (i = 0; i < dwCount; i++)
  433. {
  434. if (pPageSize = (PPAGESIZE)PGetIndexedOption(pci->pUIInfo, pFeature, pdwPaperIndex[i]))
  435. {
  436. if ((LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, awchBuf, CCHPAPERNAME)) &&
  437. (_wcsicmp(pci->pdm->dmFormName, awchBuf) == EQUAL_STRING) )
  438. {
  439. dwOptionIndex = pdwPaperIndex[i];
  440. break;
  441. }
  442. }
  443. }
  444. if (i >= dwCount)
  445. dwOptionIndex = pdwPaperIndex[0];
  446. }
  447. else
  448. dwOptionIndex = pdwPaperIndex[0];
  449. ZeroMemory(abEnabledOptions, sizeof(abEnabledOptions));
  450. abEnabledOptions[dwOptionIndex] = TRUE;
  451. ReconstructOptionArray(pci->pRawData,
  452. pci->pCombinedOptions,
  453. MAX_COMBINED_OPTIONS,
  454. GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature),
  455. abEnabledOptions);
  456. }
  457. VOID
  458. VFixOptionsArrayWithDevmode(
  459. PCOMMONINFO pci
  460. )
  461. /*++
  462. Routine Description:
  463. Fix up combined options array with information from public devmode fields
  464. Arguments:
  465. pci - Points to basic printer info
  466. Return Value:
  467. NONE
  468. --*/
  469. {
  470. //
  471. // Mapping table from public devmode fields to GID indices
  472. // We assume that GID_COLORMODE corresponds to DM_COLR
  473. //
  474. static CONST struct _DMFIELDS_GID_MAPPING {
  475. DWORD dwGid;
  476. DWORD dwMask;
  477. } DMFieldsGIDMapping[] = {
  478. { GID_RESOLUTION, DM_PRINTQUALITY|DM_YRESOLUTION },
  479. { GID_PAGESIZE, DM_FORMNAME|DM_PAPERSIZE|DM_PAPERWIDTH|DM_PAPERLENGTH },
  480. { GID_DUPLEX, DM_DUPLEX },
  481. { GID_INPUTSLOT, DM_DEFAULTSOURCE },
  482. { GID_MEDIATYPE, DM_MEDIATYPE },
  483. { GID_ORIENTATION, DM_ORIENTATION },
  484. { GID_COLLATE, DM_COLLATE },
  485. { GID_COLORMODE, DM_COLOR },
  486. };
  487. INT iIndex;
  488. BOOL bConflict;
  489. //
  490. // Validate form-related devmode fields
  491. //
  492. if (pci->pSplForms == NULL)
  493. pci->pSplForms = MyEnumForms(pci->hPrinter, 1, &pci->dwSplForms);
  494. if (! BValidateDevmodeCustomPageSizeFields(
  495. pci->pRawData,
  496. pci->pUIInfo,
  497. pci->pdm,
  498. NULL) &&
  499. ! BValidateDevmodeFormFields(
  500. pci->hPrinter,
  501. pci->pdm,
  502. NULL,
  503. pci->pSplForms,
  504. pci->dwSplForms))
  505. {
  506. VDefaultDevmodeFormFields(pci->pUIInfo, pci->pdm, IsMetricCountry());
  507. }
  508. //
  509. // Fix up options array with information from public devmode fields
  510. //
  511. iIndex = sizeof(DMFieldsGIDMapping) / sizeof(struct _DMFIELDS_GID_MAPPING);
  512. while (iIndex-- > 0)
  513. {
  514. if (pci->pdm->dmFields & DMFieldsGIDMapping[iIndex].dwMask)
  515. {
  516. #if UNIDRV
  517. if (DMFieldsGIDMapping[iIndex].dwGid == GID_PAGESIZE)
  518. {
  519. VFixOptionsArrayWithPaperSizeID(pci);
  520. }
  521. else
  522. #endif
  523. {
  524. (VOID) ChangeOptionsViaID(pci->pInfoHeader,
  525. pci->pCombinedOptions,
  526. DMFieldsGIDMapping[iIndex].dwGid,
  527. pci->pdm);
  528. }
  529. }
  530. }
  531. }
  532. BOOL
  533. BUpdateUIInfo(
  534. PCOMMONINFO pci
  535. )
  536. /*++
  537. Routine Description:
  538. Get an updated printer description data instance using the combined options array
  539. Arguments:
  540. pci - Points to basic printer info
  541. Return Value:
  542. TRUE if successful, FALSE if there is an error
  543. --*/
  544. {
  545. PINFOHEADER pInfoHeader;
  546. //
  547. // Get an updated instance of printer description data
  548. //
  549. pInfoHeader = UpdateBinaryData(pci->pRawData,
  550. pci->pInfoHeader,
  551. pci->pCombinedOptions);
  552. if (pInfoHeader == NULL)
  553. {
  554. ERR(("UpdateBinaryData failed\n"));
  555. return FALSE;
  556. }
  557. //
  558. // Reset various points in COMMONINFO structure
  559. //
  560. pci->pInfoHeader = pInfoHeader;
  561. pci->pUIInfo = OFFSET_TO_POINTER(pInfoHeader, pInfoHeader->loUIInfoOffset);
  562. ASSERT(pci->pUIInfo != NULL);
  563. return (pci->pUIInfo != NULL);
  564. }
  565. BOOL
  566. BPrepareForLoadingResource(
  567. PCOMMONINFO pci,
  568. BOOL bNeedHeap
  569. )
  570. /*++
  571. Routine Description:
  572. Make sure a heap is created and the resource DLL has been loaded
  573. Arguments:
  574. pci - Points to basic printer info
  575. bNeedHeap - Whether memory heap is necessary
  576. Return Value:
  577. TRUE if successful, FALSE if there is an error
  578. --*/
  579. {
  580. BOOL bResult = FALSE;
  581. //
  582. // Create the memory heap if necessary
  583. //
  584. if ( bNeedHeap &&
  585. ! pci->hHeap &&
  586. ! (pci->hHeap = HCreateHeapForCI()))
  587. {
  588. return bResult;
  589. }
  590. #ifdef UNIDRV
  591. if (pci->pWinResData)
  592. {
  593. bResult = TRUE;
  594. }
  595. else
  596. {
  597. if ((pci->pWinResData = MemAllocZ(sizeof(WINRESDATA))) &&
  598. (BInitWinResData(pci->pWinResData,
  599. pci->pDriverInfo3->pDriverPath,
  600. pci->pUIInfo)))
  601. bResult = TRUE;
  602. }
  603. #endif
  604. return bResult;
  605. }
  606. #ifndef PSCRIPT
  607. PWSTR
  608. PGetReadOnlyDisplayName(
  609. PCOMMONINFO pci,
  610. PTRREF loOffset
  611. )
  612. /*++
  613. Routine Description:
  614. Get a read-only copy of a display name:
  615. 1) if the display name is in the binary printer description data,
  616. then we simply return a pointer to that data.
  617. 2) otherwise, the display name is in the resource DLL.
  618. we allocate memory out of the driver's heap and
  619. load the string.
  620. Caller should NOT free the returned pointer. The memory
  621. will go away when the binary printer description data is unloaded
  622. or when the driver's heap is destroyed.
  623. Arguments:
  624. pci - Points to basic printer info
  625. loOffset - Display name string offset
  626. Return Value:
  627. Pointer to the requested display name string
  628. NULL if there is an error
  629. --*/
  630. {
  631. if (loOffset & GET_RESOURCE_FROM_DLL)
  632. {
  633. //
  634. // loOffset specifies a string resource ID
  635. // in the resource DLL
  636. //
  637. WCHAR wchbuf[MAX_DISPLAY_NAME];
  638. INT iLength;
  639. PWSTR pwstr;
  640. HANDLE hResDll;
  641. DWORD dwResID = loOffset & ~GET_RESOURCE_FROM_DLL;
  642. //
  643. // First ensure the resource DLL has been loaded
  644. // and a heap has already been created
  645. //
  646. if (! BPrepareForLoadingResource(pci, TRUE))
  647. return NULL;
  648. //
  649. // Load string resource into a temporary buffer
  650. // and allocate enough memory to hold the string
  651. //
  652. iLength = ILOADSTRING(pci, dwResID, wchbuf, MAX_DISPLAY_NAME);
  653. pwstr = HEAPALLOC(pci->hHeap, (iLength+1) * sizeof(WCHAR));
  654. if (pwstr == NULL)
  655. {
  656. ERR(("Memory allocation failed\n"));
  657. return NULL;
  658. }
  659. //
  660. // Copy the string to allocated memory and
  661. // return a pointer to it.
  662. //
  663. CopyMemory(pwstr, wchbuf, iLength*sizeof(WCHAR));
  664. return pwstr;
  665. }
  666. else
  667. {
  668. //
  669. // loOffset is a byte offset from the beginning of
  670. // the resource data block
  671. //
  672. return OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, loOffset);
  673. }
  674. }
  675. #endif // !PSCRIPT
  676. BOOL
  677. BLoadDisplayNameString(
  678. PCOMMONINFO pci,
  679. PTRREF loOffset,
  680. PWSTR pwstrBuf,
  681. INT iMaxChars
  682. )
  683. /*++
  684. Routine Description:
  685. This function is similar to PGetReadOnlyDisplayName
  686. but the caller must provide the buffer for loading the string.
  687. Arguments:
  688. pci - Points to basic printer info
  689. loOffset - Display name string offset
  690. pwstrBuf - Points to buffer for storing loaded display name string
  691. iMaxChars - Size of output buffer in characters
  692. Return Value:
  693. TRUE if successful, FALSE if there is an error
  694. --*/
  695. {
  696. ASSERT(pwstrBuf && iMaxChars > 0);
  697. pwstrBuf[0] = NUL;
  698. if (loOffset & GET_RESOURCE_FROM_DLL)
  699. {
  700. //
  701. // loOffset specifies a string resource ID
  702. // in the resource DLL
  703. //
  704. INT iLength;
  705. HANDLE hResDll;
  706. DWORD dwResID = loOffset & ~GET_RESOURCE_FROM_DLL;
  707. //
  708. // First ensure the resource DLL has been loaded
  709. //
  710. if (! BPrepareForLoadingResource(pci, FALSE))
  711. return FALSE;
  712. //
  713. // Load string resource into the output buffer
  714. // and allocate enough memory to hold the string
  715. //
  716. iLength = ILOADSTRING(pci, dwResID, pwstrBuf, (WORD)iMaxChars);
  717. return (iLength > 0);
  718. }
  719. else
  720. {
  721. //
  722. // loOffset is a byte offset from the beginning of
  723. // the resource data block
  724. //
  725. PWSTR pwstr;
  726. pwstr = OFFSET_TO_POINTER(pci->pUIInfo->pubResourceData, loOffset);
  727. if (pwstr == NULL)
  728. return FALSE;
  729. CopyString(pwstrBuf, pwstr, iMaxChars);
  730. return TRUE;
  731. }
  732. }
  733. BOOL
  734. BLoadPageSizeNameString(
  735. PCOMMONINFO pci,
  736. PTRREF loOffset,
  737. PWSTR pwstrBuf,
  738. INT iMaxChars,
  739. INT iStdId
  740. )
  741. /*++
  742. Routine Description:
  743. This function is similar to PGetReadOnlyDisplayName
  744. but the caller must provide the buffer for loading the string.
  745. Arguments:
  746. pci - Points to basic printer info
  747. loOffset - Display name string offset
  748. pwstrBuf - Points to buffer for storing loaded display name string
  749. iMaxChars - Size of output buffer in characters
  750. iStdId - Predefined standard ID for page size, e.g. DMPAPER_XXX
  751. Return Value:
  752. TRUE if successful, FALSE if there is an error
  753. --*/
  754. {
  755. ASSERT(pwstrBuf && iMaxChars > 0);
  756. pwstrBuf[0] = NUL;
  757. if (loOffset == USE_SYSTEM_NAME)
  758. {
  759. PFORM_INFO_1 pForm;
  760. INT iIndex = iStdId - DMPAPER_FIRST;
  761. //
  762. // iIndex is zero based.
  763. //
  764. if (pci->pSplForms == NULL ||
  765. (INT)pci->dwSplForms <= iIndex)
  766. {
  767. WARNING(("BLoadPageSizeName, use std name, pSplForms is NULL \n"));
  768. return FALSE;
  769. }
  770. pForm = pci->pSplForms + iIndex;
  771. CopyString(pwstrBuf, pForm->pName, iMaxChars);
  772. return (TRUE);
  773. }
  774. else
  775. return (BLoadDisplayNameString(pci, loOffset, pwstrBuf, iMaxChars));
  776. }
  777. ULONG_PTR
  778. HLoadIconFromResourceDLL(
  779. PCOMMONINFO pci,
  780. DWORD dwIconID
  781. )
  782. /*++
  783. Routine Description:
  784. Load icon resource from the resource DLL
  785. Arguments:
  786. pci - Points to common printer info
  787. dwIconID - Specifies ID of the icon to be loaded
  788. Return Value:
  789. Handle to the specified icon resource
  790. 0 if the specified icon cannot be loaded
  791. --*/
  792. {
  793. #ifdef UNIDRV
  794. //
  795. // First ensure the resource DLL has been loaded
  796. //
  797. PQUALNAMEEX pQualifiedID;
  798. HANDLE hModule;
  799. HICON hIcon;
  800. if (!BPrepareForLoadingResource(pci, FALSE))
  801. return 0;
  802. pQualifiedID = (PQUALNAMEEX)&dwIconID;
  803. if (hModule = HGetModuleHandle(pci->pWinResData, pQualifiedID))
  804. {
  805. hIcon = LoadIcon(hModule, MAKEINTRESOURCE(pQualifiedID->wResourceID));
  806. if (hIcon == NULL)
  807. {
  808. ERR(("LoadIcon failed: %d\n", GetLastError()));
  809. }
  810. return (ULONG_PTR)hIcon;
  811. }
  812. #endif
  813. return 0;
  814. }
  815. PUIDATA
  816. PFillUiData(
  817. HANDLE hPrinter,
  818. PTSTR pPrinterName,
  819. PDEVMODE pdmInput,
  820. INT iMode
  821. )
  822. /*++
  823. Routine Description:
  824. This function is called by DrvDocumentPropertySheets and
  825. DrvPrinterPropertySheets. It allocates and initializes
  826. a UIDATA structure that's used to display property pages.
  827. Arguments:
  828. hPrinter - Handle to the current printer
  829. pPrinterName - Name of the current printer
  830. pdmInput - Input devmode
  831. iMode - Identify the caller:
  832. MODE_DOCUMENT_STICKY - called from DrvDocumentPropertySheets
  833. MODE_PRINTER_STICY - called from DrvPrinterPropertySheets
  834. Return Value:
  835. Pointer to a UIDATA structure, NULL if there is an error
  836. --*/
  837. {
  838. PUIDATA pUiData;
  839. PCOMMONINFO pci;
  840. BOOL bNupOption;
  841. PFEATURE pFeature;
  842. DWORD dwFeatureIndex, dwOptionIndexOld, dwOptionIndexNew;
  843. BOOL bUpdateFormField;
  844. //
  845. // Allocate UIDATA structure and load common information
  846. //
  847. pUiData = (PUIDATA) PLoadCommonInfo(hPrinter, pPrinterName, FLAG_ALLOCATE_UIDATA);
  848. if (pUiData == NULL)
  849. goto fill_uidata_err;
  850. pUiData->pvEndSign = pUiData;
  851. pUiData->iMode = iMode;
  852. pci = &pUiData->ci;
  853. //
  854. // Create a memory heap
  855. //
  856. if ((pci->hHeap = HCreateHeapForCI()) == NULL)
  857. goto fill_uidata_err;
  858. //
  859. // Get printer-sticky property data
  860. //
  861. if (! BFillCommonInfoPrinterData(pci))
  862. goto fill_uidata_err;
  863. //
  864. // If called from DrvDocumentPropertySheets, then process
  865. // devmode information: driver default + printer default + input devmode
  866. //
  867. if (iMode == MODE_DOCUMENT_STICKY)
  868. {
  869. PPRINTER_INFO_2 pPrinterInfo2;
  870. if (! (pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) ||
  871. ! BFillCommonInfoDevmode(pci, pPrinterInfo2->pDevMode, pdmInput))
  872. {
  873. MemFree(pPrinterInfo2);
  874. goto fill_uidata_err;
  875. }
  876. MemFree(pPrinterInfo2);
  877. }
  878. //
  879. // Merge doc-sticky and printer-sticky option selections
  880. //
  881. if (! BCombineCommonInfoOptionsArray(pci))
  882. goto fill_uidata_err;
  883. //
  884. // If called from DrvDocumentPropertySheets,
  885. // fix up combined options with public devmode information
  886. //
  887. if (iMode == MODE_DOCUMENT_STICKY)
  888. {
  889. VFixOptionsArrayWithDevmode(pci);
  890. //
  891. // Remember the paper size option parser picked to support the devmode form
  892. //
  893. if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) == NULL)
  894. {
  895. ASSERT(FALSE);
  896. goto fill_uidata_err;
  897. }
  898. dwFeatureIndex = GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature);
  899. dwOptionIndexOld = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
  900. }
  901. VGetSpoolerEmfCaps(pci->hPrinter, &bNupOption, &pUiData->bEMFSpooling, 0, NULL);
  902. //
  903. // Resolve any conflicts between printer feature selections,
  904. // and get an updated printer description data instance
  905. // using the combined options array.
  906. //
  907. (VOID) ResolveUIConflicts(pci->pRawData,
  908. pci->pCombinedOptions,
  909. MAX_COMBINED_OPTIONS,
  910. iMode == MODE_PRINTER_STICKY ?
  911. iMode :
  912. MODE_DOCANDPRINTER_STICKY);
  913. if (iMode == MODE_DOCUMENT_STICKY)
  914. {
  915. dwOptionIndexNew = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
  916. bUpdateFormField = FALSE;
  917. if (dwOptionIndexNew != dwOptionIndexOld)
  918. {
  919. //
  920. // Constraint resolving has changed page size selection, so we need
  921. // to update devmode's form fields.
  922. //
  923. bUpdateFormField = TRUE;
  924. }
  925. else
  926. {
  927. FORM_INFO_1 *pForm = NULL;
  928. //
  929. // Unless the form requested by devmode is not supported on the printer,
  930. // we still want to show the original form name in upcoming doc-setting UI.
  931. // For example, if input devmode requested "Legal", parser maps it to option
  932. // "OEM Legal", but both "Legal" and "OEM Legal" will be shown as supported
  933. // forms on the printer, then we should still show "Legal" instead of "OEM Legal"
  934. // in UI's PageSize list. However, if input devmode requestd "8.5 x 12", which
  935. // won't be shown as a supportd form and it's mapped to "OEM Legal", then we should
  936. // show "OEM Legal".
  937. //
  938. //
  939. // pdm->dmFormName won't have a valid form name for custom page size (see
  940. // BValidateDevmodeFormFields()). VOptionsToDevmodeFields() knows to handle that.
  941. //
  942. if ((pci->pdm->dmFields & DM_FORMNAME) &&
  943. (pForm = MyGetForm(pci->hPrinter, pci->pdm->dmFormName, 1)) &&
  944. !BFormSupportedOnPrinter(pci, pForm, &dwOptionIndexNew))
  945. {
  946. bUpdateFormField = TRUE;
  947. }
  948. MemFree(pForm);
  949. }
  950. VOptionsToDevmodeFields(pci, bUpdateFormField);
  951. }
  952. if (BUpdateUIInfo(pci))
  953. {
  954. //
  955. // Set the flag to indicate we are within the property sheet session. This flag will
  956. // be used by new helper function interface to determine whether the helper function
  957. // is available or not.
  958. //
  959. pci->dwFlags |= FLAG_PROPSHEET_SESSION;
  960. return pUiData;
  961. }
  962. fill_uidata_err:
  963. ERR(("PFillUiData failed: %d\n", GetLastError()));
  964. VFreeUiData(pUiData);
  965. return NULL;
  966. }
  967. PTSTR
  968. PtstrDuplicateStringFromHeap(
  969. IN PTSTR ptstrSrc,
  970. IN HANDLE hHeap
  971. )
  972. /*++
  973. Routine Description:
  974. Duplicate a Unicode string
  975. Arguments:
  976. pwstrUnicodeString - Pointer to the input Unicode string
  977. hHeap - Handle to a heap from which to allocate memory
  978. Return Value:
  979. Pointer to the resulting Unicode string
  980. NULL if there is an error
  981. --*/
  982. {
  983. PTSTR ptstrDest;
  984. INT iSize;
  985. if (ptstrSrc == NULL)
  986. return NULL;
  987. iSize = SIZE_OF_STRING(ptstrSrc);
  988. if (ptstrDest = HEAPALLOC(hHeap, iSize))
  989. CopyMemory(ptstrDest, ptstrSrc, iSize);
  990. else
  991. ERR(("Couldn't duplicate string: %ws\n", ptstrSrc));
  992. return ptstrDest;
  993. }
  994. POPTITEM
  995. PFindOptItemWithKeyword(
  996. IN PUIDATA pUiData,
  997. IN PCSTR pKeywordName
  998. )
  999. /*++
  1000. Routine Description:
  1001. Find the OPTITEM with UserData's pKeywordName matching given keyword name
  1002. Arguments:
  1003. pUiData - Points to UIDATA structure
  1004. pKeywordName - Specifies the keyword name needs to be matched
  1005. Return Value:
  1006. Pointer to the specified OPTITEM, NULL if no such item is found
  1007. --*/
  1008. {
  1009. DWORD dwCount;
  1010. POPTITEM pOptItem;
  1011. ASSERT(VALIDUIDATA(pUiData));
  1012. pOptItem = pUiData->pDrvOptItem;
  1013. dwCount = pUiData->dwDrvOptItem;
  1014. while (dwCount--)
  1015. {
  1016. if (((PUSERDATA)pOptItem->UserData)->pKeyWordName != NULL &&
  1017. strcmp(((PUSERDATA)pOptItem->UserData)->pKeyWordName, pKeywordName) == EQUAL_STRING)
  1018. return pOptItem;
  1019. pOptItem++;
  1020. }
  1021. return NULL;
  1022. }
  1023. POPTITEM
  1024. PFindOptItemWithUserData(
  1025. IN PUIDATA pUiData,
  1026. IN DWORD UserData
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. Find the OPTITEM containing the specified UserData value
  1031. Arguments:
  1032. pUiData - Points to UIDATA structure
  1033. UserData - Specifies the interested UserData value
  1034. Return Value:
  1035. Pointer to the specified OPTITEM, NULL if no such item is found
  1036. --*/
  1037. {
  1038. DWORD dwCount;
  1039. POPTITEM pOptItem;
  1040. ASSERT(VALIDUIDATA(pUiData));
  1041. pOptItem = pUiData->pDrvOptItem;
  1042. dwCount = pUiData->dwDrvOptItem;
  1043. while (dwCount--)
  1044. {
  1045. if (GETUSERDATAITEM(pOptItem->UserData) == UserData)
  1046. return pOptItem;
  1047. pOptItem++;
  1048. }
  1049. return NULL;
  1050. }
  1051. #ifndef WINNT_40
  1052. VOID
  1053. VNotifyDSOfUpdate(
  1054. IN HANDLE hPrinter
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. Call SetPrinter to notify the DS of the update of driver attribute
  1059. Arguments:
  1060. hPrinter - Handle to the current printer
  1061. Return Value:
  1062. NONE
  1063. --*/
  1064. {
  1065. PRINTER_INFO_7 PrinterInfo7;
  1066. ZeroMemory(&PrinterInfo7, sizeof(PrinterInfo7));
  1067. PrinterInfo7.dwAction = DSPRINT_UPDATE;
  1068. //
  1069. // Comments from spooler DS developer:
  1070. //
  1071. // In the beginning, SetPrinter did not fail with ERROR_IO_PENDING.
  1072. // Then it was modified and would occasionally fail with this error.
  1073. // Finally, for performance reasons, it was modified again and now
  1074. // almost always fails with this error (there are situations where
  1075. // it will succeed).
  1076. //
  1077. if (!SetPrinter(hPrinter, 7, (PBYTE) &PrinterInfo7, 0) &&
  1078. (GetLastError() != ERROR_IO_PENDING))
  1079. {
  1080. WARNING(("Couldn't publish printer info into DS\n"));
  1081. }
  1082. }
  1083. #endif
  1084. HANDLE HCreateHeapForCI()
  1085. {
  1086. HANDLE hHeap;
  1087. if(!(hHeap = HeapCreate(0, 8192, 0)))
  1088. {
  1089. ERR(("CreateHeap failed: %d\n", GetLastError()));
  1090. }
  1091. return hHeap;
  1092. }
  1093. #ifndef WINNT_40
  1094. BOOL
  1095. DrvQueryColorProfile(
  1096. HANDLE hPrinter,
  1097. PDEVMODEW pdmSrc,
  1098. ULONG ulQueryMode,
  1099. VOID *pvProfileData,
  1100. ULONG *pcbProfileData,
  1101. FLONG *pflProfileData
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Call the OEM to let them determine the default color profile.
  1106. Arguments:
  1107. hPrinter - Handle to printer
  1108. pdmSrc - Input devmode
  1109. ulQueryMode - query mode
  1110. pvProfileData - Buffer for profile data
  1111. pcbProfileData - Size of profile data buffer
  1112. pflProfileData - other profile info
  1113. Return Value:
  1114. TRUE for success and FALSE for failure
  1115. --*/
  1116. {
  1117. PFN_OEMQueryColorProfile pfnQueryColorProfile;
  1118. PCOMMONINFO pci;
  1119. BOOL bRc = FALSE;
  1120. if (! (pci = PLoadCommonInfo(hPrinter, NULL, 0)) ||
  1121. ! BFillCommonInfoDevmode(pci, NULL, pdmSrc) ||
  1122. ! BCombineCommonInfoOptionsArray(pci))
  1123. {
  1124. WARNING(("Could not get PCI in DrvQueryColorProfile\n"));
  1125. VFreeCommonInfo(pci);
  1126. return FALSE;
  1127. }
  1128. VFixOptionsArrayWithDevmode(pci);
  1129. (VOID) ResolveUIConflicts(pci->pRawData,
  1130. pci->pCombinedOptions,
  1131. MAX_COMBINED_OPTIONS,
  1132. MODE_DOCUMENT_STICKY);
  1133. VOptionsToDevmodeFields(pci, TRUE);
  1134. if (! BUpdateUIInfo(pci))
  1135. {
  1136. VFreeCommonInfo(pci);
  1137. return FALSE;
  1138. }
  1139. //
  1140. // If OEM plugin returns a profile, give it back, otherwise return FALSE
  1141. //
  1142. FOREACH_OEMPLUGIN_LOOP(pci)
  1143. if (HAS_COM_INTERFACE(pOemEntry))
  1144. {
  1145. HRESULT hr;
  1146. hr = HComOEMQUeryColorProfile(pOemEntry,
  1147. hPrinter,
  1148. &pci->oemuiobj,
  1149. pci->pdm,
  1150. pOemEntry->pOEMDM,
  1151. ulQueryMode,
  1152. pvProfileData,
  1153. pcbProfileData,
  1154. pflProfileData
  1155. );
  1156. if (hr == E_NOTIMPL)
  1157. continue;
  1158. bRc = SUCCEEDED(hr);
  1159. }
  1160. else
  1161. {
  1162. pfnQueryColorProfile = GET_OEM_ENTRYPOINT(pOemEntry, OEMQueryColorProfile);
  1163. if (pfnQueryColorProfile)
  1164. {
  1165. bRc = (*pfnQueryColorProfile)(hPrinter,
  1166. &pci->oemuiobj,
  1167. pci->pdm,
  1168. pOemEntry->pOEMDM,
  1169. ulQueryMode,
  1170. pvProfileData,
  1171. pcbProfileData,
  1172. pflProfileData
  1173. );
  1174. }
  1175. }
  1176. if (bRc)
  1177. break;
  1178. END_OEMPLUGIN_LOOP
  1179. VFreeCommonInfo(pci);
  1180. return bRc;
  1181. }
  1182. #else // ifndef WINNT_40
  1183. BOOL
  1184. DrvQueryColorProfile(
  1185. HANDLE hPrinter,
  1186. PDEVMODEW pdmSrc,
  1187. ULONG ulQueryMode,
  1188. VOID *pvProfileData,
  1189. ULONG *pcbProfileData,
  1190. FLONG *pflProfileData
  1191. )
  1192. /*++
  1193. Routine Description:
  1194. Call the OEM to let them determine the default color profile.
  1195. Arguments:
  1196. hPrinter - Handle to printer
  1197. pdmSrc - Input devmode
  1198. ulQueryMode - query mode
  1199. pvProfileData - Buffer for profile data
  1200. pcbProfileData - Size of profile data buffer
  1201. pflProfileData - other profile info
  1202. Return Value:
  1203. TRUE for success and FALSE for failure
  1204. --*/
  1205. {
  1206. return TRUE;
  1207. }
  1208. #endif // WINNT_40