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