ea4333c5a93a3bc971e8b8d84bff6c79257d9333
[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 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 }