1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS text-mode setup 4 * PURPOSE: Device installation 5 * PROGRAMMER: Herv� Poussineau (hpoussin@reactos.org) 6 * Hermes Belusca-Maito 7 */ 8 9 #include <usetup.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 #define INITGUID 15 #include <guiddef.h> 16 #include <libs/umpnpmgr/sysguid.h> 17 18 /* LOCALS *******************************************************************/ 19 20 static HANDLE hEnumKey = NULL; 21 static HANDLE hServicesKey = NULL; 22 23 static HANDLE hNoPendingInstalls = NULL; 24 25 static HANDLE hPnpThread = NULL; 26 static HANDLE hDeviceInstallThread = NULL; 27 28 static SLIST_HEADER DeviceInstallListHead; 29 static HANDLE hDeviceInstallListNotEmpty = NULL; 30 31 typedef struct 32 { 33 SLIST_ENTRY ListEntry; 34 WCHAR DeviceIds[ANYSIZE_ARRAY]; 35 } DeviceInstallParams; 36 37 /* FUNCTIONS ****************************************************************/ 38 39 static BOOLEAN 40 ResetDevice( 41 IN LPCWSTR DeviceId) 42 { 43 PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData; 44 NTSTATUS Status; 45 46 RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId); 47 Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)); 48 if (!NT_SUCCESS(Status)) 49 { 50 DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status); 51 return FALSE; 52 } 53 return TRUE; 54 } 55 56 static BOOLEAN 57 InstallDriver( 58 IN HINF hInf, 59 IN HANDLE hServices, 60 IN HANDLE hDeviceKey, 61 IN LPCWSTR DeviceId, 62 IN LPCWSTR HardwareId) 63 { 64 UNICODE_STRING PathPrefix = RTL_CONSTANT_STRING(L"System32\\DRIVERS\\"); 65 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service"); 66 UNICODE_STRING ErrorControlU = RTL_CONSTANT_STRING(L"ErrorControl"); 67 UNICODE_STRING ImagePathU = RTL_CONSTANT_STRING(L"ImagePath"); 68 UNICODE_STRING StartU = RTL_CONSTANT_STRING(L"Start"); 69 UNICODE_STRING TypeU = RTL_CONSTANT_STRING(L"Type"); 70 UNICODE_STRING UpperFiltersU = RTL_CONSTANT_STRING(L"UpperFilters"); 71 PWSTR keyboardClass = L"kbdclass\0"; 72 73 UNICODE_STRING StringU; 74 OBJECT_ATTRIBUTES ObjectAttributes; 75 HANDLE hService; 76 INFCONTEXT Context; 77 PCWSTR Driver, ClassGuid, ImagePath; 78 PWSTR FullImagePath; 79 ULONG dwValue; 80 ULONG Disposition; 81 NTSTATUS Status; 82 BOOLEAN deviceInstalled = FALSE; 83 84 /* Check if we know the hardware */ 85 if (!SpInfFindFirstLine(hInf, L"HardwareIdsDatabase", HardwareId, &Context)) 86 return FALSE; 87 if (!INF_GetDataField(&Context, 1, &Driver)) 88 return FALSE; 89 90 /* Get associated class GUID (if any) */ 91 if (!INF_GetDataField(&Context, 2, &ClassGuid)) 92 ClassGuid = NULL; 93 94 /* Find associated driver name */ 95 /* FIXME: check in other sections too! */ 96 if (!SpInfFindFirstLine(hInf, L"BootBusExtenders.Load", Driver, &Context) 97 && !SpInfFindFirstLine(hInf, L"BusExtenders.Load", Driver, &Context) 98 && !SpInfFindFirstLine(hInf, L"SCSI.Load", Driver, &Context) 99 && !SpInfFindFirstLine(hInf, L"InputDevicesSupport.Load", Driver, &Context) 100 && !SpInfFindFirstLine(hInf, L"Keyboard.Load", Driver, &Context)) 101 { 102 INF_FreeData(ClassGuid); 103 INF_FreeData(Driver); 104 return FALSE; 105 } 106 107 if (!INF_GetDataField(&Context, 1, &ImagePath)) 108 { 109 INF_FreeData(ClassGuid); 110 INF_FreeData(Driver); 111 return FALSE; 112 } 113 114 /* Prepare full driver path */ 115 dwValue = PathPrefix.MaximumLength + wcslen(ImagePath) * sizeof(WCHAR); 116 FullImagePath = (PWSTR)RtlAllocateHeap(ProcessHeap, 0, dwValue); 117 if (!FullImagePath) 118 { 119 DPRINT1("RtlAllocateHeap() failed\n"); 120 INF_FreeData(ImagePath); 121 INF_FreeData(ClassGuid); 122 INF_FreeData(Driver); 123 return FALSE; 124 } 125 RtlCopyMemory(FullImagePath, PathPrefix.Buffer, PathPrefix.MaximumLength); 126 ConcatPaths(FullImagePath, dwValue / sizeof(WCHAR), 1, ImagePath); 127 128 DPRINT1("Using driver '%S' for device '%S'\n", ImagePath, DeviceId); 129 130 /* Create service key */ 131 RtlInitUnicodeString(&StringU, Driver); 132 InitializeObjectAttributes(&ObjectAttributes, &StringU, OBJ_CASE_INSENSITIVE, hServices, NULL); 133 Status = NtCreateKey(&hService, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &Disposition); 134 if (!NT_SUCCESS(Status)) 135 { 136 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08x\n", &StringU, Status); 137 RtlFreeHeap(ProcessHeap, 0, FullImagePath); 138 INF_FreeData(ImagePath); 139 INF_FreeData(ClassGuid); 140 INF_FreeData(Driver); 141 return FALSE; 142 } 143 144 /* Fill service key */ 145 if (Disposition == REG_CREATED_NEW_KEY) 146 { 147 dwValue = 0; 148 NtSetValueKey(hService, 149 &ErrorControlU, 150 0, 151 REG_DWORD, 152 &dwValue, 153 sizeof(dwValue)); 154 155 dwValue = 0; 156 NtSetValueKey(hService, 157 &StartU, 158 0, 159 REG_DWORD, 160 &dwValue, 161 sizeof(dwValue)); 162 163 dwValue = SERVICE_KERNEL_DRIVER; 164 NtSetValueKey(hService, 165 &TypeU, 166 0, 167 REG_DWORD, 168 &dwValue, 169 sizeof(dwValue)); 170 } 171 /* HACK: don't put any path in registry */ 172 NtSetValueKey(hService, 173 &ImagePathU, 174 0, 175 REG_SZ, 176 (PVOID)ImagePath, 177 (wcslen(ImagePath) + 1) * sizeof(WCHAR)); 178 179 INF_FreeData(ImagePath); 180 181 if (ClassGuid &&_wcsicmp(ClassGuid, L"{4D36E96B-E325-11CE-BFC1-08002BE10318}") == 0) 182 { 183 DPRINT1("Installing keyboard class driver for '%S'\n", DeviceId); 184 NtSetValueKey(hDeviceKey, 185 &UpperFiltersU, 186 0, 187 REG_MULTI_SZ, 188 keyboardClass, 189 (wcslen(keyboardClass) + 2) * sizeof(WCHAR)); 190 } 191 192 INF_FreeData(ClassGuid); 193 194 /* Associate device with the service we just filled */ 195 Status = NtSetValueKey(hDeviceKey, 196 &ServiceU, 197 0, 198 REG_SZ, 199 (PVOID)Driver, 200 (wcslen(Driver) + 1) * sizeof(WCHAR)); 201 if (NT_SUCCESS(Status)) 202 { 203 /* Restart the device, so it will use the driver we registered */ 204 deviceInstalled = ResetDevice(DeviceId); 205 } 206 207 INF_FreeData(Driver); 208 209 /* HACK: Update driver path */ 210 NtSetValueKey(hService, 211 &ImagePathU, 212 0, 213 REG_SZ, 214 FullImagePath, 215 (wcslen(FullImagePath) + 1) * sizeof(WCHAR)); 216 RtlFreeHeap(ProcessHeap, 0, FullImagePath); 217 218 NtClose(hService); 219 220 return deviceInstalled; 221 } 222 223 static VOID 224 InstallDevice( 225 IN HINF hInf, 226 IN HANDLE hEnum, 227 IN HANDLE hServices, 228 IN LPCWSTR DeviceId) 229 { 230 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID"); 231 UNICODE_STRING CompatibleIDsU = RTL_CONSTANT_STRING(L"CompatibleIDs"); 232 233 UNICODE_STRING DeviceIdU; 234 OBJECT_ATTRIBUTES ObjectAttributes; 235 LPCWSTR HardwareID; 236 PKEY_VALUE_PARTIAL_INFORMATION pPartialInformation = NULL; 237 HANDLE hDeviceKey; 238 ULONG ulRequired; 239 BOOLEAN bDriverInstalled = FALSE; 240 NTSTATUS Status; 241 242 RtlInitUnicodeString(&DeviceIdU, DeviceId); 243 InitializeObjectAttributes(&ObjectAttributes, &DeviceIdU, OBJ_CASE_INSENSITIVE, hEnum, NULL); 244 Status = NtOpenKey(&hDeviceKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes); 245 if (!NT_SUCCESS(Status)) 246 { 247 DPRINT("Unable to open subkey '%S'\n", DeviceId); 248 return; 249 } 250 251 Status = NtQueryValueKey( 252 hDeviceKey, 253 &HardwareIDU, 254 KeyValuePartialInformation, 255 NULL, 256 0, 257 &ulRequired); 258 if (Status == STATUS_BUFFER_TOO_SMALL) 259 { 260 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired); 261 if (!pPartialInformation) 262 { 263 DPRINT1("RtlAllocateHeap() failed\n"); 264 NtClose(hDeviceKey); 265 return; 266 } 267 Status = NtQueryValueKey( 268 hDeviceKey, 269 &HardwareIDU, 270 KeyValuePartialInformation, 271 pPartialInformation, 272 ulRequired, 273 &ulRequired); 274 } 275 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 276 { 277 /* Nothing to do */ 278 } 279 else if (!NT_SUCCESS(Status)) 280 { 281 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status); 282 if (pPartialInformation) 283 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 284 NtClose(hDeviceKey); 285 return; 286 } 287 else if (pPartialInformation) 288 { 289 for (HardwareID = (LPCWSTR)pPartialInformation->Data; 290 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength 291 && *HardwareID 292 && !bDriverInstalled; 293 HardwareID += wcslen(HardwareID) + 1) 294 { 295 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID); 296 } 297 } 298 299 if (!bDriverInstalled) 300 { 301 if (pPartialInformation) 302 { 303 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 304 pPartialInformation = NULL; 305 } 306 Status = NtQueryValueKey( 307 hDeviceKey, 308 &CompatibleIDsU, 309 KeyValuePartialInformation, 310 NULL, 311 0, 312 &ulRequired); 313 if (Status == STATUS_BUFFER_TOO_SMALL) 314 { 315 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired); 316 if (!pPartialInformation) 317 { 318 DPRINT("RtlAllocateHeap() failed\n"); 319 NtClose(hDeviceKey); 320 return; 321 } 322 Status = NtQueryValueKey( 323 hDeviceKey, 324 &CompatibleIDsU, 325 KeyValuePartialInformation, 326 pPartialInformation, 327 ulRequired, 328 &ulRequired); 329 } 330 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 331 { 332 /* Nothing to do */ 333 } 334 else if (!NT_SUCCESS(Status)) 335 { 336 if (pPartialInformation) 337 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 338 NtClose(hDeviceKey); 339 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status); 340 return; 341 } 342 else if (pPartialInformation) 343 { 344 for (HardwareID = (LPCWSTR)pPartialInformation->Data; 345 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength 346 && *HardwareID 347 && !bDriverInstalled; 348 HardwareID += wcslen(HardwareID) + 1) 349 { 350 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID); 351 } 352 } 353 } 354 if (!bDriverInstalled) 355 DPRINT("No driver available for %S\n", DeviceId); 356 357 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 358 NtClose(hDeviceKey); 359 } 360 361 /* Loop to install all queued devices installations */ 362 static ULONG NTAPI 363 DeviceInstallThread(IN PVOID Parameter) 364 { 365 HINF hSetupInf = *(HINF*)Parameter; 366 PSLIST_ENTRY ListEntry; 367 DeviceInstallParams* Params; 368 LARGE_INTEGER Timeout; 369 370 for (;;) 371 { 372 ListEntry = RtlInterlockedPopEntrySList(&DeviceInstallListHead); 373 374 if (ListEntry == NULL) 375 { 376 /* 377 * The list is now empty, but there may be a new enumerated device 378 * that is going to be added to the list soon. In order to avoid 379 * setting the hNoPendingInstalls event to release it soon after, 380 * we wait for maximum 1 second for no PnP enumeration event being 381 * received before declaring that no pending installations are 382 * taking place and setting the corresponding event. 383 */ 384 Timeout.QuadPart = -10000000LL; /* Wait for 1 second */ 385 if (NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, &Timeout) == STATUS_TIMEOUT) 386 { 387 /* We timed out: set the event and do the actual wait */ 388 NtSetEvent(hNoPendingInstalls, NULL); 389 NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, NULL); 390 } 391 } 392 else 393 { 394 NtResetEvent(hNoPendingInstalls, NULL); 395 Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry); 396 InstallDevice(hSetupInf, hEnumKey, hServicesKey, Params->DeviceIds); 397 RtlFreeHeap(ProcessHeap, 0, Params); 398 } 399 } 400 401 return 0; 402 } 403 404 static ULONG NTAPI 405 PnpEventThread(IN PVOID Parameter) 406 { 407 NTSTATUS Status; 408 PLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData = {0, 0, 0, 0}; 409 PPLUGPLAY_EVENT_BLOCK PnpEvent, NewPnpEvent; 410 ULONG PnpEventSize; 411 412 UNREFERENCED_PARAMETER(Parameter); 413 414 PnpEventSize = 0x1000; 415 PnpEvent = RtlAllocateHeap(ProcessHeap, 0, PnpEventSize); 416 if (PnpEvent == NULL) 417 { 418 Status = STATUS_NO_MEMORY; 419 goto Quit; 420 } 421 422 for (;;) 423 { 424 DPRINT("Calling NtGetPlugPlayEvent()\n"); 425 426 /* Wait for the next PnP event */ 427 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); 428 429 /* Resize the buffer for the PnP event if it's too small */ 430 if (Status == STATUS_BUFFER_TOO_SMALL) 431 { 432 PnpEventSize += 0x400; 433 NewPnpEvent = RtlReAllocateHeap(ProcessHeap, 0, PnpEvent, PnpEventSize); 434 if (NewPnpEvent == NULL) 435 { 436 Status = STATUS_NO_MEMORY; 437 goto Quit; 438 } 439 PnpEvent = NewPnpEvent; 440 continue; 441 } 442 443 if (!NT_SUCCESS(Status)) 444 { 445 DPRINT1("NtGetPlugPlayEvent() failed (Status 0x%08lx)\n", Status); 446 goto Quit; 447 } 448 449 /* Process the PnP event */ 450 DPRINT("Received PnP Event\n"); 451 if (IsEqualGUID(&PnpEvent->EventGuid, &GUID_DEVICE_ENUMERATED)) 452 { 453 DeviceInstallParams* Params; 454 ULONG len; 455 ULONG DeviceIdLength; 456 457 DPRINT("Device enumerated event: %S\n", PnpEvent->TargetDevice.DeviceIds); 458 459 DeviceIdLength = wcslen(PnpEvent->TargetDevice.DeviceIds); 460 if (DeviceIdLength) 461 { 462 /* Queue device install (will be dequeued by DeviceInstallThread) */ 463 len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR); 464 Params = RtlAllocateHeap(ProcessHeap, 0, len); 465 if (Params) 466 { 467 wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds); 468 RtlInterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry); 469 NtSetEvent(hDeviceInstallListNotEmpty, NULL); 470 } 471 else 472 { 473 DPRINT1("Not enough memory (size %lu)\n", len); 474 } 475 } 476 } 477 else 478 { 479 DPRINT("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", 480 PnpEvent->EventGuid.Data1, PnpEvent->EventGuid.Data2, PnpEvent->EventGuid.Data3, 481 PnpEvent->EventGuid.Data4[0], PnpEvent->EventGuid.Data4[1], PnpEvent->EventGuid.Data4[2], 482 PnpEvent->EventGuid.Data4[3], PnpEvent->EventGuid.Data4[4], PnpEvent->EventGuid.Data4[5], 483 PnpEvent->EventGuid.Data4[6], PnpEvent->EventGuid.Data4[7]); 484 } 485 486 /* Dequeue the current PnP event and signal the next one */ 487 Status = NtPlugPlayControl(PlugPlayControlUserResponse, 488 &ResponseData, 489 sizeof(ResponseData)); 490 if (!NT_SUCCESS(Status)) 491 { 492 DPRINT1("NtPlugPlayControl(PlugPlayControlUserResponse) failed (Status 0x%08lx)\n", Status); 493 goto Quit; 494 } 495 } 496 497 Status = STATUS_SUCCESS; 498 499 Quit: 500 if (PnpEvent) 501 RtlFreeHeap(ProcessHeap, 0, PnpEvent); 502 503 NtTerminateThread(NtCurrentThread(), Status); 504 return Status; 505 } 506 507 NTSTATUS 508 WaitNoPendingInstallEvents( 509 IN PLARGE_INTEGER Timeout OPTIONAL) 510 { 511 return NtWaitForSingleObject(hNoPendingInstalls, FALSE, Timeout); 512 } 513 514 BOOLEAN 515 EnableUserModePnpManager(VOID) 516 { 517 LARGE_INTEGER Timeout; 518 519 /* Start the PnP thread */ 520 if (hPnpThread != NULL) 521 NtResumeThread(hPnpThread, NULL); 522 523 /* 524 * Wait a little bit so that we get a chance to have some events being 525 * queued by the time the device-installation thread becomes resumed. 526 */ 527 Timeout.QuadPart = -10000000LL; /* Wait for 1 second */ 528 NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, &Timeout); 529 530 /* Start the device installation thread */ 531 if (hDeviceInstallThread != NULL) 532 NtResumeThread(hDeviceInstallThread, NULL); 533 534 return TRUE; 535 } 536 537 BOOLEAN 538 DisableUserModePnpManager(VOID) 539 { 540 /* Wait until all pending installations are done, then freeze the threads */ 541 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0) 542 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n"); 543 544 // TODO: use signalling events 545 546 NtSuspendThread(hPnpThread, NULL); 547 NtSuspendThread(hDeviceInstallThread, NULL); 548 549 return TRUE; 550 } 551 552 NTSTATUS 553 InitializeUserModePnpManager( 554 IN HINF* phSetupInf) 555 { 556 NTSTATUS Status; 557 OBJECT_ATTRIBUTES ObjectAttributes; 558 559 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); 560 UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services"); 561 562 Status = NtCreateEvent(&hDeviceInstallListNotEmpty, 563 EVENT_ALL_ACCESS, 564 NULL, 565 SynchronizationEvent, 566 FALSE); 567 if (!NT_SUCCESS(Status)) 568 { 569 DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status); 570 goto Failure; 571 } 572 573 Status = NtCreateEvent(&hNoPendingInstalls, 574 EVENT_ALL_ACCESS, 575 NULL, 576 NotificationEvent, 577 FALSE); 578 if (!NT_SUCCESS(Status)) 579 { 580 DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status); 581 goto Failure; 582 } 583 584 RtlInitializeSListHead(&DeviceInstallListHead); 585 586 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL); 587 Status = NtOpenKey(&hEnumKey, KEY_QUERY_VALUE, &ObjectAttributes); 588 if (!NT_SUCCESS(Status)) 589 { 590 DPRINT1("NtOpenKey('%wZ') failed (Status 0x%08lx)\n", &EnumU, Status); 591 goto Failure; 592 } 593 594 InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL); 595 Status = NtCreateKey(&hServicesKey, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); 596 if (!NT_SUCCESS(Status)) 597 { 598 DPRINT1("NtCreateKey('%wZ') failed (Status 0x%08lx)\n", &ServicesU, Status); 599 goto Failure; 600 } 601 602 /* Create the PnP event thread in suspended state */ 603 Status = RtlCreateUserThread(NtCurrentProcess(), 604 NULL, 605 TRUE, 606 0, 607 0, 608 0, 609 PnpEventThread, 610 NULL, 611 &hPnpThread, 612 NULL); 613 if (!NT_SUCCESS(Status)) 614 { 615 DPRINT1("Failed to create the PnP event thread (Status 0x%08lx)\n", Status); 616 hPnpThread = NULL; 617 goto Failure; 618 } 619 620 /* Create the device installation thread in suspended state */ 621 Status = RtlCreateUserThread(NtCurrentProcess(), 622 NULL, 623 TRUE, 624 0, 625 0, 626 0, 627 DeviceInstallThread, 628 phSetupInf, 629 &hDeviceInstallThread, 630 NULL); 631 if (!NT_SUCCESS(Status)) 632 { 633 DPRINT1("Failed to create the device installation thread (Status 0x%08lx)\n", Status); 634 hDeviceInstallThread = NULL; 635 goto Failure; 636 } 637 638 return STATUS_SUCCESS; 639 640 Failure: 641 if (hPnpThread) 642 { 643 NtTerminateThread(hPnpThread, STATUS_SUCCESS); 644 NtClose(hPnpThread); 645 } 646 hPnpThread = NULL; 647 648 if (hServicesKey) 649 NtClose(hServicesKey); 650 hServicesKey = NULL; 651 652 if (hEnumKey) 653 NtClose(hEnumKey); 654 hEnumKey = NULL; 655 656 if (hNoPendingInstalls) 657 NtClose(hNoPendingInstalls); 658 hNoPendingInstalls = NULL; 659 660 if (hDeviceInstallListNotEmpty) 661 NtClose(hDeviceInstallListNotEmpty); 662 hDeviceInstallListNotEmpty = NULL; 663 664 return Status; 665 } 666 667 VOID 668 TerminateUserModePnpManager(VOID) 669 { 670 DisableUserModePnpManager(); 671 672 // TODO: use signalling events 673 674 /* Kill the PnP thread as it blocks inside the NtGetPlugPlayEvent() call */ 675 if (hPnpThread) 676 { 677 NtTerminateThread(hPnpThread, STATUS_SUCCESS); 678 NtClose(hPnpThread); 679 } 680 hPnpThread = NULL; 681 682 /* Kill the device installation thread */ 683 if (hDeviceInstallThread) 684 { 685 NtTerminateThread(hDeviceInstallThread, STATUS_SUCCESS); 686 NtClose(hDeviceInstallThread); 687 } 688 hDeviceInstallThread = NULL; 689 690 /* Close the opened handles */ 691 692 if (hServicesKey) 693 NtClose(hServicesKey); 694 hServicesKey = NULL; 695 696 if (hEnumKey) 697 NtClose(hEnumKey); 698 hEnumKey = NULL; 699 700 if (hNoPendingInstalls) 701 NtClose(hNoPendingInstalls); 702 hNoPendingInstalls = NULL; 703 704 if (hDeviceInstallListNotEmpty) 705 NtClose(hDeviceInstallListNotEmpty); 706 hDeviceInstallListNotEmpty = NULL; 707 } 708