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