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.

385 lines
9.2 KiB

  1. /*++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. Module Name:
  4. srventry.c
  5. Abstract:
  6. This module contains the main entry for the User-mode Plug-and-Play Service.
  7. It also contains the service control handler and service status update
  8. routines.
  9. Author:
  10. Paula Tomlinson (paulat) 6-8-1995
  11. Environment:
  12. User-mode only.
  13. Revision History:
  14. 8-June-1995 paulat
  15. Creation and initial implementation.
  16. --*/
  17. //
  18. // includes
  19. //
  20. #include "precomp.h"
  21. #include "umpnpi.h"
  22. #include <svcsp.h>
  23. //
  24. // private prototypes
  25. //
  26. DWORD
  27. PnPControlHandlerEx(
  28. IN DWORD dwControl,
  29. IN DWORD dwEventType,
  30. IN LPVOID lpEventData,
  31. IN LPVOID lpContext
  32. );
  33. VOID
  34. PnPServiceStatusUpdate(
  35. SERVICE_STATUS_HANDLE hSvcHandle,
  36. DWORD dwState,
  37. DWORD dwCheckPoint,
  38. DWORD dwExitCode
  39. );
  40. //
  41. // global data
  42. //
  43. PSVCS_GLOBAL_DATA PnPGlobalData = NULL;
  44. HANDLE PnPGlobalSvcRefHandle = NULL;
  45. DWORD CurrentServiceState = SERVICE_START_PENDING;
  46. SERVICE_STATUS_HANDLE hSvcHandle = 0;
  47. VOID
  48. SVCS_ENTRY_POINT(
  49. DWORD argc,
  50. LPWSTR argv[],
  51. PSVCS_GLOBAL_DATA SvcsGlobalData,
  52. HANDLE SvcRefHandle
  53. )
  54. /*++
  55. Routine Description:
  56. This is the main routine for the User-mode Plug-and-Play Service. It
  57. registers itself as an RPC server and notifies the Service Controller
  58. of the PNP service control entry point.
  59. Arguments:
  60. argc, argv - Command-line arguments, not used.
  61. SvcsGlobalData - Global data for services running in services.exe that
  62. contains function entry points and pipe name for
  63. establishing an RPC server interface for this service.
  64. SvcRefHandle - Service reference handle, not used.
  65. Return Value:
  66. None.
  67. Note:
  68. None.
  69. --*/
  70. {
  71. DWORD Status;
  72. HANDLE hThread;
  73. DWORD ThreadID;
  74. UNREFERENCED_PARAMETER(argc);
  75. UNREFERENCED_PARAMETER(argv);
  76. //
  77. // Save the global data and service reference handle in global variables
  78. //
  79. PnPGlobalSvcRefHandle = SvcRefHandle;
  80. PnPGlobalData = SvcsGlobalData;
  81. //
  82. // Register our service ctrl handler
  83. //
  84. if ((hSvcHandle = RegisterServiceCtrlHandlerEx(L"PlugPlay",
  85. (LPHANDLER_FUNCTION_EX)PnPControlHandlerEx,
  86. NULL)) == 0) {
  87. KdPrintEx((DPFLTR_PNPMGR_ID,
  88. DBGF_ERRORS,
  89. "UMPNPMGR: RegisterServiceCtrlHandlerEx failed, error = %d\n",
  90. GetLastError()));
  91. return;
  92. }
  93. //
  94. // Notify Service Controller that we're alive
  95. //
  96. PnPServiceStatusUpdate(hSvcHandle, SERVICE_START_PENDING, 1, 0);
  97. //
  98. // Initialize the PNP service to recieve RPC requests
  99. //
  100. // NOTE: Now all RPC servers in services.exe share the same pipe name.
  101. // However, in order to support communication with version 1.0 of WinNt,
  102. // it is necessary for the Client Pipe name to remain the same as
  103. // it was in version 1.0. Mapping to the new name is performed in
  104. // the Named Pipe File System code.
  105. //
  106. if ((Status = PnPGlobalData->StartRpcServer(
  107. PnPGlobalData->SvcsRpcPipeName,
  108. pnp_ServerIfHandle)) != NO_ERROR) {
  109. KdPrintEx((DPFLTR_PNPMGR_ID,
  110. DBGF_ERRORS,
  111. "UMPNPMGR: StartRpcServer failed with Status = %d\n",
  112. Status));
  113. return;
  114. }
  115. //
  116. // Notify Service Controller that we're alive
  117. //
  118. PnPServiceStatusUpdate(hSvcHandle, SERVICE_START_PENDING, 2, 0);
  119. //
  120. // Lookup the "LoadDriver" and "Undock" privileges.
  121. //
  122. if (gLuidLoadDriverPrivilege.LowPart == 0 && gLuidLoadDriverPrivilege.HighPart == 0) {
  123. if (!LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &gLuidLoadDriverPrivilege)) {
  124. KdPrintEx((DPFLTR_PNPMGR_ID,
  125. DBGF_ERRORS,
  126. "UMPNPMGR: LookupPrivilegeValue failed, error = %d\n",
  127. GetLastError()));
  128. }
  129. }
  130. if (gLuidUndockPrivilege.LowPart == 0 && gLuidUndockPrivilege.HighPart == 0) {
  131. if (!LookupPrivilegeValue(NULL, SE_UNDOCK_NAME, &gLuidUndockPrivilege)) {
  132. KdPrintEx((DPFLTR_PNPMGR_ID,
  133. DBGF_ERRORS,
  134. "UMPNPMGR: LookupPrivilegeValue failed, error = %d\n",
  135. GetLastError()));
  136. }
  137. }
  138. //
  139. // Notify Service Controller that we're alive
  140. //
  141. PnPServiceStatusUpdate(hSvcHandle, SERVICE_START_PENDING, 3, 0);
  142. //
  143. // Initialize pnp manager
  144. //
  145. hThread = CreateThread(NULL,
  146. 0,
  147. (LPTHREAD_START_ROUTINE)InitializePnPManager,
  148. NULL,
  149. 0,
  150. &ThreadID);
  151. if (hThread != NULL) {
  152. CloseHandle(hThread);
  153. }
  154. //
  155. // Notify Service Controller that we're now running
  156. //
  157. PnPServiceStatusUpdate(hSvcHandle, SERVICE_RUNNING, 0, 0);
  158. //
  159. // Service initialization is complete.
  160. //
  161. return;
  162. } // SVCS_ENTRY_POINT
  163. DWORD
  164. PnPControlHandlerEx(
  165. IN DWORD dwControl,
  166. IN DWORD dwEventType,
  167. IN LPVOID lpEventData,
  168. IN LPVOID lpContext
  169. )
  170. /*++
  171. Routine Description:
  172. This is the service control handler of the Plug-and-Play service.
  173. Arguments:
  174. dwControl - The requested control code.
  175. dwEventType - The type of event that has occurred.
  176. lpEventData - Additional device information, if required.
  177. lpContext - User-defined data, not used.
  178. Return Value:
  179. Returns NO_ERROR if sucessful, otherwise returns an error code describing
  180. the problem.
  181. --*/
  182. {
  183. UNREFERENCED_PARAMETER(lpContext);
  184. switch (dwControl) {
  185. case SERVICE_CONTROL_STOP:
  186. case SERVICE_CONTROL_SHUTDOWN:
  187. //
  188. // If we aren't already in the middle of a stop, then
  189. // stop the PNP service now and perform the necessary cleanup.
  190. //
  191. if (CurrentServiceState != SERVICE_STOPPED &&
  192. CurrentServiceState != SERVICE_STOP_PENDING) {
  193. //
  194. // Notify Service Controller that we're stopping
  195. //
  196. PnPServiceStatusUpdate(hSvcHandle, SERVICE_STOP_PENDING, 1, 0);
  197. //
  198. // Stop the RPC server
  199. //
  200. PnPGlobalData->StopRpcServer(pnp_ServerIfHandle);
  201. //
  202. // Notify Service Controller that we've now stopped
  203. //
  204. PnPServiceStatusUpdate(hSvcHandle, SERVICE_STOPPED, 0, 0);
  205. }
  206. break;
  207. case SERVICE_CONTROL_INTERROGATE:
  208. //
  209. // Request to immediately notify Service Controller of
  210. // current status
  211. //
  212. PnPServiceStatusUpdate(hSvcHandle, CurrentServiceState, 0, 0);
  213. break;
  214. case SERVICE_CONTROL_SESSIONCHANGE:
  215. //
  216. // Session change notification.
  217. //
  218. SessionNotificationHandler(dwEventType, (PWTSSESSION_NOTIFICATION)lpEventData);
  219. break;
  220. default:
  221. //
  222. // No special handling for any other service controls.
  223. //
  224. break;
  225. }
  226. return NO_ERROR;
  227. } // PnPControlHandlerEx
  228. VOID
  229. PnPServiceStatusUpdate(
  230. SERVICE_STATUS_HANDLE hSvcHandle,
  231. DWORD dwState,
  232. DWORD dwCheckPoint,
  233. DWORD dwExitCode
  234. )
  235. /*++
  236. Routine Description:
  237. This routine notifies the Service Controller of the current status of the
  238. Plug-and-Play service.
  239. Arguments:
  240. hSvcHandle - Supplies the service status handle for the Plug-and-Play service.
  241. dwState - Specifies the current state of the service to report.
  242. dwCheckPoint - Specifies an intermediate checkpoint for operations during
  243. which the state is pending.
  244. dwExitCode - Specifies a service specific error code.
  245. Return Value:
  246. None.
  247. Note:
  248. This routine also updates the set of controls accepted by the service.
  249. The PlugPlay service currently accepts the following controls when the
  250. service is running:
  251. SERVICE_CONTROL_SHUTDOWN - the system is shutting down.
  252. SERVICE_CONTROL_SESSIONCHANGE - the state of some remote or console session
  253. has changed.
  254. --*/
  255. {
  256. SERVICE_STATUS SvcStatus;
  257. SvcStatus.dwServiceType = SERVICE_WIN32;
  258. SvcStatus.dwCurrentState = CurrentServiceState = dwState;
  259. SvcStatus.dwCheckPoint = dwCheckPoint;
  260. if (dwState == SERVICE_RUNNING) {
  261. SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_SESSIONCHANGE;
  262. } else {
  263. SvcStatus.dwControlsAccepted = 0;
  264. }
  265. if ((dwState == SERVICE_START_PENDING) ||
  266. (dwState == SERVICE_STOP_PENDING)) {
  267. SvcStatus.dwWaitHint = 45000; // 45 seconds
  268. } else {
  269. SvcStatus.dwWaitHint = 0;
  270. }
  271. if (dwExitCode != 0) {
  272. SvcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  273. SvcStatus.dwServiceSpecificExitCode = dwExitCode;
  274. } else {
  275. SvcStatus.dwWin32ExitCode = NO_ERROR;
  276. SvcStatus.dwServiceSpecificExitCode = 0;
  277. }
  278. SetServiceStatus(hSvcHandle, &SvcStatus);
  279. return;
  280. } // PnPServiceStatusUpdate