xref: /reactos/base/services/umpnpmgr/umpnpmgr.c (revision d326ca1f)
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
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
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
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
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
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
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
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