2efcc9e504bdd6c375c28f2ffe0cfe2dfa4978c0
[reactos.git] / reactos / services / umpnpmgr / umpnpmgr.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: services/umpnpmgr/umpnpmgr.c
23 * PURPOSE: User-mode Plug and Play manager
24 * PROGRAMMER: Eric Kohl
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <windows.h>
30 #define NTOS_MODE_USER
31 #include <ndk/ntndk.h>
32 #include <ndk/sysguid.h>
33 #include <ddk/wdmguid.h>
34 #include <ddk/cfgmgr32.h>
35
36 #include <rpc.h>
37 #include <rpcdce.h>
38
39 #include "pnp_c.h"
40
41 #define NDEBUG
42 #include <debug.h>
43
44 /* GLOBALS ******************************************************************/
45
46 static VOID CALLBACK
47 ServiceMain(DWORD argc, LPTSTR *argv);
48
49 static SERVICE_TABLE_ENTRY ServiceTable[2] =
50 {
51 {TEXT("PlugPlay"), ServiceMain},
52 {NULL, NULL}
53 };
54
55 static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0";
56
57 static HKEY hEnumKey = NULL;
58 static HKEY hClassKey = NULL;
59
60 /* FUNCTIONS *****************************************************************/
61
62 static DWORD WINAPI
63 RpcServerThread(LPVOID lpParameter)
64 {
65 RPC_STATUS Status;
66
67 DPRINT("RpcServerThread() called\n");
68
69 Status = RpcServerUseProtseqEpW(L"ncacn_np",
70 20,
71 L"\\pipe\\umpnpmgr",
72 NULL); // Security descriptor
73 if (Status != RPC_S_OK)
74 {
75 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
76 return 0;
77 }
78
79 Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec,
80 NULL,
81 NULL);
82 if (Status != RPC_S_OK)
83 {
84 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
85 return 0;
86 }
87
88 Status = RpcServerListen(1,
89 20,
90 FALSE);
91 if (Status != RPC_S_OK)
92 {
93 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
94 return 0;
95 }
96
97 DPRINT("RpcServerThread() done\n");
98
99 return 0;
100 }
101
102
103 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
104 {
105 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
106 }
107
108
109 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
110 {
111 HeapFree(GetProcessHeap(), 0, ptr);
112 }
113
114
115 CONFIGRET
116 PNP_GetVersion(handle_t BindingHandle,
117 unsigned short *Version)
118 {
119 *Version = 0x0400;
120 return CR_SUCCESS;
121 }
122
123
124 CONFIGRET
125 PNP_GetGlobalState(handle_t BindingHandle,
126 unsigned long *State,
127 unsigned long Flags)
128 {
129 *State = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
130 return CR_SUCCESS;
131 }
132
133
134 CONFIGRET
135 PNP_ValidateDeviceInstance(handle_t BindingHandle,
136 wchar_t *DeviceInstance,
137 unsigned long Flags)
138 {
139 CONFIGRET ret = CR_SUCCESS;
140 HKEY hEnumKey = NULL;
141 HKEY hDeviceKey = NULL;
142
143 DPRINT("PNP_ValidateDeviceInstance(%S %lx) called\n",
144 DeviceInstance, Flags);
145
146 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
147 L"System\\CurrentControlSet\\Enum",
148 0,
149 KEY_ALL_ACCESS,
150 &hEnumKey))
151 {
152 DPRINT("Could not open the Enum Key!\n");
153 ret = CR_FAILURE;
154 goto Done;
155 }
156
157 if (RegOpenKeyExW(hEnumKey,
158 DeviceInstance,
159 0,
160 KEY_READ,
161 &hDeviceKey))
162 {
163 DPRINT("Could not open the Device Key!\n");
164 ret = CR_NO_SUCH_DEVNODE;
165 goto Done;
166 }
167
168 /* FIXME: add more tests */
169
170 Done:
171 if (hDeviceKey != NULL)
172 RegCloseKey(hDeviceKey);
173
174 if (hEnumKey != NULL)
175 RegCloseKey(hEnumKey);
176
177 DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret);
178
179 return ret;
180 }
181
182
183 CONFIGRET
184 PNP_GetRootDeviceInstance(handle_t BindingHandle,
185 wchar_t *DeviceInstance,
186 unsigned long Length)
187 {
188 CONFIGRET ret = CR_SUCCESS;
189
190 DPRINT("PNP_GetRootDeviceInstance() called\n");
191
192 if (Length < lstrlenW(szRootDeviceId) + 1)
193 {
194 ret = CR_BUFFER_SMALL;
195 goto Done;
196 }
197
198 lstrcpyW(DeviceInstance,
199 szRootDeviceId);
200
201 Done:
202 DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret);
203
204 return ret;
205 }
206
207
208 CONFIGRET
209 PNP_GetRelatedDeviceInstance(handle_t BindingHandle,
210 unsigned long Relationship,
211 wchar_t *DeviceId,
212 wchar_t *RelatedDeviceId,
213 unsigned long Length,
214 unsigned long Flags)
215 {
216 PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData;
217 CONFIGRET ret = CR_SUCCESS;
218 NTSTATUS Status;
219
220 DPRINT("PNP_GetRelatedDeviceInstance() called\n");
221 DPRINT(" Relationship %ld\n", Relationship);
222 DPRINT(" DeviceId %S\n", DeviceId);
223
224 RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance,
225 DeviceId);
226
227 PlugPlayData.Relation = Relationship;
228
229 PlugPlayData.RelatedDeviceInstance.Length = 0;
230 PlugPlayData.RelatedDeviceInstance.MaximumLength = Length;
231 PlugPlayData.RelatedDeviceInstance.Buffer = RelatedDeviceId;
232
233 Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice,
234 (PVOID)&PlugPlayData,
235 sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
236 if (!NT_SUCCESS(Status))
237 {
238 /* FIXME: Map Status to ret */
239 ret = CR_FAILURE;
240 }
241
242 DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret);
243 if (ret == CR_SUCCESS)
244 {
245 DPRINT("RelatedDevice: %wZ\n", &PlugPlayData.RelatedDeviceInstance);
246 }
247
248 return ret;
249 }
250
251
252 CONFIGRET
253 PNP_EnumerateSubKeys(handle_t BindingHandle,
254 unsigned long Branch,
255 unsigned long Index,
256 wchar_t *Buffer,
257 unsigned long Length,
258 unsigned long *RequiredLength,
259 DWORD Flags)
260 {
261 CONFIGRET ret = CR_SUCCESS;
262 HKEY hKey;
263 DWORD dwError;
264
265 DPRINT1("PNP_EnumerateSubKeys() called\n");
266
267 switch (Branch)
268 {
269 case 1:
270 hKey = hEnumKey;
271 break;
272
273 case 2:
274 hKey = hClassKey;
275 break;
276
277 default:
278 return CR_FAILURE;
279 }
280
281 *RequiredLength = Length;
282 dwError = RegEnumKeyExW(hKey,
283 Index,
284 Buffer,
285 RequiredLength,
286 NULL,
287 NULL,
288 NULL,
289 NULL);
290 if (dwError != ERROR_SUCCESS)
291 {
292 ret = CR_FAILURE;
293 }
294
295 DPRINT1("PNP_EnumerateSubKeys() done (returns %lx)\n", ret);
296 if (ret == CR_SUCCESS)
297 {
298 DPRINT1("Sub key: %S\n", Buffer);
299 }
300
301 return ret;
302 }
303
304
305 CONFIGRET
306 PNP_GetDepth(handle_t BindingHandle,
307 wchar_t *DeviceInstance,
308 unsigned long *Depth,
309 DWORD Flags)
310 {
311 PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData;
312 CONFIGRET ret = CR_SUCCESS;
313 NTSTATUS Status;
314
315 DPRINT("PNP_GetDepth() called\n");
316
317 RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
318 DeviceInstance);
319
320 Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth,
321 (PVOID)&PlugPlayData,
322 sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
323 if (NT_SUCCESS(Status))
324 {
325 *Depth = PlugPlayData.Depth;
326 }
327 else
328 {
329 ret = CR_FAILURE; /* FIXME */
330 }
331
332 DPRINT("PNP_GetDepth() done (returns %lx)\n", ret);
333
334 return ret;
335 }
336
337
338 CONFIGRET
339 PNP_SetDeviceRegProp(handle_t BindingHandle,
340 wchar_t *DeviceId,
341 unsigned long Property,
342 unsigned long DataType,
343 char *Buffer,
344 unsigned long Length,
345 unsigned long Flags)
346 {
347 CONFIGRET ret = CR_SUCCESS;
348 LPWSTR lpValueName = NULL;
349 HKEY hKey = 0;
350
351 DPRINT("PNP_SetDeviceRegProp() called\n");
352
353 DPRINT("DeviceId: %S\n", DeviceId);
354 DPRINT("Property: %lu\n", Property);
355 DPRINT("DataType: %lu\n", DataType);
356 DPRINT("Length: %lu\n", Length);
357
358 switch (Property)
359 {
360 case CM_DRP_DEVICEDESC:
361 lpValueName = L"DeviceDesc";
362 break;
363
364 case CM_DRP_HARDWAREID:
365 lpValueName = L"HardwareID";
366 break;
367
368 case CM_DRP_COMPATIBLEIDS:
369 lpValueName = L"CompatibleIDs";
370 break;
371
372 case CM_DRP_SERVICE:
373 lpValueName = L"Service";
374 break;
375
376 case CM_DRP_CLASS:
377 lpValueName = L"Class";
378 break;
379
380 case CM_DRP_CLASSGUID:
381 lpValueName = L"ClassGUID";
382 break;
383
384 case CM_DRP_DRIVER:
385 lpValueName = L"Driver";
386 break;
387
388 case CM_DRP_CONFIGFLAGS:
389 lpValueName = L"ConfigFlags";
390 break;
391
392 case CM_DRP_MFG:
393 lpValueName = L"Mfg";
394 break;
395
396 case CM_DRP_FRIENDLYNAME:
397 lpValueName = L"FriendlyName";
398 break;
399
400 case CM_DRP_LOCATION_INFORMATION:
401 lpValueName = L"LocationInformation";
402 break;
403
404 case CM_DRP_UPPERFILTERS:
405 lpValueName = L"UpperFilters";
406 break;
407
408 case CM_DRP_LOWERFILTERS:
409 lpValueName = L"LowerFilters";
410 break;
411
412 default:
413 return CR_INVALID_PROPERTY;
414 }
415
416 DPRINT("Value name: %S\n", lpValueName);
417
418 if (RegOpenKeyExW(hEnumKey,
419 DeviceId,
420 0,
421 KEY_ALL_ACCESS,
422 &hKey))
423 return CR_INVALID_DEVNODE;
424
425 if (Length == 0)
426 {
427 if (RegDeleteValueW(hKey,
428 lpValueName))
429 ret = CR_REGISTRY_ERROR;
430 }
431 else
432 {
433 if (RegSetValueExW(hKey,
434 lpValueName,
435 0,
436 DataType,
437 (const BYTE*)Buffer,
438 Length))
439 ret = CR_REGISTRY_ERROR;
440 }
441
442 RegCloseKey(hKey);
443
444 DPRINT("PNP_SetDeviceRegProp() done (returns %lx)\n", ret);
445
446 return ret;
447 }
448
449
450 CONFIGRET
451 PNP_GetDeviceRegProp(handle_t BindingHandle,
452 wchar_t *DeviceInstance,
453 unsigned long Property,
454 unsigned long *DataType,
455 char *Buffer,
456 unsigned long *TransferLen,
457 unsigned long *Length,
458 DWORD Flags)
459 {
460 PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData;
461 CONFIGRET ret = CR_SUCCESS;
462 LPWSTR lpValueName = NULL;
463 HKEY hKey = 0;
464 NTSTATUS Status;
465
466 DPRINT("PNP_GetDeviceRegProp() called\n");
467
468 switch (Property)
469 {
470 case CM_DRP_DEVICEDESC:
471 lpValueName = L"DeviceDesc";
472 break;
473
474 case CM_DRP_HARDWAREID:
475 lpValueName = L"HardwareID";
476 break;
477
478 case CM_DRP_COMPATIBLEIDS:
479 lpValueName = L"CompatibleIDs";
480 break;
481
482 case CM_DRP_SERVICE:
483 lpValueName = L"Service";
484 break;
485
486 case CM_DRP_CLASS:
487 lpValueName = L"Class";
488 break;
489
490 case CM_DRP_CLASSGUID:
491 lpValueName = L"ClassGUID";
492 break;
493
494 case CM_DRP_DRIVER:
495 lpValueName = L"Driver";
496 break;
497
498 case CM_DRP_CONFIGFLAGS:
499 lpValueName = L"ConfigFlags";
500 break;
501
502 case CM_DRP_MFG:
503 lpValueName = L"Mfg";
504 break;
505
506 case CM_DRP_FRIENDLYNAME:
507 lpValueName = L"FriendlyName";
508 break;
509
510 case CM_DRP_LOCATION_INFORMATION:
511 lpValueName = L"LocationInformation";
512 break;
513
514 case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
515 lpValueName = NULL;
516 break;
517
518 case CM_DRP_CAPABILITIES:
519 lpValueName = L"Capabilities";
520 break;
521
522 case CM_DRP_UI_NUMBER:
523 lpValueName = NULL;
524 break;
525
526 case CM_DRP_UPPERFILTERS:
527 lpValueName = L"UpperFilters";
528 break;
529
530 case CM_DRP_LOWERFILTERS:
531 lpValueName = L"LowerFilters";
532 break;
533
534 case CM_DRP_BUSTYPEGUID:
535 lpValueName = NULL;
536 break;
537
538 case CM_DRP_LEGACYBUSTYPE:
539 lpValueName = NULL;
540 break;
541
542 case CM_DRP_BUSNUMBER:
543 lpValueName = NULL;
544 break;
545
546 case CM_DRP_ENUMERATOR_NAME:
547 lpValueName = NULL;
548 break;
549
550 default:
551 return CR_INVALID_PROPERTY;
552 }
553
554 DPRINT("Value name: %S\n", lpValueName);
555
556 if (lpValueName)
557 {
558 /* Retrieve information from the Registry */
559 if (RegOpenKeyExW(hEnumKey,
560 DeviceInstance,
561 0,
562 KEY_ALL_ACCESS,
563 &hKey))
564 return CR_INVALID_DEVNODE;
565
566 if (RegQueryValueExW(hKey,
567 lpValueName,
568 NULL,
569 DataType,
570 (LPBYTE)Buffer,
571 Length))
572 ret = CR_REGISTRY_ERROR;
573
574 /* FIXME: Check buffer size */
575
576 RegCloseKey(hKey);
577 }
578 else
579 {
580 /* Retrieve information from the Device Node */
581 RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
582 DeviceInstance);
583 PlugPlayData.Buffer = Buffer;
584 PlugPlayData.BufferSize = *TransferLen;
585
586 switch (Property)
587 {
588 #if 0
589 case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
590 PlugPlayData.Property = DevicePropertyPhysicalDeviceObjectName;
591 break;
592
593 case CM_DRP_UI_NUMBER:
594 PlugPlayData.Property = DevicePropertyUINumber;
595 break;
596
597 case CM_DRP_BUSTYPEGUID:
598 PlugPlayData.Property = DevicePropertyBusTypeGuid;
599 break;
600
601 case CM_DRP_LEGACYBUSTYPE:
602 PlugPlayData.Property = DevicePropertyLegacyBusType;
603 break;
604
605 case CM_DRP_BUSNUMBER:
606 PlugPlayData.Property = DevicePropertyBusNumber;
607 break;
608
609 case CM_DRP_ENUMERATOR_NAME:
610 PlugPlayData.Property = DevicePropertyEnumeratorName;
611 break;
612 #endif
613
614 default:
615 return CR_INVALID_PROPERTY;
616 }
617
618 Status = NtPlugPlayControl(PlugPlayControlProperty,
619 (PVOID)&PlugPlayData,
620 sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA));
621 if (NT_SUCCESS(Status))
622 {
623 *Length = PlugPlayData.BufferSize;
624 }
625 else
626 {
627 ret = CR_FAILURE; /* FIXME */
628 }
629 }
630
631 DPRINT("PNP_GetDeviceRegProp() done (returns %lx)\n", ret);
632
633 return ret;
634 }
635
636
637 CONFIGRET
638 PNP_GetClassName(handle_t BindingHandle,
639 wchar_t *ClassGuid, /* in */
640 wchar_t *Buffer, /* out */
641 unsigned long *Length, /* in out */
642 unsigned long Flags)
643 {
644 WCHAR szKeyName[MAX_PATH];
645 CONFIGRET ret = CR_SUCCESS;
646 HKEY hKey = NULL;
647 ULONG ulSize;
648
649 DPRINT1("PNP_GetClassName() called\n");
650
651 lstrcpyW(szKeyName, L"System\\CurrentControlSet\\Control\\Class");
652 lstrcatW(szKeyName, L"\\");
653 lstrcatW(szKeyName, ClassGuid);
654
655 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
656 szKeyName,
657 0,
658 KEY_QUERY_VALUE,
659 &hKey))
660 return CR_REGISTRY_ERROR;
661
662 ulSize = *Length * sizeof(WCHAR);
663 if (RegQueryValueExW(hKey,
664 L"Class",
665 NULL,
666 NULL,
667 (LPBYTE)Buffer,
668 &ulSize))
669 {
670 *Length = 0;
671 ret = CR_REGISTRY_ERROR;
672 }
673 else
674 {
675 *Length = ulSize / sizeof(WCHAR);
676 }
677
678 RegCloseKey(hKey);
679
680 DPRINT1("PNP_GetClassName() done (returns %lx)\n", ret);
681
682 return ret;
683 }
684
685
686 CONFIGRET
687 PNP_GetDeviceStatus(handle_t BindingHandle,
688 wchar_t *DeviceInstance,
689 unsigned long *pStatus,
690 unsigned long *pProblem,
691 DWORD Flags)
692 {
693 PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
694 CONFIGRET ret = CR_SUCCESS;
695 NTSTATUS Status;
696
697 DPRINT("PNP_GetDeviceStatus() called\n");
698
699 RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
700 DeviceInstance);
701 PlugPlayData.Operation = 0; /* Get status */
702
703 Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
704 (PVOID)&PlugPlayData,
705 sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
706 if (NT_SUCCESS(Status))
707 {
708 *pStatus = PlugPlayData.DeviceStatus;
709 *pProblem = PlugPlayData.DeviceProblem;
710 }
711 else
712 {
713 ret = CR_FAILURE; /* FIXME */
714 }
715
716 DPRINT("PNP_GetDeviceStatus() done (returns %lx)\n", ret);
717
718 return ret;
719 }
720
721
722 CONFIGRET
723 PNP_SetDeviceProblem(handle_t BindingHandle,
724 wchar_t *DeviceInstance,
725 unsigned long Problem,
726 DWORD Flags)
727 {
728 CONFIGRET ret = CR_SUCCESS;
729
730 DPRINT1("PNP_SetDeviceProblem() called\n");
731
732 /* FIXME */
733
734 DPRINT1("PNP_SetDeviceProblem() done (returns %lx)\n", ret);
735
736 return ret;
737 }
738
739
740 static DWORD WINAPI
741 PnpEventThread(LPVOID lpParameter)
742 {
743 PPLUGPLAY_EVENT_BLOCK PnpEvent;
744 ULONG PnpEventSize;
745 NTSTATUS Status;
746 RPC_STATUS RpcStatus;
747
748 PnpEventSize = 0x1000;
749 PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize);
750 if (PnpEvent == NULL)
751 return ERROR_OUTOFMEMORY;
752
753 for (;;)
754 {
755 DPRINT("Calling NtGetPlugPlayEvent()\n");
756
757 /* Wait for the next pnp event */
758 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
759
760 /* Resize the buffer for the PnP event if it's too small. */
761 if (Status == STATUS_BUFFER_TOO_SMALL)
762 {
763 PnpEventSize += 0x400;
764 PnpEvent = HeapReAlloc(GetProcessHeap(), 0, PnpEvent, PnpEventSize);
765 if (PnpEvent == NULL)
766 return ERROR_OUTOFMEMORY;
767 continue;
768 }
769
770 if (!NT_SUCCESS(Status))
771 {
772 DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status);
773 break;
774 }
775
776 DPRINT("Received PnP Event\n");
777 if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
778 {
779 DPRINT1("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds);
780 }
781 else
782 {
783 DPRINT1("Unknown event\n");
784 }
785
786 /* FIXME: Process the pnp event */
787
788 /* Dequeue the current pnp event and signal the next one */
789 NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
790 }
791
792 HeapFree(GetProcessHeap(), 0, PnpEvent);
793
794 return ERROR_SUCCESS;
795 }
796
797
798 static VOID CALLBACK
799 ServiceMain(DWORD argc, LPTSTR *argv)
800 {
801 HANDLE hThread;
802 DWORD dwThreadId;
803
804 DPRINT("ServiceMain() called\n");
805
806 hThread = CreateThread(NULL,
807 0,
808 PnpEventThread,
809 NULL,
810 0,
811 &dwThreadId);
812 if (hThread != NULL)
813 CloseHandle(hThread);
814
815 hThread = CreateThread(NULL,
816 0,
817 RpcServerThread,
818 NULL,
819 0,
820 &dwThreadId);
821 if (hThread != NULL)
822 CloseHandle(hThread);
823
824 DPRINT("ServiceMain() done\n");
825 }
826
827
828 int
829 main(int argc, char *argv[])
830 {
831 DWORD dwError;
832
833 DPRINT("Umpnpmgr: main() started\n");
834
835 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
836 L"System\\CurrentControlSet\\Enum",
837 0,
838 KEY_ALL_ACCESS,
839 &hEnumKey);
840 if (dwError != ERROR_SUCCESS)
841 {
842 DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
843 return dwError;
844 }
845
846 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
847 L"System\\CurrentControlSet\\Control\\Class",
848 0,
849 KEY_ALL_ACCESS,
850 &hClassKey);
851 if (dwError != ERROR_SUCCESS)
852 {
853 DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
854 return dwError;
855 }
856
857 StartServiceCtrlDispatcher(ServiceTable);
858
859 DPRINT("Umpnpmgr: main() done\n");
860
861 ExitThread(0);
862
863 return 0;
864 }
865
866 /* EOF */