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 PPLUGPLAY_EVENT_BLOCK PnpEvent, NewPnpEvent; 409 ULONG PnpEventSize; 410 411 UNREFERENCED_PARAMETER(Parameter); 412 413 PnpEventSize = 0x1000; 414 PnpEvent = RtlAllocateHeap(ProcessHeap, 0, PnpEventSize); 415 if (PnpEvent == NULL) 416 { 417 Status = STATUS_NO_MEMORY; 418 goto Quit; 419 } 420 421 for (;;) 422 { 423 DPRINT("Calling NtGetPlugPlayEvent()\n"); 424 425 /* Wait for the next PnP event */ 426 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); 427 428 /* Resize the buffer for the PnP event if it's too small */ 429 if (Status == STATUS_BUFFER_TOO_SMALL) 430 { 431 PnpEventSize += 0x400; 432 NewPnpEvent = RtlReAllocateHeap(ProcessHeap, 0, PnpEvent, PnpEventSize); 433 if (NewPnpEvent == NULL) 434 { 435 Status = STATUS_NO_MEMORY; 436 goto Quit; 437 } 438 PnpEvent = NewPnpEvent; 439 continue; 440 } 441 442 if (!NT_SUCCESS(Status)) 443 { 444 DPRINT1("NtGetPlugPlayEvent() failed (Status 0x%08lx)\n", Status); 445 goto Quit; 446 } 447 448 /* Process the PnP event */ 449 DPRINT("Received PnP Event\n"); 450 if (IsEqualGUID(&PnpEvent->EventGuid, &GUID_DEVICE_ENUMERATED)) 451 { 452 DeviceInstallParams* Params; 453 ULONG len; 454 ULONG DeviceIdLength; 455 456 DPRINT("Device enumerated event: %S\n", PnpEvent->TargetDevice.DeviceIds); 457 458 DeviceIdLength = wcslen(PnpEvent->TargetDevice.DeviceIds); 459 if (DeviceIdLength) 460 { 461 /* Queue device install (will be dequeued by DeviceInstallThread) */ 462 len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR); 463 Params = RtlAllocateHeap(ProcessHeap, 0, len); 464 if (Params) 465 { 466 wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds); 467 RtlInterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry); 468 NtSetEvent(hDeviceInstallListNotEmpty, NULL); 469 } 470 else 471 { 472 DPRINT1("Not enough memory (size %lu)\n", len); 473 } 474 } 475 } 476 else 477 { 478 DPRINT("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", 479 PnpEvent->EventGuid.Data1, PnpEvent->EventGuid.Data2, PnpEvent->EventGuid.Data3, 480 PnpEvent->EventGuid.Data4[0], PnpEvent->EventGuid.Data4[1], PnpEvent->EventGuid.Data4[2], 481 PnpEvent->EventGuid.Data4[3], PnpEvent->EventGuid.Data4[4], PnpEvent->EventGuid.Data4[5], 482 PnpEvent->EventGuid.Data4[6], PnpEvent->EventGuid.Data4[7]); 483 } 484 485 /* Dequeue the current PnP event and signal the next one */ 486 NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0); 487 } 488 489 Status = STATUS_SUCCESS; 490 491 Quit: 492 if (PnpEvent) 493 RtlFreeHeap(ProcessHeap, 0, PnpEvent); 494 495 NtTerminateThread(NtCurrentThread(), Status); 496 return Status; 497 } 498 499 NTSTATUS 500 WaitNoPendingInstallEvents( 501 IN PLARGE_INTEGER Timeout OPTIONAL) 502 { 503 return NtWaitForSingleObject(hNoPendingInstalls, FALSE, Timeout); 504 } 505 506 BOOLEAN 507 EnableUserModePnpManager(VOID) 508 { 509 LARGE_INTEGER Timeout; 510 511 /* Start the PnP thread */ 512 if (hPnpThread != NULL) 513 NtResumeThread(hPnpThread, NULL); 514 515 /* 516 * Wait a little bit so that we get a chance to have some events being 517 * queued by the time the device-installation thread becomes resumed. 518 */ 519 Timeout.QuadPart = -10000000LL; /* Wait for 1 second */ 520 NtWaitForSingleObject(hDeviceInstallListNotEmpty, FALSE, &Timeout); 521 522 /* Start the device installation thread */ 523 if (hDeviceInstallThread != NULL) 524 NtResumeThread(hDeviceInstallThread, NULL); 525 526 return TRUE; 527 } 528 529 BOOLEAN 530 DisableUserModePnpManager(VOID) 531 { 532 /* Wait until all pending installations are done, then freeze the threads */ 533 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0) 534 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n"); 535 536 // TODO: use signalling events 537 538 NtSuspendThread(hPnpThread, NULL); 539 NtSuspendThread(hDeviceInstallThread, NULL); 540 541 return TRUE; 542 } 543 544 NTSTATUS 545 InitializeUserModePnpManager( 546 IN HINF* phSetupInf) 547 { 548 NTSTATUS Status; 549 OBJECT_ATTRIBUTES ObjectAttributes; 550 551 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); 552 UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services"); 553 554 Status = NtCreateEvent(&hDeviceInstallListNotEmpty, 555 EVENT_ALL_ACCESS, 556 NULL, 557 SynchronizationEvent, 558 FALSE); 559 if (!NT_SUCCESS(Status)) 560 { 561 DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status); 562 goto Failure; 563 } 564 565 Status = NtCreateEvent(&hNoPendingInstalls, 566 EVENT_ALL_ACCESS, 567 NULL, 568 NotificationEvent, 569 FALSE); 570 if (!NT_SUCCESS(Status)) 571 { 572 DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status); 573 goto Failure; 574 } 575 576 RtlInitializeSListHead(&DeviceInstallListHead); 577 578 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL); 579 Status = NtOpenKey(&hEnumKey, KEY_QUERY_VALUE, &ObjectAttributes); 580 if (!NT_SUCCESS(Status)) 581 { 582 DPRINT1("NtOpenKey('%wZ') failed (Status 0x%08lx)\n", &EnumU, Status); 583 goto Failure; 584 } 585 586 InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL); 587 Status = NtCreateKey(&hServicesKey, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); 588 if (!NT_SUCCESS(Status)) 589 { 590 DPRINT1("NtCreateKey('%wZ') failed (Status 0x%08lx)\n", &ServicesU, Status); 591 goto Failure; 592 } 593 594 /* Create the PnP event thread in suspended state */ 595 Status = RtlCreateUserThread(NtCurrentProcess(), 596 NULL, 597 TRUE, 598 0, 599 0, 600 0, 601 PnpEventThread, 602 NULL, 603 &hPnpThread, 604 NULL); 605 if (!NT_SUCCESS(Status)) 606 { 607 DPRINT1("Failed to create the PnP event thread (Status 0x%08lx)\n", Status); 608 hPnpThread = NULL; 609 goto Failure; 610 } 611 612 /* Create the device installation thread in suspended state */ 613 Status = RtlCreateUserThread(NtCurrentProcess(), 614 NULL, 615 TRUE, 616 0, 617 0, 618 0, 619 DeviceInstallThread, 620 phSetupInf, 621 &hDeviceInstallThread, 622 NULL); 623 if (!NT_SUCCESS(Status)) 624 { 625 DPRINT1("Failed to create the device installation thread (Status 0x%08lx)\n", Status); 626 hDeviceInstallThread = NULL; 627 goto Failure; 628 } 629 630 return STATUS_SUCCESS; 631 632 Failure: 633 if (hPnpThread) 634 { 635 NtTerminateThread(hPnpThread, STATUS_SUCCESS); 636 NtClose(hPnpThread); 637 } 638 hPnpThread = NULL; 639 640 if (hServicesKey) 641 NtClose(hServicesKey); 642 hServicesKey = NULL; 643 644 if (hEnumKey) 645 NtClose(hEnumKey); 646 hEnumKey = NULL; 647 648 if (hNoPendingInstalls) 649 NtClose(hNoPendingInstalls); 650 hNoPendingInstalls = NULL; 651 652 if (hDeviceInstallListNotEmpty) 653 NtClose(hDeviceInstallListNotEmpty); 654 hDeviceInstallListNotEmpty = NULL; 655 656 return Status; 657 } 658 659 VOID 660 TerminateUserModePnpManager(VOID) 661 { 662 DisableUserModePnpManager(); 663 664 // TODO: use signalling events 665 666 /* Kill the PnP thread as it blocks inside the NtGetPlugPlayEvent() call */ 667 if (hPnpThread) 668 { 669 NtTerminateThread(hPnpThread, STATUS_SUCCESS); 670 NtClose(hPnpThread); 671 } 672 hPnpThread = NULL; 673 674 /* Kill the device installation thread */ 675 if (hDeviceInstallThread) 676 { 677 NtTerminateThread(hDeviceInstallThread, STATUS_SUCCESS); 678 NtClose(hDeviceInstallThread); 679 } 680 hDeviceInstallThread = NULL; 681 682 /* Close the opened handles */ 683 684 if (hServicesKey) 685 NtClose(hServicesKey); 686 hServicesKey = NULL; 687 688 if (hEnumKey) 689 NtClose(hEnumKey); 690 hEnumKey = NULL; 691 692 if (hNoPendingInstalls) 693 NtClose(hNoPendingInstalls); 694 hNoPendingInstalls = NULL; 695 696 if (hDeviceInstallListNotEmpty) 697 NtClose(hDeviceInstallListNotEmpty); 698 hDeviceInstallListNotEmpty = NULL; 699 } 700