1 /*
2 * ReactOS kernel
3 * Copyright (C) 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: base/services/umpnpmgr/umpnpmgr.c
23 * PURPOSE: User-mode Plug and Play manager
24 * PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
25 * Hervé Poussineau (hpoussin@reactos.org)
26 * Colin Finck (colin@reactos.org)
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include "precomp.h"
32
33 #define NDEBUG
34 #include <debug.h>
35
36
37 /* GLOBALS ******************************************************************/
38
39 static WCHAR ServiceName[] = L"PlugPlay";
40
41 static SERVICE_STATUS_HANDLE ServiceStatusHandle;
42 static SERVICE_STATUS ServiceStatus;
43
44 HKEY hEnumKey = NULL;
45 HKEY hClassKey = NULL;
46 BOOL g_IsUISuppressed = FALSE;
47 BOOL g_ShuttingDown = FALSE;
48
49 /* FUNCTIONS *****************************************************************/
50
51 static VOID
UpdateServiceStatus(_In_ DWORD dwState,_In_ DWORD dwCheckPoint)52 UpdateServiceStatus(
53 _In_ DWORD dwState,
54 _In_ DWORD dwCheckPoint)
55 {
56 if ((dwState == SERVICE_STOPPED) || (dwState == SERVICE_STOP_PENDING))
57 g_ShuttingDown = TRUE;
58
59 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
60 ServiceStatus.dwCurrentState = dwState;
61 ServiceStatus.dwWin32ExitCode = 0;
62 ServiceStatus.dwServiceSpecificExitCode = 0;
63 ServiceStatus.dwCheckPoint = dwCheckPoint;
64
65 if (dwState == SERVICE_RUNNING)
66 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
67 else
68 ServiceStatus.dwControlsAccepted = 0;
69
70 if (dwState == SERVICE_START_PENDING ||
71 dwState == SERVICE_STOP_PENDING ||
72 dwState == SERVICE_PAUSE_PENDING ||
73 dwState == SERVICE_CONTINUE_PENDING)
74 ServiceStatus.dwWaitHint = 10000;
75 else
76 ServiceStatus.dwWaitHint = 0;
77
78 SetServiceStatus(ServiceStatusHandle,
79 &ServiceStatus);
80 }
81
82
83 static DWORD WINAPI
ServiceControlHandler(DWORD dwControl,DWORD dwEventType,LPVOID lpEventData,LPVOID lpContext)84 ServiceControlHandler(DWORD dwControl,
85 DWORD dwEventType,
86 LPVOID lpEventData,
87 LPVOID lpContext)
88 {
89 DPRINT1("ServiceControlHandler() called\n");
90
91 switch (dwControl)
92 {
93 case SERVICE_CONTROL_STOP:
94 DPRINT1(" SERVICE_CONTROL_STOP received\n");
95 UpdateServiceStatus(SERVICE_STOP_PENDING, 1);
96 /* Stop listening to RPC Messages */
97 RpcMgmtStopServerListening(NULL);
98 UpdateServiceStatus(SERVICE_STOPPED, 0);
99 return ERROR_SUCCESS;
100
101 case SERVICE_CONTROL_PAUSE:
102 DPRINT1(" SERVICE_CONTROL_PAUSE received\n");
103 UpdateServiceStatus(SERVICE_PAUSED, 0);
104 return ERROR_SUCCESS;
105
106 case SERVICE_CONTROL_CONTINUE:
107 DPRINT1(" SERVICE_CONTROL_CONTINUE received\n");
108 UpdateServiceStatus(SERVICE_RUNNING, 0);
109 return ERROR_SUCCESS;
110
111 case SERVICE_CONTROL_INTERROGATE:
112 DPRINT1(" SERVICE_CONTROL_INTERROGATE received\n");
113 SetServiceStatus(ServiceStatusHandle,
114 &ServiceStatus);
115 return ERROR_SUCCESS;
116
117 case SERVICE_CONTROL_SHUTDOWN:
118 DPRINT1(" SERVICE_CONTROL_SHUTDOWN received\n");
119 UpdateServiceStatus(SERVICE_STOP_PENDING, 1);
120 /* Stop listening to RPC Messages */
121 RpcMgmtStopServerListening(NULL);
122 UpdateServiceStatus(SERVICE_STOPPED, 0);
123 return ERROR_SUCCESS;
124
125 default :
126 DPRINT1(" Control %lu received\n", dwControl);
127 return ERROR_CALL_NOT_IMPLEMENTED;
128 }
129 }
130
131 static DWORD
GetBooleanRegValue(IN HKEY hKey,IN PCWSTR lpSubKey,IN PCWSTR lpValue,OUT PBOOL pValue)132 GetBooleanRegValue(
133 IN HKEY hKey,
134 IN PCWSTR lpSubKey,
135 IN PCWSTR lpValue,
136 OUT PBOOL pValue)
137 {
138 DWORD dwError, dwType, dwData;
139 DWORD cbData = sizeof(dwData);
140 HKEY hSubKey = NULL;
141
142 /* Default value */
143 *pValue = FALSE;
144
145 dwError = RegOpenKeyExW(hKey,
146 lpSubKey,
147 0,
148 KEY_READ,
149 &hSubKey);
150 if (dwError != ERROR_SUCCESS)
151 {
152 DPRINT("GetBooleanRegValue(): RegOpenKeyExW() has failed to open '%S' key! (Error: %lu)\n",
153 lpSubKey, dwError);
154 return dwError;
155 }
156
157 dwError = RegQueryValueExW(hSubKey,
158 lpValue,
159 0,
160 &dwType,
161 (PBYTE)&dwData,
162 &cbData);
163 if (dwError != ERROR_SUCCESS)
164 {
165 DPRINT("GetBooleanRegValue(): RegQueryValueExW() has failed to query '%S' value! (Error: %lu)\n",
166 lpValue, dwError);
167 goto Cleanup;
168 }
169 if (dwType != REG_DWORD)
170 {
171 DPRINT("GetBooleanRegValue(): The value is not of REG_DWORD type!\n");
172 goto Cleanup;
173 }
174
175 /* Return the value */
176 *pValue = (dwData == 1);
177
178 Cleanup:
179 RegCloseKey(hSubKey);
180
181 return dwError;
182 }
183
184 BOOL
GetSuppressNewUIValue(VOID)185 GetSuppressNewUIValue(VOID)
186 {
187 BOOL bSuppressNewHWUI = FALSE;
188
189 /*
190 * Query the SuppressNewHWUI policy registry value. Don't cache it
191 * as we want to update our behaviour in consequence.
192 */
193 GetBooleanRegValue(HKEY_LOCAL_MACHINE,
194 L"Software\\Policies\\Microsoft\\Windows\\DeviceInstall\\Settings",
195 L"SuppressNewHWUI",
196 &bSuppressNewHWUI);
197 if (bSuppressNewHWUI)
198 DPRINT("GetSuppressNewUIValue(): newdev.dll's wizard UI won't be shown!\n");
199
200 return bSuppressNewHWUI;
201 }
202
203 VOID WINAPI
ServiceMain(DWORD argc,LPTSTR * argv)204 ServiceMain(DWORD argc, LPTSTR *argv)
205 {
206 HANDLE hThread;
207 DWORD dwThreadId;
208
209 UNREFERENCED_PARAMETER(argc);
210 UNREFERENCED_PARAMETER(argv);
211
212 DPRINT("ServiceMain() called\n");
213
214 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
215 ServiceControlHandler,
216 NULL);
217 if (!ServiceStatusHandle)
218 {
219 DPRINT1("RegisterServiceCtrlHandlerExW() failed! (Error %lu)\n", GetLastError());
220 return;
221 }
222
223 UpdateServiceStatus(SERVICE_START_PENDING, 1);
224
225 hThread = CreateThread(NULL,
226 0,
227 PnpEventThread,
228 NULL,
229 0,
230 &dwThreadId);
231 if (hThread != NULL)
232 CloseHandle(hThread);
233
234 UpdateServiceStatus(SERVICE_START_PENDING, 2);
235
236 hThread = CreateThread(NULL,
237 0,
238 RpcServerThread,
239 NULL,
240 0,
241 &dwThreadId);
242 if (hThread != NULL)
243 CloseHandle(hThread);
244
245 UpdateServiceStatus(SERVICE_START_PENDING, 3);
246
247 hThread = CreateThread(NULL,
248 0,
249 DeviceInstallThread,
250 NULL,
251 0,
252 &dwThreadId);
253 if (hThread != NULL)
254 CloseHandle(hThread);
255
256 UpdateServiceStatus(SERVICE_RUNNING, 0);
257
258 DPRINT("ServiceMain() done\n");
259 }
260
261 static DWORD
InitializePnPManager(VOID)262 InitializePnPManager(VOID)
263 {
264 BOOLEAN OldValue;
265 DWORD dwError;
266
267 DPRINT("UMPNPMGR: InitializePnPManager() started\n");
268
269 /* We need this privilege for using CreateProcessAsUserW */
270 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
271
272 hInstallEvent = CreateEventW(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
273 if (hInstallEvent == NULL)
274 {
275 dwError = GetLastError();
276 DPRINT1("Could not create the Install Event! (Error %lu)\n", dwError);
277 return dwError;
278 }
279
280 hNoPendingInstalls = CreateEventW(NULL,
281 TRUE,
282 FALSE,
283 L"Global\\PnP_No_Pending_Install_Events");
284 if (hNoPendingInstalls == NULL)
285 {
286 dwError = GetLastError();
287 DPRINT1("Could not create the Pending-Install Event! (Error %lu)\n", dwError);
288 return dwError;
289 }
290
291 /*
292 * Initialize the device-install event list
293 */
294
295 hDeviceInstallListNotEmpty = CreateEventW(NULL, FALSE, FALSE, NULL);
296 if (hDeviceInstallListNotEmpty == NULL)
297 {
298 dwError = GetLastError();
299 DPRINT1("Could not create the List Event! (Error %lu)\n", dwError);
300 return dwError;
301 }
302
303 hDeviceInstallListMutex = CreateMutexW(NULL, FALSE, NULL);
304 if (hDeviceInstallListMutex == NULL)
305 {
306 dwError = GetLastError();
307 DPRINT1("Could not create the List Mutex! (Error %lu)\n", dwError);
308 return dwError;
309 }
310 InitializeListHead(&DeviceInstallListHead);
311
312 /* Query the SuppressUI registry value and cache it for our whole lifetime */
313 GetBooleanRegValue(HKEY_LOCAL_MACHINE,
314 L"System\\CurrentControlSet\\Services\\PlugPlay\\Parameters",
315 L"SuppressUI",
316 &g_IsUISuppressed);
317 if (g_IsUISuppressed)
318 DPRINT("UMPNPMGR: newdev.dll's wizard UI won't be shown!\n");
319
320 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
321 L"System\\CurrentControlSet\\Enum",
322 0,
323 KEY_ALL_ACCESS,
324 &hEnumKey);
325 if (dwError != ERROR_SUCCESS)
326 {
327 DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
328 return dwError;
329 }
330
331 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
332 L"System\\CurrentControlSet\\Control\\Class",
333 0,
334 KEY_ALL_ACCESS,
335 &hClassKey);
336 if (dwError != ERROR_SUCCESS)
337 {
338 DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
339 return dwError;
340 }
341
342 DPRINT("UMPNPMGR: InitializePnPManager() done\n");
343
344 return 0;
345 }
346
347 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)348 DllMain(HINSTANCE hinstDLL,
349 DWORD fdwReason,
350 LPVOID lpvReserved)
351 {
352 switch (fdwReason)
353 {
354 case DLL_PROCESS_ATTACH:
355 DisableThreadLibraryCalls(hinstDLL);
356 InitializePnPManager();
357 break;
358
359 case DLL_PROCESS_DETACH:
360 break;
361 }
362
363 return TRUE;
364 }
365
366 /* EOF */
367