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.

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