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