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.

7517 lines
235 KiB

  1. /*++
  2. Copyright (c) 1990 - 1996 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. init.c
  6. Abstract:
  7. This module has all the initialization functions for the Local Print Provider
  8. Author:
  9. Dave Snipp (DaveSn) 15-Mar-1991
  10. Revision History:
  11. Felix Maxa (amaxa) 18-Jun-2000
  12. Modified SplCreateSpooler to special case cluster pIniSpooler
  13. Modified LoadPrintProcessor to be able to copy the print processor
  14. from the cluster disk
  15. Added SplCreateSpoolerWorkerThread
  16. ClusterAddDriversFromClusterDisk
  17. ClusterAddVersionDrivers
  18. ClusterAddOrUpdateDriverFromClusterDisk, all part of the DCR
  19. regarding installing rpinter drivers on clusters
  20. Adina Trufinescu (adinatru) 07-December 1998
  21. Commented InitializePrintMonitor2 ;
  22. Changed back to the old interface - InitializePrintMonitor - which is defined in localmon.c
  23. Khaled Sedky (khaleds) 1-September 1998
  24. Modified InitializePrintProcessor amd added LoadPrintProcessor
  25. as a result of merging winprint and localspl
  26. Steve Wilson (swilson) 1-November 1996
  27. Added ShadowFile2 so spooler can delete crashing shadowfiles.
  28. Muhunthan Sivapragasam (MuhuntS) 1-June-1995
  29. Driver info 3 changes; Changes to use RegGetString, RegGetDword etc
  30. Matthew A Felton (MattFe) 27-June-1994
  31. pIniSpooler - allow other providers to call the spooler functions in LocalSpl
  32. --*/
  33. #include <precomp.h>
  34. #pragma hdrstop
  35. #include <lm.h>
  36. #include <winbasep.h>
  37. #include <faxreg.h>
  38. #include "clusspl.h"
  39. #include "jobid.h"
  40. #include "filepool.hxx"
  41. MODULE_DEBUG_INIT( DBG_ERROR , DBG_ERROR );
  42. UINT gcClusterIniSpooler = 0;
  43. #if DBG
  44. HANDLE ghbtClusterRef = 0;
  45. #endif
  46. MONITORREG gMonitorReg = {
  47. sizeof( MONITORREG ),
  48. &SplRegCreateKey,
  49. &SplRegOpenKey,
  50. &SplRegCloseKey,
  51. &SplRegDeleteKey,
  52. &SplRegEnumKey,
  53. &SplRegQueryInfoKey,
  54. &SplRegSetValue,
  55. &SplRegDeleteValue,
  56. &SplRegEnumValue,
  57. &SplRegQueryValue
  58. };
  59. VOID
  60. SplCreateSpoolerWorkerThread(
  61. PVOID pv
  62. );
  63. DWORD
  64. ClusterAddOrUpdateDriverFromClusterDisk(
  65. HKEY hVersionKey,
  66. LPCWSTR pszDriverName,
  67. LPCWSTR pszEnvName,
  68. LPCWSTR pszEnvDir,
  69. PINISPOOLER pIniSpooler
  70. );
  71. BOOL
  72. Old2NewShadow(
  73. PSHADOWFILE pShadowFile1,
  74. PSHADOWFILE_3 pShadowFile2,
  75. DWORD *pnBytes
  76. );
  77. VOID
  78. FreeIniVersion(
  79. PINIVERSION pIniVersion
  80. );
  81. BOOL
  82. NotIniSpooler(
  83. BYTE *pMem
  84. );
  85. PINIDRIVER
  86. GetDriverList(
  87. HKEY hVersionKey,
  88. PINISPOOLER pIniSpooler,
  89. PINIENVIRONMENT pIniEnvironment,
  90. PINIVERSION pIniVersion
  91. );
  92. PINIVERSION
  93. GetVersionDrivers(
  94. HKEY hDriversKey,
  95. LPWSTR VersionName,
  96. PINISPOOLER pIniSpooler,
  97. PINIENVIRONMENT pIniEnvironment
  98. );
  99. VOID
  100. GetPrintSystemVersion(
  101. PINISPOOLER pIniSpooler
  102. );
  103. VOID
  104. InitializeSpoolerSettings(
  105. PINISPOOLER pIniSpooler
  106. );
  107. VOID
  108. WaitForSpoolerInitialization(
  109. VOID
  110. );
  111. BOOL
  112. ValidateProductSuite(
  113. PWSTR SuiteName
  114. );
  115. LPWSTR
  116. FormatRegistryKeyForPrinter(
  117. LPWSTR pSource, /* The string from which backslashes are to be added. */
  118. LPWSTR pScratch /* Scratch buffer for the function to write in; */
  119. ); /* must be at least as long as pSource. */
  120. #define MAX_LENGTH_DRIVERS_SHARE_REMARK 256
  121. WCHAR *szSpoolDirectory = L"\\spool";
  122. WCHAR *szPrintShareName = L""; /* No share for printers in product1 */
  123. WCHAR *szPrintDirectory = L"\\printers";
  124. WCHAR *szDriversDirectory = L"\\drivers";
  125. WCHAR *gszNT4EMF = L"NT EMF 1.003";
  126. WCHAR *gszNT5EMF = L"NT EMF 1.008";
  127. SHARE_INFO_2 DriversShareInfo={NULL, /* Netname - initialized below */
  128. STYPE_DISKTREE, /* Type of share */
  129. NULL, /* Remark */
  130. 0, /* Default permissions */
  131. SHI_USES_UNLIMITED, /* No users limit */
  132. SHI_USES_UNLIMITED, /* Current uses (??) */
  133. NULL, /* Path - initialized below */
  134. NULL}; /* No password */
  135. // WARNING
  136. // Do not access these directly always go via pIniSpooler->pszRegistr...
  137. // This will then work for multiple pIniSpoolers
  138. PWCHAR ipszRoot = L"Print";
  139. PWCHAR ipszRegistryRoot = L"System\\CurrentControlSet\\Control\\Print";
  140. PWCHAR ipszRegistryPrinters = L"System\\CurrentControlSet\\Control\\Print\\Printers";
  141. PWCHAR ipszRegSwPrinters = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers";
  142. PWCHAR ipszRegistryMonitors = L"Monitors";
  143. PWCHAR ipszRegistryMonitorsHKLM = L"\\System\\CurrentControlSet\\Control\\Print\\Monitors";
  144. PWCHAR ipszRegistryEnvironments = L"System\\CurrentControlSet\\Control\\Print\\Environments";
  145. PWCHAR ipszClusterDatabaseEnvironments = L"Environments";
  146. PWCHAR ipszRegistryEventLog = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\Print";
  147. PWCHAR ipszRegistryProviders = L"Providers";
  148. PWCHAR ipszEventLogMsgFile = L"%SystemRoot%\\System32\\LocalSpl.dll";
  149. PWCHAR ipszDriversShareName = L"print$";
  150. PWCHAR ipszRegistryForms = L"System\\CurrentControlSet\\Control\\Print\\Forms";
  151. PWCHAR ipszRegistryProductOptions = L"System\\CurrentControlSet\\Control\\ProductOptions";
  152. PWCHAR ipszRegistryWin32Root = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Servers";
  153. PWCHAR ipszRegistryClusRepository = SPLREG_CLUSTER_LOCAL_ROOT_KEY;
  154. WCHAR *szPrinterData = L"PrinterDriverData";
  155. WCHAR *szConfigurationKey = L"Configuration File";
  156. WCHAR *szDataFileKey = L"Data File";
  157. WCHAR *szDriverVersion = L"Version";
  158. WCHAR *szTempDir = L"TempDir";
  159. WCHAR *szDriverAttributes = L"DriverAttributes";
  160. WCHAR *szDriversKey = L"Drivers";
  161. WCHAR *szPrintProcKey = L"Print Processors";
  162. WCHAR *szPrintersKey = L"Printers";
  163. WCHAR *szEnvironmentsKey = L"Environments";
  164. WCHAR *szDirectory = L"Directory";
  165. WCHAR *szDriverIni = L"Drivers.ini";
  166. WCHAR *szDriverFile = L"Driver";
  167. WCHAR *szDriverDataFile = L"DataFile";
  168. WCHAR *szDriverConfigFile = L"ConfigFile";
  169. WCHAR *szDriverDir = L"DRIVERS";
  170. WCHAR *szPrintProcDir = L"PRTPROCS";
  171. WCHAR *szPrinterDir = L"PRINTERS";
  172. WCHAR *szClusterPrinterDir= L"Spool";
  173. WCHAR *szPrinterIni = L"\\printer.ini";
  174. WCHAR *szAllSpools = L"\\*.SPL";
  175. WCHAR *szNullPort = L"NULL";
  176. WCHAR *szComma = L",";
  177. WCHAR *szName = L"Name";
  178. WCHAR *szShare = L"Share Name";
  179. WCHAR *szPort = L"Port";
  180. WCHAR *szPrintProcessor = L"Print Processor";
  181. WCHAR *szDatatype = L"Datatype";
  182. WCHAR *szDriver = L"Printer Driver";
  183. WCHAR *szLocation = L"Location";
  184. WCHAR *szDescription = L"Description";
  185. WCHAR *szAttributes = L"Attributes";
  186. WCHAR *szStatus = L"Status";
  187. WCHAR *szPriority = L"Priority";
  188. WCHAR *szDefaultPriority = L"Default Priority";
  189. WCHAR *szUntilTime = L"UntilTime";
  190. WCHAR *szStartTime = L"StartTime";
  191. WCHAR *szParameters = L"Parameters";
  192. WCHAR *szSepFile = L"Separator File";
  193. WCHAR *szDevMode = L"Default DevMode";
  194. WCHAR *szSecurity = L"Security";
  195. WCHAR *szSpoolDir = L"SpoolDirectory";
  196. WCHAR *szNetMsgDll = L"NETMSG.DLL";
  197. WCHAR *szMajorVersion = L"MajorVersion";
  198. WCHAR *szMinorVersion = L"MinorVersion";
  199. WCHAR *szTimeLastChange = L"ChangeID";
  200. WCHAR *szTotalJobs = L"TotalJobs";
  201. WCHAR *szTotalBytes = L"TotalBytes";
  202. WCHAR *szTotalPages = L"TotalPages";
  203. WCHAR *szHelpFile = L"Help File";
  204. WCHAR *szMonitor = L"Monitor";
  205. WCHAR *szDependentFiles = L"Dependent Files";
  206. WCHAR *szPreviousNames = L"Previous Names";
  207. WCHAR *szDNSTimeout = L"dnsTimeout";
  208. WCHAR *szTXTimeout = L"txTimeout";
  209. WCHAR *szNTFaxDriver = FAX_DRIVER_NAME;
  210. WCHAR *szPublishPoint = L"PublishPoint";
  211. WCHAR *szCommonName = L"CommonName";
  212. WCHAR *szObjectGUID = L"ObjectGUID";
  213. WCHAR *szDsKeyUpdate = L"DsKeyUpdate";
  214. WCHAR *szDsKeyUpdateForeground = L"DsKeyUpdateForeground";
  215. WCHAR *szAction = L"Action";
  216. WCHAR *szMfgName = L"Manufacturer";
  217. WCHAR *szOEMUrl = L"OEM URL";
  218. WCHAR *szHardwareID = L"HardwareID";
  219. WCHAR *szProvider = L"Provider";
  220. WCHAR *szDriverDate = L"DriverDate";
  221. WCHAR *szLongVersion = L"DriverVersion";
  222. WCHAR *szClusDrvTimeStamp = L"TimeStamp";
  223. WCHAR *szRegistryRoot = L"System\\CurrentControlSet\\Control\\Print";
  224. WCHAR *szEMFThrottle = L"EMFThrottle";
  225. WCHAR *szFlushShadowFileBuffers = L"FlushShadowFileBuffers";
  226. WCHAR *szPendingUpgrades = L"PendingUpgrades";
  227. WCHAR *szPrintPublishPolicy = L"Software\\Policies\\Microsoft\\Windows NT\\Printers";
  228. WCHAR *szClusterDriverRoot = L"PrinterDrivers";
  229. WCHAR *szClusterNonAwareMonitors = L"OtherMonitors";
  230. #if DBG
  231. WCHAR *szDebugFlags = L"DebugFlags";
  232. #endif
  233. WCHAR *szEnvironment = LOCAL_ENVIRONMENT;
  234. WCHAR *szWin95Environment = L"Windows 4.0";
  235. const WCHAR gszCacheMasqPrinters[] = L"CacheMasqPrinters";
  236. HANDLE hInst;
  237. // Time before a job is assumed abandond and deleted during FastPrint
  238. // operation
  239. DWORD dwFastPrintWaitTimeout = FASTPRINT_WAIT_TIMEOUT;
  240. DWORD dwSpoolerPriority = THREAD_PRIORITY_NORMAL;
  241. DWORD dwPortThreadPriority = DEFAULT_PORT_THREAD_PRIORITY;
  242. DWORD dwSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
  243. DWORD dwFastPrintThrottleTimeout = FASTPRINT_THROTTLE_TIMEOUT;
  244. DWORD dwFastPrintSlowDownThreshold = FASTPRINT_SLOWDOWN_THRESHOLD;
  245. DWORD dwServerThreadPriority = DEFAULT_SERVER_THREAD_PRIORITY;
  246. DWORD dwEnableBroadcastSpoolerStatus = 0;
  247. // NT 3.1 No Version ( Version 0 ) User Mode
  248. // NT 3.5 and 3.51 Version 1 User Mode
  249. // NT 4.0 Version 2 Kernel Mode
  250. DWORD dwMajorVersion = SPOOLER_VERSION;
  251. DWORD dwMinorVersion = 0;
  252. // Unique Printer ID counter which increases monotonically. Wraps at 4G.
  253. DWORD dwUniquePrinterSessionID = 0;
  254. // Globals for EMF job scheduling
  255. DWORD dwNumberOfEMFJobsRendering = 0;
  256. BOOL bUseEMFScheduling = FALSE;
  257. SIZE_T TotalMemoryForRendering = 0;
  258. SIZE_T AvailMemoryForRendering = 0;
  259. DWORD dwLastScheduleTime = 0;
  260. PJOBDATA pWaitingList = NULL;
  261. PJOBDATA pScheduleList = NULL;
  262. DWORD dwFlushShadowFileBuffers = 0; // default for uninitialized
  263. // Time to sleep if the LocalWritePrinter WritePort doesn't write any bytes
  264. // but still returns success.
  265. DWORD dwWritePrinterSleepTime = WRITE_PRINTER_SLEEP_TIME;
  266. BOOL gbRemoteFax = TRUE;
  267. BOOL Initialized = FALSE;
  268. PINISPOOLER pLocalIniSpooler = NULL;
  269. PINIENVIRONMENT pThisEnvironment = NULL;
  270. #define POOL_TIMEOUT 120000 // 2 minutes
  271. #define MAX_POOL_FILES 50
  272. //
  273. // Global for KM Printers Blocking Policy
  274. // by default it is
  275. // 1 "blocked" for Server and
  276. // 0 "not blocked" for Workstation
  277. //
  278. DWORD DefaultKMPrintersAreBlocked;
  279. //
  280. // Read from the registry if the HKLM\...\Print\ServerInstallTimeOut DWORD entry exists
  281. // Otherwise default 5 mins.
  282. //
  283. DWORD gdwServerInstallTimeOut;
  284. //
  285. // 0 - Not upgrading, 1 - performing upgrade
  286. //
  287. DWORD dwUpgradeFlag = 0;
  288. LPWSTR szRemoteDoc;
  289. LPWSTR szLocalDoc;
  290. LPWSTR szFastPrintTimeout;
  291. LPWSTR szRaw = L"RAW";
  292. PRINTPROVIDOR PrintProvidor = {LocalOpenPrinter,
  293. LocalSetJob,
  294. LocalGetJob,
  295. LocalEnumJobs,
  296. LocalAddPrinter,
  297. SplDeletePrinter,
  298. SplSetPrinter,
  299. SplGetPrinter,
  300. LocalEnumPrinters,
  301. LocalAddPrinterDriver,
  302. LocalEnumPrinterDrivers,
  303. SplGetPrinterDriver,
  304. LocalGetPrinterDriverDirectory,
  305. LocalDeletePrinterDriver,
  306. LocalAddPrintProcessor,
  307. LocalEnumPrintProcessors,
  308. LocalGetPrintProcessorDirectory,
  309. LocalDeletePrintProcessor,
  310. LocalEnumPrintProcessorDatatypes,
  311. LocalStartDocPrinter,
  312. LocalStartPagePrinter,
  313. LocalWritePrinter,
  314. LocalEndPagePrinter,
  315. LocalAbortPrinter,
  316. LocalReadPrinter,
  317. LocalEndDocPrinter,
  318. LocalAddJob,
  319. LocalScheduleJob,
  320. SplGetPrinterData,
  321. SplSetPrinterData,
  322. LocalWaitForPrinterChange,
  323. SplClosePrinter,
  324. SplAddForm,
  325. SplDeleteForm,
  326. SplGetForm,
  327. SplSetForm,
  328. SplEnumForms,
  329. LocalEnumMonitors,
  330. LocalEnumPorts,
  331. LocalAddPort,
  332. LocalConfigurePort,
  333. LocalDeletePort,
  334. LocalCreatePrinterIC,
  335. LocalPlayGdiScriptOnPrinterIC,
  336. LocalDeletePrinterIC,
  337. LocalAddPrinterConnection,
  338. LocalDeletePrinterConnection,
  339. LocalPrinterMessageBox,
  340. LocalAddMonitor,
  341. LocalDeleteMonitor,
  342. SplResetPrinter,
  343. SplGetPrinterDriverEx,
  344. LocalFindFirstPrinterChangeNotification,
  345. LocalFindClosePrinterChangeNotification,
  346. LocalAddPortEx,
  347. NULL,
  348. LocalRefreshPrinterChangeNotification,
  349. LocalOpenPrinterEx,
  350. LocalAddPrinterEx,
  351. LocalSetPort,
  352. SplEnumPrinterData,
  353. SplDeletePrinterData,
  354. SplClusterSplOpen,
  355. SplClusterSplClose,
  356. SplClusterSplIsAlive,
  357. SplSetPrinterDataEx,
  358. SplGetPrinterDataEx,
  359. SplEnumPrinterDataEx,
  360. SplEnumPrinterKey,
  361. SplDeletePrinterDataEx,
  362. SplDeletePrinterKey,
  363. LocalSeekPrinter,
  364. LocalDeletePrinterDriverEx,
  365. LocalAddPerMachineConnection,
  366. LocalDeletePerMachineConnection,
  367. LocalEnumPerMachineConnections,
  368. LocalXcvData,
  369. LocalAddPrinterDriverEx,
  370. SplReadPrinter,
  371. LocalDriverUnloadComplete,
  372. LocalGetSpoolFileHandle,
  373. LocalCommitSpoolData,
  374. LocalCloseSpoolFileHandle,
  375. LocalFlushPrinter,
  376. LocalSendRecvBidiData,
  377. LocalAddDriverCatalog,
  378. };
  379. DWORD
  380. FinalInitAfterRouterInitCompleteThread(
  381. DWORD dwUpgrade
  382. );
  383. #if DBG
  384. VOID
  385. InitializeDebug(
  386. PINISPOOLER pIniSpooler
  387. );
  388. PDBG_POINTERS
  389. DbgSplGetPointers(
  390. VOID
  391. );
  392. #endif
  393. BOOL
  394. DllMain(
  395. HANDLE hModule,
  396. DWORD dwReason,
  397. LPVOID lpRes
  398. )
  399. {
  400. switch(dwReason) {
  401. case DLL_PROCESS_ATTACH:
  402. InitializeLocalspl();
  403. DisableThreadLibraryCalls(hModule);
  404. hInst = hModule;
  405. LocalMonInit(hInst);
  406. break;
  407. case DLL_PROCESS_DETACH :
  408. ShutdownPorts( pLocalIniSpooler );
  409. break;
  410. default:
  411. break;
  412. }
  413. return TRUE;
  414. UNREFERENCED_PARAMETER( lpRes );
  415. }
  416. VOID
  417. InitializeLocalspl(
  418. VOID
  419. )
  420. {
  421. #if DBG
  422. gpDbgPointers = DbgGetPointers();
  423. if( gpDbgPointers ){
  424. hcsSpoolerSection = gpDbgPointers->pfnAllocCritSec();
  425. SPLASSERT( hcsSpoolerSection );
  426. ghbtClusterRef = gpDbgPointers->pfnAllocBackTrace();
  427. }
  428. if( !hcsSpoolerSection ){
  429. //
  430. // Must be using the free version of spoolss.dll.
  431. //
  432. InitializeCriticalSection( &SpoolerSection );
  433. }
  434. #else
  435. InitializeCriticalSection( &SpoolerSection );
  436. #endif
  437. }
  438. VOID
  439. SplDeleteSpoolerThread(
  440. PVOID pv
  441. )
  442. {
  443. PINIPORT pIniPort;
  444. PINIPORT pIniPortNext;
  445. PINIMONITOR pIniMonitor;
  446. PINIMONITOR pIniMonitorNext;
  447. PSHARE_INFO_2 pShareInfo;
  448. PINISPOOLER pIniSpooler = (PINISPOOLER)pv;
  449. EnterSplSem();
  450. //
  451. // Cleanup the port monitors.
  452. //
  453. ShutdownMonitors( pIniSpooler );
  454. //
  455. // Close Cluster Access Token
  456. //
  457. if (pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE)
  458. NtClose(pIniSpooler->hClusterToken);
  459. //
  460. // Delete All the Strings
  461. //
  462. FreeIniSpoolerOtherNames(pIniSpooler);
  463. FreeStructurePointers((LPBYTE)pIniSpooler, NULL, IniSpoolerOffsets);
  464. DeleteShared( pIniSpooler );
  465. //
  466. // Run all of the environments down if this isn't the local ini-spoolers
  467. // environment. This frees up the memory for all of the drivers and also
  468. // handles the driver ref-counts.
  469. //
  470. if (pIniSpooler->pIniEnvironment != pLocalIniSpooler->pIniEnvironment && pIniSpooler->pIniEnvironment) {
  471. PINIENVIRONMENT pIniEnvironment = NULL;
  472. PINIENVIRONMENT pNextEnvironment = NULL;
  473. for(pIniEnvironment = pIniSpooler->pIniEnvironment; pIniEnvironment; pIniEnvironment = pNextEnvironment) {
  474. pNextEnvironment = pIniEnvironment->pNext;
  475. FreeIniEnvironment(pIniEnvironment);
  476. }
  477. }
  478. //
  479. // Delete ports and monitors.
  480. //
  481. // Note that there is no reference counting here. By the time
  482. // we get here all jobs and printers should be deleted (otherwise
  483. // the pIniSpooler reference count would be != 0). Therefore,
  484. // even though we don't refcount ports and monitors, we should
  485. // be ok.
  486. //
  487. //
  488. // Remove all ports.
  489. //
  490. for( pIniPort = pIniSpooler->pIniPort;
  491. pIniPort;
  492. pIniPort = pIniPortNext ){
  493. pIniPortNext = pIniPort->pNext;
  494. if( !DeletePortEntry( pIniPort )){
  495. DBGMSG( DBG_ERROR,
  496. ( "Unable to delete port %ws %x %x %d",
  497. pIniPort->pName,
  498. pIniPort->hPort,
  499. pIniPort->Status,
  500. pIniPort->cJobs ));
  501. }
  502. }
  503. //
  504. // Remove all the monitors.
  505. //
  506. for( pIniMonitor = pIniSpooler->pIniMonitor;
  507. pIniMonitor;
  508. pIniMonitor = pIniMonitorNext ){
  509. pIniMonitorNext = pIniMonitor->pNext;
  510. if( !pIniMonitor->cRef ){
  511. FreeIniMonitor( pIniMonitor );
  512. }
  513. }
  514. //
  515. // Close cluster resource key handle.
  516. //
  517. if( pIniSpooler->hckRoot ){
  518. SplRegCloseKey( pIniSpooler->hckRoot, pIniSpooler );
  519. }
  520. //
  521. // Close cluster resource key handle.
  522. //
  523. if( pIniSpooler->hckPrinters ){
  524. SplRegCloseKey( pIniSpooler->hckPrinters, pIniSpooler );
  525. }
  526. //
  527. // Keep a counter of cluster pIniSpoolers.
  528. //
  529. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  530. --gcClusterIniSpooler;
  531. }
  532. //
  533. // Free the shared bitmap and shared driver info.
  534. //
  535. vDeleteJobIdMap( pIniSpooler->hJobIdMap );
  536. pShareInfo = (PSHARE_INFO_2)pIniSpooler->pDriversShareInfo;
  537. FreeSplStr( pShareInfo->shi2_remark );
  538. FreeSplStr( pShareInfo->shi2_path );
  539. FreeSplMem( pIniSpooler->pDriversShareInfo );
  540. LeaveSplSem();
  541. //
  542. // Shut down the file pool for this ini-spooler. It should not delete any of
  543. // the files.
  544. //
  545. if (pIniSpooler->hFilePool != INVALID_HANDLE_VALUE) {
  546. (VOID)DestroyFilePool(pIniSpooler->hFilePool, FALSE);
  547. }
  548. // Free this IniSpooler
  549. FreeSplMem( pIniSpooler );
  550. DBGMSG( DBG_WARN, ( "SplDeleteSpooler: Refcount 0 %x\n", pIniSpooler ));
  551. }
  552. BOOL
  553. SplDeleteSpooler(
  554. HANDLE hSpooler
  555. )
  556. {
  557. PINISPOOLER pIniSpooler = (PINISPOOLER) hSpooler;
  558. BOOL bReturn = FALSE;
  559. PINISPOOLER pCurrentIniSpooler = pLocalIniSpooler;
  560. HANDLE hThread;
  561. DWORD ThreadId;
  562. SplInSem();
  563. //
  564. // Whoever calls this must have deleted all the object associated with
  565. // this spooler, ie all printers etc, just make certain
  566. //
  567. if( pIniSpooler != pLocalIniSpooler ){
  568. //
  569. // Mark us as pending deletion.
  570. //
  571. pIniSpooler->SpoolerFlags |= SPL_PENDING_DELETION;
  572. DBGMSG(DBG_CLUSTER, ("SplDeleteSpooler: Deleting %x\n cRef %u\n", pIniSpooler, pIniSpooler->cRef ));
  573. //
  574. // pIniPrinters now acquire a reference to pIniSpooler.
  575. //
  576. if( pIniSpooler->cRef == 0 ){
  577. SPLASSERT( pIniSpooler->pIniPrinter == NULL );
  578. //( pIniSpooler->pIniPort == NULL ) &&
  579. //( pIniSpooler->pIniForm == NULL ) &&
  580. //( pIniSpooler->pIniMonitor == NULL ) &&
  581. //( pIniSpooler->pIniNetPrint == NULL ) &&
  582. //( pIniSpooler->pSpool == NULL ))
  583. //
  584. // Take this Spooler Off the Linked List if it's on it.
  585. //
  586. while (( pCurrentIniSpooler->pIniNextSpooler != NULL ) &&
  587. ( pCurrentIniSpooler->pIniNextSpooler != pIniSpooler )) {
  588. pCurrentIniSpooler = pCurrentIniSpooler->pIniNextSpooler;
  589. }
  590. //
  591. // May not be on the linked list if it was removed earlier by
  592. // clustering.
  593. //
  594. if( pCurrentIniSpooler->pIniNextSpooler ){
  595. SPLASSERT( pCurrentIniSpooler->pIniNextSpooler == pIniSpooler );
  596. pCurrentIniSpooler->pIniNextSpooler = pIniSpooler->pIniNextSpooler;
  597. }
  598. //
  599. // Hack for port monitors.
  600. //
  601. // Some monitors will call ClosePrinter, which deletes the very
  602. // last printer and allows the pIniSpooler to be destroyed.
  603. // Unfortunately, we call back to the monitors to close themselves
  604. // in the same thread, which the monitor does not support.
  605. //
  606. // Create a new thread and shut everything down.
  607. //
  608. if (hThread = CreateThread( NULL, 0,
  609. (LPTHREAD_START_ROUTINE)SplDeleteSpoolerThread,
  610. (PVOID)pIniSpooler,
  611. 0,
  612. &ThreadId ))
  613. {
  614. CloseHandle(hThread);
  615. }
  616. else
  617. {
  618. //
  619. // Bug 54840
  620. //
  621. // What do we do if we can't create a thread to shut down?
  622. // Sleep and retry?
  623. //
  624. DBGMSG(DBG_ERROR, ("Unable to create SplDeleteSpoolerThread\n"));
  625. }
  626. bReturn = TRUE;
  627. }
  628. }
  629. return bReturn;
  630. }
  631. BOOL
  632. SplCloseSpooler(
  633. HANDLE hSpooler
  634. )
  635. {
  636. PINISPOOLER pIniSpooler = (PINISPOOLER) hSpooler;
  637. EnterSplSem();
  638. if ((pIniSpooler == NULL) ||
  639. (pIniSpooler == INVALID_HANDLE_VALUE) ||
  640. (pIniSpooler == pLocalIniSpooler) ||
  641. (pIniSpooler->signature != ISP_SIGNATURE) ||
  642. (pIniSpooler->cRef == 0)) {
  643. SetLastError( ERROR_INVALID_HANDLE );
  644. DBGMSG(DBG_WARNING, ("SplCloseSpooler InvalidHandle %x\n", pIniSpooler ));
  645. LeaveSplSem();
  646. return FALSE;
  647. }
  648. DBGMSG(DBG_TRACE, ("SplCloseSpooler %x %ws cRef %d\n",pIniSpooler,
  649. pIniSpooler->pMachineName,
  650. pIniSpooler->cRef-1));
  651. DECSPOOLERREF( pIniSpooler );
  652. LeaveSplSem();
  653. return TRUE;
  654. }
  655. BOOL SplRegCopyTree(
  656. HKEY hDest,
  657. HKEY hSrc
  658. )
  659. /*++
  660. Function Description: Recursives copies every key and value from under hSrc to hDest
  661. Parameters: hDest - destination key
  662. hSrc - source key
  663. Return Value: TRUE if successful; FALSE otherwise
  664. --*/
  665. {
  666. BOOL bStatus = FALSE;
  667. DWORD dwError, dwIndex, cbValueName, cbData, cbKeyName, dwType;
  668. DWORD cKeys, cMaxValueNameLen, cMaxValueLen, cMaxKeyNameLen, cValues;
  669. LPBYTE lpValueName = NULL, lpData = NULL, lpKeyName = NULL;
  670. HKEY hSrcSubKey = NULL, hDestSubKey = NULL;
  671. //
  672. // Get the max key name length and value name length and data size for
  673. // allocating the buffers
  674. //
  675. if (dwError = RegQueryInfoKey( hSrc, NULL, NULL, NULL,
  676. &cKeys, &cMaxKeyNameLen, NULL,
  677. &cValues, &cMaxValueNameLen,
  678. &cMaxValueLen, NULL, NULL ))
  679. {
  680. SetLastError(dwError);
  681. goto CleanUp;
  682. }
  683. //
  684. // Adjust for the NULL char
  685. //
  686. ++cMaxValueNameLen;
  687. ++cMaxKeyNameLen;
  688. //
  689. // Allocate the buffers
  690. //
  691. lpValueName = AllocSplMem( cMaxValueNameLen * sizeof(WCHAR) );
  692. lpData = AllocSplMem( cMaxValueLen );
  693. lpKeyName = AllocSplMem( cMaxKeyNameLen * sizeof(WCHAR) );
  694. if (!lpValueName || !lpData || !lpKeyName)
  695. {
  696. goto CleanUp;
  697. }
  698. //
  699. // Copy all the values in the current key
  700. //
  701. for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
  702. {
  703. cbData = cMaxValueLen;
  704. cbValueName = cMaxValueNameLen;
  705. //
  706. // Retrieve the value name and the data
  707. //
  708. dwError = RegEnumValue( hSrc, dwIndex, (LPWSTR) lpValueName, &cbValueName,
  709. NULL, &dwType, lpData, &cbData );
  710. if (dwError)
  711. {
  712. SetLastError( dwError );
  713. goto CleanUp;
  714. }
  715. //
  716. // Set the value in the destination
  717. //
  718. dwError = RegSetValueEx( hDest, (LPWSTR) lpValueName, 0, dwType,
  719. lpData, cbData );
  720. if (dwError)
  721. {
  722. SetLastError( dwError );
  723. goto CleanUp;
  724. }
  725. }
  726. //
  727. // Recursively copies all the subkeys
  728. //
  729. for (dwIndex = 0; dwIndex < cKeys; ++dwIndex)
  730. {
  731. cbKeyName = cMaxKeyNameLen;
  732. //
  733. // Retrieve the key name
  734. //
  735. dwError = RegEnumKeyEx( hSrc, dwIndex, (LPWSTR) lpKeyName, &cbKeyName,
  736. NULL, NULL, NULL, NULL );
  737. if (dwError)
  738. {
  739. SetLastError( dwError );
  740. goto CleanUp;
  741. }
  742. //
  743. // Open the source subkey
  744. //
  745. if (dwError = RegOpenKeyEx( hSrc, (LPWSTR) lpKeyName, 0,
  746. KEY_READ, &hSrcSubKey ))
  747. {
  748. SetLastError( dwError );
  749. goto CleanUp;
  750. }
  751. //
  752. // Create the destination subkey
  753. //
  754. if (dwError = RegCreateKeyEx( hDest, (LPWSTR) lpKeyName, 0, NULL,
  755. REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
  756. NULL, &hDestSubKey, NULL ))
  757. {
  758. SetLastError( dwError );
  759. goto CleanUp;
  760. }
  761. //
  762. // Copy the subkey tree
  763. //
  764. if (!SplRegCopyTree( hDestSubKey, hSrcSubKey ))
  765. {
  766. goto CleanUp;
  767. }
  768. //
  769. // Close the registry handle
  770. //
  771. RegCloseKey( hDestSubKey );
  772. RegCloseKey( hSrcSubKey );
  773. hDestSubKey = NULL;
  774. hSrcSubKey = NULL;
  775. }
  776. bStatus = TRUE;
  777. CleanUp:
  778. //
  779. // Free allocated resources
  780. //
  781. if (lpValueName)
  782. {
  783. FreeSplMem( lpValueName );
  784. }
  785. if (lpData)
  786. {
  787. FreeSplMem( lpData );
  788. }
  789. if (lpKeyName)
  790. {
  791. FreeSplMem( lpKeyName );
  792. }
  793. //
  794. // Close registry handles
  795. //
  796. if (hDestSubKey)
  797. {
  798. RegCloseKey( hDestSubKey );
  799. }
  800. if (hSrcSubKey)
  801. {
  802. RegCloseKey( hSrcSubKey );
  803. }
  804. return bStatus;
  805. }
  806. VOID
  807. MigratePrinterData()
  808. /*++
  809. Function Description: When the spooler starts up for the first time after upgrade,
  810. the printer data is moved from HKLM\Software to HKLM\System
  811. Parameters: None
  812. Return Values: None
  813. --*/
  814. {
  815. HKEY hSysPrinters = NULL, hSwPrinters = NULL;
  816. //
  817. // Migrate the data only immediately following upgrade
  818. //
  819. if (!dwUpgradeFlag)
  820. {
  821. return;
  822. }
  823. //
  824. // Open the source and destination keys for the migration
  825. //
  826. if (( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  827. ipszRegSwPrinters,
  828. 0,
  829. KEY_ALL_ACCESS,
  830. &hSwPrinters ) == ERROR_SUCCESS) &&
  831. ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  832. ipszRegistryPrinters,
  833. 0,
  834. KEY_ALL_ACCESS,
  835. &hSysPrinters ) == ERROR_SUCCESS) )
  836. {
  837. //
  838. // Recursively copy the keys and the values from Software to System
  839. //
  840. SplRegCopyTree( hSysPrinters, hSwPrinters );
  841. }
  842. //
  843. // Close the registry handles
  844. //
  845. if (hSwPrinters)
  846. {
  847. RegCloseKey( hSwPrinters );
  848. }
  849. if (hSysPrinters)
  850. {
  851. RegCloseKey( hSysPrinters );
  852. }
  853. //
  854. // Delete the printers key from the software since it is no longer
  855. // accessed by the spooler
  856. //
  857. RegDeleteKey( HKEY_LOCAL_MACHINE, ipszRegSwPrinters );
  858. return;
  859. }
  860. NTSTATUS
  861. IsCCSetLinkedtoSoftwareHive (
  862. PBOOL pbIsLinked
  863. )
  864. /*++
  865. Function Description:
  866. Checks to see if it is a link between SYSTEM hive and SOFTWARE hive
  867. Only Nt Apis manage to do this.
  868. Parameters:
  869. OUT pbIsLinked - TRUE if there is a symbolic link between SYSTEM hive and SOFTWARE hive
  870. Return Values:
  871. --*/
  872. {
  873. NTSTATUS Status;
  874. OBJECT_ATTRIBUTES ObjectAttributes;
  875. UNICODE_STRING KeyName;
  876. HANDLE KeyHandle;
  877. *pbIsLinked = FALSE;
  878. RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Print\\Printers");
  879. InitializeObjectAttributes( &ObjectAttributes,
  880. &KeyName,
  881. OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
  882. (HANDLE)NULL,
  883. NULL
  884. );
  885. //
  886. // Open CurrentControlSet\\Control\\Print\\Printers key
  887. //
  888. Status = NtOpenKey( (PHANDLE)(&KeyHandle),
  889. MAXIMUM_ALLOWED,
  890. &ObjectAttributes
  891. );
  892. if (NT_SUCCESS(Status))
  893. {
  894. ULONG len;
  895. UCHAR ValueBuffer[MAX_PATH];
  896. UNICODE_STRING ValueName;
  897. PKEY_VALUE_FULL_INFORMATION keyInfo;
  898. RtlInitUnicodeString( &ValueName, L"SymbolicLinkValue" );
  899. //
  900. // Query CurrentControlSet\\Control\\Print\\Printers for SymbolicLinkValue
  901. //
  902. Status = NtQueryValueKey(KeyHandle,
  903. &ValueName,
  904. KeyValueFullInformation,
  905. ValueBuffer,
  906. sizeof (ValueBuffer),
  907. &len
  908. );
  909. if( NT_SUCCESS(Status) ) {
  910. //
  911. // It's not enough that the value exists, it should be a REG_LINK value
  912. //
  913. keyInfo = ( PKEY_VALUE_FULL_INFORMATION ) ValueBuffer;
  914. *pbIsLinked = ( keyInfo->Type == REG_LINK );
  915. }
  916. NtClose(KeyHandle);
  917. }
  918. return Status;
  919. }
  920. DWORD
  921. LinkControlSet (
  922. LPCTSTR pszRegistryPrinters
  923. )
  924. /*++
  925. Function Description:
  926. Create a symbolic volatile link from SYSTEM hive to SOFTWARE hive
  927. Parameters:
  928. Return Values: ERROR_SUCCESS if succeeded
  929. --*/
  930. {
  931. HKEY hCCSKey;
  932. DWORD dwRet;
  933. BOOL bIsLinked = FALSE;
  934. PWCHAR pszRegistryPrintersFullLink = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers";
  935. dwRet = IsCCSetLinkedtoSoftwareHive(&bIsLinked);
  936. //
  937. // IsCCSetLinkedtoSoftwareHive returns NTSTATUS
  938. // If the link is not there , IsCCSetLinkedtoSoftwareHive fails with STATUS_OBJECT_NAME_NOT_FOUND
  939. // That's not an error.
  940. //
  941. if( NT_SUCCESS(dwRet) || dwRet == STATUS_OBJECT_NAME_NOT_FOUND ) {
  942. if (bIsLinked) {
  943. dwRet = ERROR_SUCCESS;
  944. }else{
  945. dwRet = SplDeleteThisKey( HKEY_LOCAL_MACHINE,
  946. NULL,
  947. (LPWSTR)pszRegistryPrinters,
  948. FALSE,
  949. NULL
  950. );
  951. if( dwRet == ERROR_SUCCESS || dwRet == ERROR_FILE_NOT_FOUND) {
  952. dwRet = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  953. pszRegistryPrinters,
  954. 0,
  955. NULL,
  956. REG_OPTION_VOLATILE|REG_OPTION_CREATE_LINK,
  957. KEY_ALL_ACCESS|KEY_CREATE_LINK,
  958. NULL,
  959. &hCCSKey,
  960. NULL);
  961. if( dwRet == ERROR_SUCCESS )
  962. {
  963. dwRet = RegSetValueEx( hCCSKey,
  964. _T("SymbolicLinkValue"),
  965. 0,
  966. REG_LINK,
  967. (CONST BYTE *)pszRegistryPrintersFullLink,
  968. (_tcsclen(pszRegistryPrintersFullLink) * sizeof(WCHAR)));
  969. RegCloseKey(hCCSKey);
  970. }
  971. }
  972. }
  973. }
  974. return dwRet;
  975. }
  976. DWORD
  977. BackupPrintersToSystemHive(
  978. LPWSTR pszSwRegistryPrinters
  979. )
  980. /*++
  981. Function Description:
  982. Because the print registry data location was moved to SOFTWARE hive, we need to create
  983. a symbolic registry link between the new location and the old one in SYSTEM hive.
  984. We are doing this for applications that read directly from registry print data and
  985. rely on the old location.
  986. Parameters:
  987. pszSwRegistryPrinters - the new printer data location under SOFTWARE hive
  988. Return Values:
  989. FALSE if the printer keys are not in SOFTWARE hive
  990. Since this fuction's failure might stop spooler working,
  991. Control set's cleanup and link failures are not considered fatal.
  992. Only apps that access printer data directly will fail.
  993. --*/
  994. {
  995. HKEY hKey;
  996. DWORD dwRet;
  997. HKEY hSwPrinters = NULL;
  998. //
  999. // Check the existence of pszSwRegistryPrinters
  1000. //
  1001. dwRet = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1002. pszSwRegistryPrinters,
  1003. 0,
  1004. NULL,
  1005. 0,
  1006. KEY_ALL_ACCESS,
  1007. NULL,
  1008. &hSwPrinters,
  1009. NULL);
  1010. if ( dwRet != ERROR_SUCCESS ) {
  1011. goto End;
  1012. }
  1013. //
  1014. // Create a volatile link between current location in SOFTWARE hive and the old one in SYSTEM hive
  1015. // Because it is volatile, this link must be created after each reboot (every time when spooler starts)
  1016. // A failure at this level is not fatal since spooler doesn't rely on SYSTEM hive location anymore
  1017. //
  1018. dwRet = LinkControlSet(ipszRegistryPrinters);
  1019. End:
  1020. if ( hSwPrinters ){
  1021. RegCloseKey( hSwPrinters );
  1022. }
  1023. return dwRet;
  1024. }
  1025. BOOL
  1026. CleanupDeletedPrinters (
  1027. PINISPOOLER pIniSpooler
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Deletes the printers in pending deletion for real if they have no more jobs and
  1032. if they are not referenced anymore
  1033. Arguments:
  1034. pIniSpooler - not null
  1035. Return Value:
  1036. BOOL - ignored
  1037. --*/
  1038. {
  1039. PINIPRINTER pIniPrinter;
  1040. BOOL bRet = FALSE;
  1041. if(pIniSpooler) {
  1042. pIniPrinter = pIniSpooler->pIniPrinter;
  1043. while (pIniPrinter) {
  1044. if (pIniPrinter->Status & PRINTER_PENDING_DELETION &&
  1045. !pIniPrinter->cJobs &&
  1046. !pIniPrinter->cRef ) {
  1047. DeletePrinterForReal(pIniPrinter, INIT_TIME);
  1048. // The link list will have changed underneath us
  1049. // DeletePrinterForReal leaves the Spooler CS
  1050. // Lets just loop through again from the beginning
  1051. pIniPrinter = pIniSpooler->pIniPrinter;
  1052. } else
  1053. pIniPrinter = pIniPrinter->pNext;
  1054. }
  1055. bRet = TRUE;
  1056. }
  1057. return bRet;
  1058. }
  1059. HANDLE
  1060. SplCreateSpooler(
  1061. LPWSTR pMachineName,
  1062. DWORD Level,
  1063. PBYTE pSpooler,
  1064. LPBYTE pReserved
  1065. )
  1066. {
  1067. HANDLE hReturn = INVALID_HANDLE_VALUE;
  1068. PINISPOOLER pIniSpooler = NULL;
  1069. PSPOOLER_INFO_2 pSpoolerInfo2 = (PSPOOLER_INFO_2)pSpooler;
  1070. DWORD i;
  1071. WCHAR Buffer[MAX_PATH];
  1072. PSHARE_INFO_2 pShareInfo = NULL;
  1073. LONG Status;
  1074. HANDLE hToken;
  1075. DWORD dwRet;
  1076. hToken = RevertToPrinterSelf();
  1077. EnterSplSem();
  1078. // Validate Parameters
  1079. if ( pMachineName == NULL ) {
  1080. SetLastError( ERROR_INVALID_NAME );
  1081. goto SplCreateDone;
  1082. }
  1083. if( Level == 1 &&
  1084. ( pSpoolerInfo2->SpoolerFlags & SPL_CLUSTER_REG ||
  1085. !pSpoolerInfo2->pszRegistryRoot ||
  1086. !pSpoolerInfo2->pszRegistryPrinters )){
  1087. SetLastError( ERROR_INVALID_PARAMETER );
  1088. goto SplCreateDone;
  1089. }
  1090. DBGMSG( DBG_TRACE, ("SplCreateSpooler %ws %d %x %x\n", pMachineName,
  1091. Level, pSpooler, pReserved ));
  1092. if( (pSpoolerInfo2->SpoolerFlags & (SPL_TYPE_LOCAL | SPL_PRINT)) &&
  1093. !(pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER) ){
  1094. if ( dwRet = (BackupPrintersToSystemHive( pSpoolerInfo2->pszRegistryPrinters )) != ERROR_SUCCESS ){
  1095. WCHAR pwszError[256];
  1096. wsprintf(pwszError,L"%x", dwRet);
  1097. SplLogEvent(pIniSpooler,
  1098. LOG_ERROR,
  1099. MSG_BACKUP_SPOOLER_REGISTRY,
  1100. TRUE,
  1101. pwszError,
  1102. NULL);
  1103. }
  1104. }
  1105. if (pLocalIniSpooler != NULL) {
  1106. pIniSpooler = FindSpooler( pMachineName, pSpoolerInfo2->SpoolerFlags );
  1107. if (pSpoolerInfo2->SpoolerFlags & SPL_OPEN_EXISTING_ONLY && !pIniSpooler) {
  1108. SetLastError( ERROR_FILE_NOT_FOUND );
  1109. goto SplCreateDone;
  1110. }
  1111. }
  1112. //
  1113. // Make sure we clear out a request to only open an existing inispooler.
  1114. // This is not a useful flag except for when we are searching for inispoolers.
  1115. //
  1116. pSpoolerInfo2->SpoolerFlags &= ~SPL_OPEN_EXISTING_ONLY;
  1117. if ( pIniSpooler == NULL ) {
  1118. pIniSpooler = AllocSplMem( sizeof(INISPOOLER) );
  1119. if (pIniSpooler == NULL ) {
  1120. DBGMSG( DBG_WARNING, ("Unable to allocate IniSpooler\n"));
  1121. goto SplCreateDone;
  1122. }
  1123. pIniSpooler->signature = ISP_SIGNATURE;
  1124. INCSPOOLERREF( pIniSpooler );
  1125. pIniSpooler->hClusSplReady = NULL;
  1126. //
  1127. // Setup the job id map.
  1128. //
  1129. pIniSpooler->hJobIdMap = hCreateJobIdMap( 256 );
  1130. pIniSpooler->pMachineName = AllocSplStr( pMachineName );
  1131. if ( pIniSpooler->pMachineName == NULL ||
  1132. pIniSpooler->hJobIdMap == NULL ) {
  1133. DBGMSG( DBG_WARNING, ("Unable to allocate\n"));
  1134. goto SplCreateDone;
  1135. }
  1136. //
  1137. // A cluster spooler own its drivers, ports, pprocessors, etc. In order to manage those
  1138. // resources, the cluster spooler needs to have information about the driver letter of
  1139. // the cluster disk. Also the spooler needs to know its own cluster resource GUID
  1140. //
  1141. if( pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER )
  1142. {
  1143. Status = ClusterGetResourceDriveLetter(pSpoolerInfo2->pszResource, &pIniSpooler->pszClusResDriveLetter);
  1144. if (Status != ERROR_SUCCESS)
  1145. {
  1146. SetLastError(Status);
  1147. goto SplCreateDone;
  1148. }
  1149. Status = ClusterGetResourceID(pSpoolerInfo2->pszResource, &pIniSpooler->pszClusResID);
  1150. if (Status != ERROR_SUCCESS)
  1151. {
  1152. SetLastError( Status );
  1153. goto SplCreateDone;
  1154. }
  1155. //
  1156. // When a node is upgraded, the resource dll writes a key in the registry. When the cluster spooler
  1157. // fails over for the first time on the node that was upgraded, then it will try to read that key
  1158. // in the registry. Then it will know if it has to do upgrade specific tasks, like upgrading its
  1159. // printer drivers.
  1160. //
  1161. Status = ClusterSplReadUpgradeKey(pIniSpooler->pszClusResID, &pIniSpooler->dwClusNodeUpgraded);
  1162. if (Status != ERROR_SUCCESS)
  1163. {
  1164. SetLastError( Status );
  1165. goto SplCreateDone;
  1166. }
  1167. DBGMSG(DBG_CLUSTER, ("SplCreateSpooler cluster ClusterUpgradeFlag %u\n", pIniSpooler->dwClusNodeUpgraded));
  1168. }
  1169. else
  1170. {
  1171. //
  1172. // For a non cluster type spooler, these properties are meaningless.
  1173. //
  1174. pIniSpooler->pszClusResDriveLetter = NULL;
  1175. pIniSpooler->pszClusResID = NULL;
  1176. }
  1177. if (pSpoolerInfo2->pDir)
  1178. {
  1179. pIniSpooler->pDir = AllocSplStr( pSpoolerInfo2->pDir );
  1180. if (!pIniSpooler->pDir)
  1181. {
  1182. DBGMSG( DBG_WARNING, ("Unable to allocate pSpoolerInfo2-pDir\n"));
  1183. goto SplCreateDone;
  1184. }
  1185. wcscpy(&Buffer[0], pIniSpooler->pDir);
  1186. }
  1187. else
  1188. {
  1189. i = GetSystemDirectory(Buffer, COUNTOF(Buffer));
  1190. wcscpy(&Buffer[i], szSpoolDirectory);
  1191. if (pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER)
  1192. {
  1193. //
  1194. // For a cluster type spooler, the directory where it stores its driver files is of the form:
  1195. // pDir = C:\Windows\system32\spool\Drivers\spooler-resource-GUID
  1196. //
  1197. StrCatAlloc(&pIniSpooler->pDir,
  1198. Buffer,
  1199. szDriversDirectory,
  1200. L"\\",
  1201. pIniSpooler->pszClusResID,
  1202. NULL);
  1203. }
  1204. else
  1205. {
  1206. //
  1207. // For the local spooler, the directory where it stores its driver files is the following:
  1208. // pDir = C:\Windows\system32\spool\Drivers
  1209. //
  1210. StrCatAlloc(&pIniSpooler->pDir,
  1211. Buffer,
  1212. NULL);
  1213. }
  1214. if (!pIniSpooler->pDir)
  1215. {
  1216. DBGMSG( DBG_WARNING, ("Unable to Allocate pIniSpooler->pDir\n"));
  1217. goto SplCreateDone;
  1218. }
  1219. }
  1220. //
  1221. // DriverShareInfo
  1222. //
  1223. pIniSpooler->pDriversShareInfo = AllocSplMem( sizeof( SHARE_INFO_2));
  1224. if ( pIniSpooler->pDriversShareInfo == NULL ) {
  1225. DBGMSG(DBG_WARNING, ("Unable to Alloc pIniSpooler->pDriversShareInfo\n"));
  1226. goto SplCreateDone;
  1227. }
  1228. pShareInfo = (PSHARE_INFO_2)pIniSpooler->pDriversShareInfo;
  1229. if ( pIniSpooler->pDriversShareInfo == NULL )
  1230. goto SplCreateDone;
  1231. pShareInfo->shi2_netname = NULL;
  1232. pShareInfo->shi2_type = STYPE_DISKTREE;
  1233. pShareInfo->shi2_remark = NULL;
  1234. pShareInfo->shi2_permissions = 0;
  1235. pShareInfo->shi2_max_uses = SHI_USES_UNLIMITED;
  1236. pShareInfo->shi2_current_uses = SHI_USES_UNLIMITED;
  1237. pShareInfo->shi2_path = NULL;
  1238. pShareInfo->shi2_passwd = NULL;
  1239. //
  1240. // Find end of "<winnt>\system32\spool"
  1241. //
  1242. i = wcslen(Buffer);
  1243. //
  1244. // Make <winnt>\system32\spool\drivers
  1245. //
  1246. wcscpy(&Buffer[i], szDriversDirectory);
  1247. pShareInfo->shi2_path = AllocSplStr(Buffer);
  1248. if ( pShareInfo->shi2_path == NULL ) {
  1249. DBGMSG( DBG_WARNING, ("Unable to alloc pShareInfo->shi2_path\n"));
  1250. goto SplCreateDone;
  1251. }
  1252. pShareInfo->shi2_netname = ipszDriversShareName;
  1253. *Buffer = L'\0';
  1254. LoadString(hInst, IDS_PRINTER_DRIVERS, Buffer, (sizeof Buffer / sizeof *Buffer));
  1255. pShareInfo->shi2_remark = AllocSplStr(Buffer);
  1256. if ( pShareInfo->shi2_remark == NULL ) {
  1257. DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
  1258. goto SplCreateDone;
  1259. }
  1260. pIniSpooler->pIniPrinter = NULL;
  1261. pIniSpooler->pIniEnvironment = NULL;
  1262. pIniSpooler->pIniNetPrint = NULL;
  1263. //
  1264. // No need to initialize shared resources.
  1265. //
  1266. pIniSpooler->pSpool = NULL;
  1267. pIniSpooler->pDefaultSpoolDir = NULL;
  1268. pIniSpooler->bEnableRetryPopups = FALSE;
  1269. pIniSpooler->dwRestartJobOnPoolTimeout = DEFAULT_JOB_RESTART_TIMEOUT_ON_POOL_ERROR;
  1270. pIniSpooler->bRestartJobOnPoolEnabled = TRUE;
  1271. if (( pSpoolerInfo2->pszRegistryMonitors == NULL ) &&
  1272. ( pSpoolerInfo2->pszRegistryEnvironments == NULL ) &&
  1273. ( pSpoolerInfo2->pszRegistryEventLog == NULL ) &&
  1274. ( pSpoolerInfo2->pszRegistryProviders == NULL ) &&
  1275. ( pSpoolerInfo2->pszEventLogMsgFile == NULL ) &&
  1276. ( pSpoolerInfo2->pszRegistryForms == NULL ) &&
  1277. ( pSpoolerInfo2->pszDriversShare == NULL )) {
  1278. DBGMSG( DBG_WARNING, ("SplCreateSpooler Invalid Parameters\n"));
  1279. goto SplCreateDone;
  1280. }
  1281. if( !( pSpoolerInfo2->SpoolerFlags & SPL_CLUSTER_REG ) &&
  1282. ( pSpoolerInfo2->pszRegistryPrinters == NULL )){
  1283. DBGMSG( DBG_WARNING, ("SplCreateSpooler Invalid RegistryPrinters\n"));
  1284. goto SplCreateDone;
  1285. }
  1286. if ( pSpoolerInfo2->pDefaultSpoolDir != NULL ) {
  1287. pIniSpooler->pDefaultSpoolDir = AllocSplStr( pSpoolerInfo2->pDefaultSpoolDir );
  1288. if ( pIniSpooler->pDefaultSpoolDir == NULL ) {
  1289. DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
  1290. goto SplCreateDone;
  1291. }
  1292. }
  1293. pIniSpooler->pszRegistryMonitors = AllocSplStr( pSpoolerInfo2->pszRegistryMonitors );
  1294. //
  1295. // The spooler stores data about environemnts, versions, drivers and print processors
  1296. // in the regsitry (or cluster data base). This data is accessed via pIniSpooler->
  1297. // pszRegistryEnvironemts
  1298. //
  1299. if (pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER)
  1300. {
  1301. //
  1302. // For a cluster spooler pIniSpooler->hckRoot maps to Parameters key of the spooler
  1303. // resource in the cluster database. pIniSpooler->pszRegistryEnvironments is a key
  1304. // called "Environemts" under hckRoot.
  1305. //
  1306. pIniSpooler->pszRegistryEnvironments = AllocSplStr(ipszClusterDatabaseEnvironments);
  1307. }
  1308. else
  1309. {
  1310. //
  1311. // For local spooler pIniSpooler->pszRegistryEnvironments is the following string:
  1312. // System\CurrentControlSet\Control\Print\Environments. It is used relative to HKLM
  1313. //
  1314. pIniSpooler->pszRegistryEnvironments = AllocSplStr(!pLocalIniSpooler ? pSpoolerInfo2->pszRegistryEnvironments :
  1315. pLocalIniSpooler->pszRegistryEnvironments);
  1316. }
  1317. pIniSpooler->pszRegistryEventLog = AllocSplStr( pSpoolerInfo2->pszRegistryEventLog );
  1318. pIniSpooler->pszRegistryProviders = AllocSplStr( pSpoolerInfo2->pszRegistryProviders );
  1319. pIniSpooler->pszEventLogMsgFile = AllocSplStr( pSpoolerInfo2->pszEventLogMsgFile );
  1320. if (pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER)
  1321. {
  1322. //
  1323. // The driver share for a cluster spooler is of the form \\server\print$\spooler-resource-GUID
  1324. //
  1325. StrCatAlloc(&pIniSpooler->pszDriversShare,
  1326. pSpoolerInfo2->pszDriversShare,
  1327. L"\\",
  1328. pIniSpooler->pszClusResID,
  1329. szDriversDirectory,
  1330. NULL);
  1331. }
  1332. else
  1333. {
  1334. //
  1335. // The driver share for the local spooler is \\server\print$
  1336. //
  1337. StrCatAlloc(&pIniSpooler->pszDriversShare, pSpoolerInfo2->pszDriversShare, NULL);
  1338. }
  1339. pIniSpooler->pszRegistryForms = AllocSplStr( pSpoolerInfo2->pszRegistryForms ) ;
  1340. pIniSpooler->hClusterToken = INVALID_HANDLE_VALUE;
  1341. pIniSpooler->hFilePool = INVALID_HANDLE_VALUE;
  1342. if ( pIniSpooler->pszRegistryMonitors == NULL ||
  1343. pIniSpooler->pszRegistryEnvironments == NULL ||
  1344. pIniSpooler->pszRegistryEventLog == NULL ||
  1345. pIniSpooler->pszRegistryProviders == NULL ||
  1346. pIniSpooler->pszEventLogMsgFile == NULL ||
  1347. pIniSpooler->pszDriversShare == NULL ||
  1348. pIniSpooler->pszRegistryForms == NULL ) {
  1349. DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
  1350. goto SplCreateDone;
  1351. }
  1352. pIniSpooler->SpoolerFlags = pSpoolerInfo2->SpoolerFlags;
  1353. //
  1354. // Initialize the shared resources (pShared).
  1355. //
  1356. if( !InitializeShared( pIniSpooler )){
  1357. DBGMSG( DBG_WARN,
  1358. ( "SplCreateSpooler: InitializeShared Failed %d\n",
  1359. GetLastError() ));
  1360. goto SplCreateDone;
  1361. }
  1362. //
  1363. // Create the print share if necessary. This is always needed
  1364. // since the cluster printers are shared, while the local ones
  1365. // on this node aren't.
  1366. //
  1367. if(pIniSpooler->SpoolerFlags & SPL_ALWAYS_CREATE_DRIVER_SHARE ){
  1368. if( !AddPrintShare( pIniSpooler )){
  1369. goto SplCreateDone;
  1370. }
  1371. }
  1372. //
  1373. // Open and store the printer and root key from
  1374. // the resource registry.
  1375. //
  1376. if( pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
  1377. SPLASSERT( Level == 2 );
  1378. // Set up the DS Cluster info. If we fail here, we can't publish printers, but let's
  1379. // not abort the cluster.
  1380. Status = InitializeDSClusterInfo(pIniSpooler, &hToken);
  1381. if (Status != ERROR_SUCCESS) {
  1382. DBGMSG(DBG_WARNING, ("InitializeDSClusterInfo FAILED: %d\n", Status));
  1383. }
  1384. pIniSpooler->hckRoot = OpenClusterParameterKey(
  1385. pSpoolerInfo2->pszResource );
  1386. if( !pIniSpooler->hckRoot ) {
  1387. goto SplCreateDone;
  1388. }
  1389. Status = SplRegCreateKey( pIniSpooler->hckRoot,
  1390. szPrintersKey,
  1391. 0,
  1392. KEY_ALL_ACCESS,
  1393. NULL,
  1394. &pIniSpooler->hckPrinters,
  1395. NULL,
  1396. pIniSpooler );
  1397. if( Status != ERROR_SUCCESS ){
  1398. SetLastError( Status );
  1399. goto SplCreateDone;
  1400. }
  1401. } else {
  1402. DWORD dwDisposition;
  1403. Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1404. pSpoolerInfo2->pszRegistryRoot,
  1405. 0,
  1406. NULL,
  1407. 0,
  1408. KEY_ALL_ACCESS,
  1409. NULL,
  1410. &pIniSpooler->hckRoot,
  1411. &dwDisposition );
  1412. if( Status != ERROR_SUCCESS ){
  1413. SetLastError( Status );
  1414. goto SplCreateDone;
  1415. }
  1416. Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1417. pSpoolerInfo2->pszRegistryPrinters,
  1418. 0,
  1419. NULL,
  1420. 0,
  1421. KEY_ALL_ACCESS,
  1422. NULL,
  1423. &pIniSpooler->hckPrinters,
  1424. &dwDisposition );
  1425. if( Status != ERROR_SUCCESS ){
  1426. SetLastError( Status );
  1427. goto SplCreateDone;
  1428. }
  1429. }
  1430. pIniSpooler->pfnReadRegistryExtra = pSpoolerInfo2->pfnReadRegistryExtra;
  1431. pIniSpooler->pfnWriteRegistryExtra = pSpoolerInfo2->pfnWriteRegistryExtra;
  1432. pIniSpooler->pfnFreePrinterExtra = pSpoolerInfo2->pfnFreePrinterExtra;
  1433. // Success add to Linked List
  1434. if ( pLocalIniSpooler != NULL ) {
  1435. pIniSpooler->pIniNextSpooler = pLocalIniSpooler->pIniNextSpooler;
  1436. pLocalIniSpooler->pIniNextSpooler = pIniSpooler;
  1437. } else {
  1438. // First One is Always LocalSpl
  1439. pLocalIniSpooler = pIniSpooler;
  1440. pIniSpooler->pIniNextSpooler = NULL;
  1441. }
  1442. //
  1443. // This function will update the global varaiable dwUpgradeFlag
  1444. //
  1445. QueryUpgradeFlag( pIniSpooler );
  1446. InitializeEventLogging( pIniSpooler );
  1447. //
  1448. // Only initialize forms if this is not a clustered spooler.
  1449. //
  1450. if( !( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER )){
  1451. InitializeForms( pIniSpooler );
  1452. }
  1453. //
  1454. // Originally ports were a per-machine (manual) resource. However,
  1455. // this has changed for clustering in 5.0, so that ports can be
  1456. // stored in the cluster registry. Note that monitors are still
  1457. // manual resources, since there isn't an easy way to install them
  1458. // on a remote machine.
  1459. //
  1460. BuildAllPorts( pIniSpooler );
  1461. InitializeSpoolerSettings( pIniSpooler );
  1462. if ( pIniSpooler == pLocalIniSpooler ) {
  1463. GetPrintSystemVersion( pIniSpooler );
  1464. BuildEnvironmentInfo( pIniSpooler );
  1465. BuildOtherNamesFromMachineName(&pIniSpooler->ppszOtherNames, &pIniSpooler->cOtherNames);
  1466. if ( dwUpgradeFlag ) {
  1467. //
  1468. // The problem is that we have built-in forms, and
  1469. // custom forms (duplicates disallowed).On NT4, we
  1470. // may have a custom "A6" form. When we upgrade to NT5,
  1471. // and we have a new built-in from "A6." We need to
  1472. // rename the custom form to "A6 Custom," otherwise we'll
  1473. // have duplicates.
  1474. //
  1475. UpgradeForms(pIniSpooler);
  1476. //
  1477. // If we are upgrading from NT 3.1 the drivers need to be
  1478. // moved to the correct target directory and the registry needs to
  1479. // be fixed. Because NT 3.1 didn't have different driver
  1480. //
  1481. Upgrade31DriversRegistryForAllEnvironments( pIniSpooler );
  1482. }
  1483. } else if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) {
  1484. HANDLE hThread;
  1485. DWORD dwThreadId;
  1486. DWORD dwError;
  1487. //
  1488. // The setup creates the registry strucutre for the local spooler:
  1489. // Environments {Windows NT x86, Windows IA64, etc}
  1490. // For a cluster spooler we need to create it ourselves in the
  1491. // cluster database
  1492. //
  1493. if ((dwError = CreateClusterSpoolerEnvironmentsStructure(pIniSpooler)) == ERROR_SUCCESS)
  1494. {
  1495. //
  1496. // Create all the environments, versions, drivers, processors strurctres
  1497. // This function always returns FALSE. We cannot take its return value
  1498. // into account.
  1499. //
  1500. BuildEnvironmentInfo(pIniSpooler);
  1501. //
  1502. // Now we launch a thread to do time consuming tasks that can
  1503. // be performed with the spooler on line. These inlude ungrading
  1504. // printer drivers, copying ICM profiles from the cluster disk etc.
  1505. //
  1506. // We need to bump the ref count so that the worker thread has
  1507. // a valid pIniSpooler. The worker thread will decref the pinispooler
  1508. // when it is done
  1509. //
  1510. INCSPOOLERREF(pIniSpooler);
  1511. //
  1512. // The event has manual reset and is not signaled.
  1513. //
  1514. pIniSpooler->hClusSplReady = CreateEvent(NULL, TRUE, FALSE, NULL);
  1515. //
  1516. // If the thread is created, then SplCreateSpoolerWorkerThread will
  1517. // close the hClusSplReady event handle.
  1518. //
  1519. if (pIniSpooler->hClusSplReady &&
  1520. (hThread = CreateThread(NULL,
  1521. 0,
  1522. (LPTHREAD_START_ROUTINE)SplCreateSpoolerWorkerThread,
  1523. (PVOID)pIniSpooler,
  1524. 0,
  1525. &dwThreadId)))
  1526. {
  1527. CloseHandle(hThread);
  1528. //
  1529. // If Level 2 then check for other names.
  1530. //
  1531. if (Level == 2)
  1532. {
  1533. BuildOtherNamesFromSpoolerInfo2(pSpoolerInfo2, pIniSpooler);
  1534. }
  1535. }
  1536. else
  1537. {
  1538. //
  1539. // Either CreateEvent or CreatreThread failed.
  1540. //
  1541. dwError = GetLastError();
  1542. if (pIniSpooler->hClusSplReady)
  1543. {
  1544. CloseHandle(pIniSpooler->hClusSplReady);
  1545. pIniSpooler->hClusSplReady = NULL;
  1546. }
  1547. DECSPOOLERREF(pIniSpooler);
  1548. DBGMSG(DBG_ERROR, ("Unable to create SplCreateSpoolerWorkerThread\n"));
  1549. }
  1550. }
  1551. //
  1552. // An error occured
  1553. //
  1554. if (dwError != ERROR_SUCCESS)
  1555. {
  1556. SetLastError(dwError);
  1557. goto SplCreateDone;
  1558. }
  1559. }
  1560. else
  1561. {
  1562. //
  1563. // This is the case of a network spooler. You get one of those when
  1564. // you make a true printer connection
  1565. //
  1566. pIniSpooler->pIniEnvironment = pLocalIniSpooler->pIniEnvironment;
  1567. //
  1568. // If Level 2 then check for other names.
  1569. //
  1570. if( Level == 2 )
  1571. BuildOtherNamesFromSpoolerInfo2( pSpoolerInfo2, pIniSpooler );
  1572. }
  1573. //
  1574. // Read Printer Info from Registry (cluster databse for cluster spooler)
  1575. // There's no cleanup in any of this code--it doesn't free any allocated memory!
  1576. //
  1577. if( !BuildPrinterInfo( pIniSpooler, (BOOL) dwUpgradeFlag )){
  1578. goto SplCreateDone;
  1579. }
  1580. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  1581. //
  1582. // Keep a counter of pIniSpoolers.
  1583. //
  1584. ++gcClusterIniSpooler;
  1585. }
  1586. //
  1587. // We need to perform some costly initialization, so we increase the refcount
  1588. // on the pIniSpooler and will do the lengthy operations outside the global
  1589. // critical section
  1590. //
  1591. INCSPOOLERREF(pIniSpooler);
  1592. LeaveSplSem();
  1593. //
  1594. // GetDNSMachineName may fail, but that's okay. Just don't be surprised
  1595. // if pszFullMachineName is NULL.
  1596. //
  1597. GetDNSMachineName(pIniSpooler->pMachineName + 2, &pIniSpooler->pszFullMachineName);
  1598. EnterSplSem();
  1599. DECSPOOLERREF(pIniSpooler);
  1600. } else {
  1601. INCSPOOLERREF( pIniSpooler );
  1602. }
  1603. //
  1604. // Initialize the DS.
  1605. //
  1606. if (pIniSpooler->SpoolerFlags & SPL_PRINT) {
  1607. InitializeDS(pIniSpooler);
  1608. }
  1609. hReturn = (HANDLE)pIniSpooler;
  1610. SplCreateDone:
  1611. //
  1612. // Check if an error occurred while creating the spooler.
  1613. //
  1614. if (hReturn == INVALID_HANDLE_VALUE && pIniSpooler)
  1615. {
  1616. //
  1617. // This will prevent leaking allocated fields
  1618. //
  1619. DECSPOOLERREF(pIniSpooler);
  1620. }
  1621. LeaveSplSem();
  1622. if ( !pIniSpooler )
  1623. {
  1624. if (!(pSpoolerInfo2->SpoolerFlags & SPL_OPEN_EXISTING_ONLY))
  1625. {
  1626. SplLogEvent(
  1627. NULL,
  1628. LOG_ERROR,
  1629. MSG_INIT_FAILED,
  1630. FALSE,
  1631. L"Spooler",
  1632. L"SplCreateSpooler",
  1633. L"Unknown Error",
  1634. NULL
  1635. );
  1636. }
  1637. }
  1638. ImpersonatePrinterClient(hToken);
  1639. //
  1640. // Set the event that the cluster spooler is initialized
  1641. //
  1642. if (pIniSpooler &&
  1643. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  1644. pIniSpooler->hClusSplReady)
  1645. {
  1646. SetEvent(pIniSpooler->hClusSplReady);
  1647. }
  1648. return hReturn;
  1649. }
  1650. BOOL
  1651. InitializePrintProvidor(
  1652. LPPRINTPROVIDOR pPrintProvidor,
  1653. DWORD cbPrintProvidor,
  1654. LPWSTR pFullRegistryPath
  1655. )
  1656. {
  1657. HANDLE hSchedulerThread;
  1658. HANDLE hFinalInitAfterRouterInitCompleteThread;
  1659. DWORD ThreadId;
  1660. BOOL bSucceeded = TRUE;
  1661. WCHAR Buffer[MAX_PATH];
  1662. DWORD i;
  1663. PINISPOOLER pIniSpooler = NULL;
  1664. LPWSTR pMachineName = NULL;
  1665. SPOOLER_INFO_1 SpoolerInfo1;
  1666. BOOL bInSem = FALSE;
  1667. try {
  1668. if (!InitializeWinSpoolDrv())
  1669. leave;
  1670. //
  1671. // Make sure sizes of structres are good
  1672. //
  1673. SPLASSERT( sizeof( PRINTER_INFO_STRESSW ) == sizeof ( PRINTER_INFO_STRESSA ) );
  1674. // !! LATER !!
  1675. // We could change this to succeed even on failure
  1676. // if we point all the routines to a function which returns failure
  1677. //
  1678. if (!InitializeNet())
  1679. leave;
  1680. //
  1681. // JobIdMap initialized when spooler created.
  1682. //
  1683. //
  1684. // Allocate LocalSpl Global IniSpooler
  1685. //
  1686. Buffer[0] = Buffer[1] = L'\\';
  1687. i = MAX_PATH-2;
  1688. OsVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1689. OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1690. if ( !GetComputerName(Buffer+2, &i) ||
  1691. !GetVersionEx((POSVERSIONINFO)&OsVersionInfoEx) ||
  1692. !GetVersionEx(&OsVersionInfo)) {
  1693. DBGMSG(DBG_WARNING, ("GetComputerName/OSVersionInfo failed.\n"));
  1694. leave;
  1695. }
  1696. pMachineName = AllocSplStr(Buffer);
  1697. if ( pMachineName == NULL )
  1698. leave;
  1699. SpoolerInfo1.pszDriversShare = AllocSplStr(ipszDriversShareName); /* print$ */
  1700. if ( SpoolerInfo1.pszDriversShare == NULL )
  1701. leave;
  1702. // Use Defaults
  1703. SpoolerInfo1.pDir = NULL;
  1704. SpoolerInfo1.pDefaultSpoolDir = NULL;
  1705. SpoolerInfo1.pszRegistryRoot = ipszRegistryRoot;
  1706. SpoolerInfo1.pszRegistryPrinters = ipszRegSwPrinters;
  1707. SpoolerInfo1.pszRegistryMonitors = ipszRegistryMonitorsHKLM;
  1708. SpoolerInfo1.pszRegistryEnvironments = ipszRegistryEnvironments;
  1709. SpoolerInfo1.pszRegistryEventLog = ipszRegistryEventLog;
  1710. SpoolerInfo1.pszRegistryProviders = ipszRegistryProviders;
  1711. SpoolerInfo1.pszEventLogMsgFile = ipszEventLogMsgFile;
  1712. SpoolerInfo1.pszRegistryForms = ipszRegistryForms;
  1713. SpoolerInfo1.SpoolerFlags = SPL_UPDATE_WININI_DEVICES |
  1714. SPL_PRINTER_CHANGES |
  1715. SPL_LOG_EVENTS |
  1716. SPL_FORMS_CHANGE |
  1717. SPL_BROADCAST_CHANGE |
  1718. SPL_SECURITY_CHECK |
  1719. SPL_OPEN_CREATE_PORTS |
  1720. SPL_FAIL_OPEN_PRINTERS_PENDING_DELETION |
  1721. SPL_REMOTE_HANDLE_CHECK |
  1722. SPL_PRINTER_DRIVER_EVENT |
  1723. SPL_SERVER_THREAD |
  1724. SPL_PRINT |
  1725. SPL_TYPE_LOCAL;
  1726. SpoolerInfo1.pfnReadRegistryExtra = NULL;
  1727. SpoolerInfo1.pfnWriteRegistryExtra = NULL;
  1728. SpoolerInfo1.pfnFreePrinterExtra = NULL;
  1729. pLocalIniSpooler = SplCreateSpooler( pMachineName,
  1730. 1,
  1731. (PBYTE)&SpoolerInfo1,
  1732. NULL );
  1733. if ( pLocalIniSpooler == INVALID_HANDLE_VALUE ) {
  1734. DBGMSG( DBG_WARNING, ("InitializePrintProvidor Unable to allocate pLocalIniSpooler\n"));
  1735. leave;
  1736. }
  1737. pIniSpooler = pLocalIniSpooler;
  1738. #if DBG
  1739. InitializeDebug( pIniSpooler );
  1740. #endif
  1741. // !! LATER !!
  1742. // Why is this done inside critical section ?
  1743. EnterSplSem();
  1744. bInSem = TRUE;
  1745. if (!LoadString(hInst, IDS_REMOTE_DOC, Buffer, MAX_PATH))
  1746. leave;
  1747. szRemoteDoc = AllocSplStr( Buffer );
  1748. if ( szRemoteDoc == NULL )
  1749. leave;
  1750. if (!LoadString(hInst, IDS_LOCAL_DOC, Buffer, MAX_PATH))
  1751. leave;
  1752. szLocalDoc = AllocSplStr( Buffer );
  1753. if ( szLocalDoc == NULL )
  1754. leave;
  1755. if (!LoadString(hInst, IDS_FASTPRINT_TIMEOUT, Buffer, MAX_PATH))
  1756. leave;
  1757. szFastPrintTimeout = AllocSplStr( Buffer );
  1758. if ( szFastPrintTimeout == NULL )
  1759. leave;
  1760. if (!InitializeSecurityStructures())
  1761. leave;
  1762. SchedulerSignal = CreateEvent( NULL,
  1763. EVENT_RESET_AUTOMATIC,
  1764. EVENT_INITIAL_STATE_NOT_SIGNALED,
  1765. NULL );
  1766. PowerManagementSignal = CreateEvent(NULL,
  1767. EVENT_RESET_MANUAL,
  1768. EVENT_INITIAL_STATE_SIGNALED,
  1769. NULL);
  1770. hSchedulerThread = CreateThread( NULL,
  1771. INITIAL_STACK_COMMIT,
  1772. (LPTHREAD_START_ROUTINE)SchedulerThread,
  1773. pIniSpooler, 0, &ThreadId );
  1774. hFinalInitAfterRouterInitCompleteThread = CreateThread( NULL, INITIAL_STACK_COMMIT,
  1775. (LPTHREAD_START_ROUTINE)FinalInitAfterRouterInitCompleteThread,
  1776. (LPVOID)ULongToPtr(dwUpgradeFlag), 0, &ThreadId );
  1777. if (!SchedulerSignal || !PowerManagementSignal || !hSchedulerThread || !hFinalInitAfterRouterInitCompleteThread) {
  1778. DBGMSG( DBG_WARNING, ("Scheduler/FinalInitAfterRouterInitCompleteThread not initialised properly: Error %d\n", GetLastError()));
  1779. leave;
  1780. }
  1781. if ( !SetThreadPriority( hSchedulerThread, dwSchedulerThreadPriority ) ) {
  1782. DBGMSG( DBG_WARNING, ("Setting Scheduler thread priority failed %d\n", GetLastError()));
  1783. }
  1784. CloseHandle( hSchedulerThread );
  1785. CloseHandle( hFinalInitAfterRouterInitCompleteThread );
  1786. //
  1787. // Read online/offline status for local printers from current config
  1788. //
  1789. SplConfigChange();
  1790. CHECK_SCHEDULER();
  1791. CopyMemory( pPrintProvidor, &PrintProvidor, min(sizeof(PRINTPROVIDOR), cbPrintProvidor));
  1792. LeaveSplSem();
  1793. bInSem = FALSE;
  1794. CloseProfileUserMapping(); // !!! We should be able to get rid of this
  1795. if (!dwUpgradeFlag) {
  1796. // Setup Internet Printing if WWW service is available on this machine.
  1797. InstallWebPrnSvc (pIniSpooler);
  1798. }
  1799. //
  1800. // Get the default value for DefaultKMPrintersAreBlocked. It depends
  1801. // what type of OS is running. If we cannot identify the type of OS,
  1802. // the default is set to "blocked"
  1803. //
  1804. DefaultKMPrintersAreBlocked = GetDefaultForKMPrintersBlockedPolicy();
  1805. gdwServerInstallTimeOut = GetServerInstallTimeOut();
  1806. Initialized = TRUE;
  1807. } finally {
  1808. if ( bInSem ) {
  1809. LeaveSplSem();
  1810. }
  1811. }
  1812. SplOutSem();
  1813. return Initialized;
  1814. }
  1815. PINIPORT
  1816. CreatePortEntry(
  1817. LPWSTR pPortName,
  1818. PINIMONITOR pIniMonitor,
  1819. PINISPOOLER pIniSpooler
  1820. )
  1821. {
  1822. DWORD cb;
  1823. PINIPORT pIniPort = NULL;
  1824. HANDLE hPort = NULL;
  1825. HANDLE hWaitToOpenOrClose = NULL;
  1826. BOOL bPlaceHolder = FALSE;
  1827. //
  1828. // This is a placeholder if there is no monitor and later if there is no
  1829. // partial print provider.
  1830. //
  1831. bPlaceHolder = pIniMonitor == NULL;
  1832. SplInSem();
  1833. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  1834. if (!pPortName || !*pPortName || wcslen(pPortName) >= MAX_PATH) {
  1835. SetLastError(ERROR_UNKNOWN_PORT);
  1836. return NULL;
  1837. }
  1838. if (!pIniMonitor) {
  1839. /* Don't bother validating the port if we aren't initialised.
  1840. * It must be valid, since we wrote it in the registry.
  1841. * This fixes the problem of attempting to open a network
  1842. * printer before the redirector has initialised,
  1843. * and the problem of access denied because we're currently
  1844. * in the system's context.
  1845. */
  1846. if (Initialized) {
  1847. //
  1848. // !! Warning !!
  1849. //
  1850. // Watch for deadlock:
  1851. //
  1852. // spoolss!OpenPrinterPortW -> RPC to self printer port
  1853. // localspl!CreatePortEntry
  1854. // localspl!ValidatePortTokenList
  1855. // localspl!SetPrinterPorts
  1856. // localspl!LocalSetPrinter
  1857. // spoolss!SetPrinterW
  1858. // spoolss!RpcSetPrinter
  1859. // spoolss!winspool_RpcSetPrinter
  1860. //
  1861. //
  1862. // If we can't open the port then fail the call since this
  1863. // spooler did not know this name before.
  1864. //
  1865. LeaveSplSem();
  1866. if ( !OpenPrinterPortW(pPortName, &hPort, NULL) ){
  1867. EnterSplSem();
  1868. goto Cleanup;
  1869. }
  1870. else {
  1871. bPlaceHolder = FALSE;
  1872. ClosePrinter(hPort);
  1873. }
  1874. EnterSplSem();
  1875. }
  1876. }
  1877. cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR);
  1878. hWaitToOpenOrClose = CreateEvent(NULL, FALSE, TRUE, NULL);
  1879. if ( !hWaitToOpenOrClose )
  1880. goto Cleanup;
  1881. if (pIniPort=AllocSplMem(cb)) {
  1882. pIniPort->pName = wcscpy((LPWSTR)(pIniPort+1), pPortName);
  1883. pIniPort->signature = IPO_SIGNATURE;
  1884. pIniPort->pIniMonitor = pIniMonitor;
  1885. pIniPort->IdleTime = GetTickCount() - 1;
  1886. pIniPort->bIdleTimeValid = FALSE;
  1887. pIniPort->ErrorTime = 0;
  1888. pIniPort->hErrorEvent = NULL;
  1889. pIniPort->InCriticalSection = 0;
  1890. if (pIniMonitor) {
  1891. pIniPort->Status |= PP_MONITOR;
  1892. }
  1893. if (bPlaceHolder) {
  1894. pIniPort->Status |= PP_PLACEHOLDER;
  1895. }
  1896. pIniPort->hWaitToOpenOrClose = hWaitToOpenOrClose;
  1897. LinkPortToSpooler( pIniPort, pIniSpooler );
  1898. }
  1899. Cleanup:
  1900. if ( !pIniPort && hWaitToOpenOrClose )
  1901. CloseHandle(hWaitToOpenOrClose);
  1902. return pIniPort;
  1903. }
  1904. BOOL
  1905. DeletePortEntry(
  1906. PINIPORT pIniPort
  1907. )
  1908. /*++
  1909. Routine Description:
  1910. Free pIniPort resources then delete it. If the pIniPort is on
  1911. a pIniSpooler's linked list, remove it too.
  1912. Arguments:
  1913. pIniPort - Port to delete. May or may not be on a pIniSpooler.
  1914. Return Value:
  1915. TRUE - deleted
  1916. FALSE - not deleted (may be in use).
  1917. --*/
  1918. {
  1919. PINISPOOLER pIniSpooler;
  1920. SplInSem();
  1921. SPLASSERT ( ( pIniPort != NULL) || ( pIniPort->signature == IPO_SIGNATURE) );
  1922. //
  1923. // We had better already closed the port monitor.
  1924. //
  1925. SPLASSERT( !pIniPort->hPort &&
  1926. !(pIniPort->Status & PP_THREADRUNNING) &&
  1927. !pIniPort->cJobs);
  1928. if (pIniPort->cRef) {
  1929. pIniPort->Status |= PP_DELETING;
  1930. return FALSE;
  1931. }
  1932. pIniSpooler = pIniPort->pIniSpooler;
  1933. //
  1934. // If currently linked to a pIniSpooler, delink it.
  1935. //
  1936. if( pIniSpooler ){
  1937. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  1938. DelinkPortFromSpooler( pIniPort, pIniSpooler );
  1939. }
  1940. if (pIniPort->ppIniPrinter)
  1941. FreeSplMem(pIniPort->ppIniPrinter);
  1942. CloseHandle(pIniPort->hWaitToOpenOrClose);
  1943. FreeSplMem(pIniPort);
  1944. return TRUE;
  1945. }
  1946. VOID
  1947. FreeIniMonitor(
  1948. PINIMONITOR pIniMonitor
  1949. )
  1950. {
  1951. if( pIniMonitor ){
  1952. FreeSplStr( pIniMonitor->pMonitorDll );
  1953. if( pIniMonitor->hModule ){
  1954. FreeLibrary( pIniMonitor->hModule );
  1955. }
  1956. if( pIniMonitor->pMonitorInit ){
  1957. FreeSplStr( (LPWSTR)pIniMonitor->pMonitorInit->pszServerName );
  1958. if( pIniMonitor->pMonitorInit->hckRegistryRoot ){
  1959. SplRegCloseKey( pIniMonitor->pMonitorInit->hckRegistryRoot,
  1960. pIniMonitor->pIniSpooler );
  1961. }
  1962. FreeSplMem( pIniMonitor->pMonitorInit );
  1963. }
  1964. FreeSplMem( pIniMonitor );
  1965. }
  1966. }
  1967. #ifdef _SPL_CLUST
  1968. LPMONITOR2
  1969. InitializePrintMonitor2(
  1970. PMONITORINIT pMonitorInit,
  1971. PHANDLE phMonitor
  1972. )
  1973. {
  1974. return(LocalMonInitializePrintMonitor2(pMonitorInit,phMonitor));
  1975. }
  1976. #endif
  1977. PINIMONITOR
  1978. CreateMonitorEntry(
  1979. LPWSTR pMonitorDll,
  1980. LPWSTR pMonitorName,
  1981. PINISPOOLER pIniSpooler
  1982. )
  1983. /*++
  1984. Routine Description:
  1985. Arguments:
  1986. Return Value:
  1987. Valid pIniMonitor - This means everything worked out fine.
  1988. NULL - This means the monitor DLL was found, but the initialisation routine
  1989. returned FALSE. This is non-fatal, as the monitor may need the
  1990. system to reboot before it can run properly.
  1991. -1 - This means the monitor DLL or the initialization routine was not found.
  1992. --*/
  1993. {
  1994. WCHAR szRegistryRoot[MAX_PATH];
  1995. DWORD cb, cbNeeded, cReturned, dwRetVal;
  1996. PPORT_INFO_1 pPorts, pPort;
  1997. PINIMONITOR pIniMonitor;
  1998. UINT uOldErrMode;
  1999. PMONITOR2 (*pfnInitializePrintMonitor2)(PMONITORINIT, PHANDLE) = NULL;
  2000. PINIMONITOR pReturnValue = (PINIMONITOR)-1;
  2001. HANDLE hKeyOut;
  2002. LPWSTR pszPathOut;
  2003. SPLASSERT( (pIniSpooler != NULL) || (pIniSpooler->signature == ISP_SIGNATURE));
  2004. SplInSem();
  2005. cb = sizeof(INIMONITOR) + wcslen(pMonitorName)*sizeof(WCHAR) + sizeof(WCHAR);
  2006. pIniMonitor = AllocSplMem(cb);
  2007. if( !pIniMonitor ){
  2008. goto Fail;
  2009. }
  2010. pIniMonitor->pName = wcscpy((LPWSTR)(pIniMonitor+1), pMonitorName);
  2011. pIniMonitor->signature = IMO_SIGNATURE;
  2012. pIniMonitor->pMonitorDll = AllocSplStr(pMonitorDll);
  2013. pIniMonitor->pIniSpooler = pIniSpooler;
  2014. if( !pIniMonitor->pMonitorDll ){
  2015. goto Fail;
  2016. }
  2017. //
  2018. // Load the library, but don't show any hard error popups if it's an
  2019. // invalid binary.
  2020. //
  2021. INCSPOOLERREF( pIniSpooler );
  2022. LeaveSplSem();
  2023. uOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  2024. pIniMonitor->hModule = LoadLibrary(pMonitorDll);
  2025. SetErrorMode( uOldErrMode );
  2026. EnterSplSem();
  2027. DECSPOOLERREF( pIniSpooler );
  2028. if (!pIniMonitor->hModule) {
  2029. DBGMSG(DBG_WARNING, ("CreateMonitorEntry( %ws, %ws ) LoadLibrary failed %d\n",
  2030. pMonitorDll ? pMonitorDll : L"(NULL)",
  2031. pMonitorName ? pMonitorName : L"(NULL)",
  2032. GetLastError()));
  2033. goto Fail;
  2034. }
  2035. GetRegistryLocation( pIniSpooler->hckRoot,
  2036. pIniSpooler->pszRegistryMonitors,
  2037. &hKeyOut,
  2038. &pszPathOut );
  2039. dwRetVal = StrNCatBuff( szRegistryRoot,
  2040. COUNTOF(szRegistryRoot),
  2041. pszPathOut,
  2042. L"\\",
  2043. pMonitorName,
  2044. NULL );
  2045. if (dwRetVal != ERROR_SUCCESS)
  2046. {
  2047. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  2048. goto Fail;
  2049. }
  2050. //
  2051. // Try calling the entry points in the following order:
  2052. // InitializePrintMonitor2 (used for clustering),
  2053. // InitializePrintMonitor,
  2054. // InitializeMonitorEx,
  2055. // InitializeMonitor
  2056. //
  2057. (FARPROC)pfnInitializePrintMonitor2 = GetProcAddress(
  2058. pIniMonitor->hModule,
  2059. "InitializePrintMonitor2" );
  2060. if( !pfnInitializePrintMonitor2 ){
  2061. //
  2062. // If this is clustered spooler, then only InitializePrintMonitor2
  2063. // monitors are supported.
  2064. //
  2065. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  2066. goto Fail;
  2067. }
  2068. //
  2069. // Add the parth to the Monitor name here.
  2070. //
  2071. pReturnValue = InitializeDMonitor( pIniMonitor,
  2072. szRegistryRoot );
  2073. if( pReturnValue == NULL ||
  2074. pReturnValue == (PINIMONITOR)-1 ){
  2075. goto Fail;
  2076. }
  2077. } else {
  2078. PMONITORINIT pMonitorInit;
  2079. DWORD Status;
  2080. PMONITOR2 pMonitor2 = NULL;
  2081. INCSPOOLERREF( pIniSpooler );
  2082. LeaveSplSem();
  2083. //
  2084. // kKeyOut must either be not HKLM, or it must not be a cluster.
  2085. // If it is both a cluster and also uses HKLM, then we have an error.
  2086. // This should never happen because only win32spl uses an absolute
  2087. // path.
  2088. //
  2089. SPLASSERT( (hKeyOut != HKEY_LOCAL_MACHINE) ||
  2090. !(pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ));
  2091. pMonitorInit = (PMONITORINIT)AllocSplMem( sizeof( MONITORINIT ));
  2092. if( !pMonitorInit ){
  2093. goto FailOutsideSem;
  2094. }
  2095. pMonitorInit->pszServerName = AllocSplStr( pIniSpooler->pMachineName );
  2096. if( !pMonitorInit->pszServerName ){
  2097. goto FailOutsideSem;
  2098. }
  2099. pMonitorInit->cbSize = sizeof( MONITORINIT );
  2100. pMonitorInit->hSpooler = (HANDLE)pIniSpooler;
  2101. pMonitorInit->pMonitorReg = &gMonitorReg;
  2102. pMonitorInit->bLocal = ( pIniSpooler == pLocalIniSpooler );
  2103. pIniMonitor->pMonitorInit = pMonitorInit;
  2104. Status = SplRegCreateKey( hKeyOut,
  2105. szRegistryRoot,
  2106. 0,
  2107. KEY_ALL_ACCESS,
  2108. NULL,
  2109. &pMonitorInit->hckRegistryRoot,
  2110. NULL,
  2111. pIniSpooler );
  2112. //
  2113. // If we can't create the hck root key, then fail
  2114. // the call. We should log an event here too.
  2115. //
  2116. if( Status == ERROR_SUCCESS ){
  2117. pMonitor2 = (*pfnInitializePrintMonitor2)(
  2118. pMonitorInit,
  2119. &pIniMonitor->hMonitor );
  2120. if( pMonitor2 ){
  2121. DBGMSG( DBG_TRACE,
  2122. ( "CreateMonitorEntry: opened %x %x on %x\n",
  2123. pIniMonitor, pIniMonitor->hMonitor, pIniSpooler ));
  2124. //
  2125. // Succeeded, copy over the pMonitor2 structure into
  2126. // pIniMonitor->Monitor2.
  2127. //
  2128. CopyMemory((LPBYTE)&pIniMonitor->Monitor2,
  2129. (LPBYTE)pMonitor2,
  2130. min(pMonitor2->cbSize, sizeof(MONITOR2)));
  2131. //
  2132. // Check if the monitor2 supports Shutdown.
  2133. //
  2134. // Raid#: 193150 - Accept any size Monitor2 as long as it supports Shutdown
  2135. //
  2136. if( !pIniMonitor->Monitor2.pfnShutdown ){
  2137. DBGMSG( DBG_ERROR,
  2138. ( "Invalid print monitor %ws (no shutdown)\n",
  2139. pMonitorName ));
  2140. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  2141. DECSPOOLERREF( pIniSpooler );
  2142. goto FailOutsideSem;
  2143. }
  2144. //
  2145. // Initialize an uplevel monitor for downlevel support.
  2146. //
  2147. InitializeUMonitor( pIniMonitor );
  2148. } else {
  2149. DBGMSG( DBG_WARN,
  2150. ( "CreateMonitorEntry: InitializePrintMonitor2 failed %d\n",
  2151. GetLastError() ));
  2152. }
  2153. } else {
  2154. DBGMSG( DBG_WARN,
  2155. ( "CreateMonitorEntry: Unable to create hckRoot "TSTR"\n",
  2156. pMonitorName ));
  2157. }
  2158. EnterSplSem();
  2159. DECSPOOLERREF( pIniSpooler );
  2160. if( !pMonitor2 ){
  2161. goto Fail;
  2162. }
  2163. pIniMonitor->bUplevel = TRUE;
  2164. }
  2165. //
  2166. // Check if the monitor supports essential functions
  2167. //
  2168. if ( (!pIniMonitor->Monitor2.pfnOpenPort &&
  2169. !pIniMonitor->Monitor2.pfnOpenPortEx) ||
  2170. !pIniMonitor->Monitor2.pfnClosePort ||
  2171. !pIniMonitor->Monitor2.pfnStartDocPort ||
  2172. !pIniMonitor->Monitor2.pfnWritePort ||
  2173. !pIniMonitor->Monitor2.pfnReadPort ||
  2174. !pIniMonitor->Monitor2.pfnEndDocPort ) {
  2175. DBGMSG(DBG_ERROR, ("Invalid print monitor %ws\n", pMonitorName));
  2176. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  2177. goto Fail;
  2178. }
  2179. if (FindMonitor(pMonitorName, pIniSpooler)) {
  2180. SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
  2181. goto Fail;
  2182. }
  2183. if ((pIniMonitor->Monitor2.pfnEnumPorts) &&
  2184. !(*pIniMonitor->Monitor2.pfnEnumPorts)(
  2185. pIniMonitor->hMonitor,
  2186. NULL,
  2187. 1,
  2188. NULL,
  2189. 0,
  2190. &cbNeeded,
  2191. &cReturned)) {
  2192. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  2193. if (pPorts = AllocSplMem(cbNeeded)) {
  2194. pPort = pPorts;
  2195. if ((*pIniMonitor->Monitor2.pfnEnumPorts)(
  2196. pIniMonitor->hMonitor,
  2197. NULL,
  2198. 1,
  2199. (LPBYTE)pPorts,
  2200. cbNeeded,
  2201. &cbNeeded,
  2202. &cReturned)) {
  2203. while (cReturned--) {
  2204. CreatePortEntry(pPort->pName,
  2205. pIniMonitor,
  2206. pIniSpooler);
  2207. pPort++;
  2208. }
  2209. }
  2210. FreeSplMem(pPorts);
  2211. }
  2212. }
  2213. }
  2214. DBGMSG(DBG_TRACE, ("CreateMonitorEntry( %ws, %ws, %ws ) returning %x\n",
  2215. pMonitorDll ? pMonitorDll : L"(NULL)",
  2216. pMonitorName ? pMonitorName : L"(NULL)",
  2217. szRegistryRoot, pIniMonitor));
  2218. SplInSem();
  2219. //
  2220. // Success, link it up.
  2221. //
  2222. pIniMonitor->pNext = pIniSpooler->pIniMonitor;
  2223. pIniSpooler->pIniMonitor = pIniMonitor;
  2224. return pIniMonitor;
  2225. FailOutsideSem:
  2226. EnterSplSem();
  2227. Fail:
  2228. FreeIniMonitor( pIniMonitor );
  2229. return pReturnValue;
  2230. }
  2231. BOOL
  2232. BuildAllPorts(
  2233. PINISPOOLER pIniSpooler
  2234. )
  2235. {
  2236. DWORD cchData, cbDll, cMonitors;
  2237. WCHAR Dll[MAX_PATH];
  2238. WCHAR MonitorName[MAX_PATH];
  2239. WCHAR RegistryPath[MAX_PATH];
  2240. HKEY hKey, hKey1, hKeyOut;
  2241. LPWSTR pszPathOut;
  2242. LONG Status;
  2243. PINIMONITOR pReturnValue = (PINIMONITOR)-1;
  2244. PINISPOOLER pIniSpoolerMonitor;
  2245. //
  2246. // For pLocalIniSpooler or clustered spooler, read the monitors out
  2247. // of HKLM (the same monitors used in pLocalIniMonitor). This is because
  2248. // you install a monitor for each node, then that monitor is initialized
  2249. // for the local spooler and all clustered spoolers.
  2250. //
  2251. // You install monitors on the node, not on specific cluster groups.
  2252. //
  2253. if( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ){
  2254. pIniSpoolerMonitor = pLocalIniSpooler;
  2255. } else {
  2256. pIniSpoolerMonitor = pIniSpooler;
  2257. }
  2258. GetRegistryLocation( pIniSpoolerMonitor->hckRoot,
  2259. pIniSpooler->pszRegistryMonitors,
  2260. &hKeyOut,
  2261. &pszPathOut );
  2262. Status = RegOpenKeyEx( hKeyOut,
  2263. pszPathOut,
  2264. 0,
  2265. KEY_READ,
  2266. &hKey);
  2267. if (Status != ERROR_SUCCESS)
  2268. return FALSE;
  2269. cMonitors=0;
  2270. cchData = COUNTOF( MonitorName );
  2271. while (RegEnumKeyEx(hKey, cMonitors, MonitorName, &cchData, NULL, NULL,
  2272. NULL, NULL) == ERROR_SUCCESS) {
  2273. DBGMSG(DBG_TRACE, ("Found monitor %ws\n", MonitorName));
  2274. if (RegOpenKeyEx(hKey, MonitorName, 0, KEY_READ, &hKey1)
  2275. == ERROR_SUCCESS) {
  2276. cbDll = sizeof(Dll);
  2277. if (RegQueryValueEx(hKey1, L"Driver", NULL, NULL,
  2278. (LPBYTE)Dll, &cbDll)
  2279. == ERROR_SUCCESS) {
  2280. CreateMonitorEntry(Dll, MonitorName, pIniSpooler);
  2281. }
  2282. RegCloseKey(hKey1);
  2283. }
  2284. cMonitors++;
  2285. cchData = COUNTOF( MonitorName );
  2286. }
  2287. RegCloseKey(hKey);
  2288. return TRUE;
  2289. }
  2290. /*
  2291. Current Directory == <NT directory>\system32\spool\printers
  2292. pFindFileData->cFileName == 0
  2293. */
  2294. BOOL
  2295. BuildPrinterInfo(
  2296. PINISPOOLER pIniSpooler,
  2297. BOOL UpdateChangeID
  2298. )
  2299. {
  2300. WCHAR PrinterName[MAX_PRINTER_NAME];
  2301. WCHAR szData[MAX_PATH];
  2302. WCHAR szDefaultPrinterDirectory[MAX_PATH];
  2303. DWORD cbData, i;
  2304. DWORD cbSecurity, dwLastError;
  2305. DWORD cPrinters, Type;
  2306. HKEY hPrinterKey;
  2307. PINIPRINTER pIniPrinter;
  2308. PINIPORT pIniPort;
  2309. LONG Status;
  2310. SECURITY_ATTRIBUTES SecurityAttributes;
  2311. PKEYDATA pKeyData = NULL;
  2312. BOOL bUpdateRegistryForThisPrinter = UpdateChangeID;
  2313. BOOL bWriteDirectory = FALSE;
  2314. BOOL bAllocMem = FALSE;
  2315. BOOL bNoPorts = FALSE;
  2316. LPWSTR szPortData;
  2317. //
  2318. // Has user specified Default Spool Directory ?
  2319. //
  2320. cbData = sizeof( szData );
  2321. *szData = (WCHAR)0;
  2322. Status = SplRegQueryValue( pIniSpooler->hckPrinters,
  2323. SPLREG_DEFAULT_SPOOL_DIRECTORY,
  2324. NULL,
  2325. (LPBYTE)szData,
  2326. &cbData,
  2327. pIniSpooler );
  2328. if (Status == ERROR_SUCCESS) { // found a value, so verify the directory
  2329. if (!(pIniSpooler->pDefaultSpoolDir = AllocSplStr( szData ))) // Copies szData to pDefaultSpoolDir
  2330. return FALSE;
  2331. } else {
  2332. bWriteDirectory = TRUE; // No registry directory, so create one
  2333. }
  2334. // Copy pDefaultSpoolDir to szDefaultPrinterDirectory
  2335. GetPrinterDirectory(NULL, FALSE, szDefaultPrinterDirectory, COUNTOF(szDefaultPrinterDirectory), pIniSpooler);
  2336. if (!pIniSpooler->pDefaultSpoolDir)
  2337. return FALSE;
  2338. // Create the directory with the proper security, or fail trying
  2339. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  2340. SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
  2341. SecurityAttributes.bInheritHandle = FALSE;
  2342. //
  2343. // CreateDirectory limits the length of a directory to 248 (MAX_PATH-12)
  2344. // characters. By calculating the length, we ensure that an escape sequence
  2345. // will not lead to the creation of a directory with a name longer than 248
  2346. //
  2347. if (wcslen(szDefaultPrinterDirectory) > MAX_PATH - 12 ||
  2348. !CreateDirectory(szDefaultPrinterDirectory, &SecurityAttributes)) {
  2349. // Failed to create the directory? Back to factory default
  2350. bWriteDirectory = TRUE;
  2351. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  2352. //
  2353. // In the clustered case, just fail.
  2354. //
  2355. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  2356. return FALSE;
  2357. }
  2358. DBGMSG(DBG_WARNING, ("Failed to create DefaultSpoolDirectory %ws\n", szDefaultPrinterDirectory));
  2359. FreeSplStr(pIniSpooler->pDefaultSpoolDir);
  2360. pIniSpooler->pDefaultSpoolDir = NULL; // This tells GetPrinterDirectory to alloc pDefaultSpoolDir
  2361. GetPrinterDirectory(NULL, FALSE, szDefaultPrinterDirectory, COUNTOF(szDefaultPrinterDirectory), pIniSpooler);
  2362. if (!pIniSpooler->pDefaultSpoolDir)
  2363. return FALSE;
  2364. Status = CreateDirectory(szDefaultPrinterDirectory, &SecurityAttributes);
  2365. if (Status != ERROR_SUCCESS && Status != ERROR_ALREADY_EXISTS) {
  2366. DBGMSG(DBG_WARNING, ("Failed to create DefaultSpoolDirectory %ws\n", szDefaultPrinterDirectory));
  2367. FreeSplStr(pIniSpooler->pDefaultSpoolDir);
  2368. pIniSpooler->pDefaultSpoolDir = NULL;
  2369. return FALSE;
  2370. }
  2371. }
  2372. }
  2373. LocalFree(SecurityAttributes.lpSecurityDescriptor);
  2374. if (bWriteDirectory) {
  2375. Status = SetPrinterDataServer( pIniSpooler,
  2376. SPLREG_DEFAULT_SPOOL_DIRECTORY,
  2377. REG_SZ,
  2378. (LPBYTE) pIniSpooler->pDefaultSpoolDir,
  2379. wcslen(pIniSpooler->pDefaultSpoolDir)*sizeof(WCHAR) + sizeof(WCHAR));
  2380. }
  2381. cPrinters=0;
  2382. cbData = COUNTOF(PrinterName);
  2383. while( SplRegEnumKey( pIniSpooler->hckPrinters,
  2384. cPrinters,
  2385. PrinterName,
  2386. &cbData,
  2387. NULL,
  2388. pIniSpooler ) == ERROR_SUCCESS) {
  2389. DBGMSG(DBG_TRACE, ("Found printer %ws\n", PrinterName));
  2390. if( SplRegCreateKey( pIniSpooler->hckPrinters,
  2391. PrinterName,
  2392. 0,
  2393. KEY_READ,
  2394. NULL,
  2395. &hPrinterKey,
  2396. NULL,
  2397. pIniSpooler ) == ERROR_SUCCESS ){
  2398. if ( pIniPrinter = AllocSplMem(sizeof(INIPRINTER) )) {
  2399. //
  2400. // Reference count the pIniSpooler.
  2401. //
  2402. INCSPOOLERREF( pIniSpooler );
  2403. DbgPrinterInit( pIniPrinter );
  2404. pIniPrinter->signature = IP_SIGNATURE;
  2405. GetSystemTime( &pIniPrinter->stUpTime );
  2406. // Give the printer a unique session ID to pass around in notifications
  2407. pIniPrinter->dwUniqueSessionID = dwUniquePrinterSessionID++;
  2408. cbData = sizeof(szData);
  2409. *szData = (WCHAR)0;
  2410. if (SplRegQueryValue(hPrinterKey,
  2411. szName,
  2412. NULL,
  2413. (LPBYTE)szData,
  2414. &cbData,
  2415. pIniSpooler) == ERROR_SUCCESS)
  2416. pIniPrinter->pName = AllocSplStr(szData);
  2417. //
  2418. // Get Spool Directory for this printer
  2419. //
  2420. cbData = sizeof(szData);
  2421. *szData = (WCHAR)0;
  2422. if (SplRegQueryValue( hPrinterKey,
  2423. szSpoolDir,
  2424. &Type,
  2425. (LPBYTE)szData,
  2426. &cbData,
  2427. pIniSpooler) == ERROR_SUCCESS) {
  2428. if ( *szData != (WCHAR)0 ) {
  2429. pIniPrinter->pSpoolDir = AllocSplStr(szData);
  2430. }
  2431. }
  2432. //
  2433. // Get ObjectGUID for this printer
  2434. //
  2435. cbData = sizeof(szData);
  2436. *szData = (WCHAR)0;
  2437. if (SplRegQueryValue( hPrinterKey,
  2438. szObjectGUID,
  2439. &Type,
  2440. (LPBYTE)szData,
  2441. &cbData,
  2442. pIniSpooler) == ERROR_SUCCESS) {
  2443. if ( *szData != (WCHAR)0 ) {
  2444. pIniPrinter->pszObjectGUID = AllocSplStr(szData);
  2445. }
  2446. }
  2447. //
  2448. // Get DsKeyUpdate and DsKeyUpdateForeground for this printer
  2449. //
  2450. cbData = sizeof(pIniPrinter->DsKeyUpdate );
  2451. SplRegQueryValue( hPrinterKey,
  2452. szDsKeyUpdate,
  2453. &Type,
  2454. (LPBYTE) &pIniPrinter->DsKeyUpdate,
  2455. &cbData,
  2456. pIniSpooler);
  2457. cbData = sizeof(pIniPrinter->DsKeyUpdateForeground );
  2458. SplRegQueryValue( hPrinterKey,
  2459. szDsKeyUpdateForeground,
  2460. &Type,
  2461. (LPBYTE) &pIniPrinter->DsKeyUpdateForeground,
  2462. &cbData,
  2463. pIniSpooler);
  2464. if ( !(pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE) ) {
  2465. // We make sure that DsKeyUpdateForeground is consistent
  2466. // when the spooler startsup. Otherwise DsKeyUpdateForeground might be
  2467. // set without dwAction being set and the printer will always be in the
  2468. // IO_PENDING state.
  2469. if (pIniPrinter->DsKeyUpdateForeground & (DS_KEY_PUBLISH | DS_KEY_REPUBLISH | DS_KEY_UNPUBLISH)) {
  2470. if (pIniPrinter->DsKeyUpdateForeground & DS_KEY_PUBLISH) {
  2471. pIniPrinter->dwAction |= DSPRINT_PUBLISH;
  2472. } else if (pIniPrinter->DsKeyUpdateForeground & DS_KEY_REPUBLISH) {
  2473. pIniPrinter->dwAction |= DSPRINT_REPUBLISH;
  2474. } else if (pIniPrinter->DsKeyUpdateForeground & DS_KEY_UNPUBLISH) {
  2475. pIniPrinter->dwAction |= DSPRINT_UNPUBLISH;
  2476. }
  2477. pIniPrinter->DsKeyUpdateForeground &= ~(DS_KEY_PUBLISH | DS_KEY_REPUBLISH | DS_KEY_UNPUBLISH);
  2478. } else {
  2479. pIniPrinter->DsKeyUpdateForeground = 0;
  2480. }
  2481. } else {
  2482. //
  2483. // For connections, dwAction is read from registry. It is updated by
  2484. // caching code with the value on the server.
  2485. //
  2486. cbData = sizeof(pIniPrinter->dwAction);
  2487. SplRegQueryValue( hPrinterKey,
  2488. szAction,
  2489. &Type,
  2490. (LPBYTE) &pIniPrinter->dwAction,
  2491. &cbData,
  2492. pIniSpooler);
  2493. }
  2494. // Make Certain this Printers Printer directory exists
  2495. // with correct security
  2496. if ((pIniPrinter->pSpoolDir) &&
  2497. (wcscmp(pIniPrinter->pSpoolDir, szDefaultPrinterDirectory) != 0)) {
  2498. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  2499. SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
  2500. SecurityAttributes.bInheritHandle = FALSE;
  2501. if (!CreateDirectory(pIniPrinter->pSpoolDir, &SecurityAttributes)) {
  2502. // Failed to Create the Directory, revert back
  2503. // to the default
  2504. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  2505. DBGMSG(DBG_WARNING, ("Could not create printer spool directory %ws %d\n",
  2506. pIniPrinter->pSpoolDir, GetLastError() ));
  2507. pIniPrinter->pSpoolDir = NULL;
  2508. }
  2509. }
  2510. LocalFree(SecurityAttributes.lpSecurityDescriptor);
  2511. }
  2512. cbData = sizeof(szData);
  2513. *szData = (WCHAR)0;
  2514. if (SplRegQueryValue( hPrinterKey,
  2515. szShare,
  2516. &Type,
  2517. (LPBYTE)szData,
  2518. &cbData,
  2519. pIniSpooler) == ERROR_SUCCESS)
  2520. pIniPrinter->pShareName = AllocSplStr(szData);
  2521. cbData = sizeof(szData);
  2522. *szData = (WCHAR)0;
  2523. dwLastError = SplRegQueryValue( hPrinterKey,
  2524. szPort,
  2525. &Type,
  2526. (LPBYTE)szData,
  2527. &cbData,
  2528. pIniSpooler );
  2529. if ((dwLastError == ERROR_MORE_DATA) &&
  2530. (szPortData = AllocSplMem(cbData)))
  2531. {
  2532. bAllocMem = TRUE;
  2533. dwLastError = SplRegQueryValue( hPrinterKey,
  2534. szPort,
  2535. &Type,
  2536. (LPBYTE)szPortData,
  2537. &cbData,
  2538. pIniSpooler );
  2539. }
  2540. else
  2541. {
  2542. bAllocMem = FALSE;
  2543. szPortData = szData;
  2544. }
  2545. if (dwLastError == ERROR_SUCCESS)
  2546. {
  2547. if (pKeyData = CreateTokenList(szPortData)) {
  2548. if (!ValidatePortTokenList( pKeyData, pIniSpooler, TRUE, &bNoPorts)) {
  2549. LogFatalPortError(pIniSpooler, pIniPrinter->pName);
  2550. FreePortTokenList(pKeyData);
  2551. pKeyData = NULL;
  2552. } else {
  2553. //
  2554. // If there are no ports on the printer, just log
  2555. // a warning message, but only for pooled printers.
  2556. //
  2557. if (bNoPorts && pKeyData->cTokens > 1) {
  2558. SplLogEvent( pIniSpooler,
  2559. LOG_WARNING,
  2560. MSG_NO_PORT_FOUND_FOR_PRINTER,
  2561. TRUE,
  2562. pIniPrinter->pName,
  2563. szPortData,
  2564. NULL );
  2565. }
  2566. pIniPrinter->ppIniPorts = AllocSplMem(pKeyData->cTokens * sizeof(PINIPORT));
  2567. }
  2568. }
  2569. }
  2570. if (bAllocMem)
  2571. {
  2572. FreeSplMem(szPortData);
  2573. szPortData = NULL;
  2574. }
  2575. cbData = sizeof(szData);
  2576. *szData = (WCHAR)0;
  2577. if (SplRegQueryValue( hPrinterKey,
  2578. szPrintProcessor,
  2579. &Type,
  2580. (LPBYTE)szData,
  2581. &cbData,
  2582. pIniSpooler ) == ERROR_SUCCESS)
  2583. {
  2584. //
  2585. // We are trying to find the environment relative to the pIniSpooler.
  2586. // The local spooler and cluster spoolers do not share the same
  2587. // environment strucutres anymore
  2588. //
  2589. PINIENVIRONMENT pIniEnv;
  2590. if (pIniEnv = FindEnvironment(szEnvironment, pIniSpooler))
  2591. {
  2592. pIniPrinter->pIniPrintProc = FindPrintProc(szData, pIniEnv);
  2593. }
  2594. }
  2595. cbData = sizeof(szData);
  2596. *szData = (WCHAR)0;
  2597. if (SplRegQueryValue( hPrinterKey,
  2598. szDatatype,
  2599. &Type,
  2600. (LPBYTE)szData,
  2601. &cbData,
  2602. pIniSpooler ) == ERROR_SUCCESS)
  2603. pIniPrinter->pDatatype = AllocSplStr(szData);
  2604. cbData = sizeof(szData);
  2605. *szData = (WCHAR)0;
  2606. if (SplRegQueryValue( hPrinterKey,
  2607. szDriver,
  2608. &Type,
  2609. (LPBYTE)szData,
  2610. &cbData,
  2611. pIniSpooler ) == ERROR_SUCCESS) {
  2612. pIniPrinter->pIniDriver = (PINIDRIVER)FindLocalDriver(pIniSpooler, szData);
  2613. if (!pIniPrinter->pIniDriver)
  2614. {
  2615. //
  2616. // The hosting node of the cluster spooler was upgraded to Whistler.
  2617. //
  2618. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  2619. pIniSpooler->dwClusNodeUpgraded &&
  2620. //
  2621. // The driver was not found in the cluster spooler, not on the cluster disk.
  2622. // We attempt to install the driver from the local spooler to our cluster
  2623. // spooler. This will get the driver files on the cluster disk.
  2624. //
  2625. AddLocalDriverToClusterSpooler(szData, pIniSpooler) == ERROR_SUCCESS)
  2626. {
  2627. //
  2628. // Search again for the driver that must have been added
  2629. //
  2630. pIniPrinter->pIniDriver = (PINIDRIVER)FindLocalDriver(pIniSpooler, szData);
  2631. }
  2632. }
  2633. if (!pIniPrinter->pIniDriver)
  2634. {
  2635. SplLogEvent(pLocalIniSpooler,
  2636. LOG_ERROR,
  2637. MSG_NO_DRIVER_FOUND_FOR_PRINTER,
  2638. TRUE,
  2639. pIniPrinter->pName,
  2640. szData,
  2641. NULL);
  2642. }
  2643. }
  2644. cbData = sizeof(szData);
  2645. *szData = (WCHAR)0;
  2646. if (SplRegQueryValue( hPrinterKey,
  2647. szLocation,
  2648. &Type,
  2649. (LPBYTE)szData,
  2650. &cbData,
  2651. pIniSpooler ) == ERROR_SUCCESS)
  2652. pIniPrinter->pLocation = AllocSplStr(szData);
  2653. cbData = sizeof(szData);
  2654. *szData = (WCHAR)0;
  2655. if (SplRegQueryValue( hPrinterKey,
  2656. szDescription,
  2657. &Type,
  2658. (LPBYTE)szData,
  2659. &cbData, pIniSpooler ) == ERROR_SUCCESS)
  2660. pIniPrinter->pComment = AllocSplStr(szData);
  2661. cbData = sizeof(szData);
  2662. *szData = (WCHAR)0;
  2663. if (SplRegQueryValue( hPrinterKey,
  2664. szParameters,
  2665. &Type,
  2666. (LPBYTE)szData,
  2667. &cbData, pIniSpooler ) == ERROR_SUCCESS)
  2668. pIniPrinter->pParameters = AllocSplStr(szData);
  2669. cbData = sizeof(szData);
  2670. *szData = (WCHAR)0;
  2671. if (SplRegQueryValue( hPrinterKey,
  2672. szSepFile,
  2673. &Type,
  2674. (LPBYTE)szData,
  2675. &cbData, pIniSpooler ) == ERROR_SUCCESS)
  2676. pIniPrinter->pSepFile = AllocSplStr(szData);
  2677. cbData = sizeof(pIniPrinter->Attributes);
  2678. SplRegQueryValue( hPrinterKey,
  2679. szAttributes,
  2680. NULL,
  2681. (LPBYTE)&pIniPrinter->Attributes,
  2682. &cbData,
  2683. pIniSpooler );
  2684. cbData = sizeof(pIniPrinter->Status);
  2685. Status = SplRegQueryValue( hPrinterKey,
  2686. szStatus,
  2687. &Type,
  2688. (LPBYTE)&pIniPrinter->Status,
  2689. &cbData,
  2690. pIniSpooler );
  2691. pIniPrinter->Status |= PRINTER_FROM_REG;
  2692. if ( Status == ERROR_SUCCESS ) {
  2693. pIniPrinter->Status &= ( PRINTER_PAUSED |
  2694. PRINTER_PENDING_DELETION |
  2695. PRINTER_ZOMBIE_OBJECT |
  2696. PRINTER_FROM_REG |
  2697. PRINTER_OK |
  2698. PRINTER_PENDING_CREATION );
  2699. } else {
  2700. pIniPrinter->Status |= PRINTER_PENDING_CREATION ;
  2701. }
  2702. // Half formed printers should be deleted
  2703. // before they cause us trouble
  2704. if ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) {
  2705. pIniPrinter->Status |= PRINTER_PENDING_DELETION ;
  2706. }
  2707. cbData = sizeof(pIniPrinter->Priority);
  2708. SplRegQueryValue( hPrinterKey,
  2709. szPriority,
  2710. &Type,
  2711. (LPBYTE)&pIniPrinter->Priority,
  2712. &cbData,
  2713. pIniSpooler );
  2714. cbData = sizeof(pIniPrinter->DefaultPriority);
  2715. SplRegQueryValue( hPrinterKey,
  2716. szDefaultPriority,
  2717. &Type,
  2718. (LPBYTE)&pIniPrinter->DefaultPriority,
  2719. &cbData,
  2720. pIniSpooler );
  2721. cbData = sizeof(pIniPrinter->UntilTime);
  2722. SplRegQueryValue( hPrinterKey,
  2723. szUntilTime,
  2724. &Type,
  2725. (LPBYTE)&pIniPrinter->UntilTime,
  2726. &cbData,
  2727. pIniSpooler );
  2728. cbData = sizeof(pIniPrinter->StartTime);
  2729. SplRegQueryValue( hPrinterKey,
  2730. szStartTime,
  2731. &Type,
  2732. (LPBYTE)&pIniPrinter->StartTime,
  2733. &cbData,
  2734. pIniSpooler );
  2735. cbData = sizeof(pIniPrinter->dnsTimeout);
  2736. if ( SplRegQueryValue( hPrinterKey,
  2737. szDNSTimeout,
  2738. &Type,
  2739. (LPBYTE)&pIniPrinter->dnsTimeout,
  2740. &cbData,
  2741. pIniSpooler ) != ERROR_SUCCESS ) {
  2742. pIniPrinter->dnsTimeout = DEFAULT_DNS_TIMEOUT;
  2743. }
  2744. cbData = sizeof(pIniPrinter->txTimeout);
  2745. if ( SplRegQueryValue( hPrinterKey,
  2746. szTXTimeout,
  2747. &Type,
  2748. (LPBYTE)&pIniPrinter->txTimeout,
  2749. &cbData,
  2750. pIniSpooler ) != ERROR_SUCCESS ) {
  2751. pIniPrinter->txTimeout = DEFAULT_TX_TIMEOUT;
  2752. }
  2753. cbData = sizeof( pIniPrinter->cChangeID ) ;
  2754. if ( SplRegQueryValue( hPrinterKey,
  2755. szTimeLastChange,
  2756. &Type,
  2757. (LPBYTE)&pIniPrinter->cChangeID,
  2758. &cbData,
  2759. pIniSpooler ) != ERROR_SUCCESS ) {
  2760. // Current Registry Doesn't have a UniqueID
  2761. // Make sure one gets written
  2762. bUpdateRegistryForThisPrinter = TRUE;
  2763. }
  2764. pIniPrinter->dwPrivateFlag = 0;
  2765. pIniPrinter->cbDevMode = 0;
  2766. pIniPrinter->pDevMode = NULL;
  2767. if (SplRegQueryValue( hPrinterKey,
  2768. szDevMode,
  2769. &Type,
  2770. NULL,
  2771. &pIniPrinter->cbDevMode,
  2772. pIniSpooler ) == ERROR_SUCCESS) {
  2773. if (pIniPrinter->cbDevMode) {
  2774. pIniPrinter->pDevMode = AllocSplMem(pIniPrinter->cbDevMode);
  2775. SplRegQueryValue( hPrinterKey,
  2776. szDevMode,
  2777. &Type,
  2778. (LPBYTE)pIniPrinter->pDevMode,
  2779. &pIniPrinter->cbDevMode,
  2780. pIniSpooler );
  2781. }
  2782. }
  2783. //
  2784. // A Provider might want to Read Extra Data from Registry
  2785. //
  2786. if ( pIniSpooler->pfnReadRegistryExtra != NULL ) {
  2787. pIniPrinter->pExtraData = (LPBYTE)(*pIniSpooler->pfnReadRegistryExtra)(hPrinterKey);
  2788. }
  2789. /* SECURITY */
  2790. Status = SplRegQueryValue( hPrinterKey,
  2791. szSecurity,
  2792. NULL,
  2793. NULL,
  2794. &cbSecurity,
  2795. pIniSpooler );
  2796. if ((Status == ERROR_MORE_DATA) || (Status == ERROR_SUCCESS)) {
  2797. /* Use the process' heap to allocate security descriptors,
  2798. * so that they can be passed to the security API, which
  2799. * may need to reallocate them.
  2800. */
  2801. if (pIniPrinter->pSecurityDescriptor =
  2802. LocalAlloc(0, cbSecurity)) {
  2803. if (Status = SplRegQueryValue( hPrinterKey,
  2804. szSecurity,
  2805. NULL,
  2806. pIniPrinter->pSecurityDescriptor,
  2807. &cbSecurity,
  2808. pIniSpooler ) != ERROR_SUCCESS) {
  2809. LocalFree(pIniPrinter->pSecurityDescriptor);
  2810. pIniPrinter->pSecurityDescriptor = NULL;
  2811. DBGMSG( DBG_WARNING,
  2812. ( "RegQueryValue returned %d on Permissions for %ws (%ws)\n",
  2813. Status,
  2814. pIniPrinter->pName ?
  2815. pIniPrinter->pName :
  2816. szNull,
  2817. PrinterName) );
  2818. }
  2819. }
  2820. } else {
  2821. pIniPrinter->pSecurityDescriptor = NULL;
  2822. DBGMSG( DBG_WARNING,
  2823. ( "RegQueryValue (2) returned %d on Permissions for %ws (%ws)\n",
  2824. Status,
  2825. pIniPrinter->pName ?
  2826. pIniPrinter->pName :
  2827. szNull,
  2828. PrinterName) );
  2829. }
  2830. pIniPrinter->MasqCache.bThreadRunning = FALSE;
  2831. pIniPrinter->MasqCache.cJobs = 0;
  2832. pIniPrinter->MasqCache.Status = 0;
  2833. pIniPrinter->MasqCache.dwError = ERROR_SUCCESS;
  2834. /* END SECURITY */
  2835. if ( pIniPrinter->pName &&
  2836. pIniPrinter->pShareName &&
  2837. pKeyData &&
  2838. pIniPrinter->ppIniPorts &&
  2839. pIniPrinter->pIniPrintProc &&
  2840. pIniPrinter->pIniDriver &&
  2841. pIniPrinter->pLocation &&
  2842. pIniPrinter->pComment &&
  2843. pIniPrinter->pSecurityDescriptor
  2844. #if DBG
  2845. && ( IsValidSecurityDescriptor (pIniPrinter->pSecurityDescriptor)
  2846. ? TRUE
  2847. : (DBGMSG( DBG_SECURITY,
  2848. ( "The security descriptor for %ws (%ws) is invalid\n",
  2849. pIniPrinter->pName ?
  2850. pIniPrinter->pName :
  2851. szNull,
  2852. PrinterName)), /* (sequential evaluation) */
  2853. FALSE) )
  2854. #endif /* DBG */
  2855. ) {
  2856. pIniPrinter->pIniFirstJob = pIniPrinter->pIniLastJob = NULL;
  2857. pIniPrinter->pIniPrintProc->cRef++;
  2858. INCDRIVERREF( pIniPrinter->pIniDriver );
  2859. for (i=0; i<pKeyData->cTokens; i++) {
  2860. pIniPort = (PINIPORT)pKeyData->pTokens[i];
  2861. pIniPrinter->ppIniPorts[i] = pIniPort;
  2862. pIniPort->ppIniPrinter =
  2863. ReallocSplMem(pIniPort->ppIniPrinter,
  2864. pIniPort->cPrinters *
  2865. sizeof(pIniPort->ppIniPrinter),
  2866. (pIniPort->cPrinters+1) *
  2867. sizeof(pIniPort->ppIniPrinter));
  2868. if (!pIniPort->ppIniPrinter) {
  2869. DBGMSG(DBG_WARNING, ("Failed to allocate memory for printer info\n." ));
  2870. }
  2871. pIniPort->ppIniPrinter[pIniPort->cPrinters] =
  2872. pIniPrinter;
  2873. //
  2874. // With the new monitors localspl does the
  2875. // redirection for LPT, COM ports
  2876. //
  2877. if ( !pIniPort->cPrinters++ )
  2878. CreateRedirectionThread(pIniPort);
  2879. }
  2880. pIniPrinter->cPorts = pKeyData->cTokens;
  2881. pIniPrinter->Priority =
  2882. pIniPrinter->Priority ? pIniPrinter->Priority
  2883. : DEF_PRIORITY;
  2884. if ((pIniPrinter->Attributes &
  2885. (PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT)) ==
  2886. (PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT))
  2887. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_DIRECT;
  2888. //
  2889. // I f we're upgrading, fix the NT4 bug that broke Masc printers.
  2890. // UpdateChangeID is passed into us as dwUpgradeFlag, so it determines
  2891. // if we're in an upgrade state.
  2892. //
  2893. // The rules: Printer name starts with \\
  2894. // Port Name starts with \\
  2895. // It's on a local IniSpooler.
  2896. // The NETWORK and LOCAL bits are not set.
  2897. //
  2898. // If all the rules are met, set the NETWORK and LOCAL bits so the printer
  2899. // will behave properly.
  2900. //
  2901. if ( UpdateChangeID && (wcslen(pIniPrinter->pName) > 2) && pIniPrinter->cPorts &&
  2902. (*pIniPrinter->ppIniPorts)->pName && (wcslen((*pIniPrinter->ppIniPorts)->pName) > 2) &&
  2903. pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL)
  2904. {
  2905. WCHAR * pNameStr = pIniPrinter->pName;
  2906. WCHAR * pPortStr = (*pIniPrinter->ppIniPorts)->pName;
  2907. DWORD MascAttr = (PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL);
  2908. if ((pNameStr[0] == L'\\') && (pNameStr[1] == L'\\') &&
  2909. (pPortStr[0] == L'\\') && (pPortStr[1] == L'\\') &&
  2910. ((pIniPrinter->Attributes & MascAttr) == 0))
  2911. {
  2912. pIniPrinter->Attributes |= MascAttr;
  2913. }
  2914. }
  2915. //
  2916. // If there were no ports for the printer, we set the state to
  2917. // work offline, but not if this was a masque printer. (In
  2918. // which case PRINTER_ATTRIBUTE_NETWORK is also set).
  2919. //
  2920. if (bNoPorts && !(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_NETWORK)) {
  2921. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_WORK_OFFLINE;
  2922. }
  2923. pIniPrinter->pNext = pIniSpooler->pIniPrinter;
  2924. pIniPrinter->pIniSpooler = pIniSpooler;
  2925. pIniSpooler->pIniPrinter = pIniPrinter;
  2926. if ( bUpdateRegistryForThisPrinter ) {
  2927. UpdatePrinterIni( pIniPrinter , UPDATE_CHANGEID );
  2928. bUpdateRegistryForThisPrinter = UpdateChangeID;
  2929. }
  2930. } else {
  2931. DBGMSG( DBG_WARNING,
  2932. ( "Initialization of printer failed:\
  2933. \n\tpPrinterName:\t%ws\
  2934. \n\tKeyName:\t%ws\
  2935. \n\tpShareName:\t%ws\
  2936. \n\tpKeyData:\t%08x\
  2937. \n\tpIniPrintProc:\t%08x",
  2938. pIniPrinter->pName ? pIniPrinter->pName : szNull,
  2939. PrinterName,
  2940. pIniPrinter->pShareName ? pIniPrinter->pShareName : szNull ,
  2941. pKeyData,
  2942. pIniPrinter->pIniPrintProc ) );
  2943. /* Do this in two lumps, because otherwise NTSD might crash.
  2944. * (Raid bug #10650)
  2945. */
  2946. DBGMSG( DBG_WARNING,
  2947. ( " \n\tpIniDriver:\t%08x\
  2948. \n\tpLocation:\t%ws\
  2949. \n\tpComment:\t%ws\
  2950. \n\tpSecurity:\t%08x\
  2951. \n\tStatus:\t\t%08x %s\n\n",
  2952. pIniPrinter->pIniDriver,
  2953. pIniPrinter->pLocation ? pIniPrinter->pLocation : szNull,
  2954. pIniPrinter->pComment ? pIniPrinter->pComment : szNull,
  2955. pIniPrinter->pSecurityDescriptor,
  2956. pIniPrinter->Status,
  2957. ( pIniPrinter->Status & PRINTER_PENDING_DELETION
  2958. ? "Pending deletion" : "" ) ) );
  2959. FreeStructurePointers((LPBYTE)pIniPrinter,
  2960. NULL,
  2961. IniPrinterOffsets);
  2962. if (pIniPrinter->pSecurityDescriptor) {
  2963. LocalFree(pIniPrinter->pSecurityDescriptor);
  2964. pIniPrinter->pSecurityDescriptor = NULL;
  2965. }
  2966. if (( pIniSpooler->pfnFreePrinterExtra != NULL ) &&
  2967. ( pIniPrinter->pExtraData != NULL )) {
  2968. (*pIniSpooler->pfnFreePrinterExtra)( pIniPrinter->pExtraData );
  2969. }
  2970. //
  2971. // Reference count the pIniSpooler.
  2972. //
  2973. DECSPOOLERREF( pIniSpooler );
  2974. DbgPrinterFree( pIniPrinter );
  2975. FreeSplMem(pIniPrinter);
  2976. }
  2977. FreePortTokenList(pKeyData);
  2978. pKeyData = NULL;
  2979. }
  2980. SplRegCloseKey( hPrinterKey, pIniSpooler );
  2981. }
  2982. cPrinters++;
  2983. cbData = COUNTOF(PrinterName);
  2984. }
  2985. if ( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL) {
  2986. WCHAR szFilename[MAX_PATH];
  2987. HRESULT RetVal;
  2988. szFilename[0] = L'\0';
  2989. //
  2990. // FP Change
  2991. // Initialize the File pool.
  2992. //
  2993. if (pIniSpooler->hFilePool == INVALID_HANDLE_VALUE)
  2994. {
  2995. if (GetPrinterDirectory(NULL, FALSE, szFilename, MAX_PATH, pIniSpooler))
  2996. {
  2997. RetVal = CreateFilePool(
  2998. &pIniSpooler->hFilePool,
  2999. szFilename,
  3000. L"FP",
  3001. L".SPL",
  3002. L".SHD",
  3003. POOL_TIMEOUT,
  3004. MAX_POOL_FILES
  3005. );
  3006. if (FAILED(RetVal))
  3007. {
  3008. DBGMSG( DBG_WARN,
  3009. ( "SplCreateSpooler: Initialization of FilePool Failed %x\n",
  3010. RetVal ));
  3011. }
  3012. }
  3013. else
  3014. {
  3015. DBGMSG( DBG_WARN, ("CreateFilePool: GetPrinterDirectory Failed\n"));
  3016. }
  3017. }
  3018. // Read .SHD/.SPL files from common printer directory
  3019. ProcessShadowJobs( NULL, pIniSpooler );
  3020. // If any printer has a separate Printer directory process them
  3021. // also
  3022. if( GetPrinterDirectory(NULL, FALSE, szData, COUNTOF(szData), pIniSpooler) ) {
  3023. for ( pIniPrinter = pIniSpooler->pIniPrinter;
  3024. pIniPrinter;
  3025. pIniPrinter = pIniPrinter->pNext ) {
  3026. if ((pIniPrinter->pSpoolDir != NULL) &&
  3027. (_wcsicmp(szData, pIniPrinter->pSpoolDir) != 0)) {
  3028. ProcessShadowJobs(pIniPrinter, pIniSpooler);
  3029. }
  3030. }
  3031. }
  3032. }
  3033. UpdateReferencesToChainedJobs( pIniSpooler );
  3034. // Finally, go through all Printers looking for PENDING_DELETION
  3035. // if there are no jobs for that Printer, then we can delete it now
  3036. CleanupDeletedPrinters(pIniSpooler);
  3037. DBGMSG( DBG_TRACE, ("BuildPrinterInfo returned\n"));
  3038. return TRUE;
  3039. }
  3040. /* InitializePrintProcessor
  3041. *
  3042. * Allocates and initialises an INIPRINTPROC structure for the specified
  3043. * print processor and environment.
  3044. *
  3045. * Arguments:
  3046. *
  3047. * hLibrary - Handle to a previously loaded library ,
  3048. *
  3049. * pIniEnvironment - Data structure for the requested environment
  3050. * The pIniPrintProc field is initialised with the chain of print
  3051. * processor structures
  3052. *
  3053. * pPrintProcessorName - The Print Processor name e.g. WinPrint
  3054. *
  3055. * pDLLName - The DLL name, e.g. WINPRINT
  3056. *
  3057. * Returns:
  3058. *
  3059. * The allocated PiniPrintProc if no error was detected, otherwise FALSE.
  3060. *
  3061. *
  3062. */
  3063. PINIPRINTPROC
  3064. InitializePrintProcessor(
  3065. HINSTANCE hLibrary,
  3066. PINIENVIRONMENT pIniEnvironment,
  3067. LPWSTR pPrintProcessorName,
  3068. LPWSTR pDLLName
  3069. )
  3070. {
  3071. DWORD cb, cbNeeded, cReturned;
  3072. PINIPRINTPROC pIniPrintProc;
  3073. BOOL rc;
  3074. DWORD Error;
  3075. DBGMSG(DBG_TRACE, ("InitializePrintProcessor( %08x, %08x ,%ws, %ws)\n",
  3076. hLibrary, pPrintProcessorName, pPrintProcessorName, pDLLName));
  3077. cb = sizeof(INIPRINTPROC) +
  3078. wcslen(pPrintProcessorName)*sizeof(WCHAR) +
  3079. sizeof(WCHAR) +
  3080. wcslen(pDLLName)*sizeof(WCHAR) +
  3081. sizeof(WCHAR);
  3082. if (!(pIniPrintProc = (PINIPRINTPROC)AllocSplMem(cb))) {
  3083. DBGMSG(DBG_WARNING, ("Failed to allocate %d bytes for print processor\n.", cb));
  3084. return NULL;
  3085. }
  3086. __try {
  3087. InitializeCriticalSection(&pIniPrintProc->CriticalSection);
  3088. } __except(EXCEPTION_EXECUTE_HANDLER) {
  3089. FreeSplMem(pIniPrintProc);
  3090. SetLastError(GetExceptionCode());
  3091. return NULL;
  3092. }
  3093. /* Typical strings used to build the full path of the DLL:
  3094. *
  3095. * pPathName = C:\NT\SYSTEM32\SPOOL\PRTPROCS
  3096. * pEnvironment = W32X86
  3097. * pDLLName = WINPRINT.DLL
  3098. */
  3099. pIniPrintProc->hLibrary = hLibrary;
  3100. if (!pIniPrintProc->hLibrary) {
  3101. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  3102. FreeSplMem(pIniPrintProc);
  3103. DBGMSG(DBG_WARNING, ("Failed to LoadLibrary(%ws)\n", pDLLName));
  3104. return NULL;
  3105. }
  3106. pIniPrintProc->EnumDatatypes = (pfnEnumDatatypes) GetProcAddress(pIniPrintProc->hLibrary,
  3107. "EnumPrintProcessorDatatypesW");
  3108. if (!pIniPrintProc->EnumDatatypes) {
  3109. DBGMSG(DBG_WARNING, ("Failed to GetProcAddress(EnumDatatypes)\n"));
  3110. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  3111. FreeLibrary(pIniPrintProc->hLibrary);
  3112. FreeSplMem(pIniPrintProc);
  3113. return NULL;
  3114. }
  3115. rc = (*pIniPrintProc->EnumDatatypes)(NULL, pPrintProcessorName, 1, NULL, 0, &cbNeeded, &cReturned);
  3116. if (!rc && ((Error = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)) {
  3117. pIniPrintProc->cbDatatypes = cbNeeded;
  3118. if (!(pIniPrintProc->pDatatypes = AllocSplMem(cbNeeded))) {
  3119. DBGMSG(DBG_WARNING, ("Failed to allocate %d bytes for print proc datatypes\n.", cbNeeded));
  3120. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  3121. FreeLibrary(pIniPrintProc->hLibrary);
  3122. FreeSplMem(pIniPrintProc);
  3123. return NULL;
  3124. }
  3125. if (!(*pIniPrintProc->EnumDatatypes)(NULL, pPrintProcessorName, 1,
  3126. (LPBYTE)pIniPrintProc->pDatatypes,
  3127. cbNeeded, &cbNeeded,
  3128. &pIniPrintProc->cDatatypes)) {
  3129. Error = GetLastError();
  3130. DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) failed: Error %d\n",
  3131. pPrintProcessorName, Error));
  3132. }
  3133. } else if(rc) {
  3134. DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) returned no data\n",
  3135. pPrintProcessorName));
  3136. } else {
  3137. DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) failed: Error %d\n",
  3138. pPrintProcessorName, Error));
  3139. }
  3140. pIniPrintProc->Install = (pfnInstallPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3141. "InstallPrintProcessor");
  3142. pIniPrintProc->Open = (pfnOpenPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3143. "OpenPrintProcessor");
  3144. pIniPrintProc->Print = (pfnPrintDocOnPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3145. "PrintDocumentOnPrintProcessor");
  3146. pIniPrintProc->Close = (pfnClosePrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3147. "ClosePrintProcessor");
  3148. pIniPrintProc->Control = (pfnControlPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3149. "ControlPrintProcessor");
  3150. pIniPrintProc->GetPrintProcCaps = (pfnGetPrintProcCaps) GetProcAddress(pIniPrintProc->hLibrary,
  3151. "GetPrintProcessorCapabilities");
  3152. /* pName and pDLLName are contiguous with the INIPRINTPROC structure:
  3153. */
  3154. pIniPrintProc->pName = (LPWSTR)(pIniPrintProc+1);
  3155. wcscpy(pIniPrintProc->pName, pPrintProcessorName);
  3156. pIniPrintProc->pDLLName = (LPWSTR)(pIniPrintProc->pName +
  3157. wcslen(pIniPrintProc->pName) + 1);
  3158. wcscpy(pIniPrintProc->pDLLName, pDLLName);
  3159. pIniPrintProc->signature = IPP_SIGNATURE;
  3160. pIniPrintProc->pNext = pIniEnvironment->pIniPrintProc;
  3161. pIniEnvironment->pIniPrintProc = pIniPrintProc;
  3162. return pIniPrintProc;
  3163. }
  3164. /*++
  3165. Routine Name:
  3166. InitializeLocalPrintProcessor
  3167. Routine Description:
  3168. We start up the local print processor, we need to bump the reference count
  3169. on it library instance so that the cleanup code does not accidentally
  3170. unload localspl.dll while it is running.
  3171. Arguments:
  3172. pIniEnvironment - The environment to add the print processor to.
  3173. Return Value:
  3174. An HRESULT.
  3175. --*/
  3176. HRESULT
  3177. InitializeLocalPrintProcessor(
  3178. IN PINIENVIRONMENT pIniEnvironment
  3179. )
  3180. {
  3181. HRESULT hRetval = E_FAIL;
  3182. HINSTANCE hLocalSpl = NULL;
  3183. WCHAR szFilename[MAX_PATH];
  3184. hRetval = pIniEnvironment ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  3185. if (SUCCEEDED(hRetval))
  3186. {
  3187. hRetval = GetModuleFileName(hInst, szFilename, COUNTOF(szFilename)) ? S_OK : GetLastErrorAsHResult();
  3188. }
  3189. if (SUCCEEDED(hRetval))
  3190. {
  3191. hLocalSpl = LoadLibrary(szFilename);
  3192. hRetval = hLocalSpl ? S_OK : GetLastErrorAsHResult();
  3193. }
  3194. if (SUCCEEDED(hRetval))
  3195. {
  3196. hRetval = InitializePrintProcessor(hLocalSpl, pIniEnvironment, L"WinPrint", L"localspl.dll") ? S_OK : GetLastErrorAsHResult();
  3197. if (SUCCEEDED(hRetval))
  3198. {
  3199. hLocalSpl = NULL;
  3200. }
  3201. }
  3202. FreeLibrary(hLocalSpl);
  3203. return hRetval;
  3204. }
  3205. /* LoadPrintProcessor
  3206. *
  3207. * Loads the DLL for the required Print Processor and then calls
  3208. * InitializePrintProcessor for the necesary allocation and
  3209. * initialization of an INIPRINTPROC structure for the specified
  3210. * print processor and environment.
  3211. *
  3212. * Arguments:
  3213. *
  3214. * pIniEnvironment - Data structure for the requested environment
  3215. * The pIniPrintProc field is initialised with the chain of print
  3216. * processor structures
  3217. *
  3218. * pPrintProcessorName - The Print Processor name e.g. WinPrint
  3219. *
  3220. * pDLLName - The DLL name, e.g. WINPRINT
  3221. *
  3222. * pInitSpooler
  3223. *
  3224. * Returns:
  3225. *
  3226. * PINIPRINTPROC if no error was detected, otherwise NULL.
  3227. *
  3228. *
  3229. */
  3230. PINIPRINTPROC
  3231. LoadPrintProcessor(
  3232. PINIENVIRONMENT pIniEnvironment,
  3233. LPWSTR pPrintProcessorName,
  3234. LPWSTR pDLLName,
  3235. PINISPOOLER pIniSpooler
  3236. )
  3237. {
  3238. WCHAR string[MAX_PATH];
  3239. DWORD dwOldErrMode = 0;
  3240. HINSTANCE hLibrary;
  3241. DWORD MinorVersion = 0;
  3242. DWORD MajorVersion = 0;
  3243. PINIPRINTPROC pIniProc;
  3244. DBGMSG(DBG_TRACE, ("LoadPrintProcessor( %08x, %ws, %ws )\n", pIniEnvironment, pPrintProcessorName, pDLLName));
  3245. /* Originally:
  3246. * Typical strings used to build the full path of the DLL:
  3247. *
  3248. * pPathName = C:\NT\SYSTEM32\SPOOL\PRTPROCS
  3249. * pEnvironment = W32X86
  3250. * pDLLName = WINPRINT.DLL
  3251. * But after merging winprint and localspl , e.g. of setting
  3252. * pPathName = C:\NT\SYSTEM32
  3253. * pDllName = LOCALSPL.DLL
  3254. */
  3255. if( StrNCatBuff ( string,
  3256. COUNTOF(string),
  3257. pIniSpooler->pDir,
  3258. L"\\PRTPROCS\\",
  3259. pIniEnvironment->pDirectory,
  3260. L"\\",
  3261. pDLLName,
  3262. NULL) != ERROR_SUCCESS) {
  3263. SetLastError(ERROR_BAD_PATHNAME);
  3264. return NULL;
  3265. }
  3266. dwOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  3267. hLibrary = LoadLibrary(string);
  3268. //
  3269. // We are a cluster spooler and we cannot find the library for a print
  3270. // processor. We will try to copy the print processor from the cluster.
  3271. // disk.
  3272. //
  3273. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  3274. !hLibrary &&
  3275. GetLastError() == ERROR_MOD_NOT_FOUND)
  3276. {
  3277. WCHAR szSourceFile[MAX_PATH];
  3278. WCHAR szDestDir[MAX_PATH];
  3279. DWORD dwError;
  3280. DBGMSG(DBG_CLUSTER, ("LoadPrintProcessor File not found "TSTR"\n", string));
  3281. if ((dwError = StrNCatBuff(szDestDir,
  3282. COUNTOF(szDestDir),
  3283. pIniSpooler->pDir,
  3284. L"\\PRTPROCS\\",
  3285. pIniEnvironment->pDirectory,
  3286. NULL)) == ERROR_SUCCESS &&
  3287. (dwError = StrNCatBuff(szSourceFile,
  3288. COUNTOF(szSourceFile),
  3289. pIniSpooler->pszClusResDriveLetter,
  3290. L"\\",
  3291. szClusterDriverRoot,
  3292. L"\\",
  3293. pIniEnvironment->pDirectory,
  3294. L"\\",
  3295. pDLLName,
  3296. NULL)) == ERROR_SUCCESS)
  3297. {
  3298. //
  3299. // Make sure the destination directory exists
  3300. //
  3301. CreateCompleteDirectory(szDestDir);
  3302. //
  3303. // Try to copy the print proc file from the cluster disk
  3304. //
  3305. if (CopyFile(szSourceFile, string, FALSE) &&
  3306. (hLibrary = LoadLibrary(string)))
  3307. {
  3308. DBGMSG(DBG_CLUSTER, ("LoadPrintProc copied "TSTR" to "TSTR"\n", szSourceFile, string));
  3309. }
  3310. else
  3311. {
  3312. dwError = GetLastError();
  3313. }
  3314. }
  3315. }
  3316. if (hLibrary)
  3317. {
  3318. if (!GetBinaryVersion(string, &MajorVersion, &MinorVersion))
  3319. {
  3320. DBGMSG(DBG_ERROR, ("GetBinaryVersion failed. Error %u\n", GetLastError()));
  3321. }
  3322. }
  3323. SetErrorMode( dwOldErrMode ); /* Restore error mode */
  3324. pIniProc = InitializePrintProcessor(hLibrary,
  3325. pIniEnvironment,
  3326. pPrintProcessorName,
  3327. pDLLName);
  3328. if (pIniProc)
  3329. {
  3330. pIniProc->FileMajorVersion = MajorVersion;
  3331. pIniProc->FileMinorVersion = MinorVersion;
  3332. }
  3333. return pIniProc;
  3334. }
  3335. /*
  3336. Current Directory == c:\winspool\drivers
  3337. pFindFileData->cFileName == win32.x86
  3338. */
  3339. /* BuildEnvironmentInfo
  3340. *
  3341. *
  3342. * The registry tree for Environments is as follows:
  3343. *
  3344. * Print
  3345. *
  3346. * Environments
  3347. *
  3348. * Windows NT x86
  3349. *
  3350. * Drivers
  3351. *
  3352. * Agfa Compugraphic Genics (e.g.)
  3353. *
  3354. * :
  3355. * :
  3356. *
  3357. * Print Processors
  3358. *
  3359. * WINPRINT : WINPRINT.DLL (e.g.)
  3360. *
  3361. * :
  3362. * :
  3363. *
  3364. * Windows NT R4000
  3365. *
  3366. * Printers
  3367. *
  3368. *
  3369. *
  3370. */
  3371. BOOL
  3372. BuildEnvironmentInfo(
  3373. PINISPOOLER pIniSpooler
  3374. )
  3375. {
  3376. WCHAR Environment[MAX_PATH];
  3377. WCHAR szData[MAX_PATH];
  3378. DWORD cbData, cb;
  3379. DWORD cchBuffer = COUNTOF(Environment);
  3380. DWORD cEnvironments=0, Type;
  3381. HKEY hEnvironmentsKey, hEnvironmentKey;
  3382. LPWSTR pDirectory;
  3383. PINIENVIRONMENT pIniEnvironment;
  3384. LONG Status;
  3385. //
  3386. // The local spooler and cluster spooler have each different places
  3387. // where they store information about environments
  3388. //
  3389. if (pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG)
  3390. {
  3391. Status = SplRegOpenKey(pIniSpooler->hckRoot,
  3392. pIniSpooler->pszRegistryEnvironments,
  3393. KEY_READ,
  3394. &hEnvironmentsKey,
  3395. pIniSpooler);
  3396. }
  3397. else
  3398. {
  3399. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryEnvironments, 0, KEY_READ, &hEnvironmentsKey);
  3400. }
  3401. if (Status != ERROR_SUCCESS)
  3402. {
  3403. DBGMSG(DBG_CLUSTER, ("RegOpenKey of %ws Failed: Error = %d\n", szEnvironmentsKey, Status));
  3404. return FALSE;
  3405. }
  3406. //
  3407. // Enumerate the subkeys of "Environment".
  3408. // This will give us "Windows NT x86", "Windows NT R4000", * and maybe others:
  3409. //
  3410. while (SplRegEnumKey(hEnvironmentsKey, cEnvironments, Environment, &cchBuffer, NULL, pIniSpooler) == ERROR_SUCCESS) {
  3411. DBGMSG(DBG_CLUSTER, ("Found environment "TSTR"\n", Environment));
  3412. //
  3413. // For each environment found, create or open the key:
  3414. //
  3415. if (SplRegCreateKey(hEnvironmentsKey, Environment, 0, KEY_READ, NULL, &hEnvironmentKey, NULL, pIniSpooler) == ERROR_SUCCESS) {
  3416. cbData = sizeof(szData);
  3417. pDirectory = NULL;
  3418. //
  3419. // Find the name of the directory associated with this environment,
  3420. // e.g. "Windows NT x86" -> "W32X86"
  3421. // "Windows NT R4000" -> "W32MIPS"
  3422. //
  3423. if (RegGetString(hEnvironmentKey, szDirectory, &pDirectory, &cbData, &Status, TRUE, pIniSpooler)) {
  3424. DBGMSG(DBG_CLUSTER, ("BuildEnvInfo pDirectory "TSTR"\n", pDirectory));
  3425. }
  3426. cb = sizeof(INIENVIRONMENT) + wcslen(Environment)*sizeof(WCHAR) + sizeof(WCHAR);
  3427. if (pDirectory && (pIniEnvironment=AllocSplMem(cb))) {
  3428. pIniEnvironment->pName = wcscpy((LPWSTR)(pIniEnvironment+1), Environment);
  3429. pIniEnvironment->signature = IE_SIGNATURE;
  3430. pIniEnvironment->pDirectory = pDirectory;
  3431. pIniEnvironment->pNext = pIniSpooler->pIniEnvironment;
  3432. pIniSpooler->pIniEnvironment = pIniEnvironment;
  3433. pIniEnvironment->pIniVersion = NULL;
  3434. pIniEnvironment->pIniPrintProc = NULL;
  3435. pIniEnvironment->pIniSpooler = pIniSpooler;
  3436. if(!_wcsicmp(Environment,LOCAL_ENVIRONMENT)) {
  3437. (VOID)InitializeLocalPrintProcessor(pIniEnvironment);
  3438. }
  3439. BuildDriverInfo(hEnvironmentKey, pIniEnvironment, pIniSpooler);
  3440. BuildPrintProcInfo (hEnvironmentKey, pIniEnvironment, pIniSpooler);
  3441. DBGMSG(DBG_TRACE, ("Data for environment %ws created:\
  3442. \n\tpDirectory: %ws\n",
  3443. Environment,
  3444. pDirectory));
  3445. }
  3446. SplRegCloseKey(hEnvironmentKey, pIniSpooler);
  3447. }
  3448. cEnvironments++;
  3449. cchBuffer = COUNTOF(Environment);
  3450. }
  3451. SplRegCloseKey(hEnvironmentsKey, pIniSpooler);
  3452. if (!(pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER))
  3453. {
  3454. pThisEnvironment = FindEnvironment(szEnvironment, pIniSpooler);
  3455. }
  3456. return FALSE;
  3457. }
  3458. BOOL
  3459. BuildDriverInfo(
  3460. HKEY hKeyEnvironment,
  3461. PINIENVIRONMENT pIniEnvironment,
  3462. PINISPOOLER pIniSpooler
  3463. )
  3464. /*++
  3465. Routine Description:
  3466. Creates driver and version ini structures based on environment.
  3467. Arguments:
  3468. hKeyEnvironment - Registry key specifying environment.
  3469. pIniEnvironment - Structure for environemnt. Will be initialized
  3470. to hold pIniVersions and pIniDrivers.
  3471. Return Value:
  3472. TRUE - Success,
  3473. False - Failure.
  3474. --*/
  3475. {
  3476. WCHAR szVersionName[MAX_PATH];
  3477. DWORD cchBuffer;
  3478. DWORD cVersion;
  3479. HKEY hDriversKey;
  3480. DWORD Status;
  3481. PINIVERSION pIniVersionList, pIniVersion;
  3482. Status = SplRegCreateKey(hKeyEnvironment,szDriversKey, 0, KEY_READ, NULL, &hDriversKey, NULL, pIniSpooler);
  3483. if (Status != ERROR_SUCCESS) {
  3484. DBGMSG(DBG_ERROR, ("RegOpenKeyEx of %ws failed: Error = %d\n", szDriversKey, Status));
  3485. return FALSE;
  3486. }
  3487. DBGMSG(DBG_TRACE,("RegCreateKeyEx succeeded in BuildDriverInfo\n"));
  3488. for( pIniVersionList = NULL, cVersion = 0;
  3489. cchBuffer = COUNTOF( szVersionName ),
  3490. SplRegEnumKey(hDriversKey, cVersion, szVersionName, &cchBuffer, NULL, pIniSpooler) == ERROR_SUCCESS;
  3491. cVersion++ ){
  3492. DBGMSG(DBG_TRACE,("Version found %ws\n", szVersionName));
  3493. //
  3494. // If it isn't a version -- remember we look for current
  3495. // drivers before we upgrade, just move on.
  3496. //
  3497. if (_wcsnicmp(szVersionName, L"Version-", 8)) {
  3498. continue;
  3499. }
  3500. pIniVersion = GetVersionDrivers( hDriversKey,
  3501. szVersionName,
  3502. pIniSpooler,
  3503. pIniEnvironment );
  3504. if( pIniVersion ){
  3505. InsertVersionList( &pIniVersionList, pIniVersion );
  3506. }
  3507. }
  3508. SplRegCloseKey(hDriversKey, pIniSpooler);
  3509. pIniEnvironment->pIniVersion = pIniVersionList;
  3510. return TRUE;
  3511. }
  3512. /* BuildPrintProcInfo
  3513. *
  3514. * Opens the printproc subkey for the specified environment and enumerates
  3515. * the print processors listed.
  3516. *
  3517. * For each print processor found, calls InitializePrintProcessor to allocate
  3518. * and inintialize a data structure.
  3519. *
  3520. * This function was adapted to use SplReg functions. Those functions are
  3521. * cluster aware.
  3522. *
  3523. * Arguments:
  3524. *
  3525. * hKeyEnvironment - The key for the specified environment,
  3526. * used for Registry API calls.
  3527. *
  3528. * pIniEnvironment - Data structure for the environment.
  3529. * The pIniPrintProc field will be initialised to contain a chain
  3530. * of one or more print processors enumerated from the registry.
  3531. *
  3532. * Return:
  3533. *
  3534. * TRUE if operation was successful, otherwise FALSE
  3535. *
  3536. *
  3537. * 8 Sept 1992 by andrewbe, based on an original idea by davesn
  3538. */
  3539. BOOL
  3540. BuildPrintProcInfo(
  3541. HKEY hKeyEnvironment,
  3542. PINIENVIRONMENT pIniEnvironment,
  3543. PINISPOOLER pIniSpooler
  3544. )
  3545. {
  3546. WCHAR PrintProcName[MAX_PATH];
  3547. WCHAR DLLName[MAX_PATH];
  3548. DWORD cchBuffer, cbDLLName;
  3549. DWORD cPrintProcs = 0;
  3550. HKEY hPrintProcKey, hPrintProc;
  3551. DWORD Status;
  3552. PINIPRINTPROC pIniPrintProc;
  3553. if ((Status = SplRegOpenKey(hKeyEnvironment,
  3554. szPrintProcKey,
  3555. KEY_READ,
  3556. &hPrintProcKey,
  3557. pIniSpooler)) == ERROR_SUCCESS)
  3558. {
  3559. cchBuffer = COUNTOF(PrintProcName);
  3560. while (SplRegEnumKey(hPrintProcKey,
  3561. cPrintProcs,
  3562. (LPTSTR)PrintProcName,
  3563. &cchBuffer,
  3564. NULL,
  3565. pIniSpooler) == ERROR_SUCCESS)
  3566. {
  3567. DBGMSG(DBG_TRACE, ("BuildPrintProcInfo Print processor found: %ws\n", PrintProcName));
  3568. if (SplRegOpenKey(hPrintProcKey,
  3569. PrintProcName,
  3570. KEY_READ,
  3571. &hPrintProc,
  3572. pIniSpooler) == ERROR_SUCCESS)
  3573. {
  3574. cbDLLName = sizeof(DLLName);
  3575. if (SplRegQueryValue(hPrintProc,
  3576. szDriverFile,
  3577. NULL,
  3578. (LPBYTE)DLLName,
  3579. &cbDLLName,
  3580. pIniSpooler) == ERROR_SUCCESS)
  3581. {
  3582. pIniPrintProc = LoadPrintProcessor(pIniEnvironment,
  3583. PrintProcName,
  3584. DLLName,
  3585. pIniSpooler);
  3586. }
  3587. SplRegCloseKey(hPrintProc, pIniSpooler);
  3588. }
  3589. //
  3590. // Don't delete the key !! If winprint.dll was corrupt,
  3591. // then we nuke it and we are hosed since there is no UI
  3592. // to add print procs.
  3593. // We can afford to be a little slow on init, since we only
  3594. // do it once.
  3595. //
  3596. cchBuffer = COUNTOF(PrintProcName);
  3597. cPrintProcs++;
  3598. }
  3599. SplRegCloseKey(hPrintProcKey, pIniSpooler);
  3600. DBGMSG(DBG_TRACE, ("End of print processor initialization.\n"));
  3601. } else {
  3602. DBGMSG (DBG_WARNING, ("SplRegOpenKey failed: Error = %d\n", Status));
  3603. return FALSE;
  3604. }
  3605. return TRUE;
  3606. }
  3607. #define SetOffset(Dest, Source, End) \
  3608. if (Source) { \
  3609. Dest=End; \
  3610. End+=wcslen(Source)+1; \
  3611. }
  3612. #define SetPointer(struc, off) \
  3613. if (struc->off) { \
  3614. struc->off += (ULONG_PTR)struc/sizeof(*struc->off); \
  3615. }
  3616. #define WriteString(hFile, pStr) \
  3617. if (pStr) {\
  3618. rc = WriteFile(hFile, pStr, wcslen(pStr)*sizeof(WCHAR) + \
  3619. sizeof(WCHAR), &BytesWritten, NULL); \
  3620. if (!rc) { \
  3621. DBGMSG(DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", \
  3622. GetLastError())); \
  3623. } \
  3624. }
  3625. #define AddSize(pStr, dwSize) \
  3626. if (pStr) { \
  3627. dwSize = dwSize + (wcslen(pStr) + 1)*sizeof(WCHAR); \
  3628. }
  3629. #define CopyString(pBuffer, dwOffset, pStr) \
  3630. if (pStr) { \
  3631. wcscpy((LPWSTR)(pBuffer + dwOffset), pStr); \
  3632. dwOffset += (wcslen(pStr) + 1)*sizeof(WCHAR); \
  3633. }
  3634. BOOL
  3635. WriteShadowJob(
  3636. IN PINIJOB pIniJob,
  3637. IN BOOL bLeaveCS
  3638. )
  3639. {
  3640. BOOL bAllocBuffer = FALSE;
  3641. BOOL bRet = FALSE;
  3642. BOOL bFileCreated = FALSE;
  3643. HANDLE hFile = INVALID_HANDLE_VALUE;
  3644. HANDLE hImpersonationToken = INVALID_HANDLE_VALUE;
  3645. DWORD BytesWritten, dwSize, dwType, dwData, dwcbData;
  3646. ULONG_PTR dwOffset, cb;
  3647. SHADOWFILE_3 ShadowFile;
  3648. LPWSTR pEnd;
  3649. WCHAR szFileName[MAX_PATH];
  3650. BYTE ShdFileBuffer[MAX_STATIC_ALLOC];
  3651. LPBYTE pBuffer;
  3652. HKEY hPrintRegKey = NULL;
  3653. BOOL UsePools = TRUE;
  3654. SplInSem();
  3655. //
  3656. // Only update if this is not a direct job and the spooler requests it.
  3657. // Also don't update if the shadow file has been deleted at some other point.
  3658. // This check must be performed in the CS else the FilePool starts leaking
  3659. // jobs.
  3660. //
  3661. if ( (pIniJob->Status & JOB_DIRECT) ||
  3662. (pIniJob->pIniPrinter->pIniSpooler->SpoolerFlags
  3663. & SPL_NO_UPDATE_JOBSHD) ||
  3664. (pIniJob->Status & JOB_SHADOW_DELETED) ) {
  3665. bRet = TRUE;
  3666. //
  3667. // Setting this to FALSE prevents us reentering the CS accidentally.
  3668. //
  3669. bLeaveCS = FALSE;
  3670. goto CleanUp;
  3671. }
  3672. if (bLeaveCS) {
  3673. LeaveSplSem();
  3674. SplOutSem();
  3675. }
  3676. //
  3677. // FP Change
  3678. // if we don't have a handle to a filepool item, we
  3679. // revert to the old methods.
  3680. //
  3681. if (pIniJob->hFileItem == INVALID_HANDLE_VALUE)
  3682. {
  3683. UsePools = FALSE;
  3684. }
  3685. if (!UsePools)
  3686. {
  3687. GetFullNameFromId(pIniJob->pIniPrinter, pIniJob->JobId, FALSE, szFileName, FALSE);
  3688. }
  3689. hImpersonationToken = RevertToPrinterSelf();
  3690. if (UsePools)
  3691. {
  3692. HRESULT RetVal = S_OK;
  3693. //
  3694. // FP Change
  3695. // We Get a write handle from the pool for the shadow files and
  3696. // truncate it for use.
  3697. //
  3698. RetVal = GetWriterFromHandle(pIniJob->hFileItem, &hFile, FALSE);
  3699. if (SUCCEEDED(RetVal))
  3700. {
  3701. //
  3702. // Even if we can't set the file pointer, we have signalled to the
  3703. // file pool that a writer is busy with this file pool object.
  3704. //
  3705. bFileCreated = TRUE;
  3706. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
  3707. {
  3708. DBGMSG( DBG_WARNING,
  3709. ( "WriteShadowJob Failed to set File pointer. Error %d\n", GetLastError() ));
  3710. hFile = INVALID_HANDLE_VALUE;
  3711. }
  3712. }
  3713. else
  3714. {
  3715. DBGMSG( DBG_WARNING,
  3716. ( "WriteShadowJob Failed to get File Handle from Pool Item. Error %x\n", RetVal ));
  3717. hFile = INVALID_HANDLE_VALUE;
  3718. }
  3719. }
  3720. else
  3721. {
  3722. //
  3723. // Open file in Cached IO. Big performance gain.
  3724. //
  3725. hFile=CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ,
  3726. NULL, CREATE_ALWAYS,
  3727. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  3728. NULL);
  3729. if (hFile != INVALID_HANDLE_VALUE) {
  3730. bFileCreated = TRUE;
  3731. }
  3732. }
  3733. ImpersonatePrinterClient(hImpersonationToken);
  3734. if ( hFile == INVALID_HANDLE_VALUE ) {
  3735. DBGMSG( DBG_WARNING,
  3736. ( "WriteShadowJob failed to open shadow file "TSTR"\n Error %d\n",
  3737. szFileName, GetLastError() ));
  3738. bRet = FALSE;
  3739. goto CleanUp;
  3740. }
  3741. memset(&ShadowFile, 0, sizeof(ShadowFile));
  3742. ShadowFile.signature = SF_SIGNATURE_3;
  3743. ShadowFile.cbSize = sizeof( SHADOWFILE_3 );
  3744. ShadowFile.Version = SF_VERSION_3;
  3745. ShadowFile.Status = pIniJob->Status;
  3746. ShadowFile.JobId = pIniJob->JobId;
  3747. ShadowFile.Priority = pIniJob->Priority;
  3748. ShadowFile.Submitted = pIniJob->Submitted;
  3749. ShadowFile.StartTime = pIniJob->StartTime;
  3750. ShadowFile.UntilTime = pIniJob->UntilTime;
  3751. ShadowFile.Size = pIniJob->Size;
  3752. ShadowFile.dwValidSize = pIniJob->dwValidSize;
  3753. ShadowFile.cPages = pIniJob->cPages;
  3754. ShadowFile.dwReboots = pIniJob->dwReboots;
  3755. if(pIniJob->pSecurityDescriptor)
  3756. ShadowFile.cbSecurityDescriptor=GetSecurityDescriptorLength(
  3757. pIniJob->pSecurityDescriptor);
  3758. pEnd=(LPWSTR)sizeof(ShadowFile);
  3759. if (pIniJob->pDevMode) {
  3760. ShadowFile.pDevMode=(LPDEVMODE)pEnd;
  3761. cb = pIniJob->pDevMode->dmSize + pIniJob->pDevMode->dmDriverExtra;
  3762. cb = ALIGN_UP(cb,ULONG_PTR);
  3763. cb /= sizeof(WCHAR);
  3764. pEnd += cb;
  3765. }
  3766. if (pIniJob->pSecurityDescriptor) {
  3767. ShadowFile.pSecurityDescriptor=(PSECURITY_DESCRIPTOR)pEnd;
  3768. cb = ShadowFile.cbSecurityDescriptor;
  3769. cb = ALIGN_UP(cb,ULONG_PTR);
  3770. cb /= sizeof(WCHAR);
  3771. pEnd += cb;
  3772. }
  3773. ShadowFile.NextJobId = pIniJob->NextJobId;
  3774. SetOffset( ShadowFile.pNotify, pIniJob->pNotify, pEnd );
  3775. SetOffset( ShadowFile.pUser, pIniJob->pUser, pEnd );
  3776. SetOffset( ShadowFile.pDocument, pIniJob->pDocument, pEnd );
  3777. SetOffset( ShadowFile.pOutputFile, pIniJob->pOutputFile, pEnd );
  3778. SetOffset( ShadowFile.pPrinterName, pIniJob->pIniPrinter->pName, pEnd );
  3779. SetOffset( ShadowFile.pDriverName, pIniJob->pIniDriver->pName, pEnd );
  3780. SetOffset( ShadowFile.pPrintProcName, pIniJob->pIniPrintProc->pName, pEnd );
  3781. SetOffset( ShadowFile.pDatatype, pIniJob->pDatatype, pEnd );
  3782. SetOffset( ShadowFile.pParameters, pIniJob->pParameters, pEnd );
  3783. SetOffset( ShadowFile.pMachineName, pIniJob->pMachineName, pEnd );
  3784. dwSize = (DWORD)ALIGN_UP(pEnd,ULONG_PTR);
  3785. if (dwSize > MAX_STATIC_ALLOC) {
  3786. if (!(pBuffer = (LPBYTE) AllocSplMem(dwSize))) {
  3787. DBGMSG( DBG_WARNING, ("WriteShadowJob: Memory Allocation failed %d\n", GetLastError()));
  3788. bRet = FALSE;
  3789. goto CleanUp;
  3790. }
  3791. bAllocBuffer = TRUE;
  3792. } else {
  3793. pBuffer = (LPBYTE) ShdFileBuffer;
  3794. }
  3795. //
  3796. // Copy SHADOWFILE_3 and data pointed thru it, into the buffer
  3797. //
  3798. dwOffset = 0;
  3799. CopyMemory(pBuffer + dwOffset, &ShadowFile, sizeof(SHADOWFILE_3));
  3800. dwOffset += sizeof(SHADOWFILE_3);
  3801. if (pIniJob->pDevMode) {
  3802. CopyMemory(pBuffer + dwOffset, pIniJob->pDevMode, pIniJob->pDevMode->dmSize +
  3803. pIniJob->pDevMode->dmDriverExtra);
  3804. dwOffset += (pIniJob->pDevMode->dmSize + pIniJob->pDevMode->dmDriverExtra);
  3805. dwOffset = ALIGN_UP(dwOffset,ULONG_PTR);
  3806. }
  3807. if (pIniJob->pSecurityDescriptor) {
  3808. CopyMemory(pBuffer + dwOffset, pIniJob->pSecurityDescriptor,
  3809. ShadowFile.cbSecurityDescriptor);
  3810. dwOffset += ShadowFile.cbSecurityDescriptor;
  3811. dwOffset = ALIGN_UP(dwOffset,ULONG_PTR);
  3812. }
  3813. //
  3814. // CopyString is defined at the start of the function
  3815. //
  3816. CopyString(pBuffer, dwOffset, pIniJob->pNotify);
  3817. CopyString(pBuffer, dwOffset, pIniJob->pUser);
  3818. CopyString(pBuffer, dwOffset, pIniJob->pDocument);
  3819. CopyString(pBuffer, dwOffset, pIniJob->pOutputFile);
  3820. CopyString(pBuffer, dwOffset, pIniJob->pIniPrinter->pName);
  3821. CopyString(pBuffer, dwOffset, pIniJob->pIniDriver->pName);
  3822. CopyString(pBuffer, dwOffset, pIniJob->pIniPrintProc->pName);
  3823. CopyString(pBuffer, dwOffset, pIniJob->pDatatype);
  3824. CopyString(pBuffer, dwOffset, pIniJob->pParameters);
  3825. CopyString(pBuffer, dwOffset, pIniJob->pMachineName);
  3826. //
  3827. // Copy the structure into the Shadow file. Buffers need not be buffered since the
  3828. // file is opened in WRITE_THROUGH mode.
  3829. //
  3830. bRet = WriteFile( hFile, pBuffer, dwSize, &BytesWritten, NULL);
  3831. //
  3832. // Flush the file buffers if the corresponding flag is set in the registry
  3833. //
  3834. if (dwFlushShadowFileBuffers == 0) {
  3835. // Avoid repeated initializations
  3836. dwFlushShadowFileBuffers = 2;
  3837. // flag has to be initialized from the registry
  3838. dwcbData = sizeof(DWORD);
  3839. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3840. szRegistryRoot,
  3841. 0,
  3842. KEY_READ,
  3843. &hPrintRegKey) == ERROR_SUCCESS) {
  3844. if (RegQueryValueEx(hPrintRegKey,
  3845. szFlushShadowFileBuffers,
  3846. NULL,
  3847. &dwType,
  3848. (LPBYTE) &dwData,
  3849. &dwcbData) == ERROR_SUCCESS) {
  3850. if (dwData == 1) {
  3851. // Flush the shadow file buffers
  3852. dwFlushShadowFileBuffers = 1;
  3853. }
  3854. }
  3855. RegCloseKey(hPrintRegKey);
  3856. }
  3857. }
  3858. if (dwFlushShadowFileBuffers == 1) {
  3859. bRet = FlushFileBuffers(hFile);
  3860. }
  3861. if (!bRet) {
  3862. DBGMSG( DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", GetLastError()));
  3863. }
  3864. CleanUp:
  3865. if (bAllocBuffer) {
  3866. FreeSplMem(pBuffer);
  3867. }
  3868. if (!UsePools && hFile != INVALID_HANDLE_VALUE)
  3869. {
  3870. //
  3871. // FP Change
  3872. // Only close the file if it's a non-pooled file.
  3873. //
  3874. if (!CloseHandle(hFile)) {
  3875. DBGMSG(DBG_WARNING, ("WriteShadowJob CloseHandle failed %d %d\n",
  3876. hFile, GetLastError()));
  3877. }
  3878. }
  3879. //
  3880. // Reenter the CS if we were asked to leave it.
  3881. //
  3882. if (bLeaveCS) {
  3883. EnterSplSem();
  3884. }
  3885. //
  3886. // We can be called just before the shadow file was deleted (or sent back to
  3887. // the file pool) and then either recreate the shadow file on the disk or
  3888. // potentially leak a file pool handle. The final DeleteJob when the reference
  3889. // count is zero will see that the shadow file has already been deleted and will
  3890. // not attempt to clean it up. So, we remove the JOB_SHADOW_DELETED bit here to
  3891. // ensure that this will not happen.
  3892. //
  3893. if (bFileCreated) {
  3894. pIniJob->Status &= ~JOB_SHADOW_DELETED;
  3895. }
  3896. return bRet;
  3897. }
  3898. #undef CopyString
  3899. #undef AddSize
  3900. VOID
  3901. ProcessShadowJobs(
  3902. PINIPRINTER pIniPrinter,
  3903. PINISPOOLER pIniSpooler
  3904. )
  3905. {
  3906. WCHAR wczPrintDirAllSpools[MAX_PATH];
  3907. WCHAR wczPrinterDirectory[MAX_PATH];
  3908. HANDLE fFile;
  3909. BOOL b;
  3910. PWIN32_FIND_DATA pFindFileData;
  3911. PINIJOB pIniJob;
  3912. UINT ErrorMode;
  3913. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  3914. //
  3915. // Don't Process Shadow Jobs during Upgrade
  3916. //
  3917. if ( dwUpgradeFlag != 0 || !( pIniSpooler->SpoolerFlags & SPL_PRINT )) {
  3918. return;
  3919. }
  3920. ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  3921. if( GetPrinterDirectory(pIniPrinter,
  3922. FALSE,
  3923. wczPrintDirAllSpools,
  3924. (COUNTOF(wczPrintDirAllSpools) - COUNTOF(szAllSpools)),
  3925. pIniSpooler) &&
  3926. GetPrinterDirectory(pIniPrinter,
  3927. FALSE,
  3928. wczPrinterDirectory,
  3929. COUNTOF(wczPrinterDirectory),
  3930. pIniSpooler) ) {
  3931. wcscat(wczPrintDirAllSpools, szAllSpools);
  3932. if ( pFindFileData = AllocSplMem(sizeof(WIN32_FIND_DATA) )) {
  3933. fFile = FindFirstFile( wczPrintDirAllSpools, pFindFileData );
  3934. if ( fFile != (HANDLE)-1 ) {
  3935. b=TRUE;
  3936. while( b ) {
  3937. if ( !(pFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  3938. ReadShadowJob(wczPrinterDirectory, pFindFileData, pIniSpooler);
  3939. }
  3940. b = FindNextFile(fFile, pFindFileData);
  3941. }
  3942. FindClose( fFile );
  3943. }
  3944. FreeSplMem( pFindFileData );
  3945. }
  3946. }
  3947. SetErrorMode(ErrorMode);
  3948. }
  3949. #define CheckPointer( strptr ) \
  3950. if( strptr ) { \
  3951. if( (ULONG_PTR)(strptr + wcslen(strptr) + 1) > (ULONG_PTR)pEnd ) { \
  3952. bRet = FALSE; \
  3953. goto BailOut; \
  3954. } \
  3955. }
  3956. //
  3957. // make sure all pointers contain embedded data bounded within the pShadowFile (not passed the end).
  3958. //
  3959. BOOL
  3960. CheckAllPointers(
  3961. PSHADOWFILE_3 pShadowFile,
  3962. DWORD dwSize
  3963. )
  3964. {
  3965. LPBYTE pEnd = (LPBYTE)pShadowFile + dwSize;
  3966. DWORD cb;
  3967. BOOL bRet = TRUE;
  3968. try {
  3969. CheckPointer(pShadowFile->pDatatype);
  3970. CheckPointer(pShadowFile->pNotify);
  3971. CheckPointer(pShadowFile->pUser);
  3972. CheckPointer(pShadowFile->pDocument);
  3973. CheckPointer(pShadowFile->pOutputFile);
  3974. CheckPointer(pShadowFile->pPrinterName);
  3975. CheckPointer(pShadowFile->pDriverName);
  3976. CheckPointer(pShadowFile->pPrintProcName);
  3977. CheckPointer(pShadowFile->pParameters);
  3978. CheckPointer(pShadowFile->pMachineName);
  3979. // Now check the rest of the two data structures
  3980. if( (ULONG_PTR)pShadowFile->pSecurityDescriptor + pShadowFile->cbSecurityDescriptor > (ULONG_PTR)pEnd ) {
  3981. bRet = FALSE;
  3982. goto BailOut;
  3983. }
  3984. if( pShadowFile->pDevMode ) {
  3985. cb = pShadowFile->pDevMode->dmSize + pShadowFile->pDevMode->dmDriverExtra;
  3986. if( (ULONG_PTR)pShadowFile->pDevMode + cb > (ULONG_PTR)pEnd )
  3987. bRet = FALSE;
  3988. }
  3989. } except (EXCEPTION_EXECUTE_HANDLER) {
  3990. bRet = FALSE;
  3991. }
  3992. BailOut:
  3993. return bRet;
  3994. }
  3995. #undef CheckPointer
  3996. PINIJOB
  3997. ReadShadowJob(
  3998. LPWSTR szDir,
  3999. PWIN32_FIND_DATA pFindFileData,
  4000. PINISPOOLER pIniSpooler
  4001. )
  4002. /*++
  4003. Routine Description:
  4004. Reads a *.spl/*.shd file and partially validates the file.
  4005. Arguments:
  4006. szDir -- pointer to spool directory string
  4007. pFindFileData -- found file data (spl file)
  4008. pIniSpooler -- spooler the *.spl belongs to
  4009. Return Value:
  4010. Allocated pIniJob.
  4011. Notes:
  4012. Warning: Changing the format of SHADOWFILE requires modifying the
  4013. data integrity checks performed here!
  4014. If the shadow file structure size is grown, then when reading,
  4015. you must check the old sizes before touching memory. Current layout is:
  4016. | DWORD | ... | String | DWORD | DWORD | StringData | StringData |
  4017. *--------------------------------------*
  4018. ^ This is the SHADOWFILE_3 structure.
  4019. If you grow it, then the next field will point to StringData, and
  4020. won't be valid--you can't touch it since you'll corrupt the string.
  4021. --*/
  4022. {
  4023. HANDLE hFile = INVALID_HANDLE_VALUE;
  4024. HANDLE hFileSpl = INVALID_HANDLE_VALUE;
  4025. DWORD BytesRead;
  4026. PSHADOWFILE_3 pShadowFile3 = NULL;
  4027. PSHADOWFILE_3 pShadowFile = NULL;
  4028. PINIJOB pIniJob;
  4029. DWORD cb,i;
  4030. WCHAR szFileName[MAX_PATH];
  4031. LPWSTR pExt;
  4032. BOOL rc;
  4033. LPWSTR pFileSpec;
  4034. DWORD nFileSizeLow;
  4035. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  4036. wcscpy(&szFileName[0], szDir);
  4037. pFileSpec = szFileName + wcslen(szFileName);
  4038. *pFileSpec++ = L'\\';
  4039. wcscpy(pFileSpec, pFindFileData->cFileName);
  4040. hFileSpl=CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ,
  4041. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  4042. if (hFileSpl == INVALID_HANDLE_VALUE) {
  4043. DBGMSG(DBG_WARNING, ("ReadShadowJob CreateFile( %ws ) failed: LastError = %d\n",
  4044. szFileName, GetLastError()));
  4045. goto Fail;
  4046. }
  4047. CharUpper(szFileName);
  4048. pExt = wcsstr(szFileName, L".SPL");
  4049. if (!pExt)
  4050. goto Fail;
  4051. pExt[2] = L'H';
  4052. pExt[3] = L'D';
  4053. hFile=CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ,
  4054. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  4055. if (hFile == INVALID_HANDLE_VALUE) {
  4056. DBGMSG(DBG_WARNING, ("ReadShadowJob CreateFile( %ws ) failed: LastError = %d\n",
  4057. szFileName, GetLastError()));
  4058. goto Fail;
  4059. }
  4060. nFileSizeLow = GetFileSize(hFile, NULL);
  4061. if (nFileSizeLow == 0xffffffff)
  4062. {
  4063. DBGMSG(DBG_WARNING, ("ReadShadowJob GetFileSize( %ws ) failed: LastError = %d\n",
  4064. szFileName, GetLastError()));
  4065. goto Fail;
  4066. }
  4067. if ( nFileSizeLow < sizeof( SHADOWFILE ) ||
  4068. !(pShadowFile=AllocSplMem(nFileSizeLow))) {
  4069. goto Fail;
  4070. }
  4071. rc = ReadFile(hFile, pShadowFile, nFileSizeLow, &BytesRead, NULL);
  4072. // If Shadow file is old style, then convert it to new
  4073. if (rc && (BytesRead == nFileSizeLow) &&
  4074. ( pShadowFile->signature == SF_SIGNATURE ||
  4075. pShadowFile->signature == SF_SIGNATURE_2 )) {
  4076. BOOL bStatus;
  4077. if (!(pShadowFile3 = AllocSplMem(nFileSizeLow +
  4078. sizeof(SHADOWFILE_3) - sizeof(SHADOWFILE))) ) {
  4079. goto Fail;
  4080. }
  4081. bStatus = Old2NewShadow((PSHADOWFILE)pShadowFile, pShadowFile3, &BytesRead);
  4082. nFileSizeLow = BytesRead; // This is used in CheckAllPointers, below
  4083. FreeSplMem(pShadowFile);
  4084. pShadowFile = pShadowFile3;
  4085. if( !bStatus ){
  4086. goto Fail;
  4087. }
  4088. }
  4089. //
  4090. // Initial size of SF_3 must include pMachineName.
  4091. //
  4092. if (!rc ||
  4093. (pShadowFile->signature != SF_SIGNATURE_3 ) ||
  4094. (BytesRead != nFileSizeLow) ||
  4095. (BytesRead < pShadowFile->cbSize ) ||
  4096. (BytesRead < sizeof( SHADOWFILE_3 )) ||
  4097. (pShadowFile->Status & (JOB_SPOOLING | JOB_PENDING_DELETION))) {
  4098. DBGMSG(DBG_WARNING, ( "Error reading shadow job:\
  4099. \n\tReadFile returned %d: Error %d\
  4100. \n\tsignature = %08x\
  4101. \n\tBytes read = %d; expected %d\
  4102. \n\tFile size = %d; expected %d\
  4103. \n\tStatus = %08x %s\n",
  4104. rc, ( rc ? 0 : GetLastError() ),
  4105. pShadowFile->signature,
  4106. BytesRead, nFileSizeLow,
  4107. sizeof(*pShadowFile), pShadowFile->Size,
  4108. pShadowFile->Status,
  4109. ( (pShadowFile->Status & JOB_SPOOLING) ?
  4110. "Job is spooling!" : "" ) ) );
  4111. goto Fail;
  4112. }
  4113. if (!CloseHandle(hFile)) {
  4114. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
  4115. }
  4116. hFile = INVALID_HANDLE_VALUE;
  4117. if (!CloseHandle(hFileSpl)) {
  4118. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
  4119. }
  4120. hFileSpl = INVALID_HANDLE_VALUE;
  4121. // Check number of reboots on this file & delete if too many
  4122. if (pShadowFile->dwReboots > 1) {
  4123. DBGMSG(DBG_WARNING, ("Corrupt shadow file %ws\n", szFileName));
  4124. if ( pShadowFile->pDocument && pShadowFile->pDriverName ) {
  4125. SplLogEvent(pIniSpooler,
  4126. LOG_ERROR,
  4127. MSG_BAD_JOB,
  4128. FALSE,
  4129. pShadowFile->pDocument + (ULONG_PTR)pShadowFile/sizeof(*pShadowFile->pDocument),
  4130. pShadowFile->pDriverName + (ULONG_PTR)pShadowFile/sizeof(*pShadowFile->pDriverName),
  4131. NULL);
  4132. }
  4133. goto Fail;
  4134. }
  4135. if (pIniJob = AllocSplMem(sizeof(INIJOB))) {
  4136. INITJOBREFZERO(pIniJob);
  4137. pIniJob->signature = IJ_SIGNATURE;
  4138. pIniJob->Status = pShadowFile->Status & (JOB_PAUSED | JOB_REMOTE | JOB_PRINTED | JOB_COMPLETE );
  4139. pIniJob->JobId = pShadowFile->JobId;
  4140. pIniJob->Priority = pShadowFile->Priority;
  4141. pIniJob->Submitted = pShadowFile->Submitted;
  4142. pIniJob->StartTime = pShadowFile->StartTime;
  4143. pIniJob->UntilTime = pShadowFile->UntilTime;
  4144. pIniJob->Size = pShadowFile->Size;
  4145. pIniJob->dwValidSize = pShadowFile->dwValidSize;
  4146. pIniJob->cPages = pShadowFile->cPages;
  4147. pIniJob->cbPrinted = 0;
  4148. pIniJob->NextJobId = pShadowFile->NextJobId;
  4149. pIniJob->dwReboots = pShadowFile->dwReboots;
  4150. pIniJob->dwJobNumberOfPagesPerSide = 0;
  4151. pIniJob->dwDrvNumberOfPagesPerSide = 0;
  4152. pIniJob->cLogicalPages = 0;
  4153. pIniJob->cLogicalPagesPrinted = 0;
  4154. pIniJob->WaitForWrite = NULL;
  4155. pIniJob->WaitForRead = NULL;
  4156. pIniJob->hWriteFile = INVALID_HANDLE_VALUE;
  4157. // Additional fields for SeekPrinter.
  4158. pIniJob->WaitForSeek = NULL;
  4159. pIniJob->bWaitForEnd = FALSE;
  4160. pIniJob->bWaitForSeek = FALSE;
  4161. pIniJob->liFileSeekPosn.u.HighPart = 0;
  4162. pIniJob->liFileSeekPosn.u.LowPart = 0;
  4163. SetPointer(pShadowFile, pDatatype);
  4164. SetPointer(pShadowFile, pNotify);
  4165. SetPointer(pShadowFile, pUser);
  4166. SetPointer(pShadowFile, pDocument);
  4167. SetPointer(pShadowFile, pOutputFile);
  4168. SetPointer(pShadowFile, pPrinterName);
  4169. SetPointer(pShadowFile, pDriverName);
  4170. SetPointer(pShadowFile, pPrintProcName);
  4171. SetPointer(pShadowFile, pParameters);
  4172. SetPointer(pShadowFile, pMachineName);
  4173. if( (pShadowFile->cbSecurityDescriptor > 0) && pShadowFile->pSecurityDescriptor )
  4174. pShadowFile->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((LPBYTE)pShadowFile +
  4175. (ULONG_PTR)pShadowFile->pSecurityDescriptor);
  4176. if (pShadowFile->pDevMode)
  4177. pShadowFile->pDevMode = (LPDEVMODEW)((LPBYTE)pShadowFile +
  4178. (ULONG_PTR)pShadowFile->pDevMode);
  4179. // check the length of the embedded strings as well as DevMode and Security structs.
  4180. if( !CheckAllPointers( pShadowFile, nFileSizeLow )) {
  4181. DBGMSG( DBG_WARNING, ("CheckAllPointers() failed; bad shadow file %ws\n", pFindFileData->cFileName ));
  4182. DELETEJOBREF(pIniJob);
  4183. FreeSplMem(pIniJob);
  4184. goto Fail;
  4185. }
  4186. //
  4187. // Discard any jobs which were NT JNL 1.000 since the fonts might not
  4188. // be correct
  4189. if ( pShadowFile->pDatatype != NULL ) {
  4190. if (!lstrcmpi( pShadowFile->pDatatype, L"NT JNL 1.000" )) {
  4191. DBGMSG(DBG_WARNING, ("Deleteing job Datatype %ws %ws %ws\n",
  4192. pShadowFile->pDatatype,
  4193. pFindFileData->cFileName, szFileName));
  4194. DELETEJOBREF(pIniJob);
  4195. FreeSplMem(pIniJob);
  4196. goto Fail;
  4197. }
  4198. }
  4199. pIniJob->pIniDriver = (PINIDRIVER)FindLocalDriver(pIniSpooler, pShadowFile->pDriverName);
  4200. if ((pIniJob->pIniPrinter = FindPrinter(pShadowFile->pPrinterName,pIniSpooler)) &&
  4201. pIniJob->pIniDriver &&
  4202. (pIniJob->pIniPrintProc = FindPrintProc(pShadowFile->pPrintProcName, FindEnvironment(szEnvironment, pIniSpooler)))) {
  4203. // Notice that MaxJobId is really the number of job slots in the pJobIdMap, so
  4204. // the maximum job id we can allow is (MaxJobId - 1).
  4205. if (pIniJob->JobId >= MaxJobId( pIniSpooler->hJobIdMap )) {
  4206. // If the job id is too huge (i.e. from a corrupt file) then we might allocate
  4207. // too much unnecessary memory for the JobIdMap!
  4208. // Notice we need to ask for (JobId+1) number of slots in the map!.
  4209. if( !ReallocJobIdMap( pIniSpooler->hJobIdMap,
  4210. pIniJob->JobId + 1 )) {
  4211. // probably a bad job id, dump the job!
  4212. DBGMSG( DBG_WARNING, ("Failed to alloc JobIdMap in ShadowFile %ws for JobId %d\n", pFindFileData->cFileName, pIniJob->JobId ));
  4213. DELETEJOBREF(pIniJob);
  4214. FreeSplMem(pIniJob);
  4215. goto Fail;
  4216. }
  4217. }
  4218. else {
  4219. if( bBitOn( pIniSpooler->hJobIdMap, pIniJob->JobId )) {
  4220. // A bad job id from a corrupt shadowfile; dump the job!
  4221. DBGMSG( DBG_WARNING, ("Duplicate Job Id in ShadowFile %ws for JobId %d\n", pFindFileData->cFileName, pIniJob->JobId ));
  4222. DELETEJOBREF(pIniJob);
  4223. FreeSplMem(pIniJob);
  4224. goto Fail;
  4225. }
  4226. }
  4227. SPLASSERT( pIniSpooler->hJobIdMap != NULL );
  4228. vMarkOn( pIniSpooler->hJobIdMap, pIniJob->JobId);
  4229. pIniJob->pIniPrinter->cJobs++;
  4230. pIniJob->pIniPrinter->cTotalJobs++;
  4231. INCDRIVERREF( pIniJob->pIniDriver );
  4232. pIniJob->pIniPrintProc->cRef++;
  4233. pIniJob->pIniPort = NULL;
  4234. if (pShadowFile->pSecurityDescriptor) {
  4235. if (pIniJob->pSecurityDescriptor=LocalAlloc(LPTR,
  4236. pShadowFile->cbSecurityDescriptor))
  4237. memcpy(pIniJob->pSecurityDescriptor,
  4238. pShadowFile->pSecurityDescriptor,
  4239. pShadowFile->cbSecurityDescriptor);
  4240. else
  4241. DBGMSG(DBG_WARNING, ("Failed to alloc ini job security descriptor.\n"));
  4242. }
  4243. if (pShadowFile->pDevMode) {
  4244. cb=pShadowFile->pDevMode->dmSize +
  4245. pShadowFile->pDevMode->dmDriverExtra;
  4246. if (pIniJob->pDevMode=AllocSplMem(cb))
  4247. memcpy(pIniJob->pDevMode, pShadowFile->pDevMode, cb);
  4248. else
  4249. DBGMSG(DBG_WARNING, ("Failed to alloc ini job devmode.\n"));
  4250. }
  4251. pIniJob->pNotify = AllocSplStr( pShadowFile->pNotify);
  4252. pIniJob->pUser = AllocSplStr( pShadowFile->pUser);
  4253. pIniJob->pDocument = AllocSplStr( pShadowFile->pDocument);
  4254. pIniJob->pOutputFile = AllocSplStr( pShadowFile->pOutputFile);
  4255. pIniJob->pDatatype = AllocSplStr( pShadowFile->pDatatype);
  4256. pIniJob->pParameters = AllocSplStr( pShadowFile->pParameters);
  4257. if( pShadowFile->pMachineName ){
  4258. pIniJob->pMachineName = AllocSplStr( pShadowFile->pMachineName );
  4259. } else {
  4260. pIniJob->pMachineName = AllocSplStr( pIniSpooler->pMachineName );
  4261. }
  4262. //
  4263. // FP Change
  4264. // Add the files to the File pool if it's not KeepPrintedJobs, and
  4265. // if the printer does not have its own spool directory.
  4266. //
  4267. if (!(pIniJob->pIniPrinter->Attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) &&
  4268. pIniJob->pIniPrinter->pSpoolDir == NULL)
  4269. {
  4270. pIniJob->pszSplFileName = AllocSplStr( szFileName );
  4271. if ((pIniJob->pIniPrinter->pIniSpooler->hFilePool != INVALID_HANDLE_VALUE)
  4272. && pIniJob->pszSplFileName && SUCCEEDED(ConvertFileExt(pIniJob->pszSplFileName, L".SHD", L".SPL")))
  4273. {
  4274. if (FAILED(GetFileItemHandle(
  4275. pIniJob->pIniPrinter->pIniSpooler->hFilePool,
  4276. &pIniJob->hFileItem,
  4277. pIniJob->pszSplFileName )))
  4278. {
  4279. pIniJob->hFileItem = INVALID_HANDLE_VALUE;
  4280. FreeSplStr(pIniJob->pszSplFileName);
  4281. pIniJob->pszSplFileName = NULL;
  4282. }
  4283. }
  4284. else
  4285. {
  4286. FreeSplStr(pIniJob->pszSplFileName);
  4287. pIniJob->pszSplFileName = NULL;
  4288. }
  4289. }
  4290. else
  4291. {
  4292. pIniJob->pszSplFileName = NULL;
  4293. pIniJob->hFileItem = INVALID_HANDLE_VALUE;
  4294. }
  4295. pIniJob->pIniNextJob = NULL;
  4296. pIniJob->pStatus = NULL;
  4297. if (pIniJob->pIniPrevJob = pIniJob->pIniPrinter->pIniLastJob)
  4298. pIniJob->pIniPrevJob->pIniNextJob=pIniJob;
  4299. if (!pIniJob->pIniPrinter->pIniFirstJob)
  4300. pIniJob->pIniPrinter->pIniFirstJob = pIniJob;
  4301. pIniJob->pIniPrinter->pIniLastJob=pIniJob;
  4302. } else {
  4303. DBGMSG( DBG_WARNING, ("Failed to find printer %ws\n",pShadowFile->pPrinterName));
  4304. DELETEJOBREF(pIniJob);
  4305. FreeSplMem(pIniJob);
  4306. goto Fail;
  4307. }
  4308. } else {
  4309. DBGMSG(DBG_WARNING, ("Failed to allocate ini job.\n"));
  4310. }
  4311. FreeSplMem( pShadowFile );
  4312. return pIniJob;
  4313. Fail:
  4314. if (pShadowFile) {
  4315. FreeSplMem(pShadowFile);
  4316. }
  4317. if (hFile != INVALID_HANDLE_VALUE && !CloseHandle(hFile)) {
  4318. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFile, GetLastError()));
  4319. }
  4320. if (hFileSpl != INVALID_HANDLE_VALUE && !CloseHandle(hFileSpl)) {
  4321. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
  4322. }
  4323. DeleteFile(szFileName);
  4324. wcscpy(pFileSpec, pFindFileData->cFileName);
  4325. DeleteFile(szFileName);
  4326. return FALSE;
  4327. }
  4328. BOOL
  4329. Old2NewShadow(
  4330. PSHADOWFILE pShadowFile1,
  4331. PSHADOWFILE_3 pShadowFile3,
  4332. DWORD *pnBytes
  4333. )
  4334. /*++
  4335. Routine Description:
  4336. Converts an original format *.shd file to a new format (version 2).
  4337. Arguments:
  4338. pShadowFile1 -- pointer to version 1 shadow file
  4339. pShadowFile2 -- pointer to version 2 shadow file
  4340. *pnBytes -- pointer to number of bytes read from version 1 shadow file. On
  4341. return, pnBytes contains the number of bytes in the version 2 shadow file.
  4342. Return Value:
  4343. None
  4344. Author: Steve Wilson (NT)
  4345. --*/
  4346. {
  4347. DWORD cbOld;
  4348. DWORD cbDiff;
  4349. switch( pShadowFile1->signature ){
  4350. case SF_SIGNATURE:
  4351. cbOld = sizeof( SHADOWFILE );
  4352. cbDiff = sizeof( SHADOWFILE_3 ) - sizeof( SHADOWFILE );
  4353. break;
  4354. case SF_SIGNATURE_2:
  4355. cbOld = sizeof ( SHADOWFILE_2 );
  4356. cbDiff = sizeof( SHADOWFILE_3 ) - sizeof( SHADOWFILE_2 );
  4357. break;
  4358. default:
  4359. return FALSE;
  4360. }
  4361. if( *pnBytes < cbOld ){
  4362. return FALSE;
  4363. }
  4364. //
  4365. // Copy everything except signature.
  4366. //
  4367. MoveMemory((PVOID)(&pShadowFile3->Status),
  4368. (PVOID)(&pShadowFile1->Status),
  4369. cbOld - sizeof( pShadowFile1->signature ));
  4370. //
  4371. // Now update signature and size.
  4372. //
  4373. pShadowFile3->signature = SF_SIGNATURE_3;
  4374. pShadowFile3->cbSize = *pnBytes + cbDiff;
  4375. //
  4376. // Move strings.
  4377. //
  4378. MoveMemory( (PVOID)(pShadowFile3 + 1),
  4379. ((PBYTE)pShadowFile1) + cbOld,
  4380. *pnBytes - cbOld );
  4381. pShadowFile3->pNotify += pShadowFile1->pNotify ? cbDiff/sizeof *pShadowFile1->pNotify : 0;
  4382. pShadowFile3->pUser += pShadowFile1->pUser ? cbDiff/sizeof *pShadowFile1->pUser : 0;
  4383. pShadowFile3->pDocument += pShadowFile1->pDocument ? cbDiff/sizeof *pShadowFile3->pDocument : 0;
  4384. pShadowFile3->pOutputFile += pShadowFile1->pOutputFile ? cbDiff/sizeof *pShadowFile3->pOutputFile : 0;
  4385. pShadowFile3->pPrinterName += pShadowFile1->pPrinterName ? cbDiff/sizeof *pShadowFile3->pPrinterName : 0;
  4386. pShadowFile3->pDriverName += pShadowFile1->pDriverName ? cbDiff/sizeof *pShadowFile3->pDriverName : 0;
  4387. pShadowFile3->pPrintProcName += pShadowFile1->pPrintProcName ? cbDiff/sizeof *pShadowFile3->pPrintProcName : 0;
  4388. pShadowFile3->pDatatype += pShadowFile1->pDatatype ? cbDiff/sizeof *pShadowFile3->pDatatype : 0;
  4389. pShadowFile3->pParameters += pShadowFile1->pParameters ? cbDiff/sizeof *pShadowFile3->pParameters : 0;
  4390. pShadowFile3->pDevMode = (PDEVMODE) (pShadowFile1->pDevMode ?
  4391. (ULONG_PTR) pShadowFile1->pDevMode + cbDiff : 0);
  4392. pShadowFile3->pSecurityDescriptor = (PSECURITY_DESCRIPTOR) (pShadowFile1->pSecurityDescriptor ?
  4393. (ULONG_PTR) pShadowFile1->pSecurityDescriptor + cbDiff : 0);
  4394. pShadowFile3->Version = SF_VERSION_3;
  4395. //
  4396. // The first shadow file didn't have dwReboots.
  4397. //
  4398. if( pShadowFile1->signature == SF_SIGNATURE ){
  4399. pShadowFile3->dwReboots = 0;
  4400. }
  4401. pShadowFile3->pMachineName = NULL;
  4402. *pnBytes += cbDiff;
  4403. return TRUE;
  4404. }
  4405. PINIVERSION
  4406. GetVersionDrivers(
  4407. HKEY hDriversKey,
  4408. LPWSTR szVersionName,
  4409. PINISPOOLER pIniSpooler,
  4410. PINIENVIRONMENT pIniEnvironment
  4411. )
  4412. {
  4413. HKEY hVersionKey;
  4414. WCHAR szDirectoryValue[MAX_PATH];
  4415. PINIDRIVER pIniDriver;
  4416. DWORD cMajorVersion, cMinorVersion;
  4417. DWORD cbData;
  4418. DWORD Type;
  4419. PINIVERSION pIniVersion = NULL;
  4420. if (SplRegOpenKey(hDriversKey, szVersionName, KEY_READ, &hVersionKey, pIniSpooler) != ERROR_SUCCESS)
  4421. {
  4422. DBGMSG(DBG_TRACE, ("GetVersionDrivers SplRegOpenKey on "TSTR" failed\n", szVersionName));
  4423. return NULL;
  4424. }
  4425. cbData = sizeof(szDirectoryValue);
  4426. if (SplRegQueryValue(hVersionKey, szDirectory, &Type, (LPBYTE)szDirectoryValue, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4427. {
  4428. DBGMSG(DBG_TRACE, ("Couldn't query for directory in version structure\n"));
  4429. goto Done;
  4430. }
  4431. cbData = sizeof(DWORD);
  4432. if (SplRegQueryValue(hVersionKey, szMajorVersion, &Type, (LPBYTE)&cMajorVersion, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4433. {
  4434. DBGMSG(DBG_TRACE, ("Couldn't query for major version in version structure\n"));
  4435. goto Done;
  4436. }
  4437. cbData = sizeof(DWORD);
  4438. if (SplRegQueryValue(hVersionKey, szMinorVersion, &Type, (LPBYTE)&cMinorVersion, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4439. {
  4440. DBGMSG(DBG_TRACE, ("Couldn't query for minor version in version structure\n"));
  4441. goto Done;
  4442. }
  4443. DBGMSG(DBG_TRACE, ("Got all information to build the version entry\n"));
  4444. //
  4445. // Now build the version node structure.
  4446. //
  4447. pIniVersion = AllocSplMem(sizeof(INIVERSION));
  4448. if( pIniVersion ){
  4449. pIniVersion->signature = IV_SIGNATURE;
  4450. pIniVersion->pName = AllocSplStr(szVersionName);
  4451. pIniVersion->szDirectory = AllocSplStr(szDirectoryValue);
  4452. pIniVersion->cMajorVersion = cMajorVersion;
  4453. pIniVersion->cMinorVersion = cMinorVersion;
  4454. pIniVersion->pDrvRefCnt = NULL;
  4455. if (!pIniVersion->pName || !pIniVersion->szDirectory) {
  4456. FreeIniVersion(pIniVersion);
  4457. pIniVersion = NULL;
  4458. } else {
  4459. pIniDriver = GetDriverList(hVersionKey,
  4460. pIniSpooler,
  4461. pIniEnvironment,
  4462. pIniVersion);
  4463. pIniVersion->pIniDriver = pIniDriver;
  4464. while (pIniDriver) {
  4465. if (!UpdateDriverFileRefCnt(pIniEnvironment,pIniVersion,pIniDriver,NULL,0,TRUE)) {
  4466. FreeIniVersion(pIniVersion);
  4467. pIniVersion = NULL;
  4468. break;
  4469. }
  4470. pIniDriver = pIniDriver->pNext;
  4471. }
  4472. }
  4473. }
  4474. Done:
  4475. SplRegCloseKey(hVersionKey, pIniSpooler);
  4476. return pIniVersion;
  4477. }
  4478. /*++
  4479. Routine Name:
  4480. FreeIniDriver
  4481. Routine Description:
  4482. This handles the memory in an inidriver after first decrementing the driver
  4483. ref-count correctly.
  4484. Arguments:
  4485. pIniEnvironment - The environment of the driver.
  4486. pIniVersion - The version of the driver.
  4487. pIniDriver - The driver to delete.
  4488. Return Value:
  4489. None.
  4490. --*/
  4491. VOID
  4492. FreeIniDriver(
  4493. IN PINIENVIRONMENT pIniEnvironment,
  4494. IN PINIVERSION pIniVersion,
  4495. IN PINIDRIVER pIniDriver
  4496. )
  4497. {
  4498. if (pIniEnvironment && pIniVersion && pIniDriver)
  4499. {
  4500. //
  4501. // This is to reverse the ref-count for when the spooler is first created.
  4502. //
  4503. UpdateDriverFileRefCnt(pIniEnvironment, pIniVersion, pIniDriver, NULL, 0, FALSE);
  4504. //
  4505. // The monitors will be deleted shortly. So we don't need to worry about
  4506. // the language monitors.
  4507. //
  4508. FreeStructurePointers((LPBYTE) pIniDriver, NULL, IniDriverOffsets);
  4509. FreeSplMem(pIniDriver);
  4510. }
  4511. }
  4512. /*++
  4513. Routine Name:
  4514. FreeIniVersion
  4515. Routine Description:
  4516. This frees all the memory in an ini-version without handling either the
  4517. drivers or the driver ref-counts in it.
  4518. Arguments:
  4519. pIniVersion - The version to delete.
  4520. Return Value:
  4521. None.
  4522. --*/
  4523. VOID
  4524. FreeIniVersion(
  4525. IN PINIVERSION pIniVersion
  4526. )
  4527. {
  4528. PDRVREFCNT pdrc,pdrctemp;
  4529. FreeSplStr( pIniVersion->pName );
  4530. FreeSplStr( pIniVersion->szDirectory );
  4531. pdrc = pIniVersion->pDrvRefCnt;
  4532. while (pdrc) {
  4533. FreeSplStr(pdrc->szDrvFileName);
  4534. pdrctemp = pdrc->pNext;
  4535. FreeSplMem(pdrc);
  4536. pdrc = pdrctemp;
  4537. }
  4538. FreeSplMem( pIniVersion );
  4539. }
  4540. /*++
  4541. Routine Name:
  4542. DeleteIniVersion
  4543. Routine Description:
  4544. This runs all of the drivers in an iniVersion and then calls FreeIniVersion
  4545. to free the contents of the iniversion.
  4546. Arguments:
  4547. pIniEnvironment - The environment used for handling driver ref-counts.
  4548. pIniVersion - The version to delete.
  4549. Return Value:
  4550. None.
  4551. --*/
  4552. VOID
  4553. DeleteIniVersion(
  4554. IN PINIENVIRONMENT pIniEnvironment,
  4555. IN PINIVERSION pIniVersion
  4556. )
  4557. {
  4558. if (pIniVersion && pIniEnvironment)
  4559. {
  4560. PINIDRIVER pIniDriver = NULL;
  4561. PINIDRIVER pNextIniDriver = NULL;
  4562. for(pIniDriver = pIniVersion->pIniDriver; pIniDriver; pIniDriver = pNextIniDriver)
  4563. {
  4564. pNextIniDriver = pIniDriver->pNext;
  4565. FreeIniDriver(pIniEnvironment, pIniVersion, pIniDriver);
  4566. }
  4567. FreeIniVersion(pIniVersion);
  4568. }
  4569. }
  4570. /*++
  4571. Routine Name:
  4572. FreeIniEnvironment
  4573. Routine Description:
  4574. This runs all of the ini-versions in an environvironment
  4575. and then deletes the environment.
  4576. Arguments:
  4577. pIniEnvironment - The environment to free.
  4578. Return Value:
  4579. None.
  4580. --*/
  4581. VOID
  4582. FreeIniEnvironment(
  4583. IN PINIENVIRONMENT pIniEnvironment
  4584. )
  4585. {
  4586. if (pIniEnvironment)
  4587. {
  4588. PINIVERSION pIniVersion = NULL;
  4589. PINIVERSION pNextIniVersion = NULL;
  4590. for(pIniVersion = pIniEnvironment->pIniVersion; pIniVersion; pIniVersion = pNextIniVersion)
  4591. {
  4592. pNextIniVersion = pIniVersion->pNext;
  4593. DeleteIniVersion(pIniEnvironment, pIniVersion);
  4594. }
  4595. FreeIniPrintProc(pIniEnvironment->pIniPrintProc);
  4596. FreeStructurePointers((LPBYTE)pIniEnvironment, NULL, IniEnvironmentOffsets);
  4597. FreeSplMem(pIniEnvironment);
  4598. }
  4599. }
  4600. /*++
  4601. Routine Name:
  4602. FreeIniPrintProc
  4603. Routine Description:
  4604. This deletes all of the print processor fields.
  4605. Arguments:
  4606. pIniPrintProc - The print processor to delete.
  4607. Return Value:
  4608. None.
  4609. --*/
  4610. VOID
  4611. FreeIniPrintProc(
  4612. IN PINIPRINTPROC pIniPrintProc
  4613. )
  4614. {
  4615. if (pIniPrintProc)
  4616. {
  4617. FreeLibrary(pIniPrintProc->hLibrary);
  4618. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  4619. FreeStructurePointers((LPBYTE)pIniPrintProc, NULL, IniPrintProcOffsets);
  4620. FreeSplMem(pIniPrintProc);
  4621. }
  4622. }
  4623. PINIDRIVER
  4624. GetDriverList(
  4625. HKEY hVersionKey,
  4626. PINISPOOLER pIniSpooler,
  4627. PINIENVIRONMENT pIniEnvironment,
  4628. PINIVERSION pIniVersion
  4629. )
  4630. {
  4631. PINIDRIVER pIniDriverList = NULL;
  4632. DWORD cDrivers = 0;
  4633. PINIDRIVER pIniDriver;
  4634. WCHAR DriverName[MAX_PATH];
  4635. DWORD cchBuffer =0;
  4636. pIniDriverList = NULL;
  4637. cchBuffer = COUNTOF(DriverName);
  4638. while (SplRegEnumKey(hVersionKey, cDrivers++, DriverName, &cchBuffer, NULL, pIniSpooler) == ERROR_SUCCESS)
  4639. {
  4640. cchBuffer = COUNTOF(DriverName);
  4641. DBGMSG(DBG_TRACE, ("Found a driver - "TSTR"\n", DriverName));
  4642. pIniDriver = GetDriver(hVersionKey, DriverName, pIniSpooler, pIniEnvironment, pIniVersion);
  4643. if (pIniDriver != NULL)
  4644. {
  4645. pIniDriver->pNext = pIniDriverList;
  4646. pIniDriverList = pIniDriver;
  4647. }
  4648. //
  4649. // On a cluster, a driver may have changed while the cluster spooler
  4650. // was hosted by another node. Here we check if we need to update or
  4651. // add a new driver
  4652. //
  4653. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  4654. ClusterCheckDriverChanged(hVersionKey,
  4655. DriverName,
  4656. pIniEnvironment->pName,
  4657. pIniVersion->pName,
  4658. pIniSpooler))
  4659. {
  4660. DWORD dwError;
  4661. //
  4662. // Add or update the driver.
  4663. //
  4664. LeaveSplSem();
  4665. if ((dwError = ClusterAddOrUpdateDriverFromClusterDisk(hVersionKey,
  4666. DriverName,
  4667. pIniEnvironment->pName,
  4668. pIniEnvironment->pDirectory,
  4669. pIniSpooler)) != ERROR_SUCCESS)
  4670. {
  4671. WCHAR szError[20];
  4672. DBGMSG(DBG_CLUSTER, ("GetDriverList failed to add/update driver "TSTR". Win32 error %u\n",
  4673. DriverName, dwError));
  4674. wsprintf(szError, L"%u", dwError);
  4675. SplLogEvent(pIniSpooler,
  4676. LOG_ERROR,
  4677. MSG_CANT_ADD_UPDATE_CLUSTER_DRIVER,
  4678. FALSE,
  4679. DriverName,
  4680. pIniSpooler->pMachineName,
  4681. szError,
  4682. NULL);
  4683. }
  4684. EnterSplSem();
  4685. }
  4686. }
  4687. return pIniDriverList;
  4688. }
  4689. PINIDRIVER
  4690. GetDriver(
  4691. HKEY hVersionKey,
  4692. LPWSTR DriverName,
  4693. PINISPOOLER pIniSpooler,
  4694. PINIENVIRONMENT pIniEnvironment,
  4695. PINIVERSION pIniVersion
  4696. )
  4697. {
  4698. HKEY hDriverKey = NULL;
  4699. DWORD Type;
  4700. WCHAR szData[MAX_PATH];
  4701. WCHAR szTempDir[MAX_PATH];
  4702. DWORD cbData;
  4703. DWORD Version;
  4704. DWORD DriverAttributes;
  4705. LPWSTR pConfigFile, pDataFile, pDriver;
  4706. LPWSTR pHelpFile, pMonitorName, pDefaultDataType, pDependentFiles, pTemp;
  4707. LPWSTR pDriverName, pszzPreviousNames;
  4708. LPWSTR pszMfgName, pszOEMUrl, pszHardwareID, pszProvider;
  4709. FILETIME DriverDate;
  4710. DWORDLONG DriverVersion;
  4711. PINIDRIVER pIniDriver = NULL;
  4712. DWORD cb, cLen, cchDependentFiles = 0, cchPreviousNames = 0;
  4713. DWORD dwTempDir, dwLastError = ERROR_SUCCESS;
  4714. pDriverName = pConfigFile = pDataFile = pDriver = pHelpFile = pTemp = NULL;
  4715. pMonitorName = pDefaultDataType = pDependentFiles = pszzPreviousNames = NULL;
  4716. pszMfgName = pszOEMUrl = pszHardwareID = pszProvider = NULL;
  4717. if ((dwLastError = SplRegOpenKey(hVersionKey, DriverName, KEY_READ, &hDriverKey, pIniSpooler)) != ERROR_SUCCESS) {
  4718. goto Fail;
  4719. }
  4720. else {
  4721. if ( !(pDriverName=AllocSplStr(DriverName)) ) {
  4722. dwLastError = GetLastError();
  4723. goto Fail;
  4724. }
  4725. RegGetString( hDriverKey, szConfigurationKey, &pConfigFile, &cLen, &dwLastError, TRUE, pIniSpooler );
  4726. if (!pConfigFile) {
  4727. goto Fail;
  4728. }
  4729. RegGetString( hDriverKey, szDataFileKey, &pDataFile, &cLen, &dwLastError, TRUE, pIniSpooler );
  4730. if ( !pDataFile ) {
  4731. goto Fail;
  4732. }
  4733. RegGetString( hDriverKey, szDriverFile, &pDriver, &cLen, &dwLastError, TRUE, pIniSpooler );
  4734. if ( !pDriver ) {
  4735. goto Fail;
  4736. }
  4737. RegGetString( hDriverKey, szHelpFile, &pHelpFile, &cLen, &dwLastError, FALSE, pIniSpooler );
  4738. RegGetString( hDriverKey, szMonitor, &pMonitorName, &cLen, &dwLastError, FALSE, pIniSpooler );
  4739. RegGetString( hDriverKey, szDatatype, &pDefaultDataType, &cLen, &dwLastError, FALSE, pIniSpooler );
  4740. RegGetMultiSzString( hDriverKey, szDependentFiles, &pDependentFiles, &cchDependentFiles, &dwLastError, FALSE, pIniSpooler );
  4741. RegGetMultiSzString( hDriverKey, szPreviousNames, &pszzPreviousNames, &cchPreviousNames, &dwLastError, FALSE, pIniSpooler );
  4742. RegGetString( hDriverKey, szMfgName, &pszMfgName, &cLen, &dwLastError, FALSE, pIniSpooler );
  4743. RegGetString( hDriverKey, szOEMUrl, &pszOEMUrl, &cLen, &dwLastError, FALSE, pIniSpooler );
  4744. RegGetString( hDriverKey, szHardwareID, &pszHardwareID, &cLen, &dwLastError, TRUE, pIniSpooler );
  4745. RegGetString( hDriverKey, szProvider, &pszProvider, &cLen, &dwLastError, TRUE, pIniSpooler );
  4746. cbData = sizeof(DriverDate);
  4747. if (SplRegQueryValue(hDriverKey, szDriverDate, NULL, (LPBYTE)&DriverDate, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4748. {
  4749. //
  4750. // don't leave the data uninitialized
  4751. //
  4752. DriverDate.dwLowDateTime = DriverDate.dwHighDateTime = 0;
  4753. }
  4754. cbData = sizeof(DriverVersion);
  4755. if (SplRegQueryValue(hDriverKey, szLongVersion, NULL, (LPBYTE)&DriverVersion, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4756. {
  4757. //
  4758. // don't leave the data uninitialized
  4759. //
  4760. DriverVersion = 0;
  4761. }
  4762. // Retrieve the version number
  4763. cbData = sizeof(DWORD);
  4764. if (SplRegQueryValue(hDriverKey, szDriverAttributes, &Type, (LPBYTE)&DriverAttributes, &cbData, pIniSpooler) != ERROR_SUCCESS)
  4765. {
  4766. DriverAttributes = 0;
  4767. }
  4768. // Retrieve the version number
  4769. cbData = sizeof(DWORD);
  4770. if (SplRegQueryValue(hDriverKey, szDriverVersion, &Type, (LPBYTE)&Version, &cbData, pIniSpooler) != ERROR_SUCCESS)
  4771. {
  4772. Version = 0;
  4773. }
  4774. // Retrieve the TempDir number
  4775. cbData = sizeof(DWORD);
  4776. if (SplRegQueryValue(hDriverKey, szTempDir, &Type, (LPBYTE)&dwTempDir, &cbData, pIniSpooler) != ERROR_SUCCESS)
  4777. {
  4778. dwTempDir = 0;
  4779. }
  4780. // After REBOOT temp directories are deleted. So check for the presence of the
  4781. // directory on spooler startup.
  4782. if (dwTempDir && pIniEnvironment && pIniVersion)
  4783. {
  4784. _itow(dwTempDir,szTempDir,10);
  4785. if(StrNCatBuff(szData,
  4786. COUNTOF(szData),
  4787. pIniSpooler->pDir,
  4788. L"\\drivers\\",
  4789. pIniEnvironment->pDirectory,
  4790. L"\\",
  4791. pIniVersion->szDirectory,
  4792. L"\\",
  4793. szTempDir,
  4794. NULL) == ERROR_SUCCESS)
  4795. {
  4796. if (!DirectoryExists(szData))
  4797. {
  4798. // Files must have been moved in Reboot, reset dwTempDir to 0
  4799. dwTempDir = 0;
  4800. }
  4801. }
  4802. }
  4803. SplRegCloseKey(hDriverKey, pIniSpooler);
  4804. }
  4805. //
  4806. // Win95 driver needs every file as a dependent file for point and print.
  4807. // For others we eliminate duplicates
  4808. //
  4809. if ( pIniEnvironment && _wcsicmp(pIniEnvironment->pName, szWin95Environment) ) {
  4810. pTemp = pDependentFiles;
  4811. pDependentFiles = NULL;
  4812. if ( !BuildTrueDependentFileField(pDriver,
  4813. pDataFile,
  4814. pConfigFile,
  4815. pHelpFile,
  4816. pTemp,
  4817. &pDependentFiles) )
  4818. goto Fail;
  4819. FreeSplMem(pTemp);
  4820. for ( pTemp = pDependentFiles ; pTemp && *pTemp ;
  4821. pTemp += wcslen(pTemp) + 1 )
  4822. ;
  4823. if ( pTemp )
  4824. cchDependentFiles = (DWORD) (pTemp - pDependentFiles + 1);
  4825. else
  4826. cchDependentFiles = 0;
  4827. }
  4828. cb = sizeof( INIDRIVER );
  4829. if ( pIniDriver = AllocSplMem( cb )) {
  4830. pIniDriver->signature = ID_SIGNATURE;
  4831. pIniDriver->pName = pDriverName;
  4832. pIniDriver->pDriverFile = pDriver;
  4833. pIniDriver->pDataFile = pDataFile;
  4834. pIniDriver->pConfigFile = pConfigFile;
  4835. pIniDriver->cVersion = Version;
  4836. pIniDriver->pHelpFile = pHelpFile;
  4837. pIniDriver->pMonitorName = pMonitorName;
  4838. pIniDriver->pDefaultDataType = pDefaultDataType;
  4839. pIniDriver->pDependentFiles = pDependentFiles;
  4840. pIniDriver->cchDependentFiles = cchDependentFiles;
  4841. pIniDriver->pszzPreviousNames = pszzPreviousNames;
  4842. pIniDriver->cchPreviousNames = cchPreviousNames;
  4843. pIniDriver->dwTempDir = dwTempDir;
  4844. pIniDriver->pszMfgName = pszMfgName;
  4845. pIniDriver->pszOEMUrl = pszOEMUrl;
  4846. pIniDriver->pszHardwareID = pszHardwareID;
  4847. pIniDriver->pszProvider = pszProvider;
  4848. pIniDriver->dwlDriverVersion = DriverVersion;
  4849. pIniDriver->ftDriverDate = DriverDate;
  4850. pIniDriver->dwDriverAttributes = DriverAttributes;
  4851. pIniDriver->DriverFileMinorVersion = 0;
  4852. pIniDriver->DriverFileMajorVersion = 0;
  4853. DBGMSG( DBG_TRACE, ("Data for driver %ws created:\
  4854. \n\tpDriverFile:\t%ws\
  4855. \n\tpDataFile:\t%ws\
  4856. \n\tpConfigFile:\t%ws\n\n",
  4857. pDriverName, pDriver, pDataFile, pConfigFile));
  4858. if ( pIniDriver->pMonitorName && *pIniDriver->pMonitorName ) {
  4859. //
  4860. // Don't we add ref the monitor here?
  4861. //
  4862. pIniDriver->pIniLangMonitor = FindMonitor(pIniDriver->pMonitorName, pIniSpooler);
  4863. //
  4864. // Cluster spoolers do not have keep their own lists of language monitors.
  4865. // This is because most language monitors are not cluster aware. Therefore,
  4866. // cluster spooler share language monitors with the local spooler.
  4867. //
  4868. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  4869. !pIniDriver->pIniLangMonitor &&
  4870. pLocalIniSpooler)
  4871. {
  4872. //
  4873. // We try to find the langauge monitor off the local spooler
  4874. //
  4875. pIniDriver->pIniLangMonitor = FindMonitor(pIniDriver->pMonitorName, pLocalIniSpooler);
  4876. }
  4877. if (!pIniDriver->pIniLangMonitor)
  4878. {
  4879. DBGMSG(DBG_TRACE, ("Can't find print monitor %ws\n", pIniDriver->pMonitorName));
  4880. }
  4881. }
  4882. return pIniDriver;
  4883. }
  4884. Fail:
  4885. FreeSplStr( pDriverName );
  4886. FreeSplStr( pConfigFile );
  4887. FreeSplStr( pDataFile );
  4888. FreeSplStr( pHelpFile );
  4889. FreeSplStr( pMonitorName );
  4890. FreeSplStr( pDefaultDataType );
  4891. FreeSplStr( pDependentFiles );
  4892. FreeSplStr( pszzPreviousNames );
  4893. FreeSplStr( pDriver );
  4894. FreeSplStr( pTemp);
  4895. FreeSplStr( pszMfgName);
  4896. FreeSplStr( pszOEMUrl);
  4897. FreeSplStr( pszProvider);
  4898. FreeSplStr( pszHardwareID);
  4899. if( hDriverKey ) {
  4900. SplRegCloseKey(hDriverKey, pIniSpooler);
  4901. }
  4902. SetLastError( dwLastError );
  4903. return NULL;
  4904. }
  4905. PINIDRIVER
  4906. FindLocalDriver(
  4907. PINISPOOLER pIniSpooler,
  4908. LPWSTR pz
  4909. )
  4910. {
  4911. PINIVERSION pIniVersion;
  4912. if ( !pz || !*pz ) {
  4913. return NULL;
  4914. }
  4915. //
  4916. // During Upgrade we load any driver so we have a valid printer, which might not be able to boot.
  4917. //
  4918. return FindCompatibleDriver(GetLocalArchEnv(pIniSpooler),
  4919. &pIniVersion,
  4920. pz,
  4921. dwMajorVersion,
  4922. dwUpgradeFlag);
  4923. }
  4924. BOOL
  4925. FindLocalDriverAndVersion(
  4926. PINISPOOLER pIniSpooler,
  4927. LPWSTR pz,
  4928. PINIDRIVER *ppIniDriver,
  4929. PINIVERSION *ppIniVersion
  4930. )
  4931. {
  4932. if ( !pz || !*pz || !ppIniDriver || !ppIniVersion) {
  4933. return FALSE;
  4934. }
  4935. //
  4936. // During Upgrade we load any driver so we have a valid printer, which might not be able to boot.
  4937. //
  4938. *ppIniDriver = FindCompatibleDriver( GetLocalArchEnv(pIniSpooler),
  4939. ppIniVersion,
  4940. pz,
  4941. dwMajorVersion,
  4942. dwUpgradeFlag );
  4943. if ( !*ppIniDriver || !*ppIniVersion ) {
  4944. return FALSE;
  4945. }
  4946. return TRUE;
  4947. }
  4948. #if DBG
  4949. VOID
  4950. InitializeDebug(
  4951. PINISPOOLER pIniSpooler
  4952. )
  4953. {
  4954. DWORD Status;
  4955. HKEY hKey = pIniSpooler->hckRoot;
  4956. DWORD cbData;
  4957. INT TimeOut = 60;
  4958. cbData = sizeof(DWORD);
  4959. Status = SplRegQueryValue( hKey,
  4960. szDebugFlags,
  4961. NULL,
  4962. (LPBYTE)&MODULE_DEBUG,
  4963. &cbData,
  4964. pIniSpooler );
  4965. // Wait until someone turns off the Pause Flag
  4966. if ( Status != NO_ERROR )
  4967. return;
  4968. while ( MODULE_DEBUG & DBG_PAUSE ) {
  4969. Sleep(1*1000);
  4970. if ( TimeOut-- == 0)
  4971. break;
  4972. }
  4973. DBGMSG(DBG_TRACE, ("DebugFlags %x\n", MODULE_DEBUG));
  4974. }
  4975. #endif
  4976. VOID
  4977. GetPrintSystemVersion(
  4978. PINISPOOLER pIniSpooler
  4979. )
  4980. {
  4981. DWORD Status;
  4982. HKEY hKey;
  4983. DWORD cbData;
  4984. hKey = pIniSpooler->hckRoot;
  4985. cbData = sizeof(DWORD);
  4986. RegQueryValueEx(hKey, szMinorVersion, NULL, NULL,
  4987. (LPBYTE)&dwMinorVersion, &cbData);
  4988. DBGMSG(DBG_TRACE, ("This Minor Version - %d\n", dwMinorVersion));
  4989. cbData = sizeof(DWORD);
  4990. RegQueryValueEx(hKey, L"FastPrintWaitTimeout", NULL, NULL,
  4991. (LPBYTE)&dwFastPrintWaitTimeout, &cbData);
  4992. DBGMSG(DBG_TRACE, ("dwFastPrintWaitTimeout - %d\n", dwFastPrintWaitTimeout));
  4993. cbData = sizeof(DWORD);
  4994. RegQueryValueEx(hKey, L"FastPrintThrottleTimeout", NULL, NULL,
  4995. (LPBYTE)&dwFastPrintThrottleTimeout, &cbData);
  4996. DBGMSG(DBG_TRACE, ("dwFastPrintThrottleTimeout - %d\n", dwFastPrintThrottleTimeout));
  4997. // If the values look invalid use Defaults
  4998. if (( dwFastPrintThrottleTimeout == 0) ||
  4999. ( dwFastPrintWaitTimeout < dwFastPrintThrottleTimeout)) {
  5000. DBGMSG( DBG_WARNING, ("Bad timeout values FastPrintThrottleTimeout %d FastPrintWaitTimeout %d using defaults\n",
  5001. dwFastPrintThrottleTimeout, dwFastPrintWaitTimeout));
  5002. dwFastPrintThrottleTimeout = FASTPRINT_THROTTLE_TIMEOUT;
  5003. dwFastPrintWaitTimeout = FASTPRINT_WAIT_TIMEOUT;
  5004. }
  5005. // Calculate a reasonable Threshold based on the two timeouts
  5006. dwFastPrintSlowDownThreshold = dwFastPrintWaitTimeout / dwFastPrintThrottleTimeout;
  5007. // FastPrintSlowDownThreshold
  5008. cbData = sizeof(DWORD);
  5009. RegQueryValueEx(hKey, L"FastPrintSlowDownThreshold", NULL, NULL,
  5010. (LPBYTE)&dwFastPrintSlowDownThreshold, &cbData);
  5011. DBGMSG(DBG_TRACE, ("dwFastPrintSlowDownThreshold - %d\n", dwFastPrintSlowDownThreshold));
  5012. // PortThreadPriority
  5013. cbData = sizeof dwPortThreadPriority;
  5014. Status = RegQueryValueEx(hKey, SPLREG_PORT_THREAD_PRIORITY, NULL, NULL,
  5015. (LPBYTE)&dwPortThreadPriority, &cbData);
  5016. if (Status != ERROR_SUCCESS ||
  5017. (dwPortThreadPriority != THREAD_PRIORITY_LOWEST &&
  5018. dwPortThreadPriority != THREAD_PRIORITY_BELOW_NORMAL &&
  5019. dwPortThreadPriority != THREAD_PRIORITY_NORMAL &&
  5020. dwPortThreadPriority != THREAD_PRIORITY_ABOVE_NORMAL &&
  5021. dwPortThreadPriority != THREAD_PRIORITY_HIGHEST)) {
  5022. dwPortThreadPriority = DEFAULT_PORT_THREAD_PRIORITY;
  5023. SetPrinterDataServer( pIniSpooler,
  5024. SPLREG_PORT_THREAD_PRIORITY,
  5025. REG_DWORD,
  5026. (LPBYTE) &dwPortThreadPriority,
  5027. sizeof dwPortThreadPriority
  5028. );
  5029. }
  5030. DBGMSG(DBG_TRACE, ("dwPortThreadPriority - %d\n", dwPortThreadPriority));
  5031. // SchedulerThreadPriority
  5032. cbData = sizeof dwSchedulerThreadPriority;
  5033. Status = RegQueryValueEx(hKey, SPLREG_SCHEDULER_THREAD_PRIORITY, NULL, NULL,
  5034. (LPBYTE)&dwSchedulerThreadPriority, &cbData);
  5035. if (Status != ERROR_SUCCESS ||
  5036. (dwSchedulerThreadPriority != THREAD_PRIORITY_LOWEST &&
  5037. dwSchedulerThreadPriority != THREAD_PRIORITY_BELOW_NORMAL &&
  5038. dwSchedulerThreadPriority != THREAD_PRIORITY_NORMAL &&
  5039. dwSchedulerThreadPriority != THREAD_PRIORITY_ABOVE_NORMAL &&
  5040. dwSchedulerThreadPriority != THREAD_PRIORITY_HIGHEST)) {
  5041. dwSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
  5042. SetPrinterDataServer( pIniSpooler,
  5043. SPLREG_SCHEDULER_THREAD_PRIORITY,
  5044. REG_DWORD,
  5045. (LPBYTE) &dwSchedulerThreadPriority,
  5046. sizeof dwSchedulerThreadPriority
  5047. );
  5048. }
  5049. DBGMSG(DBG_TRACE, ("dwSchedulerThreadPriority - %d\n", dwSchedulerThreadPriority));
  5050. // WritePrinterSleepTime
  5051. cbData = sizeof(DWORD);
  5052. RegQueryValueEx(hKey, L"WritePrinterSleepTime", NULL, NULL,
  5053. (LPBYTE)&dwWritePrinterSleepTime, &cbData);
  5054. DBGMSG(DBG_TRACE, ("dwWritePrinterSleepTime - %d\n", dwWritePrinterSleepTime));
  5055. // ServerThreadPriority
  5056. cbData = sizeof(DWORD);
  5057. RegQueryValueEx(hKey, L"ServerThreadPriority", NULL, NULL,
  5058. (LPBYTE)&dwServerThreadPriority, &cbData);
  5059. DBGMSG(DBG_TRACE, ("dwServerThreadPriority - %d\n", dwServerThreadPriority));
  5060. // ServerThreadTimeout
  5061. cbData = sizeof(DWORD);
  5062. RegQueryValueEx(hKey, L"ServerThreadTimeout", NULL, NULL,
  5063. (LPBYTE)&ServerThreadTimeout, &cbData);
  5064. DBGMSG(DBG_TRACE, ("ServerThreadTimeout - %d\n", ServerThreadTimeout));
  5065. // EnableBroadcastSpoolerStatus
  5066. cbData = sizeof(DWORD);
  5067. RegQueryValueEx(hKey, L"EnableBroadcastSpoolerStatus", NULL, NULL,
  5068. (LPBYTE)&dwEnableBroadcastSpoolerStatus, &cbData);
  5069. DBGMSG(DBG_TRACE, ("EnableBroadcastSpoolerStatus - %d\n",
  5070. dwEnableBroadcastSpoolerStatus ));
  5071. // NetPrinterDecayPeriod
  5072. cbData = sizeof(DWORD);
  5073. RegQueryValueEx(hKey, L"NetPrinterDecayPeriod", NULL, NULL,
  5074. (LPBYTE)&NetPrinterDecayPeriod, &cbData);
  5075. DBGMSG(DBG_TRACE, ("NetPrinterDecayPeriod - %d\n", NetPrinterDecayPeriod));
  5076. // RefreshTimesPerDecayPeriod
  5077. cbData = sizeof(DWORD);
  5078. RegQueryValueEx(hKey, L"RefreshTimesPerDecayPeriod", NULL, NULL,
  5079. (LPBYTE)&RefreshTimesPerDecayPeriod, &cbData);
  5080. DBGMSG(DBG_TRACE, ("RefreshTimesPerDecayPeriod - %d\n", RefreshTimesPerDecayPeriod));
  5081. if ( RefreshTimesPerDecayPeriod == 0 ) {
  5082. RefreshTimesPerDecayPeriod = DEFAULT_REFRESH_TIMES_PER_DECAY_PERIOD;
  5083. }
  5084. // BrowsePrintWorkstations
  5085. cbData = sizeof( BrowsePrintWorkstations );
  5086. RegQueryValueEx( hKey, L"BrowsePrintWorkstations", NULL, NULL, (LPBYTE)&BrowsePrintWorkstations, &cbData );
  5087. DBGMSG( DBG_TRACE, ("BrowsePrintWorkstations - %d\n", BrowsePrintWorkstations ));
  5088. }
  5089. VOID
  5090. InitializeSpoolerSettings(
  5091. PINISPOOLER pIniSpooler
  5092. )
  5093. {
  5094. HKEY hKey;
  5095. HKEY hKeyProvider;
  5096. DWORD cbData;
  5097. DWORD dwLastError;
  5098. DWORD Status;
  5099. DWORD CacheMasqPrinters;
  5100. DWORDLONG dwlConditionMask = 0;
  5101. OSVERSIONINFOEX osvi;
  5102. hKey = pIniSpooler->hckRoot;
  5103. //
  5104. // BeepEnabled
  5105. //
  5106. cbData = sizeof pIniSpooler->dwBeepEnabled;
  5107. Status = SplRegQueryValue(hKey,
  5108. SPLREG_BEEP_ENABLED,
  5109. NULL,
  5110. (LPBYTE)&pIniSpooler->dwBeepEnabled,
  5111. &cbData,
  5112. pIniSpooler);
  5113. if (Status!=ERROR_SUCCESS) {
  5114. DBGMSG(DBG_TRACE, ("BeepEnabled - SplRegQueryValue failed with error %u\n", Status));
  5115. }
  5116. pIniSpooler->dwBeepEnabled = !!pIniSpooler->dwBeepEnabled;
  5117. SetPrinterDataServer(pIniSpooler,
  5118. SPLREG_BEEP_ENABLED,
  5119. REG_DWORD,
  5120. (LPBYTE) &pIniSpooler->dwBeepEnabled,
  5121. sizeof pIniSpooler->dwBeepEnabled);
  5122. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  5123. //
  5124. // Restart job time.
  5125. //
  5126. cbData = sizeof( pIniSpooler->dwJobCompletionTimeout );
  5127. Status = SplRegQueryValue( hKey,
  5128. L"JobCompletionTimeout",
  5129. NULL,
  5130. (LPBYTE)&pIniSpooler->dwJobCompletionTimeout,
  5131. &cbData,
  5132. pIniSpooler );
  5133. if( Status != ERROR_SUCCESS ){
  5134. pIniSpooler->dwJobCompletionTimeout = DEFAULT_JOB_COMPLETION_TIMEOUT;
  5135. }
  5136. DBGMSG( DBG_TRACE, ("JobCompletionTimeout - %d\n", pIniSpooler->dwJobCompletionTimeout ));
  5137. }
  5138. //
  5139. // Retrieve whether we want to cache masq printer settings, default is FALSE.
  5140. //
  5141. cbData = sizeof(CacheMasqPrinters);
  5142. Status = SplRegQueryValue(hKey,
  5143. gszCacheMasqPrinters,
  5144. NULL,
  5145. (BYTE *)&CacheMasqPrinters,
  5146. &cbData,
  5147. pIniSpooler);
  5148. //
  5149. // We only set the bit for caching masq printers if CacbeMasqPrinters is
  5150. // non-NULL.
  5151. //
  5152. if (Status == ERROR_SUCCESS && CacheMasqPrinters != 0) {
  5153. pIniSpooler->dwSpoolerSettings |= SPOOLER_CACHEMASQPRINTERS;
  5154. }
  5155. //
  5156. // Some Folks like the NT FAX Service Don't want people to be able
  5157. // to remotely print with specific printer drivers.
  5158. //
  5159. // For Whistler we don't allow sharing the fax printer on Personal & Professional
  5160. //
  5161. ZeroMemory(&osvi, sizeof(osvi));
  5162. osvi.dwOSVersionInfoSize = sizeof(osvi);
  5163. osvi.wProductType = VER_NT_WORKSTATION;
  5164. VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_LESS_EQUAL);
  5165. if (VerifyVersionInfo( &osvi,
  5166. VER_PRODUCT_TYPE,
  5167. dwlConditionMask)) {
  5168. pIniSpooler->pNoRemotePrintDrivers = AllocSplStr(szNTFaxDriver);
  5169. pIniSpooler->cchNoRemotePrintDrivers = wcslen(szNTFaxDriver) + 1;
  5170. gbRemoteFax = FALSE;
  5171. }
  5172. //
  5173. // If this is embedded NT, then allow masq printers to get non-RAW
  5174. // jobs. This is for Xerox.
  5175. //
  5176. dwlConditionMask = 0;
  5177. ZeroMemory(&osvi, sizeof(osvi));
  5178. osvi.wSuiteMask = VER_SUITE_EMBEDDEDNT;
  5179. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
  5180. if (VerifyVersionInfo( &osvi,
  5181. VER_SUITENAME,
  5182. dwlConditionMask)) {
  5183. pIniSpooler->SpoolerFlags |= SPL_NON_RAW_TO_MASQ_PRINTERS;
  5184. }
  5185. Status = SplRegCreateKey( pIniSpooler->hckRoot,
  5186. pIniSpooler->pszRegistryProviders,
  5187. 0,
  5188. KEY_READ,
  5189. NULL,
  5190. &hKeyProvider,
  5191. NULL,
  5192. pIniSpooler );
  5193. if( Status == NO_ERROR ){
  5194. DWORD Flags;
  5195. // NonRawToMasqPrinters
  5196. cbData = sizeof( Flags );
  5197. Status = SplRegQueryValue( hKeyProvider,
  5198. SPLREG_NON_RAW_TO_MASQ_PRINTERS,
  5199. NULL,
  5200. (LPBYTE)&Flags,
  5201. &cbData,
  5202. pIniSpooler );
  5203. if (Status == ERROR_SUCCESS) {
  5204. if (Flags) {
  5205. pIniSpooler->SpoolerFlags |= SPL_NON_RAW_TO_MASQ_PRINTERS;
  5206. }
  5207. }
  5208. // EventLog
  5209. cbData = sizeof( Flags );
  5210. Status = SplRegQueryValue( hKeyProvider,
  5211. SPLREG_EVENT_LOG,
  5212. NULL,
  5213. (LPBYTE)&Flags,
  5214. &cbData,
  5215. pIniSpooler );
  5216. if (Status == ERROR_SUCCESS) {
  5217. pIniSpooler->dwEventLogging = Flags;
  5218. } else {
  5219. Status = SetPrinterDataServer( pIniSpooler,
  5220. SPLREG_EVENT_LOG,
  5221. REG_DWORD,
  5222. (LPBYTE)&pIniSpooler->dwEventLogging,
  5223. sizeof( pIniSpooler->dwEventLogging ));
  5224. }
  5225. // NetPopup
  5226. cbData = sizeof( Flags );
  5227. Status = SplRegQueryValue( hKeyProvider,
  5228. SPLREG_NET_POPUP,
  5229. NULL,
  5230. (LPBYTE)&Flags,
  5231. &cbData,
  5232. pIniSpooler );
  5233. if (Status == ERROR_SUCCESS) {
  5234. pIniSpooler->bEnableNetPopups = !!Flags;
  5235. if (Flags != 1 && Flags != 0) {
  5236. Status = SetPrinterDataServer( pIniSpooler,
  5237. SPLREG_NET_POPUP,
  5238. REG_DWORD,
  5239. (LPBYTE)&pIniSpooler->bEnableNetPopups,
  5240. sizeof( pIniSpooler->bEnableNetPopups ));
  5241. }
  5242. } else {
  5243. Status = SetPrinterDataServer( pIniSpooler,
  5244. SPLREG_NET_POPUP,
  5245. REG_DWORD,
  5246. (LPBYTE)&pIniSpooler->bEnableNetPopups,
  5247. sizeof( pIniSpooler->bEnableNetPopups ));
  5248. }
  5249. // NetPopupToComputer
  5250. cbData = sizeof( Flags );
  5251. Status = SplRegQueryValue( hKeyProvider,
  5252. SPLREG_NET_POPUP_TO_COMPUTER,
  5253. NULL,
  5254. (LPBYTE)&Flags,
  5255. &cbData,
  5256. pIniSpooler );
  5257. if (Status == ERROR_SUCCESS) {
  5258. pIniSpooler->bEnableNetPopupToComputer = !!Flags;
  5259. if (Flags != 1 && Flags != 0) {
  5260. Status = SetPrinterDataServer( pIniSpooler,
  5261. SPLREG_NET_POPUP_TO_COMPUTER,
  5262. REG_DWORD,
  5263. (LPBYTE)&pIniSpooler->bEnableNetPopupToComputer,
  5264. sizeof( pIniSpooler->bEnableNetPopupToComputer ));
  5265. }
  5266. } else {
  5267. Status = SetPrinterDataServer( pIniSpooler,
  5268. SPLREG_NET_POPUP_TO_COMPUTER,
  5269. REG_DWORD,
  5270. (LPBYTE)&pIniSpooler->bEnableNetPopupToComputer,
  5271. sizeof( pIniSpooler->bEnableNetPopupToComputer ));
  5272. }
  5273. // RetryPopup
  5274. cbData = sizeof( Flags );
  5275. Status = SplRegQueryValue( hKeyProvider,
  5276. SPLREG_RETRY_POPUP,
  5277. NULL,
  5278. (LPBYTE)&Flags,
  5279. &cbData,
  5280. pIniSpooler );
  5281. if (Status == ERROR_SUCCESS) {
  5282. pIniSpooler->bEnableRetryPopups = !!Flags;
  5283. if (Flags != 1 && Flags != 0) {
  5284. Status = SetPrinterDataServer( pIniSpooler,
  5285. SPLREG_RETRY_POPUP,
  5286. REG_DWORD,
  5287. (LPBYTE)&pIniSpooler->bEnableRetryPopups,
  5288. sizeof( pIniSpooler->bEnableRetryPopups ));
  5289. }
  5290. } else {
  5291. Status = SetPrinterDataServer( pIniSpooler,
  5292. SPLREG_RETRY_POPUP,
  5293. REG_DWORD,
  5294. (LPBYTE)&pIniSpooler->bEnableRetryPopups,
  5295. sizeof( pIniSpooler->bEnableRetryPopups ));
  5296. }
  5297. // RestartJobOnPoolError
  5298. cbData = sizeof( Flags );
  5299. Status = SplRegQueryValue( hKeyProvider,
  5300. SPLREG_RESTART_JOB_ON_POOL_ERROR,
  5301. NULL,
  5302. (LPBYTE)&Flags,
  5303. &cbData,
  5304. pIniSpooler );
  5305. if (Status == ERROR_SUCCESS) {
  5306. pIniSpooler->dwRestartJobOnPoolTimeout = Flags;
  5307. } else {
  5308. Status = SetPrinterDataServer( pIniSpooler,
  5309. SPLREG_RESTART_JOB_ON_POOL_ERROR,
  5310. REG_DWORD,
  5311. (LPBYTE)&pIniSpooler->dwRestartJobOnPoolTimeout,
  5312. sizeof( pIniSpooler->dwRestartJobOnPoolTimeout ));
  5313. }
  5314. // RestartJobOnPoolEnabled
  5315. cbData = sizeof( Flags );
  5316. Status = SplRegQueryValue( hKeyProvider,
  5317. SPLREG_RESTART_JOB_ON_POOL_ENABLED,
  5318. NULL,
  5319. (LPBYTE)&Flags,
  5320. &cbData,
  5321. pIniSpooler );
  5322. if (Status == ERROR_SUCCESS) {
  5323. pIniSpooler->bRestartJobOnPoolEnabled = !!Flags;
  5324. if (Flags != 1 && Flags != 0) {
  5325. Status = SetPrinterDataServer( pIniSpooler,
  5326. SPLREG_RESTART_JOB_ON_POOL_ENABLED,
  5327. REG_DWORD,
  5328. (LPBYTE)&pIniSpooler->bRestartJobOnPoolEnabled,
  5329. sizeof( pIniSpooler->bRestartJobOnPoolEnabled ));
  5330. }
  5331. } else {
  5332. Status = SetPrinterDataServer( pIniSpooler,
  5333. SPLREG_RESTART_JOB_ON_POOL_ENABLED,
  5334. REG_DWORD,
  5335. (LPBYTE)&pIniSpooler->bRestartJobOnPoolEnabled,
  5336. sizeof( pIniSpooler->bRestartJobOnPoolEnabled ));
  5337. }
  5338. SplRegCloseKey( hKeyProvider, pIniSpooler );
  5339. }
  5340. }
  5341. DWORD
  5342. FinalInitAfterRouterInitComplete(
  5343. DWORD dwUpgrade,
  5344. PINISPOOLER pIniSpooler
  5345. )
  5346. /*++
  5347. Routine Description:
  5348. This thread does LocalSpl initialization that has to happen after
  5349. the router has completely initialized.
  5350. There are 2 jobs:-
  5351. Upgrading Printer Driver Data
  5352. Sharing Printers
  5353. Ensures that printers are shared. This case occurs when the spooler
  5354. service not running on startup (and the server is), and then the
  5355. user starts the spooler.
  5356. We also get the benefit of closing down any invalid printer handles
  5357. (in the server).
  5358. Arguments:
  5359. dwUpgrade != 0 upgrade printer driver data.
  5360. Return Value:
  5361. DWORD - ignored
  5362. --*/
  5363. {
  5364. DWORD dwPort;
  5365. PINIPORT pIniPort;
  5366. PINIMONITOR pIniLangMonitor;
  5367. PINIPRINTER pIniPrinter;
  5368. PINIPRINTER pIniPrinterNext;
  5369. // Do Not share all the printers during an Upgrade.
  5370. if ( dwUpgrade ) {
  5371. return 0;
  5372. }
  5373. WaitForSpoolerInitialization();
  5374. // Try pending driver upgrades on spooler startup
  5375. PendingDriverUpgrades(NULL);
  5376. EnterSplSem();
  5377. // Delete printers in pending deletion state with no jobs
  5378. CleanupDeletedPrinters(pIniSpooler);
  5379. //
  5380. // Re-share all shared printers.
  5381. //
  5382. for( pIniPrinter = pIniSpooler->pIniPrinter;
  5383. pIniPrinter;
  5384. pIniPrinter = pIniPrinterNext ) {
  5385. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  5386. //
  5387. // Up the ref count to prevent deletion
  5388. //
  5389. INCPRINTERREF( pIniPrinter );
  5390. //
  5391. // Unshare it first to close all handles in the
  5392. // server.
  5393. //
  5394. ShareThisPrinter( pIniPrinter,
  5395. pIniPrinter->pShareName,
  5396. FALSE );
  5397. //
  5398. // ShareThisPrinter leave SplSem, so check again to
  5399. // decrease window.
  5400. //
  5401. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  5402. BOOL bReturn;
  5403. //
  5404. // Now share it again.
  5405. //
  5406. bReturn = ShareThisPrinter( pIniPrinter,
  5407. pIniPrinter->pShareName,
  5408. TRUE );
  5409. if( !bReturn ){
  5410. DWORD rc = GetLastError();
  5411. if( rc != NERR_ServerNotStarted &&
  5412. rc != NERR_DuplicateShare ){
  5413. WCHAR pwszError[256];
  5414. DBGMSG( DBG_WARNING,
  5415. ( "NetShareAdd failed %lx\n", rc));
  5416. wsprintf(pwszError, L"+ %d", rc);
  5417. SplLogEvent( pIniSpooler,
  5418. LOG_ERROR,
  5419. MSG_SHARE_FAILED,
  5420. TRUE,
  5421. pwszError,
  5422. pIniPrinter->pName,
  5423. pIniPrinter->pShareName,
  5424. NULL );
  5425. }
  5426. }
  5427. }
  5428. DECPRINTERREF( pIniPrinter );
  5429. pIniPrinterNext = pIniPrinter->pNext;
  5430. } else {
  5431. //
  5432. // The unshared case.
  5433. //
  5434. pIniPrinterNext = pIniPrinter->pNext;
  5435. }
  5436. INCPRINTERREF(pIniPrinter);
  5437. if (pIniPrinterNext)
  5438. INCPRINTERREF(pIniPrinterNext);
  5439. for ( dwPort = 0 ; dwPort < pIniPrinter->cPorts ; ++dwPort ) {
  5440. pIniPort = pIniPrinter->ppIniPorts[dwPort];
  5441. //
  5442. // Bidi monitor can inform spooler of errors. First
  5443. // printer will keep the port at the beginning
  5444. //
  5445. if ( pIniPort->ppIniPrinter[0] != pIniPrinter )
  5446. continue;
  5447. if ( !pIniPort->hPort && dwUpgradeFlag == 0 ) {
  5448. LPTSTR pszPrinter;
  5449. TCHAR szFullPrinter[ MAX_UNC_PRINTER_NAME ];
  5450. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  5451. pszPrinter = szFullPrinter;
  5452. wsprintf(szFullPrinter,
  5453. L"%ws\\%ws",
  5454. pIniSpooler->pMachineName,
  5455. pIniPrinter->pName );
  5456. } else {
  5457. pszPrinter = pIniPrinter->pName;
  5458. }
  5459. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI )
  5460. pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
  5461. else
  5462. pIniLangMonitor = NULL;
  5463. OpenMonitorPort(pIniPort,
  5464. &pIniLangMonitor,
  5465. pszPrinter,
  5466. TRUE);
  5467. }
  5468. }
  5469. if (pIniPrinterNext)
  5470. DECPRINTERREF(pIniPrinterNext);
  5471. DECPRINTERREF(pIniPrinter);
  5472. }
  5473. LeaveSplSem();
  5474. return 0;
  5475. }
  5476. DWORD
  5477. FinalInitAfterRouterInitCompleteThread(
  5478. DWORD dwUpgrade
  5479. )
  5480. /*++
  5481. Routine Description:
  5482. Async thread called when initializing provider.
  5483. Arguments:
  5484. Return Value:
  5485. --*/
  5486. {
  5487. return FinalInitAfterRouterInitComplete( dwUpgrade, pLocalIniSpooler );
  5488. }
  5489. // DEBUG PURPOSE ONLY - - returns TRUE if pMem is an IniSpooler, FALSE otherwise
  5490. BOOL
  5491. NotIniSpooler(
  5492. BYTE *pMem
  5493. )
  5494. {
  5495. PINISPOOLER pIniSpooler;
  5496. for (pIniSpooler = pLocalIniSpooler ; pIniSpooler ; pIniSpooler = pIniSpooler->pIniNextSpooler)
  5497. if (pIniSpooler == (PINISPOOLER) pMem)
  5498. return FALSE;
  5499. return TRUE;
  5500. }
  5501. BOOL
  5502. ValidateProductSuite(
  5503. PWSTR pszSuiteName
  5504. )
  5505. {
  5506. BOOL bRet = FALSE;
  5507. LONG Rslt;
  5508. HKEY hKey = NULL;
  5509. DWORD Type = 0;
  5510. DWORD Size = 0;
  5511. PWSTR pszProductSuite = NULL;
  5512. PWSTR psz;
  5513. Rslt = RegOpenKey(
  5514. HKEY_LOCAL_MACHINE,
  5515. ipszRegistryProductOptions,
  5516. &hKey
  5517. );
  5518. if (Rslt != ERROR_SUCCESS)
  5519. goto exit;
  5520. Rslt = RegQueryValueEx(
  5521. hKey,
  5522. L"ProductSuite",
  5523. NULL,
  5524. &Type,
  5525. NULL,
  5526. &Size
  5527. );
  5528. if (!Size || Rslt != ERROR_SUCCESS)
  5529. goto exit;
  5530. pszProductSuite = AllocSplMem(Size);
  5531. if (!pszProductSuite) {
  5532. goto exit;
  5533. }
  5534. Rslt = RegQueryValueEx(
  5535. hKey,
  5536. L"ProductSuite",
  5537. NULL,
  5538. &Type,
  5539. (LPBYTE) pszProductSuite,
  5540. &Size
  5541. );
  5542. if (Rslt != ERROR_SUCCESS || Type != REG_MULTI_SZ)
  5543. goto exit;
  5544. for(psz = pszProductSuite ; *psz && wcscmp(psz, pszSuiteName) ; psz += wcslen(psz) + 1)
  5545. ;
  5546. if (*psz)
  5547. bRet = TRUE;
  5548. exit:
  5549. FreeSplMem(pszProductSuite);
  5550. if (hKey)
  5551. RegCloseKey(hKey);
  5552. return bRet;
  5553. }
  5554. /*++
  5555. Routine Name:
  5556. ClusterAddOrUpdateDriverFromClusterDisk
  5557. Routine Description:
  5558. Takes in a driver key and a cluster type pIniSpooler. It will add
  5559. a driver from the cluster disk to the cluster spooler. If the driver
  5560. already exists in the list of drivers, then it will attempt to upgrade
  5561. it.
  5562. Arguments:
  5563. hKeyVersion - key to Ex. "Environments\Windows NT x86\Drivers\Version-3"
  5564. pszDriverName - name a a driver
  5565. pszEnvName - environemnt of the driver
  5566. pszenvDir - directory for the driver files on the disk (Ex. w32x86)
  5567. pIniSpooler - cluster type pIniSpooler
  5568. Return Value:
  5569. Win32 error code
  5570. --*/
  5571. DWORD
  5572. ClusterAddOrUpdateDriverFromClusterDisk(
  5573. IN HKEY hKeyVersion,
  5574. IN LPCWSTR pszDriverName,
  5575. IN LPCWSTR pszEnvName,
  5576. IN LPCWSTR pszEnvDir,
  5577. IN PINISPOOLER pIniSpooler
  5578. )
  5579. {
  5580. LPWSTR pszzPathDepFiles = NULL;
  5581. DRIVER_INFO_6 Drv = {0};
  5582. HKEY hDrvKey = NULL;
  5583. WCHAR szVerPath[10] = {0};
  5584. DWORD dwError = ERROR_SUCCESS;
  5585. WCHAR szData[MAX_PATH];
  5586. WCHAR szPathConfigFile[MAX_PATH];
  5587. WCHAR szPathDataFile[MAX_PATH];
  5588. WCHAR szPathDriverFile[MAX_PATH];
  5589. WCHAR szPathHelpFile[MAX_PATH];
  5590. DWORD cbData;
  5591. DWORD cLen;
  5592. //
  5593. // Open the driver's key
  5594. //
  5595. if ((dwError = SplRegOpenKey(hKeyVersion,
  5596. pszDriverName,
  5597. KEY_READ,
  5598. &hDrvKey,
  5599. pIniSpooler)) == ERROR_SUCCESS &&
  5600. (dwError = (Drv.pName = AllocSplStr(pszDriverName)) ? ERROR_SUCCESS : GetLastError()) == ERROR_SUCCESS &&
  5601. RegGetString(hDrvKey, szConfigurationKey, &Drv.pConfigFile, &cLen, &dwError, TRUE, pIniSpooler) &&
  5602. RegGetString(hDrvKey, szDataFileKey, &Drv.pDataFile, &cLen, &dwError, TRUE, pIniSpooler) &&
  5603. RegGetString(hDrvKey, szDriverFile, &Drv.pDriverPath, &cLen, &dwError, TRUE, pIniSpooler) &&
  5604. (dwError = Drv.pConfigFile &&
  5605. Drv.pDataFile &&
  5606. Drv.pDriverPath ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER) == ERROR_SUCCESS &&
  5607. RegGetString(hDrvKey, szHelpFile, &Drv.pHelpFile, &cLen, &dwError, FALSE, pIniSpooler) &&
  5608. RegGetString(hDrvKey, szMonitor, &Drv.pMonitorName, &cLen, &dwError, FALSE, pIniSpooler) &&
  5609. RegGetString(hDrvKey, szDatatype, &Drv.pDefaultDataType, &cLen, &dwError, FALSE, pIniSpooler) &&
  5610. RegGetMultiSzString(hDrvKey, szDependentFiles, &Drv.pDependentFiles, &cLen, &dwError, FALSE, pIniSpooler) &&
  5611. RegGetMultiSzString(hDrvKey, szPreviousNames, &Drv.pszzPreviousNames,&cLen, &dwError, FALSE, pIniSpooler) &&
  5612. RegGetString(hDrvKey, szMfgName, &Drv.pszMfgName, &cLen, &dwError, FALSE, pIniSpooler) &&
  5613. RegGetString(hDrvKey, szOEMUrl, &Drv.pszOEMUrl, &cLen, &dwError, FALSE, pIniSpooler) &&
  5614. RegGetString(hDrvKey, szHardwareID, &Drv.pszHardwareID, &cLen, &dwError, TRUE, pIniSpooler) &&
  5615. RegGetString(hDrvKey, szProvider, &Drv.pszProvider, &cLen, &dwError, TRUE, pIniSpooler) &&
  5616. (dwError = ClusterFindLanguageMonitor(Drv.pMonitorName, pszEnvName, pIniSpooler)) == ERROR_SUCCESS)
  5617. {
  5618. cbData = sizeof(Drv.ftDriverDate);
  5619. SplRegQueryValue(hDrvKey,
  5620. szDriverDate,
  5621. NULL,
  5622. (LPBYTE)&Drv.ftDriverDate,
  5623. &cbData,
  5624. pIniSpooler);
  5625. cbData = sizeof(Drv.dwlDriverVersion);
  5626. SplRegQueryValue(hDrvKey,
  5627. szLongVersion,
  5628. NULL,
  5629. (LPBYTE)&Drv.dwlDriverVersion,
  5630. &cbData,
  5631. pIniSpooler);
  5632. cbData = sizeof(Drv.cVersion);
  5633. SplRegQueryValue(hDrvKey,
  5634. szDriverVersion,
  5635. NULL,
  5636. (LPBYTE)&Drv.cVersion,
  5637. &cbData,
  5638. pIniSpooler);
  5639. //
  5640. // We need the matching version <-> directory on disk
  5641. // Ex. Version-3 <-> 3
  5642. //
  5643. wsprintf(szVerPath, L"%u", Drv.cVersion);
  5644. //
  5645. // Get fully qualified driver file paths. We will do an add printer driver
  5646. // without using the scratch directory. So the files have to be fully
  5647. // qualified
  5648. //
  5649. if ((dwError = StrNCatBuff(szPathDriverFile,
  5650. COUNTOF(szPathDriverFile),
  5651. pIniSpooler->pszClusResDriveLetter, L"\\",
  5652. szClusterDriverRoot, L"\\",
  5653. pszEnvDir, L"\\",
  5654. szVerPath, L"\\",
  5655. Drv.pDriverPath,
  5656. NULL)) == ERROR_SUCCESS &&
  5657. (dwError = StrNCatBuff(szPathDataFile,
  5658. COUNTOF(szPathDataFile),
  5659. pIniSpooler->pszClusResDriveLetter, L"\\",
  5660. szClusterDriverRoot, L"\\",
  5661. pszEnvDir, L"\\",
  5662. szVerPath, L"\\",
  5663. Drv.pDataFile,
  5664. NULL)) == ERROR_SUCCESS &&
  5665. (dwError = StrNCatBuff(szPathConfigFile,
  5666. COUNTOF(szPathConfigFile),
  5667. pIniSpooler->pszClusResDriveLetter, L"\\",
  5668. szClusterDriverRoot, L"\\",
  5669. pszEnvDir, L"\\",
  5670. szVerPath, L"\\",
  5671. Drv.pConfigFile,
  5672. NULL)) == ERROR_SUCCESS &&
  5673. (dwError = StrNCatBuff(szPathHelpFile,
  5674. COUNTOF(szPathHelpFile),
  5675. pIniSpooler->pszClusResDriveLetter, L"\\",
  5676. szClusterDriverRoot, L"\\",
  5677. pszEnvDir, L"\\",
  5678. szVerPath, L"\\",
  5679. Drv.pHelpFile,
  5680. NULL)) == ERROR_SUCCESS &&
  5681. (dwError = StrNCatBuff(szData,
  5682. COUNTOF(szData),
  5683. pIniSpooler->pszClusResDriveLetter, L"\\",
  5684. szClusterDriverRoot, L"\\",
  5685. pszEnvDir, L"\\",
  5686. szVerPath, L"\\",
  5687. NULL)) == ERROR_SUCCESS &&
  5688. (dwError = StrCatPrefixMsz(szData,
  5689. Drv.pDependentFiles,
  5690. &pszzPathDepFiles)) == ERROR_SUCCESS)
  5691. {
  5692. LPWSTR pszTempDriver = Drv.pDriverPath;
  5693. LPWSTR pszTempData = Drv.pDataFile;
  5694. LPWSTR pszTempConfig = Drv.pConfigFile;
  5695. LPWSTR pszTempHelp = Drv.pHelpFile;
  5696. LPWSTR pszTempDep = Drv.pDependentFiles;
  5697. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathDriverFile = "TSTR"\n", szPathDriverFile));
  5698. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathDataFile = "TSTR"\n", szPathDataFile));
  5699. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathConfigFile = "TSTR"\n", szPathConfigFile));
  5700. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathHelpFile = "TSTR"\n", szPathHelpFile));
  5701. Drv.pDriverPath = szPathDriverFile;
  5702. Drv.pEnvironment = (LPWSTR)pszEnvName;
  5703. Drv.pDataFile = szPathDataFile;
  5704. Drv.pConfigFile = szPathConfigFile;
  5705. Drv.pHelpFile = szPathHelpFile;
  5706. Drv.pDependentFiles = pszzPathDepFiles;
  5707. if (!SplAddPrinterDriverEx(NULL,
  5708. 6,
  5709. (LPBYTE)&Drv,
  5710. APD_COPY_NEW_FILES | APD_DONT_COPY_FILES_TO_CLUSTER,
  5711. pIniSpooler,
  5712. FALSE,
  5713. DO_NOT_IMPERSONATE_USER))
  5714. {
  5715. dwError = GetLastError();
  5716. }
  5717. //
  5718. // Restore pointers
  5719. //
  5720. Drv.pDriverPath = pszTempDriver;
  5721. Drv.pConfigFile = pszTempConfig;
  5722. Drv.pDataFile = pszTempData;
  5723. Drv.pHelpFile = pszTempHelp;
  5724. Drv.pDependentFiles = pszTempDep;
  5725. }
  5726. }
  5727. FreeSplStr(Drv.pName);
  5728. FreeSplStr(Drv.pDriverPath);
  5729. FreeSplStr(Drv.pConfigFile);
  5730. FreeSplStr(Drv.pDataFile);
  5731. FreeSplStr(Drv.pHelpFile);
  5732. FreeSplStr(Drv.pMonitorName);
  5733. FreeSplStr(Drv.pDefaultDataType);
  5734. FreeSplStr(Drv.pDependentFiles);
  5735. FreeSplStr(Drv.pszzPreviousNames);
  5736. FreeSplStr(Drv.pszMfgName);
  5737. FreeSplStr(Drv.pszOEMUrl);
  5738. FreeSplStr(Drv.pszProvider);
  5739. FreeSplStr(Drv.pszHardwareID);
  5740. FreeSplStr(pszzPathDepFiles);
  5741. if (hDrvKey)
  5742. {
  5743. SplRegCloseKey(hDrvKey, pIniSpooler);
  5744. }
  5745. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpdateDriverFromClusterDisk returns Win32 error %u\n", dwError));
  5746. return dwError;
  5747. }
  5748. /*++
  5749. Routine Name:
  5750. SplCreateSpoolerWorkerThread
  5751. Routine Description:
  5752. This routine will be launched in a separate thread to perform time consuming
  5753. initialization as part of SplCreateSpooler when the spooler is a cluster spooler.
  5754. Tasks that it will do include copying down ICM profiles from the cluster disk.
  5755. The caller needs to AddRef the pIniSpooler so that it doesn't become invalid
  5756. (deleted) while we are using it.
  5757. This function closes the hClusSplReady event handle.
  5758. Arguments:
  5759. PINISPOOLER pIniSpooler
  5760. Return Value:
  5761. None
  5762. --*/
  5763. VOID
  5764. SplCreateSpoolerWorkerThread(
  5765. IN PVOID pv
  5766. )
  5767. {
  5768. PINISPOOLER pIniSpooler;
  5769. WCHAR szDir[MAX_PATH];
  5770. pIniSpooler = (PINISPOOLER)pv;
  5771. if (pIniSpooler &&
  5772. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  5773. pIniSpooler->hClusSplReady)
  5774. {
  5775. HANDLE hSplReady = pIniSpooler->hClusSplReady;
  5776. //
  5777. // Waiting for the creating function (SplCreateSpooler) to terminate
  5778. //
  5779. WaitForSingleObject(pIniSpooler->hClusSplReady, INFINITE);
  5780. EnterSplSem();
  5781. pIniSpooler->hClusSplReady = NULL;
  5782. LeaveSplSem();
  5783. //
  5784. // We use hSplReady so we do not hold the critical section while doing CloseHandle
  5785. //
  5786. CloseHandle(hSplReady);
  5787. CopyICMFromClusterDiskToLocalDisk(pIniSpooler);
  5788. //
  5789. // If the node was upgraded, we need to upgrade the print drivers
  5790. // We cannot load ntprint and printui. So we create a process and
  5791. // call an entry point in ntprint. That one will enumerate all the
  5792. // cluster drivers and will try to upgrade them based on the new cab.
  5793. //
  5794. if (pIniSpooler->dwClusNodeUpgraded)
  5795. {
  5796. DWORD dwError;
  5797. DWORD dwCode = 0;
  5798. LPWSTR pszCommand = NULL;
  5799. LPWSTR pszExe = NULL;
  5800. //
  5801. // We need to pass as argument the name of the cluster spooler
  5802. //
  5803. if ((dwError = StrCatSystemPath(L"rundll32.exe",
  5804. kSystemDir,
  5805. &pszExe)) == ERROR_SUCCESS &&
  5806. (dwError = StrCatAlloc(&pszCommand,
  5807. L"rundll32.exe ntprint.dll,PSetupUpgradeClusterDrivers ",
  5808. pIniSpooler->pMachineName,
  5809. NULL)) == ERROR_SUCCESS &&
  5810. (dwError = RunProcess(pszExe, pszCommand, INFINITE, &dwCode)) == ERROR_SUCCESS)
  5811. {
  5812. //
  5813. // dwCode is the return code of the function PSetupUpgradeClusterDrivers in ntprint,
  5814. // executed inside the rundll32 process
  5815. //
  5816. if (dwCode == ERROR_SUCCESS)
  5817. {
  5818. //
  5819. // We upgraded all the printer drivers, now we delete the key from the registry
  5820. // so we don't go though upgrading printer drivers again next time when the
  5821. // cluster group comes online on this node
  5822. //
  5823. ClusterSplDeleteUpgradeKey(pIniSpooler->pszClusResID);
  5824. }
  5825. else
  5826. {
  5827. DBGMSG(DBG_ERROR, ("Error upgrading cluster drivers! dwCode %u\n", dwCode));
  5828. }
  5829. }
  5830. FreeSplMem(pszCommand);
  5831. FreeSplMem(pszExe);
  5832. DBGMSG(DBG_CLUSTER, ("SplCreateSpoolerWorkerThread dwError %u dwCode %u\n", dwError, dwCode));
  5833. }
  5834. //
  5835. // Set resource private property ClusterDriverDirectry. This will be used by the
  5836. // ResDll to perform clean up when the spooler is deleted
  5837. //
  5838. if (StrNCatBuff(szDir,
  5839. COUNTOF(szDir),
  5840. pIniSpooler->pszClusResDriveLetter,
  5841. L"\\",
  5842. szClusterDriverRoot,
  5843. NULL) == ERROR_SUCCESS)
  5844. {
  5845. SplRegSetValue(pIniSpooler->hckRoot,
  5846. SPLREG_CLUSTER_DRIVER_DIRECTORY,
  5847. REG_SZ,
  5848. (LPBYTE)szDir,
  5849. (wcslen(szDir) + 1) * sizeof(WCHAR),
  5850. pIniSpooler);
  5851. }
  5852. EnterSplSem();
  5853. DECSPOOLERREF(pIniSpooler);
  5854. LeaveSplSem();
  5855. DBGMSG(DBG_CLUSTER, ("SplCreateSpoolerWorkerThread terminates pIniSpooler->cRef %u\n", pIniSpooler->cRef));
  5856. }
  5857. }
  5858. /*++
  5859. Routine Name:
  5860. LogFatalPortError
  5861. Routine Description:
  5862. This routine logs a message when a printer cannot be brought up because its
  5863. ports are missing.
  5864. Arguments:
  5865. pszName - The name of the printer.
  5866. Return Value:
  5867. None.
  5868. --*/
  5869. VOID
  5870. LogFatalPortError(
  5871. IN PINISPOOLER pIniSpooler,
  5872. IN PCWSTR pszName
  5873. )
  5874. {
  5875. DWORD LastError = ERROR_SUCCESS;
  5876. WCHAR szError[40] = {0};
  5877. LastError = GetLastError();
  5878. _snwprintf(szError, COUNTOF(szError), L"%u (0x%x)", LastError, LastError);
  5879. SplLogEvent(pIniSpooler,
  5880. LOG_ERROR,
  5881. MSG_PORT_INITIALIZATION_ERROR,
  5882. FALSE,
  5883. (PWSTR)pszName,
  5884. szError,
  5885. NULL);
  5886. }