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.

914 lines
24 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. init.c
  6. Abstract:
  7. Author:
  8. Environment:
  9. User Mode -Win32
  10. Revision History:
  11. 4-Jan-1999 Khaleds
  12. Added Code for optimiziting the load time of the spooler by decoupling
  13. the startup dependency between spoolsv and spoolss
  14. --*/
  15. #include "precomp.h"
  16. #include "local.h"
  17. #include <wmi.h>
  18. #pragma hdrstop
  19. WCHAR szDefaultPrinterNotifyInfoDataSize[] = L"DefaultPrinterNotifyInfoDataSize";
  20. WCHAR szFailAllocs[] = L"FailAllocs";
  21. WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 3];
  22. #define DEFAULT_PRINTER_NOTIFY_DATA 0x80
  23. DWORD cDefaultPrinterNotifyInfoData = DEFAULT_PRINTER_NOTIFY_DATA;
  24. WCHAR szRouterCacheSize[] = L"RouterCacheSize";
  25. fnWinSpoolDrv fnClientSide;
  26. BOOL bInitialized = FALSE;
  27. HANDLE hEventInit = NULL;
  28. BOOL Initialized = FALSE;
  29. DWORD dwUpgradeFlag = 0;
  30. SERVICE_STATUS_HANDLE ghSplHandle = NULL;
  31. extern CRITICAL_SECTION RouterCriticalSection;
  32. extern PROUTERCACHE RouterCacheTable;
  33. extern DWORD RouterCacheSize;
  34. extern LPWSTR *ppszOtherNames;
  35. VOID
  36. SpoolerInitAll();
  37. VOID
  38. RegisterForPnPEvents(
  39. VOID
  40. );
  41. LPPROVIDOR
  42. InitializeProvidor(
  43. LPWSTR pProvidorName,
  44. LPWSTR pFullName)
  45. {
  46. BOOL bRet = FALSE;
  47. HANDLE hModule = NULL;
  48. LPPROVIDOR pProvidor;
  49. UINT ErrorMode;
  50. HANDLE hToken = NULL;
  51. hToken = RevertToPrinterSelf();
  52. if (!hToken)
  53. {
  54. goto Cleanup;
  55. }
  56. //
  57. // WARNING-WARNING-WARNING, we null set the print providor
  58. // structure. older version of the print providor have different print
  59. // providor sizes so they will set only some function pointers and not
  60. // all of them
  61. //
  62. if ( !(pProvidor = (LPPROVIDOR)AllocSplMem(sizeof(PROVIDOR))) ||
  63. !(pProvidor->lpName = AllocSplStr(pProvidorName)) ) {
  64. DBGMSG(DBG_ERROR,
  65. ("InitializeProvidor can't allocate memory for %ws\n",
  66. pProvidorName));
  67. goto Cleanup;
  68. }
  69. //
  70. // Make sure we don't get any dialogs popping up while this goes on.
  71. //
  72. ErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  73. hModule = pProvidor->hModule = LoadLibraryEx( pProvidorName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
  74. SetErrorMode( ErrorMode );
  75. if ( !hModule ) {
  76. DBGMSG(DBG_WARNING,
  77. ("InitializeProvider failed LoadLibrary( %ws ) error %d\n",
  78. pProvidorName, GetLastError() ));
  79. goto Cleanup;
  80. }
  81. pProvidor->fpInitialize = GetProcAddress(hModule, "InitializePrintProvidor");
  82. if ( !pProvidor->fpInitialize )
  83. goto Cleanup;
  84. bRet = (BOOL)pProvidor->fpInitialize(&pProvidor->PrintProvidor,
  85. sizeof(PRINTPROVIDOR),
  86. pFullName);
  87. if ( !bRet ) {
  88. DBGMSG(DBG_WARNING,
  89. ("InitializePrintProvider failed for providor %ws error %d\n",
  90. pProvidorName, GetLastError()));
  91. }
  92. //
  93. // It is not a critical error if ImpersonatePrinterClient fails.
  94. // If fpInitialize succeeds and ImpersonatePrinterClient fails,
  95. // then if we set bRet to FALSE we forcefully unload the initialized
  96. // provider DLL and can cause resource leaks.
  97. //
  98. ImpersonatePrinterClient(hToken);
  99. Cleanup:
  100. if ( bRet ) {
  101. //
  102. // Fixup any NULL entrypoints.
  103. //
  104. FixupOldProvidor( &pProvidor->PrintProvidor );
  105. return pProvidor;
  106. } else {
  107. if ( hModule )
  108. FreeLibrary(hModule);
  109. if ( pProvidor ) {
  110. FreeSplStr(pProvidor->lpName);
  111. FreeSplMem(pProvidor);
  112. }
  113. return NULL;
  114. }
  115. }
  116. #if SPOOLER_HEAP
  117. HANDLE ghMidlHeap;
  118. #endif
  119. BOOL
  120. DllMain(
  121. HINSTANCE hInstDLL,
  122. DWORD fdwReason,
  123. LPVOID lpvReserved)
  124. {
  125. BOOL Failed = FALSE;
  126. BOOL ThreadInitted = FALSE,
  127. WPCInitted = FALSE,
  128. CritSecInit = TRUE;
  129. switch (fdwReason)
  130. {
  131. case DLL_PROCESS_ATTACH:
  132. #if SPOOLER_HEAP
  133. ghMidlHeap = HeapCreate( 0, 1024*4, 0 );
  134. if ( ghMidlHeap == NULL ) {
  135. DBGMSG( DBG_WARNING, ("DllMain heap Failed %d\n", GetLastError() ));
  136. Failed = TRUE;
  137. goto Done;
  138. }
  139. #endif
  140. if( !bSplLibInit(NULL)){
  141. Failed = TRUE;
  142. goto Done;
  143. }
  144. DisableThreadLibraryCalls(hInstDLL);
  145. __try {
  146. InitializeCriticalSection(&RouterCriticalSection);
  147. } __except(EXCEPTION_EXECUTE_HANDLER) {
  148. SetLastError(GetExceptionCode());
  149. Failed = TRUE;
  150. CritSecInit = FALSE;
  151. goto Done;
  152. }
  153. if (!WPCInit()) {
  154. Failed = TRUE;
  155. goto Done;
  156. } else {
  157. WPCInitted = TRUE;
  158. }
  159. if (!ThreadInit()) {
  160. Failed = TRUE;
  161. goto Done;
  162. } else {
  163. ThreadInitted = TRUE;
  164. }
  165. //
  166. // Create our global init event (manual reset)
  167. // This will be set when we are initialized.
  168. //
  169. hEventInit = CreateEvent(NULL,
  170. TRUE,
  171. FALSE,
  172. NULL);
  173. if (!hEventInit) {
  174. Failed = TRUE;
  175. goto Done;
  176. }
  177. Done:
  178. if (Failed)
  179. {
  180. #if SPOOLER_HEAP
  181. if ( ghMidlHeap != NULL ) {
  182. (void)HeapDestroy(ghMidlHeap);
  183. }
  184. #endif
  185. if (CritSecInit) {
  186. DeleteCriticalSection(&RouterCriticalSection);
  187. }
  188. if (hEventInit) {
  189. CloseHandle(hEventInit);
  190. }
  191. if (WPCInitted) {
  192. WPCDestroy();
  193. }
  194. if (ThreadInitted) {
  195. ThreadDestroy();
  196. }
  197. WmiTerminateTrace(); // Unregisters spoolss from WMI.
  198. return FALSE;
  199. }
  200. break;
  201. case DLL_PROCESS_DETACH:
  202. ThreadDestroy();
  203. WPCDestroy();
  204. CloseHandle(hEventInit);
  205. break;
  206. }
  207. return TRUE;
  208. }
  209. BOOL
  210. InitializeRouter(
  211. SERVICE_STATUS_HANDLE SpoolerStatusHandle
  212. )
  213. /*++
  214. Routine Description:
  215. This function will Initialize the Routing layer for the Print Providors.
  216. This will involve scanning the win.ini file, loading Print Providors, and
  217. creating instance data for each.
  218. Arguments:
  219. None
  220. Return Value:
  221. TRUE - The operation was successful.
  222. FALSE/NULL - The operation failed. Extended error status is available
  223. using GetLastError.
  224. --*/
  225. {
  226. LPPROVIDOR pProvidor;
  227. DWORD cbDll;
  228. WCHAR ProvidorName[MAX_PATH], Dll[MAX_PATH], szFullName[MAX_PATH];
  229. HKEY hKey, hKey1;
  230. LONG Status;
  231. LPWSTR lpMem = NULL;
  232. LPWSTR psz = NULL;
  233. DWORD dwRequired = 0;
  234. DWORD SpoolerPriorityClass = 0;
  235. NT_PRODUCT_TYPE NtProductType;
  236. DWORD dwCacheSize = 0;
  237. DWORD dwType;
  238. DWORD cbData;
  239. DWORD i;
  240. extern DWORD cOtherNames;
  241. WCHAR szSetupKey[] = L"System\\Setup";
  242. //
  243. // WMI Trace Events. Registers spoolss with WMI.
  244. //
  245. WmiInitializeTrace();
  246. ghSplHandle = SpoolerStatusHandle;
  247. //
  248. // We are now assume that the other services and drivers have
  249. // initialized. The loader of this dll must do this syncing.
  250. //
  251. // spoolss\server does this by using the GroupOrderList
  252. // SCM will try load load parallel and serial before starting
  253. // the spooler service.
  254. //
  255. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  256. szPrintKey,
  257. 0,
  258. KEY_ALL_ACCESS,
  259. &hKey)) {
  260. cbData = sizeof(SpoolerPriorityClass);
  261. // SpoolerPriority
  262. Status = RegQueryValueEx(hKey,
  263. L"SpoolerPriority",
  264. NULL,
  265. &dwType,
  266. (LPBYTE)&SpoolerPriorityClass,
  267. &cbData);
  268. if (Status == ERROR_SUCCESS &&
  269. (SpoolerPriorityClass == IDLE_PRIORITY_CLASS ||
  270. SpoolerPriorityClass == NORMAL_PRIORITY_CLASS ||
  271. SpoolerPriorityClass == HIGH_PRIORITY_CLASS)) {
  272. Status = SetPriorityClass(GetCurrentProcess(), SpoolerPriorityClass);
  273. }
  274. cbData = sizeof(cDefaultPrinterNotifyInfoData);
  275. //
  276. // Ignore failure case since we can use the default
  277. //
  278. RegQueryValueEx(hKey,
  279. szDefaultPrinterNotifyInfoDataSize,
  280. NULL,
  281. &dwType,
  282. (LPBYTE)&cDefaultPrinterNotifyInfoData,
  283. &cbData);
  284. #if DBG
  285. //
  286. // Inore failure default is to not fail memory allocations
  287. //
  288. RegQueryValueEx(hKey,
  289. szFailAllocs,
  290. NULL,
  291. &dwType,
  292. (LPBYTE)&gbFailAllocs,
  293. &cbData);
  294. #endif
  295. RegCloseKey(hKey);
  296. }
  297. // Is it an upgrade?
  298. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  299. szSetupKey,
  300. 0,
  301. KEY_QUERY_VALUE,
  302. &hKey)) {
  303. /*++
  304. You can tell if you are inside gui setup by looking for
  305. HKLM\System\Setup\SystemSetupInProgress -- non zero means gui-setup is running.
  306. The following description is outdated.
  307. Description: the query update flag is set up by TedM. We will read this flag
  308. if the flag has been set, we will set a boolean variable saying that we're in
  309. the upgrade mode. All upgrade activities will be carried out based on this flag.
  310. For subsequents startups of the spooler, this flag will be unvailable so we
  311. won't run the spooler in upgrade mode.
  312. --*/
  313. dwUpgradeFlag = 0;
  314. cbData = sizeof(dwUpgradeFlag);
  315. Status = RegQueryValueEx(hKey,
  316. L"SystemSetupInProgress",
  317. NULL,
  318. &dwType,
  319. (LPBYTE)&dwUpgradeFlag,
  320. &cbData);
  321. if (Status != ERROR_SUCCESS) {
  322. dwUpgradeFlag = 0;
  323. }
  324. DBGMSG(DBG_TRACE, ("The Spooler Upgrade flag is %d\n", dwUpgradeFlag));
  325. RegCloseKey(hKey);
  326. }
  327. // Setup machine names
  328. szMachineName[0] = szMachineName[1] = L'\\';
  329. i = MAX_COMPUTERNAME_LENGTH + 1;
  330. if (!GetComputerName(szMachineName+2, &i)) {
  331. DBGMSG(DBG_ERROR, ("Failed to get computer name %d\n", GetLastError()));
  332. ExitProcess(0);
  333. }
  334. if (!BuildOtherNamesFromMachineName(&ppszOtherNames, &cOtherNames)) {
  335. DBGMSG(DBG_TRACE, ("Failed to determine other machine names %d\n", GetLastError()));
  336. }
  337. if (!(pLocalProvidor = InitializeProvidor(szLocalSplDll, NULL))) {
  338. DBGMSG(DBG_WARN, ("Failed to initialize local print provider, error %d\n", GetLastError() ));
  339. ExitProcess(0);
  340. }
  341. pProvidor = pLocalProvidor;
  342. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegistryProvidors, 0,
  343. KEY_READ, &hKey);
  344. if (Status == ERROR_SUCCESS) {
  345. //
  346. // Now query szCacheSize for the RouterCacheSize value
  347. // if there is no RouterCacheSize replace it with the
  348. // default value.
  349. //
  350. RouterCacheSize = ROUTERCACHE_DEFAULT_MAX;
  351. cbData = sizeof(dwCacheSize);
  352. Status = RegQueryValueEx(hKey,
  353. szRouterCacheSize,
  354. NULL, NULL,
  355. (LPBYTE)&dwCacheSize,
  356. &cbData);
  357. if (Status == ERROR_SUCCESS) {
  358. DBGMSG(DBG_TRACE, ("RouterCacheSize = %d\n", dwCacheSize));
  359. if (dwCacheSize > 0) {
  360. RouterCacheSize = dwCacheSize;
  361. }
  362. }
  363. if ((RouterCacheTable = AllocSplMem(RouterCacheSize *
  364. sizeof(ROUTERCACHE))) == NULL) {
  365. DBGMSG(DBG_ERROR, ("Error: Cannot create RouterCache Table\n"));
  366. RouterCacheSize = 0;
  367. }
  368. //
  369. // Now query szRegistryProvidors for the Order value
  370. // if there is no Order value for szRegistryProvidors
  371. // RegQueryValueEx will return ERROR_FILE_NOT_FOUND
  372. // if that's the case, then quit, because we have
  373. // no providors to initialize.
  374. //
  375. Status = RegQueryValueEx(hKey, szOrder, NULL, NULL,
  376. (LPBYTE)NULL, &dwRequired);
  377. //
  378. // If RegQueryValueEx returned ERROR_SUCCESS, then
  379. // call it again to determine how many bytes were
  380. // allocated. Note, if Order does exist, but it has
  381. // no data then dwReturned will be zero, in which
  382. // don't allocate any memory for it, and don't
  383. // bother to call RegQueryValueEx a second time.
  384. //
  385. if (Status == ERROR_SUCCESS) {
  386. if (dwRequired != 0) {
  387. lpMem = (LPWSTR) AllocSplMem(dwRequired);
  388. if (lpMem == NULL) {
  389. Status = GetLastError();
  390. } else {
  391. Status = RegQueryValueEx(hKey, szOrder, NULL, NULL,
  392. (LPBYTE)lpMem, &dwRequired);
  393. }
  394. }
  395. }
  396. if (Status == ERROR_SUCCESS) {
  397. cbDll = sizeof(Dll);
  398. pProvidor = pLocalProvidor;
  399. // Now parse the string retrieved from \Providors{Order = "....."}
  400. // Remember each string is separated by a null terminator char ('\0')
  401. // and the entire array is terminated by two null terminator chars
  402. // Also remember, that if there was no data in Order, then
  403. // psz = lpMem = NULL, and we have nothing to parse, so
  404. // break out of the while loop, if psz is NULL as well
  405. psz = lpMem;
  406. while (psz && *psz) {
  407. //
  408. // Truncate the provider name if it does not fit in
  409. // the stack allocated buffer.
  410. //
  411. lstrcpyn(ProvidorName, psz, COUNTOF(ProvidorName));
  412. psz = psz + lstrlen(psz) + 1; // skip (length) + 1
  413. // lstrlen returns length sans '\0'
  414. if (RegOpenKeyEx(hKey, ProvidorName, 0, KEY_READ, &hKey1)
  415. == ERROR_SUCCESS) {
  416. cbDll = sizeof(Dll);
  417. if (RegQueryValueEx(hKey1, L"Name", NULL, NULL,
  418. (LPBYTE)Dll, &cbDll) == ERROR_SUCCESS)
  419. {
  420. if((StrNCatBuff(szFullName,
  421. COUNTOF(szFullName),
  422. szRegistryProvidors,
  423. L"\\",
  424. ProvidorName,
  425. NULL)==ERROR_SUCCESS))
  426. {
  427. if (pProvidor->pNext = InitializeProvidor(Dll, szFullName))
  428. {
  429. pProvidor = pProvidor->pNext;
  430. }
  431. }
  432. } //close RegQueryValueEx
  433. RegCloseKey(hKey1);
  434. } // closes RegOpenKeyEx on ERROR_SUCCESS
  435. } // end of while loop parsing REG_MULTI_SZ
  436. // Now free the buffer allocated for RegQuery
  437. // (that is if you have allocated - if dwReturned was
  438. // zero, then no memory was allocated (since none was
  439. // required (Order was empty)))
  440. if (lpMem) {
  441. FreeSplMem(lpMem);
  442. }
  443. } // closes RegQueryValueEx on ERROR_SUCCESS
  444. RegCloseKey(hKey);
  445. }
  446. //
  447. // We are now initialized!
  448. //
  449. SetEvent(hEventInit);
  450. Initialized=TRUE;
  451. //
  452. // Register for PnP events we care about
  453. //
  454. RegisterForPnPEvents();
  455. SpoolerInitAll();
  456. // When we return this thread goes away
  457. //
  458. // NOTE-NOTE-NOTE-NOTE-NOTE KrishnaG 12/22/93
  459. // This thread should go away, however the HP Monitor relies on this
  460. // thread. HPMon calls the initialization function on this thread which
  461. // calls an asynchronous receive for data. While the data itself is
  462. // picked up by hmon!_ReadThread, if the thread which initiated the
  463. // receive goes away, we will not be able to receive the data.
  464. //
  465. //
  466. // Instead of sleeping infinite, let's use it to for providors that
  467. // just want FFPCNs to poll. This call never returns.
  468. //
  469. HandlePollNotifications();
  470. return TRUE;
  471. }
  472. VOID
  473. WaitForSpoolerInitialization(
  474. VOID)
  475. {
  476. HANDLE hPhase2Init;
  477. HANDLE hImpersonationToken = NULL;
  478. if (!Initialized)
  479. {
  480. //
  481. // Impersonate the spooler service token
  482. //
  483. hImpersonationToken = RevertToPrinterSelf();
  484. //
  485. // Start phase 2 initialization. hPhase2Init may set multiple times, but that
  486. // is OK since there is only 1 thread waiting once on this event.
  487. //
  488. hPhase2Init = OpenEvent(EVENT_ALL_ACCESS,FALSE,L"RouterPreInitEvent");
  489. if (hPhase2Init == NULL)
  490. {
  491. //
  492. // Fail if the event is not created
  493. //
  494. DBGMSG(DBG_ERROR, ("Failed to create Phase2Init Event in WaitForSpoolerInitialization, error %d\n", GetLastError()));
  495. ExitProcess(0);
  496. }
  497. SetEvent(hPhase2Init);
  498. CloseHandle(hPhase2Init);
  499. //
  500. // Revert back to the client token
  501. //
  502. if (hImpersonationToken)
  503. {
  504. if (!ImpersonatePrinterClient(hImpersonationToken))
  505. {
  506. DBGMSG(DBG_ERROR, ("Failed to impersonate the client, error %d\n", GetLastError()));
  507. ExitProcess(0);
  508. }
  509. }
  510. WaitForSingleObject(hEventInit, INFINITE);
  511. }
  512. }
  513. VOID
  514. SplStartPhase2Init(
  515. VOID)
  516. {
  517. HANDLE hPhase2Init;
  518. HANDLE hImpersonationToken = NULL;
  519. //
  520. // Impersonate the spooler service token
  521. //
  522. hImpersonationToken = RevertToPrinterSelf();
  523. //
  524. // Start the phase 2 initialization. This function is when SERVICE_CONTROL_SYSTEM_IDLE
  525. // message is sent to the spooler by the SCM.
  526. //
  527. hPhase2Init = OpenEvent(EVENT_ALL_ACCESS,FALSE,L"RouterPreInitEvent");
  528. if (hPhase2Init == NULL)
  529. {
  530. //
  531. // Fail if the event is not created
  532. //
  533. DBGMSG(DBG_ERROR, ("Failed to open Phase2Init Event in SplStartPhase2Init, error %d\n", GetLastError()));
  534. ExitProcess(0);
  535. }
  536. SetEvent(hPhase2Init);
  537. CloseHandle(hPhase2Init);
  538. //
  539. // Revert back to the client token
  540. //
  541. if (hImpersonationToken)
  542. {
  543. ImpersonatePrinterClient(hImpersonationToken);
  544. }
  545. }
  546. VOID
  547. ShutDownProvidor(
  548. LPPROVIDOR pProvidor)
  549. {
  550. if (pProvidor->PrintProvidor.fpShutDown) {
  551. (*pProvidor->PrintProvidor.fpShutDown)(NULL);
  552. }
  553. FreeSplStr(pProvidor->lpName);
  554. FreeLibrary(pProvidor->hModule);
  555. FreeSplMem(pProvidor);
  556. return;
  557. }
  558. VOID
  559. SplShutDownRouter(
  560. VOID
  561. )
  562. {
  563. DBGMSG(DBG_TRACE, ("SplShutDownRouter:\n"));
  564. //
  565. // WMI Trace Events. Unregisters spoolss from WMI.
  566. //
  567. WmiTerminateTrace();
  568. //
  569. // This code is commented out because it is not
  570. // tested and clearly it will not work with
  571. // all known print providers. Maybe in the future
  572. // we will have correct provider shutdown.
  573. //
  574. #if 0
  575. LPPROVIDOR pTemp;
  576. LPPROVIDOR pProvidor;
  577. DbgPrint("We're in the cleanup function now!!\n");
  578. pProvidor = pLocalProvidor;
  579. while (pProvidor) {
  580. pTemp = pProvidor;
  581. pProvidor = pProvidor->pNext;
  582. ShutDownProvidor(pTemp);
  583. }
  584. #endif
  585. }
  586. BOOL
  587. SplInitializeWinSpoolDrv(
  588. pfnWinSpoolDrv pfnList)
  589. {
  590. HANDLE hWinSpoolDrv;
  591. // Check if the client side handles are available in fnClientSide
  592. if (!bInitialized) {
  593. if (!(hWinSpoolDrv = LoadLibrary(TEXT("winspool.drv")))) {
  594. // Could not load the client side of the spooler
  595. return FALSE;
  596. }
  597. fnClientSide.pfnOpenPrinter = (BOOL (*)(LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS))
  598. GetProcAddress( hWinSpoolDrv,"OpenPrinterW" );
  599. fnClientSide.pfnClosePrinter = (BOOL (*)(HANDLE))
  600. GetProcAddress( hWinSpoolDrv,"ClosePrinter" );
  601. fnClientSide.pfnDocumentProperties = (LONG (*)(HWND, HANDLE, LPWSTR, PDEVMODE,
  602. PDEVMODE, DWORD))
  603. GetProcAddress( hWinSpoolDrv,"DocumentPropertiesW" );
  604. fnClientSide.pfnDevQueryPrint = (BOOL (*)(HANDLE, LPDEVMODE, DWORD *, LPWSTR, DWORD))
  605. GetProcAddress( hWinSpoolDrv,"SpoolerDevQueryPrintW" );
  606. fnClientSide.pfnPrinterEvent = (BOOL (*)(LPWSTR, INT, DWORD, LPARAM))
  607. GetProcAddress( hWinSpoolDrv,"SpoolerPrinterEvent" );
  608. fnClientSide.pfnLoadPrinterDriver = (HANDLE (*)(HANDLE))
  609. GetProcAddress( hWinSpoolDrv,
  610. (LPCSTR)MAKELPARAM( 212, 0 ));
  611. fnClientSide.pfnRefCntLoadDriver = (HANDLE (*)(LPWSTR, DWORD, DWORD, BOOL))
  612. GetProcAddress( hWinSpoolDrv,
  613. (LPCSTR)MAKELPARAM( 213, 0 ));
  614. fnClientSide.pfnRefCntUnloadDriver = (BOOL (*)(HANDLE, BOOL))
  615. GetProcAddress( hWinSpoolDrv,
  616. (LPCSTR)MAKELPARAM( 214, 0 ));
  617. fnClientSide.pfnForceUnloadDriver = (BOOL (*)(LPWSTR))
  618. GetProcAddress( hWinSpoolDrv,
  619. (LPCSTR)MAKELPARAM( 215, 0 ));
  620. if ( fnClientSide.pfnOpenPrinter == NULL ||
  621. fnClientSide.pfnClosePrinter == NULL ||
  622. fnClientSide.pfnDocumentProperties == NULL ||
  623. fnClientSide.pfnPrinterEvent == NULL ||
  624. fnClientSide.pfnDevQueryPrint == NULL ||
  625. fnClientSide.pfnLoadPrinterDriver == NULL ||
  626. fnClientSide.pfnRefCntLoadDriver == NULL ||
  627. fnClientSide.pfnRefCntUnloadDriver == NULL ||
  628. fnClientSide.pfnForceUnloadDriver == NULL ) {
  629. return FALSE;
  630. }
  631. // Use these pointers for future calls to SplInitializeWinspoolDrv
  632. bInitialized = TRUE;
  633. }
  634. pfnList->pfnOpenPrinter = fnClientSide.pfnOpenPrinter;
  635. pfnList->pfnClosePrinter = fnClientSide.pfnClosePrinter;
  636. pfnList->pfnDocumentProperties = fnClientSide.pfnDocumentProperties;
  637. pfnList->pfnDevQueryPrint = fnClientSide.pfnDevQueryPrint;
  638. pfnList->pfnPrinterEvent = fnClientSide.pfnPrinterEvent;
  639. pfnList->pfnLoadPrinterDriver = fnClientSide.pfnLoadPrinterDriver;
  640. pfnList->pfnRefCntLoadDriver = fnClientSide.pfnRefCntLoadDriver;
  641. pfnList->pfnRefCntUnloadDriver = fnClientSide.pfnRefCntUnloadDriver;
  642. pfnList->pfnForceUnloadDriver = fnClientSide.pfnForceUnloadDriver;
  643. return TRUE;
  644. }
  645. BOOL
  646. SpoolerHasInitialized(
  647. VOID
  648. )
  649. {
  650. return Initialized;
  651. }
  652. /*++
  653. Routine Name
  654. SplPowerEvent
  655. Routine Description:
  656. Checks if the spooler is ready for power management events like hibernation/stand by.
  657. Arguments:
  658. Event - power management event
  659. Return Value:
  660. TRUE - the spooler allowd the system to be powered down
  661. FALSE - the spooler denies the request for powering down
  662. --*/
  663. BOOL
  664. SplPowerEvent(
  665. DWORD Event
  666. )
  667. {
  668. BOOL bRet = TRUE;
  669. //
  670. // We need the router to be completely initialized and having loaded
  671. // all print providers in order to check if we can allow powering down
  672. // the system
  673. //
  674. if (bInitialized)
  675. {
  676. HMODULE hLib = NULL;
  677. typedef BOOL (*PACPIFUNC)(DWORD);
  678. PACPIFUNC pfn;
  679. if ((hLib = LoadLibrary(L"localspl.dll")) &&
  680. (pfn = (PACPIFUNC)GetProcAddress(hLib, "SplPowerEvent")))
  681. {
  682. bRet = (*pfn)(Event);
  683. }
  684. if (hLib)
  685. {
  686. FreeLibrary(hLib);
  687. }
  688. }
  689. return bRet;
  690. }