Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1449 lines
33 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. prnevent.c
  5. Abstract:
  6. This file handles the DrvPrinterEvent spooler API.
  7. Environment:
  8. Win32 subsystem, DriverUI module, user mode
  9. Revision History:
  10. 08/30/00 -fengy-
  11. Added DrvDocumentEvent support.
  12. 02/13/97 -davidx-
  13. Implement OEM plugin support.
  14. 02/06/97 -davidx-
  15. Rewrote it to use common data management functions.
  16. 02/04/97 -davidx-
  17. Reorganize driver UI to separate ps and uni DLLs.
  18. 07/17/96 -amandan-
  19. Modified for common UI and shared binary data
  20. 05/20/96 -davidx-
  21. Created it.
  22. --*/
  23. #include "precomp.h"
  24. //
  25. // DOCUMENTEVENT_QUERYFILTER is introduced in Whistler.
  26. // We need to define it if it's not defined (on Win2K)
  27. // so our code can be built with Win2K DDK.
  28. //
  29. #ifndef DOCUMENTEVENT_QUERYFILTER
  30. #define DOCUMENTEVENT_QUERYFILTER 14
  31. #endif
  32. //
  33. // Private APIs exported by the spooler for printer drivers and port monitors.
  34. // These must be kept in sync with winsplp.h.
  35. //
  36. typedef HANDLE (*LPREVERTTOPRINTERSELF)(VOID);
  37. typedef BOOL (*LPIMPERSONATEPRINTERCLIENT)(HANDLE);
  38. //
  39. // Forward and external function declarations
  40. //
  41. BOOL BInitOrUpgradePrinterProperties(PCOMMONINFO);
  42. VOID DeleteFontIntallerFile(HANDLE);
  43. PTSTR
  44. GetBinaryFileName(
  45. PTSTR ptstrDataFileName
  46. )
  47. /*++
  48. Routine Description:
  49. This function generates a binary file name from the data file name.
  50. Arguments:
  51. ptstrDataFileName specifies the data file name
  52. Return Value:
  53. TRUE for success and FALSE for failure
  54. Note:
  55. --*/
  56. {
  57. INT iLen;
  58. PTSTR ptstrFileName, ptstrExtension;
  59. PTSTR ptstrBinaryExt, ptstrFileExt;
  60. ptstrFileName = ptstrExtension = NULL;
  61. #ifdef UNIDRV
  62. ptstrBinaryExt = BUD_FILENAME_EXT;
  63. ptstrFileExt = GPD_FILENAME_EXT;
  64. #else
  65. ptstrBinaryExt = BPD_FILENAME_EXT;
  66. ptstrFileExt = PPD_FILENAME_EXT;
  67. #endif
  68. iLen = _tcslen(ptstrDataFileName);
  69. if ((ptstrExtension = _tcsrchr(ptstrDataFileName, TEXT('.'))) == NULL ||
  70. _tcsicmp(ptstrExtension, ptstrFileExt) != EQUAL_STRING)
  71. {
  72. ptstrExtension = ptstrDataFileName + iLen;
  73. iLen += _tcslen(ptstrBinaryExt);
  74. }
  75. if (ptstrFileName = MemAlloc((iLen + 1) * sizeof(TCHAR)))
  76. {
  77. _tcscpy(ptstrFileName, ptstrDataFileName);
  78. _tcscpy(ptstrFileName + (ptstrExtension - ptstrDataFileName), ptstrBinaryExt);
  79. }
  80. return ptstrFileName;
  81. }
  82. BOOL
  83. DrvDriverEvent(
  84. DWORD dwDriverEvent,
  85. DWORD dwLevel,
  86. LPBYTE pDriverInfo,
  87. LPARAM lParam
  88. )
  89. /*++
  90. Routine Description:
  91. This function handles the DrvDriverEvent spooler API
  92. Arguments:
  93. dwDriverEvent specifies the event
  94. dwLevel level of DRIVER_INFO_*
  95. pDriverInfo pointer to DRIVER_INFO_*
  96. lParam event specific parameters.
  97. Return Value:
  98. TRUE for success and FALSE for failure
  99. Note:
  100. --*/
  101. {
  102. BOOL bResult = TRUE;
  103. #ifndef WINNT_40
  104. PDRIVER_INFO_3 pDriverInfo3 = (PDRIVER_INFO_3)pDriverInfo;
  105. PTSTR ptstrFileName;
  106. if (pDriverInfo3 == NULL || pDriverInfo3->pDataFile == NULL)
  107. return FALSE;
  108. switch (dwDriverEvent)
  109. {
  110. case DRIVER_EVENT_INITIALIZE:
  111. break;
  112. case DRIVER_EVENT_DELETE:
  113. //
  114. // Need to delete the binary data generated by the parsers
  115. //
  116. ptstrFileName = GetBinaryFileName(pDriverInfo3->pDataFile);
  117. if (ptstrFileName)
  118. {
  119. DeleteFile(ptstrFileName);
  120. MemFree(ptstrFileName);
  121. }
  122. }
  123. //
  124. // Call the OEM to handle DrvDriverEvent
  125. //
  126. {
  127. PFN_OEMDriverEvent pfnOEMDriverEvent;
  128. POEM_PLUGINS pOemPlugins;
  129. POEM_PLUGIN_ENTRY pOemEntry;
  130. DWORD dwOemCount;
  131. if (! (pOemPlugins = PGetOemPluginInfo(NULL, pDriverInfo3->pConfigFile, pDriverInfo3)) ||
  132. ! BLoadOEMPluginModules(pOemPlugins))
  133. {
  134. ERR(("DrvDriverEvent, Cannot load OEM plugins: %d\n", GetLastError()));
  135. if (pOemPlugins)
  136. {
  137. VFreeOemPluginInfo(pOemPlugins);
  138. }
  139. return FALSE;
  140. }
  141. dwOemCount = pOemPlugins->dwCount;
  142. pOemEntry = pOemPlugins->aPlugins;
  143. //
  144. // call OEMDriverEvent entrypoint for each plugin
  145. //
  146. for (; dwOemCount--; pOemEntry++)
  147. {
  148. if (pOemEntry->hInstance == NULL)
  149. continue;
  150. if (HAS_COM_INTERFACE(pOemEntry))
  151. {
  152. HRESULT hr;
  153. hr = HComOEMDriverEvent(pOemEntry,
  154. dwDriverEvent,
  155. dwLevel,
  156. pDriverInfo,
  157. lParam);
  158. if (hr == E_NOTIMPL)
  159. continue;
  160. bResult = SUCCEEDED(hr);
  161. }
  162. else
  163. {
  164. if ((pfnOEMDriverEvent = GET_OEM_ENTRYPOINT(pOemEntry, OEMDriverEvent)) &&
  165. !pfnOEMDriverEvent(dwDriverEvent, dwLevel, pDriverInfo, lParam))
  166. {
  167. ERR(("OEMDriverEvent failed for '%ws': %d\n",
  168. CURRENT_OEM_MODULE_NAME(pOemEntry),
  169. GetLastError()));
  170. bResult = FALSE;
  171. }
  172. }
  173. }
  174. if (pOemPlugins)
  175. VFreeOemPluginInfo(pOemPlugins);
  176. }
  177. #endif // WINNT_40
  178. return bResult;
  179. }
  180. /*++
  181. Routine Name:
  182. DrvDocumentEvent
  183. Routine Description:
  184. Handle certain events associated with printing a document.
  185. Although our core driver doesn't do anything for any events,
  186. this function allows OEM plugins to add their event handling.
  187. Arguments:
  188. hPrinter - printer handle
  189. hdc - device contect handle
  190. iEsc - escape code identifying the event to be handled
  191. cbIn - size in bytes of the array pointed to by pbIn
  192. pbIn - pointer to a ULONG array, whose usage depends on iEsc
  193. cbOut - only used as cbOutput parameter for ExtEscape
  194. pbOut - pointer to an output buffer, whose usage depends on iEsc
  195. Return Value:
  196. DOCUMENTEVENT_FAILURE - iEsc event is supported but a failure occurred
  197. DOCUMENTEVENT_SUCCESS - iEsc event is handled successfully
  198. DOCUMENTEVENT_UNSUPPORTED - iEsc event is not supported
  199. Last Error:
  200. None
  201. --*/
  202. INT
  203. DrvDocumentEvent(
  204. HANDLE hPrinter,
  205. HDC hdc,
  206. int iEsc,
  207. ULONG cbIn,
  208. #ifdef WINNT_40
  209. PULONG pbIn,
  210. #else
  211. PVOID pbIn,
  212. #endif
  213. ULONG cbOut,
  214. #ifdef WINNT_40
  215. PULONG pbOut
  216. #else
  217. PVOID pbOut
  218. #endif
  219. )
  220. {
  221. POEM_PLUGINS pOemPlugins = NULL;
  222. PDRIVER_INFO_3 pDriverInfo3 = NULL;
  223. INT iReturn;
  224. if ((pDriverInfo3 = MyGetPrinterDriver(hPrinter, NULL, 3)) == NULL)
  225. {
  226. ERR(("Cannot get printer driver info: %d\n", GetLastError()));
  227. iReturn = DOCUMENTEVENT_FAILURE;
  228. goto docevent_exit;
  229. }
  230. if (!(pOemPlugins = PGetOemPluginInfo(hPrinter,
  231. pDriverInfo3->pConfigFile,
  232. pDriverInfo3)) ||
  233. !BLoadOEMPluginModules(pOemPlugins))
  234. {
  235. //
  236. // Note that BLoadOEMPluginModules always returns TRUE, even in
  237. // the case when plugin(s) can't be loaded, which is treated
  238. // as there is no plugin(s).
  239. //
  240. ERR(("Cannot get OEM plugin info: %d\n", GetLastError()));
  241. iReturn = DOCUMENTEVENT_FAILURE;
  242. goto docevent_exit;
  243. }
  244. if (pOemPlugins->dwCount)
  245. {
  246. POEM_PLUGIN_ENTRY pOemEntry = pOemPlugins->aPlugins;
  247. DWORD cOemCount = pOemPlugins->dwCount;
  248. INT iResult;
  249. BOOL bOEMDocEventOK = FALSE;
  250. for ( ; cOemCount--; pOemEntry++)
  251. {
  252. HRESULT hr;
  253. if (pOemEntry->hInstance == NULL ||
  254. !HAS_COM_INTERFACE(pOemEntry))
  255. {
  256. continue;
  257. }
  258. hr = HComOEMDocumentEvent(pOemEntry,
  259. hPrinter,
  260. hdc,
  261. iEsc,
  262. cbIn,
  263. (PVOID)pbIn,
  264. cbOut,
  265. (PVOID)pbOut,
  266. &iResult);
  267. if (SUCCEEDED(hr))
  268. {
  269. bOEMDocEventOK = TRUE;
  270. #ifndef WINNT_40
  271. //
  272. // DOCUMENTEVENT_QUERYFILTER is introduced in Whistler.
  273. //
  274. if (iEsc == DOCUMENTEVENT_QUERYFILTER)
  275. {
  276. //
  277. // At most one plugin is allowed to handle the event
  278. // DOCUMENTEVENT_QUERYFILTER, and the filter it specifies
  279. // will be used by spooler.
  280. //
  281. // For all other events, we will call every plugin so
  282. // each will have the chance to perform its tasks.
  283. //
  284. break;
  285. }
  286. #endif // !WINNT_40
  287. }
  288. }
  289. if (bOEMDocEventOK)
  290. {
  291. //
  292. // At least one plugin handled the event successfully, so
  293. // use the return value specified by the plugin(s).
  294. //
  295. iReturn = iResult;
  296. }
  297. else
  298. {
  299. //
  300. // None of the plugins handled the event successfully.
  301. //
  302. iReturn = DOCUMENTEVENT_UNSUPPORTED;
  303. }
  304. }
  305. else
  306. {
  307. //
  308. // There is no plugin.
  309. //
  310. iReturn = DOCUMENTEVENT_UNSUPPORTED;
  311. }
  312. docevent_exit:
  313. if (pDriverInfo3)
  314. {
  315. MemFree(pDriverInfo3);
  316. }
  317. if (pOemPlugins)
  318. {
  319. VFreeOemPluginInfo(pOemPlugins);
  320. }
  321. //
  322. // If there is no plugin, or none of the plugins handles DocumentEvent
  323. // successfully, we return DOCUMENTEVENT_UNSUPPORTED since our driver
  324. // doesn't do anything for DrvDocumentEvent. When spooler sees this
  325. // return value for DOCUMENTEVENT_CREATEDCPRE, it will decide not to
  326. // make any more event calls to the driver.
  327. //
  328. // If the event is handled successfully by the plugins, we will return
  329. // the return value specified by the plugin(s).
  330. //
  331. return iReturn;
  332. }
  333. BOOL
  334. DrvPrinterEvent(
  335. LPWSTR pPrinterName,
  336. INT DriverEvent,
  337. DWORD Flags,
  338. LPARAM lParam
  339. )
  340. /*++
  341. Routine Description:
  342. This function handles the DrvPrinterEvent spooler API
  343. Arguments:
  344. pPrinterName name of device
  345. DriverEvent specifies the event
  346. Flags bits flag
  347. lParam event specific parameters.
  348. Return Value:
  349. TRUE for success and FALSE for failure
  350. Note:
  351. --*/
  352. {
  353. LPREVERTTOPRINTERSELF pRevertToPrinterSelf;
  354. LPIMPERSONATEPRINTERCLIENT pImpersonatePrinterClient;
  355. HINSTANCE hSpoolss = NULL;
  356. HANDLE hToken = NULL;
  357. PCOMMONINFO pci = NULL;
  358. HANDLE hPrinter = NULL;
  359. BOOL bResult = TRUE;
  360. CACHEDFILE CachedFile;
  361. VERBOSE(("Entering DrvPrinterEvent: %d ...\n", DriverEvent));
  362. switch (DriverEvent)
  363. {
  364. case PRINTER_EVENT_CACHE_REFRESH:
  365. //
  366. // Open a handle to the printer connection
  367. //
  368. if (! OpenPrinter(pPrinterName, &hPrinter, NULL))
  369. {
  370. ERR(("OpenPrinter '%ws' failed: %d\n", pPrinterName, GetLastError()));
  371. hPrinter = NULL;
  372. break;
  373. }
  374. //
  375. // Prepare to copy cached driver files from the server, if any
  376. //
  377. #ifdef PSCRIPT
  378. _BPrepareToCopyCachedFile(hPrinter, &CachedFile, REGVAL_NTFFILENAME);
  379. #else
  380. _BPrepareToCopyCachedFile(hPrinter, &CachedFile, REGVAL_FONTFILENAME);
  381. #endif
  382. //
  383. // Load spoolss.dll and get address of functions:
  384. // RevertToPrinterSelf - switch to spooler's security context
  385. // ImpersonatePrinterClient - switch to current user's security context
  386. //
  387. if (! (hSpoolss = LoadLibrary(TEXT("spoolss.dll"))) ||
  388. ! (pRevertToPrinterSelf = (LPREVERTTOPRINTERSELF)
  389. GetProcAddress(hSpoolss, "RevertToPrinterSelf")) ||
  390. ! (pImpersonatePrinterClient = (LPIMPERSONATEPRINTERCLIENT)
  391. GetProcAddress(hSpoolss, "ImpersonatePrinterClient")))
  392. {
  393. ERR(("Couldn't load spoolss.dll: %d\n", GetLastError()));
  394. if (hSpoolss != NULL)
  395. FreeLibrary(hSpoolss);
  396. _VDisposeCachedFileInfo(&CachedFile);
  397. break;
  398. }
  399. //
  400. // Switch to spooler security context so that we can create
  401. // binary printer description data file in the driver directory
  402. //
  403. // When we call to load raw printer description data, the parser
  404. // will check its cache. If no binary data file exists or existing
  405. // binary data file is out of date, the parser will regenerate
  406. // an up-to-date binary data file.
  407. //
  408. hToken = pRevertToPrinterSelf();
  409. pci = PLoadCommonInfo(hPrinter, pPrinterName, 0);
  410. //
  411. // Copy cached driver file from the server
  412. //
  413. _BCopyCachedFile(pci, &CachedFile);
  414. _VDisposeCachedFileInfo(&CachedFile);
  415. if (hToken)
  416. {
  417. if (!(bResult = pImpersonatePrinterClient(hToken)))
  418. {
  419. ERR(("PrinterEvent-ImpersonatePrinterClient failed: %d\n", GetLastError()));
  420. }
  421. }
  422. FreeLibrary(hSpoolss);
  423. break;
  424. case PRINTER_EVENT_INITIALIZE:
  425. //
  426. // Open a printer with administrator privilege, and
  427. // process OEM plugin configuration information
  428. //
  429. pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_ADMIN|FLAG_INIT_PRINTER);
  430. if (pci == NULL)
  431. break;
  432. //
  433. // Initialize default printer-sticky properties in registry
  434. // Add printer forms to the spooler's forms database
  435. //
  436. (VOID) BInitOrUpgradePrinterProperties(pci);
  437. #ifndef WINNT_40
  438. VNotifyDSOfUpdate(pci->hPrinter);
  439. #endif // !WINNT_40
  440. break;
  441. case PRINTER_EVENT_ADD_CONNECTION:
  442. //
  443. // Fix the bug where when NT5 client connects to NT4 server, the server registry
  444. // doesn't have the REGVAL_INIDATA entry. Calling PLoadCommonInfo with
  445. // FLAG_PROCESS_INIFILE will write REGVAL_INIDATA to NT4 registry.
  446. //
  447. pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_ADMIN|FLAG_PROCESS_INIFILE);
  448. break;
  449. #ifdef UNIDRV
  450. case PRINTER_EVENT_DELETE:
  451. case PRINTER_EVENT_DELETE_CONNECTION:
  452. //
  453. // Delete font installer file
  454. //
  455. //
  456. // Open a handle to the printer
  457. //
  458. if (! OpenPrinter(pPrinterName, &hPrinter, NULL))
  459. {
  460. ERR(("OpenPrinter '%ws' failed: %d\n", pPrinterName, GetLastError()));
  461. hPrinter = NULL;
  462. break;
  463. }
  464. pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_NORMAL);
  465. DeleteFontIntallerFile(hPrinter);
  466. break;
  467. #endif
  468. default:
  469. pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_NORMAL);
  470. break;
  471. }
  472. if (pci != NULL)
  473. {
  474. if (bResult)
  475. {
  476. PFN_OEMPrinterEvent pfnOEMPrinterEvent;
  477. //
  478. // call OEMPrinterEvent entrypoint for each plugin
  479. //
  480. FOREACH_OEMPLUGIN_LOOP(pci)
  481. if (HAS_COM_INTERFACE(pOemEntry))
  482. {
  483. HRESULT hr;
  484. hr = HComOEMPrinterEvent(pOemEntry,
  485. pPrinterName,
  486. DriverEvent,
  487. Flags,
  488. lParam);
  489. if (hr == E_NOTIMPL)
  490. continue;
  491. bResult = SUCCEEDED(hr);
  492. }
  493. else
  494. {
  495. if ((pfnOEMPrinterEvent = GET_OEM_ENTRYPOINT(pOemEntry, OEMPrinterEvent)) &&
  496. !pfnOEMPrinterEvent(pPrinterName, DriverEvent, Flags, lParam))
  497. {
  498. ERR(("OEMPrinterEvent failed for '%ws': %d\n",
  499. CURRENT_OEM_MODULE_NAME(pOemEntry),
  500. GetLastError()));
  501. bResult = FALSE;
  502. }
  503. }
  504. END_OEMPLUGIN_LOOP
  505. }
  506. VFreeCommonInfo(pci);
  507. }
  508. else
  509. bResult = FALSE;
  510. if (hPrinter != NULL)
  511. ClosePrinter(hPrinter);
  512. return (bResult);
  513. }
  514. BOOL
  515. BUpgradePrivateFlags(
  516. PCOMMONINFO pci
  517. )
  518. /*++
  519. Routine Description:
  520. Upgrade pPrinterData->dwFlags if necessary
  521. Arguments:
  522. pci - Points to basic printer info
  523. Return Value:
  524. TRUE if successful, FALSE if there is an error
  525. --*/
  526. {
  527. #if 0
  528. DWORD dwFlag, dwIndex, dwSelection, dwFeatureIndex;
  529. PFEATURE pFeature;
  530. PPAGEPROTECT pPageProtect;
  531. //
  532. // UniDriver specific upgrade steps
  533. //
  534. if (BGetPrinterDataDWord(pci->hPrinter, REGVAL_PAGE_PROTECTION, &dwFlag) &&
  535. (pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGEPROTECTION)) &&
  536. BCombineCommonInfoOptionsArray(pci))
  537. {
  538. if (dwFlag & DXF_PAGEPROT)
  539. dwSelection = PAGEPRO_ON;
  540. else
  541. dwSelection = PAGEPRO_OFF;
  542. pPageProtect = PGetIndexedOption(pci->pUIInfo, pFeature, 0);
  543. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++, pPageProtect++)
  544. {
  545. if (dwSelection == pPageProtect->dwPageProtectID)
  546. break;
  547. }
  548. if (dwIndex == pFeature->Options.dwCount)
  549. dwIndex = pFeature->dwDefaultOptIndex;
  550. dwFeatureIndex = GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature);
  551. pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex = (BYTE)dwIndex;
  552. SeparateOptionArray(pci->pRawData,
  553. pci->pCombinedOptions,
  554. pci->pPrinterData->aOptions,
  555. MAX_PRINTER_OPTIONS,
  556. MODE_PRINTER_STICKY
  557. );
  558. }
  559. #endif
  560. return TRUE;
  561. }
  562. BOOL
  563. BInitOrUpgradePrinterData(
  564. PCOMMONINFO pci
  565. )
  566. /*++
  567. Routine Description:
  568. Initialize the driver's printer-sticky property data
  569. or upgrade it to current version if it already exists
  570. Arguments:
  571. pci - Points to basic printer info
  572. Return Value:
  573. TRUE if successful, FALSE if there is an error
  574. --*/
  575. {
  576. DWORD dwSize;
  577. BOOL bResult = TRUE;
  578. //
  579. // If the printer property data already exists in the registry
  580. // and it's at least as big as the current PRINTERDATA, then
  581. // we assume it's ok and there is no need to upgrade it.
  582. //
  583. if (!BGetPrinterDataDWord(pci->hPrinter, REGVAL_PRINTER_DATA_SIZE, &dwSize) ||
  584. dwSize < sizeof(PRINTERDATA))
  585. {
  586. //
  587. // Otherwise, upgrade the existing printer property data in the registry
  588. // or save a copy of the default printer property data to registry.
  589. //
  590. bResult = BFillCommonInfoPrinterData(pci) &&
  591. BUpgradePrivateFlags(pci) &&
  592. BSavePrinterProperties(pci->hPrinter, pci->pRawData,
  593. pci->pPrinterData, sizeof(PRINTERDATA));
  594. }
  595. return bResult;
  596. }
  597. BOOL
  598. BAddOrUpgradePrinterForms(
  599. PCOMMONINFO pci
  600. )
  601. /*++
  602. Routine Description:
  603. Add printer specific forms to the spooler's forms database
  604. Arguments:
  605. pci - Points to basic printer info
  606. Return Value:
  607. TRUE if successful, FALSE if there is an error
  608. --*/
  609. {
  610. PPAGESIZE pPageSize;
  611. FORM_INFO_1 FormInfo1;
  612. DWORD dwIndex, dwChecksum32, dwForm;
  613. PFEATURE pFeature;
  614. WCHAR awchBuf[CCHPAPERNAME];
  615. //
  616. // If forms has already been added and printer description
  617. // data hasn't changed, we don't need to do anything
  618. //
  619. if (BGetPrinterDataDWord(pci->hPrinter, REGVAL_FORMS_ADDED, &dwChecksum32) &&
  620. dwChecksum32 == pci->pRawData->dwChecksum32)
  621. {
  622. return TRUE;
  623. }
  624. if (pci->pSplForms == NULL)
  625. pci->pSplForms = MyEnumForms(pci->hPrinter, 1, &pci->dwSplForms);
  626. //
  627. // Get pointer to PageSize feature
  628. //
  629. if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) == NULL)
  630. {
  631. WARNING(("No paper size supported\n"));
  632. return FALSE;
  633. }
  634. ZeroMemory(&FormInfo1, sizeof(FormInfo1));
  635. FormInfo1.Flags = FORM_PRINTER;
  636. FormInfo1.pName = awchBuf;
  637. //
  638. // Go through each printer form
  639. //
  640. for (dwIndex=0; dwIndex < pFeature->Options.dwCount; dwIndex++)
  641. {
  642. pPageSize = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex);
  643. ASSERT(pPageSize != NULL);
  644. //
  645. // Ignore the custom page size option
  646. //
  647. if (pPageSize->dwPaperSizeID == DMPAPER_USER ||
  648. pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE)
  649. {
  650. continue;
  651. }
  652. if (pPageSize->szPaperSize.cx <= 0 ||
  653. pPageSize->szPaperSize.cy <= 0)
  654. {
  655. ERR(("Paper size is too small\n"));
  656. continue;
  657. }
  658. if (! LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, awchBuf, CCHPAPERNAME))
  659. {
  660. ERR(("Cannot get paper name\n"));
  661. continue;
  662. }
  663. //
  664. // Check if the paper name is already in the forms database.
  665. // If it's already in the database as a
  666. //
  667. for (dwForm=0; dwForm < pci->dwSplForms; dwForm++)
  668. {
  669. if (pci->pSplForms[dwForm].Flags == FORM_USER &&
  670. wcscmp(pci->pSplForms[dwForm].pName, awchBuf) == EQUAL_STRING)
  671. {
  672. VERBOSE(("Delete user/driver rdefined form: %ws\n", awchBuf));
  673. DeleteForm(pci->hPrinter, awchBuf);
  674. }
  675. }
  676. //
  677. // Page size:
  678. // remember that FORM_INFO_1 uses micron units while
  679. // PAGESIZE.szPaperSize are in Master units.
  680. //
  681. FormInfo1.Size.cx = MASTER_UNIT_TO_MICRON(pPageSize->szPaperSize.cx,
  682. pci->pUIInfo->ptMasterUnits.x);
  683. FormInfo1.Size.cy = MASTER_UNIT_TO_MICRON(pPageSize->szPaperSize.cy,
  684. pci->pUIInfo->ptMasterUnits.y);
  685. //
  686. // Imageable area:
  687. // for driver-defined forms, all margins should be set to 0.
  688. //
  689. FormInfo1.ImageableArea.left =
  690. FormInfo1.ImageableArea.top = 0;
  691. FormInfo1.ImageableArea.right = FormInfo1.Size.cx;
  692. FormInfo1.ImageableArea.bottom = FormInfo1.Size.cy;
  693. //
  694. // We'll try to add the form first. If that fails,
  695. // we assume the form is already there and try to
  696. // update the form with the new info.
  697. //
  698. (VOID) AddForm(pci->hPrinter, 1, (PBYTE) &FormInfo1);
  699. }
  700. (VOID) BSetPrinterDataDWord(pci->hPrinter,
  701. REGVAL_FORMS_ADDED,
  702. pci->pRawData->dwChecksum32);
  703. return TRUE;
  704. }
  705. BOOL
  706. BInitOrUpgradePrinterProperties(
  707. PCOMMONINFO pci
  708. )
  709. /*++
  710. Routine Description:
  711. Initialize or upgrade printer property information in the registry
  712. Arguments:
  713. pci - Points to basic printer info
  714. Return Value:
  715. TRUE if successful, FALSE if there is an error
  716. --*/
  717. {
  718. BOOL bResult;
  719. //
  720. // Handle PRINTERDATA structure in registry
  721. //
  722. bResult = BInitOrUpgradePrinterData(pci);
  723. //
  724. // Handle driver-defined forms in the spooler's database
  725. //
  726. if (! BAddOrUpgradePrinterForms(pci))
  727. bResult = FALSE;
  728. #ifdef PSCRIPT
  729. //
  730. // pscript specific initializations
  731. //
  732. // Save model-specific NTF filename in registry for NT4 compatibility
  733. if (! BUpdateModelNtfFilename(pci))
  734. bResult = FALSE;
  735. #ifdef WINNT_40
  736. // Also save the current user locale too.
  737. if (! BUpdateVMErrorMessageID(pci))
  738. bResult = FALSE;
  739. #endif // WINNT_40
  740. #endif // PSCRIPT
  741. return bResult;
  742. }
  743. PWSTR
  744. PGetFileDirectory(
  745. PWSTR pServerName
  746. )
  747. /*++
  748. Routine Description:
  749. Get the name of the directory used by the font downloader
  750. to store NTF information about downloaded fonts
  751. Arguments:
  752. pServerName - Name of the print server
  753. Return Value:
  754. Pointer to the directory used for storing NTF information
  755. about downloaded fonts, NULL if there is an error
  756. --*/
  757. {
  758. PWSTR p, pDir = NULL;
  759. DWORD cbNeeded;
  760. static WCHAR wszDir[] = FONTDIR;
  761. //
  762. // Get the printer driver directory path
  763. //
  764. if (GetPrinterDriverDirectory(pServerName, NULL, 1, NULL, 0, &cbNeeded) ||
  765. GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  766. (pDir = MemAlloc(cbNeeded + sizeof(wszDir))) == NULL ||
  767. !GetPrinterDriverDirectory(pServerName, NULL, 1, (PBYTE) pDir, cbNeeded, &cbNeeded))
  768. {
  769. ERR(("GetPrinterDriverDirectory failed: %d\n", GetLastError()));
  770. MemFree(pDir);
  771. return NULL;
  772. }
  773. //
  774. // Replace the last component of the directory path (which should be w32...)
  775. // with \psfont\
  776. //
  777. if (p = wcsrchr(pDir, TEXT(PATH_SEPARATOR)))
  778. wcscpy(p, wszDir);
  779. else
  780. {
  781. WARNING(("Driver directory is not fully-qualified: %ws\n", pDir));
  782. wcscat(pDir, wszDir);
  783. }
  784. return pDir;
  785. }
  786. PWSTR
  787. PConcatFilename(
  788. PWSTR pDir,
  789. PWSTR pFilename
  790. )
  791. {
  792. PWSTR pBasename;
  793. //
  794. // Strip any directory prefix from the input filename
  795. //
  796. if (pBasename = wcsrchr(pFilename, TEXT(PATH_SEPARATOR)))
  797. pBasename++;
  798. else
  799. pBasename = pFilename;
  800. //
  801. // Concatenate the input directory with the base filename
  802. //
  803. if (! (pFilename = MemAlloc(SIZE_OF_STRING(pDir) + SIZE_OF_STRING(pBasename))))
  804. {
  805. ERR(("Memory allocation failed\n"));
  806. return NULL;
  807. }
  808. wcscpy(pFilename, pDir);
  809. wcscat(pFilename, pBasename);
  810. return pFilename;
  811. }
  812. BOOL
  813. _BPrepareToCopyCachedFile(
  814. HANDLE hPrinter,
  815. PCACHEDFILE pCachedFile,
  816. PWSTR pRegKey
  817. )
  818. /*++
  819. Routine Description:
  820. Prepare to copy files from the server during a printer-connection
  821. cache refresh event
  822. Arguments:
  823. hPrinter - Handle to the printer connection
  824. pCachedFile - Buffer to store information about cached file
  825. Return Value:
  826. TRUE if successful, FALSE if there is an error
  827. Note:
  828. We assume this function is called from within the spooler process
  829. and with current user's security context. Specifically, we must
  830. be able to access the server's print$ share at this point.
  831. --*/
  832. {
  833. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  834. PWSTR pRemoteFilename;
  835. DWORD dwSize;
  836. ZeroMemory(pCachedFile, sizeof(CACHEDFILE));
  837. pCachedFile->hRemoteFile = INVALID_HANDLE_VALUE;
  838. //
  839. // Find out the name of the file to copy
  840. //
  841. #if !defined(PSCRIPT)
  842. pCachedFile->pFilename = PtstrGetPrinterDataString(hPrinter, pRegKey, &dwSize);
  843. #else
  844. return TRUE;
  845. #endif
  846. if (pCachedFile->pFilename == NULL || *pCachedFile->pFilename == NUL)
  847. return TRUE;
  848. //
  849. // Get the remote NTF filename on the server
  850. //
  851. // NOTE: We're really like to use level 4 here. But due to bug in the
  852. // spooler, GetPrinter level 4 doesn't work for printer connections.
  853. //
  854. if (! (pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) ||
  855. ! pPrinterInfo2->pServerName ||
  856. ! (pCachedFile->pRemoteDir = PGetFileDirectory(pPrinterInfo2->pServerName)) ||
  857. ! (pCachedFile->pLocalDir = PGetFileDirectory(NULL)) ||
  858. ! (pRemoteFilename = PConcatFilename(pCachedFile->pRemoteDir, pCachedFile->pFilename)))
  859. {
  860. goto exit_prepare_copyfile;
  861. }
  862. pCachedFile->hRemoteFile = CreateFile(pRemoteFilename,
  863. GENERIC_READ,
  864. FILE_SHARE_READ,
  865. NULL,
  866. OPEN_EXISTING,
  867. FILE_FLAG_SEQUENTIAL_SCAN,
  868. NULL);
  869. MemFree(pRemoteFilename);
  870. exit_prepare_copyfile:
  871. MemFree(pPrinterInfo2);
  872. if (pCachedFile->hRemoteFile == INVALID_HANDLE_VALUE)
  873. {
  874. ERR(("Couldn't open remote NTF/FontInfo file: %d\n", GetLastError()));
  875. _VDisposeCachedFileInfo(pCachedFile);
  876. }
  877. return (pCachedFile->hRemoteFile != INVALID_HANDLE_VALUE);
  878. }
  879. BOOL
  880. _BCopyCachedFile(
  881. PCOMMONINFO pci,
  882. PCACHEDFILE pCachedFile
  883. )
  884. /*++
  885. Routine Description:
  886. Copy files from the server during printer-connection cache refresh event
  887. Arguments:
  888. pci - Points to basic printer information
  889. pCachedFile - Points to information about cached file
  890. Return Value:
  891. TRUE if successful, FALSE if there is an error
  892. Note:
  893. We assume this function is called from within the spooler process
  894. and with system's security context. Specifically, we must
  895. be able to write into local machines' printer driver directory.
  896. --*/
  897. #define BUFFER_SIZE 4096
  898. {
  899. HANDLE hLocalFile;
  900. PWSTR pLocalFilename = NULL;
  901. PVOID pBuffer = NULL;
  902. BOOL bResult = FALSE;
  903. DWORD dwCount;
  904. //
  905. // We don't have any file to copy
  906. //
  907. if (pCachedFile->hRemoteFile == INVALID_HANDLE_VALUE)
  908. return TRUE;
  909. //
  910. // Get the name for the local copy of the NTF file
  911. // and allocate temporary buffer
  912. //
  913. ASSERT(BUFFER_SIZE >= MAX_PATH * sizeof(WCHAR));
  914. if (! (pLocalFilename = PConcatFilename(pCachedFile->pLocalDir, pCachedFile->pFilename)) ||
  915. ! (pBuffer = MemAlloc(BUFFER_SIZE)))
  916. {
  917. goto exit_copyfile;
  918. }
  919. // Make sure the local directory is created
  920. (VOID) CreateDirectory(pCachedFile->pLocalDir, NULL);
  921. for (dwCount=0; dwCount < 2; dwCount++)
  922. {
  923. hLocalFile = CreateFile(pLocalFilename,
  924. GENERIC_WRITE,
  925. 0,
  926. NULL,
  927. CREATE_ALWAYS,
  928. FILE_FLAG_SEQUENTIAL_SCAN,
  929. NULL);
  930. if (hLocalFile != INVALID_HANDLE_VALUE)
  931. break;
  932. if (dwCount == 0)
  933. {
  934. //
  935. // If this is our first try, then attempt to move
  936. // the existing file to a temporary file and set
  937. // it to be delete-on-reboot.
  938. //
  939. #ifdef PSCRIPT
  940. if (! GetTempFileName(pCachedFile->pLocalDir, L"NTF", 0, pBuffer) ||
  941. #else
  942. if (! GetTempFileName(pCachedFile->pLocalDir, L"FON", 0, pBuffer) ||
  943. #endif
  944. ! MoveFileEx(pLocalFilename, pBuffer, MOVEFILE_REPLACE_EXISTING) ||
  945. ! MoveFileEx(pBuffer, NULL, MOVEFILE_DELAY_UNTIL_REBOOT))
  946. {
  947. break;
  948. }
  949. }
  950. }
  951. if (hLocalFile != INVALID_HANDLE_VALUE)
  952. {
  953. while (ReadFile(pCachedFile->hRemoteFile, pBuffer, BUFFER_SIZE, &dwCount, NULL))
  954. {
  955. //
  956. // Have we reached end-of-file?
  957. //
  958. if (dwCount == 0)
  959. {
  960. bResult = TRUE;
  961. break;
  962. }
  963. if (! WriteFile(hLocalFile, pBuffer, dwCount, &dwCount, NULL))
  964. break;
  965. }
  966. CloseHandle(hLocalFile);
  967. //
  968. // If file copying failed, be sure to delete the temporary file
  969. //
  970. if (! bResult)
  971. DeleteFile(pLocalFilename);
  972. }
  973. exit_copyfile:
  974. MemFree(pLocalFilename);
  975. MemFree(pBuffer);
  976. if (! bResult)
  977. ERR(("Couldn't copy remote NTF/FontInfo file: %d\n", GetLastError()));
  978. return bResult;
  979. }
  980. VOID
  981. _VDisposeCachedFileInfo(
  982. PCACHEDFILE pCachedFile
  983. )
  984. /*++
  985. Routine Description:
  986. Clean up after copying files from the server
  987. during printer-connection cache refresh
  988. Arguments:
  989. pCachedFile - Points to information about cached file
  990. Return Value:
  991. NONE
  992. --*/
  993. {
  994. if (pCachedFile->hRemoteFile != INVALID_HANDLE_VALUE)
  995. CloseHandle(pCachedFile->hRemoteFile);
  996. MemFree(pCachedFile->pFilename);
  997. MemFree(pCachedFile->pRemoteDir);
  998. MemFree(pCachedFile->pLocalDir);
  999. ZeroMemory(pCachedFile, sizeof(CACHEDFILE));
  1000. pCachedFile->hRemoteFile = INVALID_HANDLE_VALUE;
  1001. }
  1002. #ifdef UNIDRV
  1003. VOID
  1004. DeleteFontIntallerFile(
  1005. HANDLE hPrinter
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. Delete font installer file when printer is deleted
  1010. Arguments:
  1011. hPrinter - Handle to printer
  1012. Return Value:
  1013. NONE
  1014. --*/
  1015. {
  1016. PWSTR pFilename;
  1017. PWSTR pLocalDir;
  1018. PWSTR pLocalFilename = NULL;
  1019. pFilename = PtstrGetPrinterDataString(hPrinter, REGVAL_FONTFILENAME, NULL);
  1020. if (!pFilename || !*pFilename)
  1021. return;
  1022. if (!(pLocalDir = PGetFileDirectory(NULL)))
  1023. goto exit_deletefile;
  1024. if (!(pLocalFilename = PConcatFilename(pLocalDir, pFilename)))
  1025. goto exit_deletefile;
  1026. DeleteFile(pLocalFilename);
  1027. exit_deletefile:
  1028. MemFree(pFilename);
  1029. MemFree(pLocalDir);
  1030. MemFree(pLocalFilename);
  1031. return;
  1032. }
  1033. #endif