xref: /reactos/base/services/umpnpmgr/umpnpmgr.c (revision 5140a990)
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 
48 /* FUNCTIONS *****************************************************************/
49 
50 static VOID
51 UpdateServiceStatus(
52     _In_ DWORD dwState,
53     _In_ DWORD dwCheckPoint)
54 {
55     ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
56     ServiceStatus.dwCurrentState = dwState;
57     ServiceStatus.dwWin32ExitCode = 0;
58     ServiceStatus.dwServiceSpecificExitCode = 0;
59     ServiceStatus.dwCheckPoint = dwCheckPoint;
60 
61     if (dwState == SERVICE_RUNNING)
62         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
63     else
64         ServiceStatus.dwControlsAccepted = 0;
65 
66     if (dwState == SERVICE_START_PENDING ||
67         dwState == SERVICE_STOP_PENDING ||
68         dwState == SERVICE_PAUSE_PENDING ||
69         dwState == SERVICE_CONTINUE_PENDING)
70         ServiceStatus.dwWaitHint = 10000;
71     else
72         ServiceStatus.dwWaitHint = 0;
73 
74     SetServiceStatus(ServiceStatusHandle,
75                      &ServiceStatus);
76 }
77 
78 
79 static DWORD WINAPI
80 ServiceControlHandler(DWORD dwControl,
81                       DWORD dwEventType,
82                       LPVOID lpEventData,
83                       LPVOID lpContext)
84 {
85     DPRINT1("ServiceControlHandler() called\n");
86 
87     switch (dwControl)
88     {
89         case SERVICE_CONTROL_STOP:
90             DPRINT1("  SERVICE_CONTROL_STOP received\n");
91             UpdateServiceStatus(SERVICE_STOP_PENDING, 1);
92             /* Stop listening to RPC Messages */
93             RpcMgmtStopServerListening(NULL);
94             UpdateServiceStatus(SERVICE_STOPPED, 0);
95             return ERROR_SUCCESS;
96 
97         case SERVICE_CONTROL_PAUSE:
98             DPRINT1("  SERVICE_CONTROL_PAUSE received\n");
99             UpdateServiceStatus(SERVICE_PAUSED, 0);
100             return ERROR_SUCCESS;
101 
102         case SERVICE_CONTROL_CONTINUE:
103             DPRINT1("  SERVICE_CONTROL_CONTINUE received\n");
104             UpdateServiceStatus(SERVICE_RUNNING, 0);
105             return ERROR_SUCCESS;
106 
107         case SERVICE_CONTROL_INTERROGATE:
108             DPRINT1("  SERVICE_CONTROL_INTERROGATE received\n");
109             SetServiceStatus(ServiceStatusHandle,
110                              &ServiceStatus);
111             return ERROR_SUCCESS;
112 
113         case SERVICE_CONTROL_SHUTDOWN:
114             DPRINT1("  SERVICE_CONTROL_SHUTDOWN received\n");
115             UpdateServiceStatus(SERVICE_STOP_PENDING, 1);
116             /* Stop listening to RPC Messages */
117             RpcMgmtStopServerListening(NULL);
118             UpdateServiceStatus(SERVICE_STOPPED, 0);
119             return ERROR_SUCCESS;
120 
121         default :
122             DPRINT1("  Control %lu received\n", dwControl);
123             return ERROR_CALL_NOT_IMPLEMENTED;
124     }
125 }
126 
127 static DWORD
128 GetBooleanRegValue(
129     IN HKEY hKey,
130     IN PCWSTR lpSubKey,
131     IN PCWSTR lpValue,
132     OUT PBOOL pValue)
133 {
134     DWORD dwError, dwType, dwData;
135     DWORD cbData = sizeof(dwData);
136     HKEY hSubKey = NULL;
137 
138     /* Default value */
139     *pValue = FALSE;
140 
141     dwError = RegOpenKeyExW(hKey,
142                             lpSubKey,
143                             0,
144                             KEY_READ,
145                             &hSubKey);
146     if (dwError != ERROR_SUCCESS)
147     {
148         DPRINT("GetBooleanRegValue(): RegOpenKeyExW() has failed to open '%S' key! (Error: %lu)\n",
149                lpSubKey, dwError);
150         return dwError;
151     }
152 
153     dwError = RegQueryValueExW(hSubKey,
154                                lpValue,
155                                0,
156                                &dwType,
157                                (PBYTE)&dwData,
158                                &cbData);
159     if (dwError != ERROR_SUCCESS)
160     {
161         DPRINT("GetBooleanRegValue(): RegQueryValueExW() has failed to query '%S' value! (Error: %lu)\n",
162                lpValue, dwError);
163         goto Cleanup;
164     }
165     if (dwType != REG_DWORD)
166     {
167         DPRINT("GetBooleanRegValue(): The value is not of REG_DWORD type!\n");
168         goto Cleanup;
169     }
170 
171     /* Return the value */
172     *pValue = (dwData == 1);
173 
174 Cleanup:
175     RegCloseKey(hSubKey);
176 
177     return dwError;
178 }
179 
180 BOOL
181 GetSuppressNewUIValue(VOID)
182 {
183     BOOL bSuppressNewHWUI = FALSE;
184 
185     /*
186      * Query the SuppressNewHWUI policy registry value. Don't cache it
187      * as we want to update our behaviour in consequence.
188      */
189     GetBooleanRegValue(HKEY_LOCAL_MACHINE,
190                        L"Software\\Policies\\Microsoft\\Windows\\DeviceInstall\\Settings",
191                        L"SuppressNewHWUI",
192                        &bSuppressNewHWUI);
193     if (bSuppressNewHWUI)
194         DPRINT("GetSuppressNewUIValue(): newdev.dll's wizard UI won't be shown!\n");
195 
196     return bSuppressNewHWUI;
197 }
198 
199 VOID WINAPI
200 ServiceMain(DWORD argc, LPTSTR *argv)
201 {
202     HANDLE hThread;
203     DWORD dwThreadId;
204 
205     UNREFERENCED_PARAMETER(argc);
206     UNREFERENCED_PARAMETER(argv);
207 
208     DPRINT("ServiceMain() called\n");
209 
210     ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
211                                                         ServiceControlHandler,
212                                                         NULL);
213     if (!ServiceStatusHandle)
214     {
215         DPRINT1("RegisterServiceCtrlHandlerExW() failed! (Error %lu)\n", GetLastError());
216         return;
217     }
218 
219     UpdateServiceStatus(SERVICE_START_PENDING, 1);
220 
221     hThread = CreateThread(NULL,
222                            0,
223                            PnpEventThread,
224                            NULL,
225                            0,
226                            &dwThreadId);
227     if (hThread != NULL)
228         CloseHandle(hThread);
229 
230     UpdateServiceStatus(SERVICE_START_PENDING, 2);
231 
232     hThread = CreateThread(NULL,
233                            0,
234                            RpcServerThread,
235                            NULL,
236                            0,
237                            &dwThreadId);
238     if (hThread != NULL)
239         CloseHandle(hThread);
240 
241     UpdateServiceStatus(SERVICE_START_PENDING, 3);
242 
243     hThread = CreateThread(NULL,
244                            0,
245                            DeviceInstallThread,
246                            NULL,
247                            0,
248                            &dwThreadId);
249     if (hThread != NULL)
250         CloseHandle(hThread);
251 
252     UpdateServiceStatus(SERVICE_RUNNING, 0);
253 
254     DPRINT("ServiceMain() done\n");
255 }
256 
257 static DWORD
258 InitializePnPManager(VOID)
259 {
260     BOOLEAN OldValue;
261     DWORD dwError;
262 
263     DPRINT("UMPNPMGR: InitializePnPManager() started\n");
264 
265     /* We need this privilege for using CreateProcessAsUserW */
266     RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
267 
268     hInstallEvent = CreateEventW(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
269     if (hInstallEvent == NULL)
270     {
271         dwError = GetLastError();
272         DPRINT1("Could not create the Install Event! (Error %lu)\n", dwError);
273         return dwError;
274     }
275 
276     hNoPendingInstalls = CreateEventW(NULL,
277                                       TRUE,
278                                       FALSE,
279                                       L"Global\\PnP_No_Pending_Install_Events");
280     if (hNoPendingInstalls == NULL)
281     {
282         dwError = GetLastError();
283         DPRINT1("Could not create the Pending-Install Event! (Error %lu)\n", dwError);
284         return dwError;
285     }
286 
287     /*
288      * Initialize the device-install event list
289      */
290 
291     hDeviceInstallListNotEmpty = CreateEventW(NULL, FALSE, FALSE, NULL);
292     if (hDeviceInstallListNotEmpty == NULL)
293     {
294         dwError = GetLastError();
295         DPRINT1("Could not create the List Event! (Error %lu)\n", dwError);
296         return dwError;
297     }
298 
299     hDeviceInstallListMutex = CreateMutexW(NULL, FALSE, NULL);
300     if (hDeviceInstallListMutex == NULL)
301     {
302         dwError = GetLastError();
303         DPRINT1("Could not create the List Mutex! (Error %lu)\n", dwError);
304         return dwError;
305     }
306     InitializeListHead(&DeviceInstallListHead);
307 
308     /* Query the SuppressUI registry value and cache it for our whole lifetime */
309     GetBooleanRegValue(HKEY_LOCAL_MACHINE,
310                        L"System\\CurrentControlSet\\Services\\PlugPlay\\Parameters",
311                        L"SuppressUI",
312                        &g_IsUISuppressed);
313     if (g_IsUISuppressed)
314         DPRINT("UMPNPMGR: newdev.dll's wizard UI won't be shown!\n");
315 
316     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
317                             L"System\\CurrentControlSet\\Enum",
318                             0,
319                             KEY_ALL_ACCESS,
320                             &hEnumKey);
321     if (dwError != ERROR_SUCCESS)
322     {
323         DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
324         return dwError;
325     }
326 
327     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
328                             L"System\\CurrentControlSet\\Control\\Class",
329                             0,
330                             KEY_ALL_ACCESS,
331                             &hClassKey);
332     if (dwError != ERROR_SUCCESS)
333     {
334         DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
335         return dwError;
336     }
337 
338     DPRINT("UMPNPMGR: InitializePnPManager() done\n");
339 
340     return 0;
341 }
342 
343 BOOL WINAPI
344 DllMain(HINSTANCE hinstDLL,
345         DWORD fdwReason,
346         LPVOID lpvReserved)
347 {
348     switch (fdwReason)
349     {
350         case DLL_PROCESS_ATTACH:
351             DisableThreadLibraryCalls(hinstDLL);
352             InitializePnPManager();
353             break;
354 
355         case DLL_PROCESS_DETACH:
356             break;
357     }
358 
359     return TRUE;
360 }
361 
362 /* EOF */
363