Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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