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