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