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.

298 lines
6.9 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. splinit.c
  5. Abstract:
  6. Spooler Service Initialization Routines.
  7. The following is a list of functions in this file:
  8. SpoolerInitializeSpooler
  9. Author:
  10. Krishna Ganugapati (KrishnaG) 17-Oct-1993
  11. Environment:
  12. User Mode - Win32
  13. Notes:
  14. optional-notes
  15. Revision History:
  16. 4-Jan-1999 Khaleds
  17. Added Code for optimiziting the load time of the spooler by decoupling
  18. the startup dependency between spoolsv and spoolss
  19. 17-October-1993 KrishnaG
  20. Created.
  21. --*/
  22. //
  23. // Includes
  24. //
  25. #define NOMINMAX
  26. #include <nt.h>
  27. #include <ntrtl.h>
  28. #include <nturtl.h>
  29. #include <windows.h>
  30. #include <winspool.h>
  31. #include <winsplp.h>
  32. #include <rpc.h>
  33. #include "splsvr.h"
  34. #include "splr.h"
  35. #include "server.h"
  36. #include "client.h"
  37. #include "kmspool.h"
  38. #include <winsvc.h> // Service control APIs
  39. #include <lmsname.h>
  40. #include <rpc.h> // DataTypes and runtime APIs
  41. DWORD MessageThreadId; // message thread ID
  42. extern DWORD GetSpoolMessages(VOID);
  43. HANDLE hPhase2Init = NULL;
  44. //
  45. // Following is to make sure only one spooler process runs at a time.
  46. // When spooler is asked to stop it will tell SCM SERVICE_STOPPED but it may
  47. // be some more time before the spoolsv process dies.
  48. // In the meantime if a SCM starts another spooler process it will not
  49. // initialize. This is because GDI assumes one spooler process at a time.
  50. //
  51. // To fix when spooler is asked to stop it creates a named event Spooler_exiting
  52. // The handle to which will be closed when the process dies.
  53. //
  54. // On spooler startup we will look for this event and wait for it to go away.
  55. // A named event goes away when the last handle is closed.
  56. //
  57. //
  58. WCHAR szSpoolerExitingEvent[] = L"Spooler_exiting";
  59. #define WAITFOR_SPOOLEREXIT_TIMEOUT 3*1000
  60. BOOL
  61. PreInitializeRouter(
  62. SERVICE_STATUS_HANDLE SpoolerStatusHandle
  63. );
  64. DWORD
  65. SpoolerInitializeSpooler(
  66. DWORD argc,
  67. LPTSTR *argv
  68. )
  69. /*++
  70. Routine Description:
  71. Registers the control handler with the dispatcher thread. Then it
  72. performs all initialization including the starting of the RPC server.
  73. If any of the initialization fails, SpoolerStatusUpdate is called so that the
  74. status is updated and the thread is terminated.
  75. Arguments:
  76. Return Value:
  77. --*/
  78. {
  79. RPC_STATUS rpcStatus;
  80. DWORD Win32status;
  81. HANDLE hThread, hEvent;
  82. DWORD ThreadId;
  83. //
  84. // Initialize the ThreadCritical Section which serializes access to
  85. // the Status database.
  86. //
  87. InitializeCriticalSection(&ThreadCriticalSection);
  88. //
  89. // Initialize the status structure
  90. //
  91. SpoolerStatusInit();
  92. //
  93. // Register this service with the ControlHandler.
  94. // Now we can accept control requests and be requested to UNINSTALL.
  95. //
  96. DBGMSG(DBG_TRACE, ("Calling RegisterServiceCtrlHandler\n"));
  97. if ((SpoolerStatusHandle = RegisterServiceCtrlHandlerEx(
  98. SERVICE_SPOOLER,
  99. SpoolerCtrlHandler,
  100. NULL
  101. )) == (SERVICE_STATUS_HANDLE)ERROR_SUCCESS) {
  102. Win32status = GetLastError();
  103. DBGMSG(DBG_ERROR,
  104. ("FAILURE: RegisterServiceCtrlHandler status = %d\n", Win32status));
  105. return( SpoolerBeginForcedShutdown (
  106. IMMEDIATE,
  107. Win32status,
  108. (DWORD)0
  109. ));
  110. }
  111. //
  112. // Notify that installation is pending
  113. //
  114. SpoolerState = SpoolerStatusUpdate(STARTING);
  115. if (SpoolerState != STARTING) {
  116. //
  117. // An UNINSTALL control request must have been received
  118. //
  119. return(SpoolerState);
  120. }
  121. //
  122. // If there is another spooler process exiting wait for it to die
  123. // Look at comments in splctrlh.c
  124. //
  125. for ( ; ; ) {
  126. hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, szSpoolerExitingEvent);
  127. if ( hEvent == NULL )
  128. break;
  129. DBGMSG(DBG_WARNING, ("Waiting for previous spooler to exit\n"));
  130. CloseHandle(hEvent);
  131. SpoolerState = SpoolerStatusUpdate(STARTING);
  132. if (SpoolerState != STARTING) {
  133. //
  134. // An UNINSTALL control request must have been received
  135. //
  136. return(SpoolerState);
  137. }
  138. Sleep(WAITFOR_SPOOLEREXIT_TIMEOUT);
  139. }
  140. hPhase2Init = CreateEvent( NULL, TRUE, FALSE, L"RouterPreInitEvent" );
  141. if (hPhase2Init == NULL)
  142. {
  143. //
  144. // Fail if the event is not created
  145. //
  146. DBGMSG(DBG_ERROR, ("Failed to create Phase2Init Event, error %d\n", GetLastError()));
  147. ExitProcess(0);
  148. }
  149. DBGMSG(DBG_TRACE,
  150. ("SpoolerInitializeSpooler:getting ready to start RPC server\n"));
  151. rpcStatus = SpoolerStartRpcServer();
  152. if (rpcStatus != RPC_S_OK) {
  153. DBGMSG(DBG_WARN, ("RPC Initialization Failed %d\n", rpcStatus));
  154. return (SpoolerBeginForcedShutdown(
  155. PENDING,
  156. rpcStatus,
  157. (DWORD)0
  158. ));
  159. }
  160. SpoolerStatusUpdate(STARTING);
  161. DBGMSG(DBG_TRACE,
  162. ("SpoolerInitializeSpooler:Getting ready to kick off the Router\n"));
  163. hThread = CreateThread(NULL,
  164. LARGE_INITIAL_STACK_COMMIT,
  165. (LPTHREAD_START_ROUTINE)PreInitializeRouter,
  166. (LPVOID)SpoolerStatusHandle,
  167. 0,
  168. &ThreadId);
  169. if( hThread ){
  170. CloseHandle(hThread);
  171. //
  172. // Create Kernel Spooler Message Thread
  173. //
  174. Win32status=GetSpoolMessages();
  175. } else {
  176. Win32status = GetLastError();
  177. }
  178. if (Win32status != ERROR_SUCCESS) {
  179. DBGMSG(DBG_WARNING, ("Kernel Spooler Messaging Initialization Failed %d\n", Win32status));
  180. return SpoolerBeginForcedShutdown(PENDING, Win32status, (DWORD) 0);
  181. }
  182. //
  183. // Update the status to indicate that installation is complete.
  184. // Get the current state back in case the ControlHandling thread has
  185. // told us to shutdown.
  186. //
  187. DBGMSG(DBG_TRACE, ("Exiting SpoolerInitializeSpooler - Init Done!\n"));
  188. return (SpoolerStatusUpdate(RUNNING));
  189. }
  190. BOOL
  191. PreInitializeRouter(
  192. SERVICE_STATUS_HANDLE SpoolerStatusHandle
  193. )
  194. {
  195. HANDLE hThread;
  196. DWORD ThreadId;
  197. SECURITY_ATTRIBUTES Sa;
  198. SECURITY_DESCRIPTOR Sd;
  199. //
  200. // Wait on hPhase2Init
  201. //
  202. WaitForSingleObject( hPhase2Init, SPOOLER_START_PHASE_TWO_INIT );
  203. hThread = CreateThread(NULL,
  204. LARGE_INITIAL_STACK_COMMIT,
  205. (LPTHREAD_START_ROUTINE) InitializeRouter,
  206. (LPVOID)SpoolerStatusHandle,
  207. 0,
  208. &ThreadId);
  209. if( hThread )
  210. {
  211. CloseHandle(hThread);
  212. }
  213. return(hThread?TRUE:FALSE);
  214. }