xref: /reactos/base/services/umpnpmgr/umpnpmgr.c (revision f4d29a74)
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 along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:        See COPYING in the top level directory
21  * PROJECT:          ReactOS kernel
22  * FILE:             base/services/umpnpmgr/umpnpmgr.c
23  * PURPOSE:          User-mode Plug and Play manager
24  * PROGRAMMER:       Eric Kohl (eric.kohl@reactos.org)
25  *                   Herv� Poussineau (hpoussin@reactos.org)
26  *                   Colin Finck (colin@reactos.org)
27  */
28 
29 /* INCLUDES *****************************************************************/
30 
31 //#define HAVE_SLIST_ENTRY_IMPLEMENTED
32 #define WIN32_NO_STATUS
33 #define _INC_WINDOWS
34 #define COM_NO_WINDOWS_H
35 #include <stdarg.h>
36 #include <windef.h>
37 #include <winbase.h>
38 #include <winreg.h>
39 #include <winsvc.h>
40 #include <winuser.h>
41 #include <dbt.h>
42 #include <stdio.h>
43 #include <cmfuncs.h>
44 #include <rtlfuncs.h>
45 #include <setypes.h>
46 #include <umpnpmgr/sysguid.h>
47 #include <cfgmgr32.h>
48 #include <regstr.h>
49 #include <userenv.h>
50 #include <shlwapi.h>
51 #include <pnp_s.h>
52 
53 #define NDEBUG
54 #include <debug.h>
55 
56 /* GLOBALS ******************************************************************/
57 
58 static WCHAR ServiceName[] = L"PlugPlay";
59 
60 static SERVICE_STATUS_HANDLE ServiceStatusHandle;
61 static SERVICE_STATUS ServiceStatus;
62 
63 static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0";
64 
65 static HKEY hEnumKey = NULL;
66 static HKEY hClassKey = NULL;
67 
68 static HANDLE hUserToken = NULL;
69 static HANDLE hInstallEvent = NULL;
70 static HANDLE hNoPendingInstalls = NULL;
71 
72 #ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
73 static SLIST_HEADER DeviceInstallListHead;
74 #else
75 static LIST_ENTRY DeviceInstallListHead;
76 #endif
77 static HANDLE hDeviceInstallListNotEmpty;
78 
79 typedef struct
80 {
81 #ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
82     SLIST_ENTRY ListEntry;
83 #else
84     LIST_ENTRY ListEntry;
85 #endif
86     WCHAR DeviceIds[1];
87 } DeviceInstallParams;
88 
89 /* FUNCTIONS *****************************************************************/
90 
91 static DWORD WINAPI
92 RpcServerThread(LPVOID lpParameter)
93 {
94     RPC_STATUS Status;
95     BOOLEAN RegisteredProtSeq = FALSE;
96 
97     UNREFERENCED_PARAMETER(lpParameter);
98 
99     DPRINT("RpcServerThread() called\n");
100 
101 #if 0
102     /* 2k/XP/2k3-compatible protocol sequence/endpoint */
103     Status = RpcServerUseProtseqEpW(L"ncacn_np",
104                                     20,
105                                     L"\\pipe\\ntsvcs",
106                                     NULL);  // Security descriptor
107     if (Status == RPC_S_OK)
108         RegisteredProtSeq = TRUE;
109     else
110         DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
111 #endif
112 
113     /* Vista/7-compatible protocol sequence/endpoint */
114     Status = RpcServerUseProtseqEpW(L"ncacn_np",
115                                     20,
116                                     L"\\pipe\\plugplay",
117                                     NULL);  // Security descriptor
118     if (Status == RPC_S_OK)
119         RegisteredProtSeq = TRUE;
120     else
121         DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
122 
123     /* Make sure there's a usable endpoint */
124     if (RegisteredProtSeq == FALSE)
125         return 0;
126 
127     Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec,
128                                  NULL,
129                                  NULL);
130     if (Status != RPC_S_OK)
131     {
132         DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
133         return 0;
134     }
135 
136     Status = RpcServerListen(1,
137                              20,
138                              FALSE);
139     if (Status != RPC_S_OK)
140     {
141         DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
142         return 0;
143     }
144 
145     /* ROS HACK (this should never happen...) */
146     DPRINT1("*** Other devices won't be installed correctly. If something\n");
147     DPRINT1("*** doesn't work, try to reboot to get a new chance.\n");
148 
149     DPRINT("RpcServerThread() done\n");
150 
151     return 0;
152 }
153 
154 
155 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
156 {
157     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
158 }
159 
160 
161 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
162 {
163     HeapFree(GetProcessHeap(), 0, ptr);
164 }
165 
166 
167 static CONFIGRET WINAPI
168 NtStatusToCrError(NTSTATUS Status)
169 {
170     switch (Status)
171     {
172         case STATUS_NOT_IMPLEMENTED:
173             return CR_CALL_NOT_IMPLEMENTED;
174 
175         case STATUS_INVALID_PARAMETER:
176             return CR_INVALID_DATA;
177 
178         case STATUS_NO_SUCH_DEVICE:
179             return CR_NO_SUCH_DEVINST;
180 
181         case STATUS_ACCESS_DENIED:
182             return CR_ACCESS_DENIED;
183 
184         case STATUS_BUFFER_TOO_SMALL:
185             return CR_BUFFER_SMALL;
186 
187         case STATUS_OBJECT_NAME_NOT_FOUND:
188             return CR_NO_SUCH_VALUE;
189 
190         default:
191             return CR_FAILURE;
192     }
193 }
194 
195 
196 /* Function 0 */
197 DWORD
198 WINAPI
199 PNP_Disconnect(
200     handle_t hBinding)
201 {
202     UNREFERENCED_PARAMETER(hBinding);
203     return CR_SUCCESS;
204 }
205 
206 
207 /* Function 1 */
208 DWORD
209 WINAPI
210 PNP_Connect(
211     handle_t hBinding)
212 {
213     UNREFERENCED_PARAMETER(hBinding);
214     return CR_SUCCESS;
215 }
216 
217 
218 /* Function 2 */
219 DWORD
220 WINAPI
221 PNP_GetVersion(
222     handle_t hBinding,
223     WORD *pVersion)
224 {
225     UNREFERENCED_PARAMETER(hBinding);
226 
227     *pVersion = 0x0400;
228     return CR_SUCCESS;
229 }
230 
231 
232 /* Function 3 */
233 DWORD
234 WINAPI
235 PNP_GetGlobalState(
236     handle_t hBinding,
237     DWORD *pulState,
238     DWORD ulFlags)
239 {
240     UNREFERENCED_PARAMETER(hBinding);
241     UNREFERENCED_PARAMETER(ulFlags);
242 
243     *pulState = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
244     return CR_SUCCESS;
245 }
246 
247 
248 /* Function 4 */
249 DWORD
250 WINAPI
251 PNP_InitDetection(
252     handle_t hBinding)
253 {
254     UNREFERENCED_PARAMETER(hBinding);
255 
256     DPRINT("PNP_InitDetection() called\n");
257     return CR_SUCCESS;
258 }
259 
260 
261 /* Function 5 */
262 DWORD
263 WINAPI
264 PNP_ReportLogOn(
265     handle_t hBinding,
266     BOOL Admin,
267     DWORD ProcessId)
268 {
269     DWORD ReturnValue = CR_FAILURE;
270     HANDLE hProcess;
271 
272     UNREFERENCED_PARAMETER(hBinding);
273     UNREFERENCED_PARAMETER(Admin);
274 
275     DPRINT("PNP_ReportLogOn(%u, %u) called\n", Admin, ProcessId);
276 
277     /* Get the users token */
278     hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
279 
280     if (!hProcess)
281     {
282         DPRINT1("OpenProcess failed with error %u\n", GetLastError());
283         goto cleanup;
284     }
285 
286     if (hUserToken)
287     {
288         CloseHandle(hUserToken);
289         hUserToken = NULL;
290     }
291 
292     if (!OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY, &hUserToken))
293     {
294         DPRINT1("OpenProcessToken failed with error %u\n", GetLastError());
295         goto cleanup;
296     }
297 
298     /* Trigger the installer thread */
299     if (hInstallEvent)
300         SetEvent(hInstallEvent);
301 
302     ReturnValue = CR_SUCCESS;
303 
304 cleanup:
305     if (hProcess)
306         CloseHandle(hProcess);
307 
308     return ReturnValue;
309 }
310 
311 
312 /* Function 6 */
313 DWORD
314 WINAPI
315 PNP_ValidateDeviceInstance(
316     handle_t hBinding,
317     LPWSTR pDeviceID,
318     DWORD ulFlags)
319 {
320     CONFIGRET ret = CR_SUCCESS;
321     HKEY hDeviceKey = NULL;
322 
323     UNREFERENCED_PARAMETER(hBinding);
324     UNREFERENCED_PARAMETER(ulFlags);
325 
326     DPRINT("PNP_ValidateDeviceInstance(%S %lx) called\n",
327            pDeviceID, ulFlags);
328 
329     if (RegOpenKeyExW(hEnumKey,
330                       pDeviceID,
331                       0,
332                       KEY_READ,
333                       &hDeviceKey))
334     {
335         DPRINT("Could not open the Device Key!\n");
336         ret = CR_NO_SUCH_DEVNODE;
337         goto Done;
338     }
339 
340     /* FIXME: add more tests */
341 
342 Done:
343     if (hDeviceKey != NULL)
344         RegCloseKey(hDeviceKey);
345 
346     DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret);
347 
348     return ret;
349 }
350 
351 
352 /* Function 7 */
353 DWORD
354 WINAPI
355 PNP_GetRootDeviceInstance(
356     handle_t hBinding,
357     LPWSTR pDeviceID,
358     PNP_RPC_STRING_LEN ulLength)
359 {
360     CONFIGRET ret = CR_SUCCESS;
361 
362     UNREFERENCED_PARAMETER(hBinding);
363 
364     DPRINT("PNP_GetRootDeviceInstance() called\n");
365 
366     if (!pDeviceID)
367     {
368         ret = CR_INVALID_POINTER;
369         goto Done;
370     }
371     if (ulLength < lstrlenW(szRootDeviceId) + 1)
372     {
373         ret = CR_BUFFER_SMALL;
374         goto Done;
375     }
376 
377     lstrcpyW(pDeviceID,
378              szRootDeviceId);
379 
380 Done:
381     DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret);
382 
383     return ret;
384 }
385 
386 
387 /* Function 8 */
388 DWORD
389 WINAPI
390 PNP_GetRelatedDeviceInstance(
391     handle_t hBinding,
392     DWORD ulRelationship,
393     LPWSTR pDeviceID,
394     LPWSTR pRelatedDeviceId,
395     PNP_RPC_STRING_LEN *pulLength,
396     DWORD ulFlags)
397 {
398     PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData;
399     CONFIGRET ret = CR_SUCCESS;
400     NTSTATUS Status;
401 
402     UNREFERENCED_PARAMETER(hBinding);
403     UNREFERENCED_PARAMETER(ulFlags);
404 
405     DPRINT("PNP_GetRelatedDeviceInstance() called\n");
406     DPRINT("  Relationship %ld\n", ulRelationship);
407     DPRINT("  DeviceId %S\n", pDeviceID);
408 
409     RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance,
410                          pDeviceID);
411 
412     PlugPlayData.Relation = ulRelationship;
413 
414     PlugPlayData.RelatedDeviceInstanceLength = *pulLength;
415     PlugPlayData.RelatedDeviceInstance = pRelatedDeviceId;
416 
417     Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice,
418                                (PVOID)&PlugPlayData,
419                                sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
420     if (!NT_SUCCESS(Status))
421     {
422         ret = NtStatusToCrError(Status);
423     }
424 
425     DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret);
426     if (ret == CR_SUCCESS)
427     {
428         DPRINT("RelatedDevice: %wZ\n", &PlugPlayData.RelatedDeviceInstance);
429     }
430 
431     return ret;
432 }
433 
434 
435 /* Function 9 */
436 DWORD
437 WINAPI
438 PNP_EnumerateSubKeys(
439     handle_t hBinding,
440     DWORD ulBranch,
441     DWORD ulIndex,
442     LPWSTR Buffer,
443     PNP_RPC_STRING_LEN ulLength,
444     PNP_RPC_STRING_LEN *pulRequiredLen,
445     DWORD ulFlags)
446 {
447     CONFIGRET ret = CR_SUCCESS;
448     HKEY hKey;
449     DWORD dwError;
450 
451     UNREFERENCED_PARAMETER(hBinding);
452     UNREFERENCED_PARAMETER(ulFlags);
453 
454     DPRINT("PNP_EnumerateSubKeys() called\n");
455 
456     switch (ulBranch)
457     {
458         case PNP_ENUMERATOR_SUBKEYS:
459             hKey = hEnumKey;
460             break;
461 
462         case PNP_CLASS_SUBKEYS:
463             hKey = hClassKey;
464             break;
465 
466         default:
467             return CR_FAILURE;
468     }
469 
470     *pulRequiredLen = ulLength;
471     dwError = RegEnumKeyExW(hKey,
472                             ulIndex,
473                             Buffer,
474                             pulRequiredLen,
475                             NULL,
476                             NULL,
477                             NULL,
478                             NULL);
479     if (dwError != ERROR_SUCCESS)
480     {
481         ret = (dwError == ERROR_NO_MORE_ITEMS) ? CR_NO_SUCH_VALUE : CR_FAILURE;
482     }
483     else
484     {
485         (*pulRequiredLen)++;
486     }
487 
488     DPRINT("PNP_EnumerateSubKeys() done (returns %lx)\n", ret);
489 
490     return ret;
491 }
492 
493 
494 /* Function 10 */
495 DWORD
496 WINAPI
497 PNP_GetDeviceList(
498     handle_t hBinding,
499     LPWSTR pszFilter,
500     LPWSTR Buffer,
501     PNP_RPC_STRING_LEN *pulLength,
502     DWORD ulFlags)
503 {
504     PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
505     CONFIGRET ret = CR_SUCCESS;
506     NTSTATUS Status;
507 
508     DPRINT("PNP_GetDeviceList() called\n");
509 
510     if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
511         return CR_INVALID_FLAG;
512 
513     if (pulLength == NULL || pszFilter == NULL)
514         return CR_INVALID_POINTER;
515 
516 //    if (Buffer == NULL)
517 //        return CR_INVALID_POINTER;
518 
519     if (ulFlags &
520         (CM_GETIDLIST_FILTER_BUSRELATIONS |
521          CM_GETIDLIST_FILTER_POWERRELATIONS |
522          CM_GETIDLIST_FILTER_REMOVALRELATIONS |
523          CM_GETIDLIST_FILTER_EJECTRELATIONS))
524     {
525         RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
526                              pszFilter);
527         if (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)
528         {
529             PlugPlayData.Relations = 3;
530         }
531         else if (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS)
532         {
533             PlugPlayData.Relations = 2;
534         }
535         else if (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS)
536         {
537             PlugPlayData.Relations = 1;
538         }
539         else if (ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS)
540         {
541             PlugPlayData.Relations = 0;
542         }
543 
544         PlugPlayData.BufferSize = *pulLength * sizeof(WCHAR);
545         PlugPlayData.Buffer = Buffer;
546 
547         Status = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
548                                    (PVOID)&PlugPlayData,
549                                    sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
550         if (NT_SUCCESS(Status))
551         {
552             *pulLength = PlugPlayData.BufferSize / sizeof(WCHAR);
553         }
554         else
555         {
556             ret = NtStatusToCrError(Status);
557         }
558     }
559     else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
560     {
561         ret = CR_CALL_NOT_IMPLEMENTED;
562     }
563     else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
564     {
565         ret = CR_CALL_NOT_IMPLEMENTED;
566     }
567     else /* CM_GETIDLIST_FILTER_NONE */
568     {
569         ret = CR_CALL_NOT_IMPLEMENTED;
570     }
571 
572     return ret;
573 }
574 
575 
576 /* Function 11 */
577 DWORD
578 WINAPI
579 PNP_GetDeviceListSize(
580     handle_t hBinding,
581     LPWSTR pszFilter,
582     PNP_RPC_BUFFER_SIZE *pulLength,
583     DWORD ulFlags)
584 {
585     PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
586     CONFIGRET ret = CR_SUCCESS;
587     NTSTATUS Status;
588 
589     DPRINT("PNP_GetDeviceListSize() called\n");
590 
591     if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
592         return CR_INVALID_FLAG;
593 
594     if (pulLength == NULL || pszFilter == NULL)
595         return CR_INVALID_POINTER;
596 
597     *pulLength = 0;
598 
599     if (ulFlags &
600         (CM_GETIDLIST_FILTER_BUSRELATIONS |
601          CM_GETIDLIST_FILTER_POWERRELATIONS |
602          CM_GETIDLIST_FILTER_REMOVALRELATIONS |
603          CM_GETIDLIST_FILTER_EJECTRELATIONS))
604     {
605         RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
606                              pszFilter);
607         if (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)
608         {
609             PlugPlayData.Relations = 3;
610         }
611         else if (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS)
612         {
613             PlugPlayData.Relations = 2;
614         }
615         else if (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS)
616         {
617             PlugPlayData.Relations = 1;
618         }
619         else if (ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS)
620         {
621             PlugPlayData.Relations = 0;
622         }
623 
624         PlugPlayData.BufferSize = 0;
625         PlugPlayData.Buffer = NULL;
626 
627         Status = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
628                                    (PVOID)&PlugPlayData,
629                                    sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
630         if (NT_SUCCESS(Status))
631         {
632             *pulLength = PlugPlayData.BufferSize / sizeof(WCHAR);
633         }
634         else
635         {
636             ret = NtStatusToCrError(Status);
637         }
638     }
639     else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
640     {
641         ret = CR_CALL_NOT_IMPLEMENTED;
642     }
643     else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
644     {
645         ret = CR_CALL_NOT_IMPLEMENTED;
646     }
647     else /* CM_GETIDLIST_FILTER_NONE */
648     {
649         ret = CR_CALL_NOT_IMPLEMENTED;
650     }
651 
652     return ret;
653 }
654 
655 
656 /* Function 12 */
657 DWORD
658 WINAPI
659 PNP_GetDepth(
660     handle_t hBinding,
661     LPWSTR pszDeviceID,
662     DWORD *pulDepth,
663     DWORD ulFlags)
664 {
665     PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData;
666     CONFIGRET ret = CR_SUCCESS;
667     NTSTATUS Status;
668 
669     UNREFERENCED_PARAMETER(hBinding);
670     UNREFERENCED_PARAMETER(ulFlags);
671 
672     DPRINT("PNP_GetDepth() called\n");
673 
674     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
675                          pszDeviceID);
676 
677     Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth,
678                                (PVOID)&PlugPlayData,
679                                sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
680     if (NT_SUCCESS(Status))
681     {
682         *pulDepth = PlugPlayData.Depth;
683     }
684     else
685     {
686         ret = NtStatusToCrError(Status);
687     }
688 
689     DPRINT("PNP_GetDepth() done (returns %lx)\n", ret);
690 
691     return ret;
692 }
693 
694 
695 /* Function 13 */
696 DWORD
697 WINAPI
698 PNP_GetDeviceRegProp(
699     handle_t hBinding,
700     LPWSTR pDeviceID,
701     DWORD ulProperty,
702     DWORD *pulRegDataType,
703     BYTE *Buffer,
704     PNP_PROP_SIZE *pulTransferLen,
705     PNP_PROP_SIZE *pulLength,
706     DWORD ulFlags)
707 {
708     PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData;
709     CONFIGRET ret = CR_SUCCESS;
710     LPWSTR lpValueName = NULL;
711     HKEY hKey = NULL;
712     LONG lError;
713     NTSTATUS Status;
714 
715     UNREFERENCED_PARAMETER(hBinding);
716 
717     DPRINT("PNP_GetDeviceRegProp() called\n");
718 
719     if (pulTransferLen == NULL || pulLength == NULL)
720     {
721         ret = CR_INVALID_POINTER;
722         goto done;
723     }
724 
725     if (ulFlags != 0)
726     {
727         ret = CR_INVALID_FLAG;
728         goto done;
729     }
730 
731     /* FIXME: Check pDeviceID */
732 
733     if (*pulLength < *pulTransferLen)
734         *pulLength = *pulTransferLen;
735 
736     *pulTransferLen = 0;
737 
738     switch (ulProperty)
739     {
740         case CM_DRP_DEVICEDESC:
741             lpValueName = L"DeviceDesc";
742             break;
743 
744         case CM_DRP_HARDWAREID:
745             lpValueName = L"HardwareID";
746             break;
747 
748         case CM_DRP_COMPATIBLEIDS:
749             lpValueName = L"CompatibleIDs";
750             break;
751 
752         case CM_DRP_SERVICE:
753             lpValueName = L"Service";
754             break;
755 
756         case CM_DRP_CLASS:
757             lpValueName = L"Class";
758             break;
759 
760         case CM_DRP_CLASSGUID:
761             lpValueName = L"ClassGUID";
762             break;
763 
764         case CM_DRP_DRIVER:
765             lpValueName = L"Driver";
766             break;
767 
768         case CM_DRP_CONFIGFLAGS:
769             lpValueName = L"ConfigFlags";
770             break;
771 
772         case CM_DRP_MFG:
773             lpValueName = L"Mfg";
774             break;
775 
776         case CM_DRP_FRIENDLYNAME:
777             lpValueName = L"FriendlyName";
778             break;
779 
780         case CM_DRP_LOCATION_INFORMATION:
781             lpValueName = L"LocationInformation";
782             break;
783 
784         case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
785             PlugPlayData.Property = PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME;
786             break;
787 
788         case CM_DRP_CAPABILITIES:
789             lpValueName = L"Capabilities";
790             break;
791 
792         case CM_DRP_UI_NUMBER:
793             PlugPlayData.Property = PNP_PROPERTY_UI_NUMBER;
794             break;
795 
796         case CM_DRP_UPPERFILTERS:
797             lpValueName = L"UpperFilters";
798             break;
799 
800         case CM_DRP_LOWERFILTERS:
801             lpValueName = L"LowerFilters";
802             break;
803 
804         case CM_DRP_BUSTYPEGUID:
805             PlugPlayData.Property = PNP_PROPERTY_BUSTYPEGUID;
806             break;
807 
808         case CM_DRP_LEGACYBUSTYPE:
809             PlugPlayData.Property = PNP_PROPERTY_LEGACYBUSTYPE;
810             break;
811 
812         case CM_DRP_BUSNUMBER:
813             PlugPlayData.Property = PNP_PROPERTY_BUSNUMBER;
814             break;
815 
816         case CM_DRP_ENUMERATOR_NAME:
817             PlugPlayData.Property = PNP_PROPERTY_ENUMERATOR_NAME;
818             break;
819 
820         case CM_DRP_SECURITY:
821             lpValueName = L"Security";
822             break;
823 
824         case CM_DRP_DEVTYPE:
825             lpValueName = L"DeviceType";
826             break;
827 
828         case CM_DRP_EXCLUSIVE:
829             lpValueName = L"Exclusive";
830             break;
831 
832         case CM_DRP_CHARACTERISTICS:
833             lpValueName = L"DeviceCharacteristics";
834             break;
835 
836         case CM_DRP_ADDRESS:
837             PlugPlayData.Property = PNP_PROPERTY_ADDRESS;
838             break;
839 
840         case CM_DRP_UI_NUMBER_DESC_FORMAT:
841             lpValueName = L"UINumberDescFormat";
842             break;
843 
844         case CM_DRP_DEVICE_POWER_DATA:
845             PlugPlayData.Property = PNP_PROPERTY_POWER_DATA;
846             break;
847 
848         case CM_DRP_REMOVAL_POLICY:
849             PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY;
850             break;
851 
852         case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
853             PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT;
854             break;
855 
856         case CM_DRP_REMOVAL_POLICY_OVERRIDE:
857             lpValueName = L"RemovalPolicy";
858             break;
859 
860         case CM_DRP_INSTALL_STATE:
861             PlugPlayData.Property = PNP_PROPERTY_INSTALL_STATE;
862             break;
863 
864 #if (WINVER >= _WIN32_WINNT_WS03)
865         case CM_DRP_LOCATION_PATHS:
866             PlugPlayData.Property = PNP_PROPERTY_LOCATION_PATHS;
867             break;
868 #endif
869 
870 #if (WINVER >= _WIN32_WINNT_WIN7)
871         case CM_DRP_BASE_CONTAINERID:
872             PlugPlayData.Property = PNP_PROPERTY_CONTAINERID;
873             break;
874 #endif
875 
876         default:
877             ret = CR_INVALID_PROPERTY;
878             goto done;
879     }
880 
881     DPRINT("Value name: %S\n", lpValueName);
882 
883     if (lpValueName)
884     {
885         /* Retrieve information from the Registry */
886         lError = RegOpenKeyExW(hEnumKey,
887                                pDeviceID,
888                                0,
889                                KEY_QUERY_VALUE,
890                                &hKey);
891         if (lError != ERROR_SUCCESS)
892         {
893             hKey = NULL;
894             *pulLength = 0;
895             ret = CR_INVALID_DEVNODE;
896             goto done;
897         }
898 
899         lError = RegQueryValueExW(hKey,
900                                   lpValueName,
901                                   NULL,
902                                   pulRegDataType,
903                                   Buffer,
904                                   pulLength);
905         if (lError != ERROR_SUCCESS)
906         {
907             if (lError == ERROR_MORE_DATA)
908             {
909                 ret = CR_BUFFER_SMALL;
910             }
911             else
912             {
913                 *pulLength = 0;
914                 ret = CR_NO_SUCH_VALUE;
915             }
916         }
917     }
918     else
919     {
920         /* Retrieve information from the Device Node */
921         RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
922                              pDeviceID);
923         PlugPlayData.Buffer = Buffer;
924         PlugPlayData.BufferSize = *pulLength;
925 
926         Status = NtPlugPlayControl(PlugPlayControlProperty,
927                                    (PVOID)&PlugPlayData,
928                                    sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA));
929         if (NT_SUCCESS(Status))
930         {
931             *pulLength = PlugPlayData.BufferSize;
932         }
933         else
934         {
935             ret = NtStatusToCrError(Status);
936         }
937     }
938 
939 done:
940     if (pulTransferLen)
941         *pulTransferLen = (ret == CR_SUCCESS) ? *pulLength : 0;
942 
943     if (hKey != NULL)
944         RegCloseKey(hKey);
945 
946     DPRINT("PNP_GetDeviceRegProp() done (returns %lx)\n", ret);
947 
948     return ret;
949 }
950 
951 
952 /* Function 14 */
953 DWORD
954 WINAPI
955 PNP_SetDeviceRegProp(
956     handle_t hBinding,
957     LPWSTR pDeviceId,
958     DWORD ulProperty,
959     DWORD ulDataType,
960     BYTE *Buffer,
961     PNP_PROP_SIZE ulLength,
962     DWORD ulFlags)
963 {
964     CONFIGRET ret = CR_SUCCESS;
965     LPWSTR lpValueName = NULL;
966     HKEY hKey = 0;
967 
968     UNREFERENCED_PARAMETER(hBinding);
969     UNREFERENCED_PARAMETER(ulFlags);
970 
971     DPRINT("PNP_SetDeviceRegProp() called\n");
972 
973     DPRINT("DeviceId: %S\n", pDeviceId);
974     DPRINT("Property: %lu\n", ulProperty);
975     DPRINT("DataType: %lu\n", ulDataType);
976     DPRINT("Length: %lu\n", ulLength);
977 
978     switch (ulProperty)
979     {
980         case CM_DRP_DEVICEDESC:
981             lpValueName = L"DeviceDesc";
982             break;
983 
984         case CM_DRP_HARDWAREID:
985             lpValueName = L"HardwareID";
986             break;
987 
988         case CM_DRP_COMPATIBLEIDS:
989             lpValueName = L"CompatibleIDs";
990             break;
991 
992         case CM_DRP_SERVICE:
993             lpValueName = L"Service";
994             break;
995 
996         case CM_DRP_CLASS:
997             lpValueName = L"Class";
998             break;
999 
1000         case CM_DRP_CLASSGUID:
1001             lpValueName = L"ClassGUID";
1002             break;
1003 
1004         case CM_DRP_DRIVER:
1005             lpValueName = L"Driver";
1006             break;
1007 
1008         case CM_DRP_CONFIGFLAGS:
1009             lpValueName = L"ConfigFlags";
1010             break;
1011 
1012         case CM_DRP_MFG:
1013             lpValueName = L"Mfg";
1014             break;
1015 
1016         case CM_DRP_FRIENDLYNAME:
1017             lpValueName = L"FriendlyName";
1018             break;
1019 
1020         case CM_DRP_LOCATION_INFORMATION:
1021             lpValueName = L"LocationInformation";
1022             break;
1023 
1024         case CM_DRP_UPPERFILTERS:
1025             lpValueName = L"UpperFilters";
1026             break;
1027 
1028         case CM_DRP_LOWERFILTERS:
1029             lpValueName = L"LowerFilters";
1030             break;
1031 
1032         case CM_DRP_SECURITY:
1033             lpValueName = L"Security";
1034             break;
1035 
1036         case CM_DRP_DEVTYPE:
1037             lpValueName = L"DeviceType";
1038             break;
1039 
1040         case CM_DRP_EXCLUSIVE:
1041             lpValueName = L"Exclusive";
1042             break;
1043 
1044         case CM_DRP_CHARACTERISTICS:
1045             lpValueName = L"DeviceCharacteristics";
1046             break;
1047 
1048         case CM_DRP_UI_NUMBER_DESC_FORMAT:
1049             lpValueName = L"UINumberDescFormat";
1050             break;
1051 
1052         case CM_DRP_REMOVAL_POLICY_OVERRIDE:
1053             lpValueName = L"RemovalPolicy";
1054             break;
1055 
1056         default:
1057             return CR_INVALID_PROPERTY;
1058     }
1059 
1060     DPRINT("Value name: %S\n", lpValueName);
1061 
1062     if (RegOpenKeyExW(hEnumKey,
1063                       pDeviceId,
1064                       0,
1065                       KEY_SET_VALUE,
1066                       &hKey))
1067         return CR_INVALID_DEVNODE;
1068 
1069     if (ulLength == 0)
1070     {
1071         if (RegDeleteValueW(hKey,
1072                             lpValueName))
1073             ret = CR_REGISTRY_ERROR;
1074     }
1075     else
1076     {
1077         if (RegSetValueExW(hKey,
1078                            lpValueName,
1079                            0,
1080                            ulDataType,
1081                            Buffer,
1082                            ulLength))
1083             ret = CR_REGISTRY_ERROR;
1084     }
1085 
1086     RegCloseKey(hKey);
1087 
1088     DPRINT("PNP_SetDeviceRegProp() done (returns %lx)\n", ret);
1089 
1090     return ret;
1091 }
1092 
1093 
1094 /* Function 15 */
1095 DWORD
1096 WINAPI
1097 PNP_GetClassInstance(
1098     handle_t hBinding,
1099     LPWSTR pDeviceId,
1100     LPWSTR pszClassInstance,
1101     PNP_RPC_STRING_LEN ulLength)
1102 {
1103     UNIMPLEMENTED;
1104     return CR_CALL_NOT_IMPLEMENTED;
1105 }
1106 
1107 
1108 /* Function 16 */
1109 DWORD
1110 WINAPI
1111 PNP_CreateKey(
1112     handle_t hBinding,
1113     LPWSTR pszSubKey,
1114     DWORD samDesired,
1115     DWORD ulFlags)
1116 {
1117     HKEY hKey = 0;
1118 
1119     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
1120                         pszSubKey,
1121                         0,
1122                         NULL,
1123                         0,
1124                         KEY_ALL_ACCESS,
1125                         NULL,
1126                         &hKey,
1127                         NULL))
1128         return CR_REGISTRY_ERROR;
1129 
1130     /* FIXME: Set security key */
1131 
1132     RegCloseKey(hKey);
1133 
1134     return CR_SUCCESS;
1135 }
1136 
1137 
1138 /* Function 17 */
1139 DWORD
1140 WINAPI
1141 PNP_DeleteRegistryKey(
1142     handle_t hBinding,
1143     LPWSTR pszDeviceID,
1144     LPWSTR pszParentKey,
1145     LPWSTR pszChildKey,
1146     DWORD ulFlags)
1147 {
1148     UNIMPLEMENTED;
1149     return CR_CALL_NOT_IMPLEMENTED;
1150 }
1151 
1152 
1153 /* Function 18 */
1154 DWORD
1155 WINAPI
1156 PNP_GetClassCount(
1157     handle_t hBinding,
1158     DWORD *pulClassCount,
1159     DWORD ulFlags)
1160 {
1161     HKEY hKey;
1162     DWORD dwError;
1163 
1164     UNREFERENCED_PARAMETER(hBinding);
1165     UNREFERENCED_PARAMETER(ulFlags);
1166 
1167     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1168                             REGSTR_PATH_CLASS,
1169                             0,
1170                             KEY_QUERY_VALUE,
1171                             &hKey);
1172     if (dwError != ERROR_SUCCESS)
1173         return CR_INVALID_DATA;
1174 
1175     dwError = RegQueryInfoKeyW(hKey,
1176                                NULL,
1177                                NULL,
1178                                NULL,
1179                                pulClassCount,
1180                                NULL,
1181                                NULL,
1182                                NULL,
1183                                NULL,
1184                                NULL,
1185                                NULL,
1186                                NULL);
1187     RegCloseKey(hKey);
1188     if (dwError != ERROR_SUCCESS)
1189         return CR_INVALID_DATA;
1190 
1191     return CR_SUCCESS;
1192 }
1193 
1194 
1195 /* Function 19 */
1196 DWORD
1197 WINAPI
1198 PNP_GetClassName(
1199     handle_t hBinding,
1200     LPWSTR pszClassGuid,
1201     LPWSTR Buffer,
1202     PNP_RPC_STRING_LEN *pulLength,
1203     DWORD ulFlags)
1204 {
1205     WCHAR szKeyName[MAX_PATH];
1206     CONFIGRET ret = CR_SUCCESS;
1207     HKEY hKey;
1208     DWORD dwSize;
1209 
1210     UNREFERENCED_PARAMETER(hBinding);
1211     UNREFERENCED_PARAMETER(ulFlags);
1212 
1213     DPRINT("PNP_GetClassName() called\n");
1214 
1215     lstrcpyW(szKeyName, L"System\\CurrentControlSet\\Control\\Class\\");
1216     if (lstrlenW(pszClassGuid) + 1 < sizeof(szKeyName)/sizeof(WCHAR)-(lstrlenW(szKeyName) * sizeof(WCHAR)))
1217         lstrcatW(szKeyName, pszClassGuid);
1218     else
1219         return CR_INVALID_DATA;
1220 
1221     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1222                       szKeyName,
1223                       0,
1224                       KEY_QUERY_VALUE,
1225                       &hKey))
1226         return CR_REGISTRY_ERROR;
1227 
1228     dwSize = *pulLength * sizeof(WCHAR);
1229     if (RegQueryValueExW(hKey,
1230                          L"Class",
1231                          NULL,
1232                          NULL,
1233                          (LPBYTE)Buffer,
1234                          &dwSize))
1235     {
1236         *pulLength = 0;
1237         ret = CR_REGISTRY_ERROR;
1238     }
1239     else
1240     {
1241         *pulLength = dwSize / sizeof(WCHAR);
1242     }
1243 
1244     RegCloseKey(hKey);
1245 
1246     DPRINT("PNP_GetClassName() done (returns %lx)\n", ret);
1247 
1248     return ret;
1249 }
1250 
1251 
1252 /* Function 20 */
1253 DWORD
1254 WINAPI
1255 PNP_DeleteClassKey(
1256     handle_t hBinding,
1257     LPWSTR pszClassGuid,
1258     DWORD ulFlags)
1259 {
1260     CONFIGRET ret = CR_SUCCESS;
1261 
1262     UNREFERENCED_PARAMETER(hBinding);
1263 
1264     DPRINT("PNP_GetClassName(%S, %lx) called\n", pszClassGuid, ulFlags);
1265 
1266     if (ulFlags & CM_DELETE_CLASS_SUBKEYS)
1267     {
1268         if (SHDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
1269             ret = CR_REGISTRY_ERROR;
1270     }
1271     else
1272     {
1273         if (RegDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
1274             ret = CR_REGISTRY_ERROR;
1275     }
1276 
1277     DPRINT("PNP_DeleteClassKey() done (returns %lx)\n", ret);
1278 
1279     return ret;
1280 }
1281 
1282 
1283 /* Function 21 */
1284 DWORD
1285 WINAPI
1286 PNP_GetInterfaceDeviceAlias(
1287     handle_t hBinding,
1288     LPWSTR pszInterfaceDevice,
1289     GUID *AliasInterfaceGuid,
1290     LPWSTR pszAliasInterfaceDevice,
1291     PNP_RPC_STRING_LEN *pulLength,
1292     PNP_RPC_STRING_LEN *pulTransferLen,
1293     DWORD ulFlags)
1294 {
1295     UNIMPLEMENTED;
1296     return CR_CALL_NOT_IMPLEMENTED;
1297 }
1298 
1299 
1300 /* Function 22 */
1301 DWORD
1302 WINAPI
1303 PNP_GetInterfaceDeviceList(
1304     handle_t hBinding,
1305     GUID *InterfaceGuid,
1306     LPWSTR pszDeviceID,
1307     BYTE *Buffer,
1308     PNP_RPC_BUFFER_SIZE *pulLength,
1309     DWORD ulFlags)
1310 {
1311     NTSTATUS Status;
1312     PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData;
1313     DWORD ret = CR_SUCCESS;
1314 
1315     UNREFERENCED_PARAMETER(hBinding);
1316 
1317     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
1318                          pszDeviceID);
1319 
1320     PlugPlayData.Flags = ulFlags;
1321     PlugPlayData.FilterGuid = InterfaceGuid;
1322     PlugPlayData.Buffer = Buffer;
1323     PlugPlayData.BufferSize = *pulLength;
1324 
1325     Status = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
1326                                (PVOID)&PlugPlayData,
1327                                sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
1328     if (NT_SUCCESS(Status))
1329     {
1330         *pulLength = PlugPlayData.BufferSize;
1331     }
1332     else
1333     {
1334         ret = NtStatusToCrError(Status);
1335     }
1336 
1337     DPRINT("PNP_GetInterfaceDeviceListSize() done (returns %lx)\n", ret);
1338     return ret;
1339 }
1340 
1341 
1342 /* Function 23 */
1343 DWORD
1344 WINAPI
1345 PNP_GetInterfaceDeviceListSize(
1346     handle_t hBinding,
1347     PNP_RPC_BUFFER_SIZE *pulLen,
1348     GUID *InterfaceGuid,
1349     LPWSTR pszDeviceID,
1350     DWORD ulFlags)
1351 {
1352     NTSTATUS Status;
1353     PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData;
1354     DWORD ret = CR_SUCCESS;
1355 
1356     UNREFERENCED_PARAMETER(hBinding);
1357 
1358     DPRINT("PNP_GetInterfaceDeviceListSize() called\n");
1359 
1360     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
1361                          pszDeviceID);
1362 
1363     PlugPlayData.FilterGuid = InterfaceGuid;
1364     PlugPlayData.Buffer = NULL;
1365     PlugPlayData.BufferSize = 0;
1366     PlugPlayData.Flags = ulFlags;
1367 
1368     Status = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
1369                                (PVOID)&PlugPlayData,
1370                                sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
1371     if (NT_SUCCESS(Status))
1372     {
1373         *pulLen = PlugPlayData.BufferSize;
1374     }
1375     else
1376     {
1377         ret = NtStatusToCrError(Status);
1378     }
1379 
1380     DPRINT("PNP_GetInterfaceDeviceListSize() done (returns %lx)\n", ret);
1381     return ret;
1382 }
1383 
1384 
1385 /* Function 24 */
1386 DWORD
1387 WINAPI
1388 PNP_RegisterDeviceClassAssociation(
1389     handle_t hBinding,
1390     LPWSTR pszDeviceID,
1391     GUID *InterfaceGuid,
1392     LPWSTR pszReference,
1393     LPWSTR pszSymLink,
1394     PNP_RPC_STRING_LEN *pulLength,
1395     PNP_RPC_STRING_LEN *pulTransferLen,
1396     DWORD ulFlags)
1397 {
1398     UNIMPLEMENTED;
1399     return CR_CALL_NOT_IMPLEMENTED;
1400 }
1401 
1402 
1403 /* Function 25 */
1404 DWORD
1405 WINAPI
1406 PNP_UnregisterDeviceClassAssociation(
1407     handle_t hBinding,
1408     LPWSTR pszInterfaceDevice,
1409     DWORD ulFlags)
1410 {
1411     UNIMPLEMENTED;
1412     return CR_CALL_NOT_IMPLEMENTED;
1413 }
1414 
1415 
1416 /* Function 26 */
1417 DWORD
1418 WINAPI
1419 PNP_GetClassRegProp(
1420     handle_t hBinding,
1421     LPWSTR pszClassGuid,
1422     DWORD ulProperty,
1423     DWORD *pulRegDataType,
1424     BYTE *Buffer,
1425     PNP_RPC_STRING_LEN *pulTransferLen,
1426     PNP_RPC_STRING_LEN *pulLength,
1427     DWORD ulFlags)
1428 {
1429     CONFIGRET ret = CR_SUCCESS;
1430     LPWSTR lpValueName = NULL;
1431     HKEY hInstKey = NULL;
1432     HKEY hPropKey = NULL;
1433     LONG lError;
1434 
1435     UNREFERENCED_PARAMETER(hBinding);
1436 
1437     DPRINT("PNP_GetClassRegProp() called\n");
1438 
1439     if (pulTransferLen == NULL || pulLength == NULL)
1440     {
1441         ret = CR_INVALID_POINTER;
1442         goto done;
1443     }
1444 
1445     if (ulFlags != 0)
1446     {
1447         ret = CR_INVALID_FLAG;
1448         goto done;
1449     }
1450 
1451     if (*pulLength < *pulTransferLen)
1452         *pulLength = *pulTransferLen;
1453 
1454     *pulTransferLen = 0;
1455 
1456     switch (ulProperty)
1457     {
1458         case CM_CRP_SECURITY:
1459             lpValueName = L"Security";
1460             break;
1461 
1462         case CM_CRP_DEVTYPE:
1463             lpValueName = L"DeviceType";
1464             break;
1465 
1466         case CM_CRP_EXCLUSIVE:
1467             lpValueName = L"Exclusive";
1468             break;
1469 
1470         case CM_CRP_CHARACTERISTICS:
1471             lpValueName = L"DeviceCharacteristics";
1472             break;
1473 
1474         default:
1475             ret = CR_INVALID_PROPERTY;
1476             goto done;
1477     }
1478 
1479     DPRINT("Value name: %S\n", lpValueName);
1480 
1481     lError = RegOpenKeyExW(hClassKey,
1482                            pszClassGuid,
1483                            0,
1484                            KEY_READ,
1485                            &hInstKey);
1486     if (lError != ERROR_SUCCESS)
1487     {
1488         *pulLength = 0;
1489         ret = CR_NO_SUCH_REGISTRY_KEY;
1490         goto done;
1491     }
1492 
1493     lError = RegOpenKeyExW(hInstKey,
1494                            L"Properties",
1495                            0,
1496                            KEY_READ,
1497                            &hPropKey);
1498     if (lError != ERROR_SUCCESS)
1499     {
1500         *pulLength = 0;
1501         ret = CR_NO_SUCH_REGISTRY_KEY;
1502         goto done;
1503     }
1504 
1505     lError = RegQueryValueExW(hPropKey,
1506                               lpValueName,
1507                               NULL,
1508                               pulRegDataType,
1509                               Buffer,
1510                               pulLength);
1511     if (lError != ERROR_SUCCESS)
1512     {
1513         if (lError == ERROR_MORE_DATA)
1514         {
1515             ret = CR_BUFFER_SMALL;
1516         }
1517         else
1518         {
1519             *pulLength = 0;
1520             ret = CR_NO_SUCH_VALUE;
1521         }
1522     }
1523 
1524 done:
1525     if (ret == CR_SUCCESS)
1526         *pulTransferLen = *pulLength;
1527 
1528     if (hPropKey != NULL)
1529         RegCloseKey(hPropKey);
1530 
1531     if (hInstKey != NULL)
1532         RegCloseKey(hInstKey);
1533 
1534     DPRINT("PNP_GetClassRegProp() done (returns %lx)\n", ret);
1535 
1536     return ret;
1537 }
1538 
1539 
1540 /* Function 27 */
1541 DWORD
1542 WINAPI
1543 PNP_SetClassRegProp(
1544     handle_t hBinding,
1545     LPWSTR pszClassGuid,
1546     DWORD ulProperty,
1547     DWORD ulDataType,
1548     BYTE *Buffer,
1549     PNP_PROP_SIZE ulLength,
1550     DWORD ulFlags)
1551 {
1552     CONFIGRET ret = CR_SUCCESS;
1553     LPWSTR lpValueName = NULL;
1554     HKEY hInstKey = 0;
1555     HKEY hPropKey = 0;
1556     LONG lError;
1557 
1558     UNREFERENCED_PARAMETER(hBinding);
1559 
1560     DPRINT("PNP_SetClassRegProp() called\n");
1561 
1562     if (ulFlags != 0)
1563         return CR_INVALID_FLAG;
1564 
1565     switch (ulProperty)
1566     {
1567         case CM_CRP_SECURITY:
1568             lpValueName = L"Security";
1569             break;
1570 
1571         case CM_CRP_DEVTYPE:
1572             lpValueName = L"DeviceType";
1573             break;
1574 
1575         case CM_CRP_EXCLUSIVE:
1576             lpValueName = L"Exclusive";
1577             break;
1578 
1579         case CM_CRP_CHARACTERISTICS:
1580             lpValueName = L"DeviceCharacteristics";
1581             break;
1582 
1583         default:
1584             return CR_INVALID_PROPERTY;
1585     }
1586 
1587     lError = RegOpenKeyExW(hClassKey,
1588                            pszClassGuid,
1589                            0,
1590                            KEY_WRITE,
1591                            &hInstKey);
1592     if (lError != ERROR_SUCCESS)
1593     {
1594         ret = CR_NO_SUCH_REGISTRY_KEY;
1595         goto done;
1596     }
1597 
1598     /* FIXME: Set security descriptor */
1599     lError = RegCreateKeyExW(hInstKey,
1600                              L"Properties",
1601                              0,
1602                              NULL,
1603                              REG_OPTION_NON_VOLATILE,
1604                              KEY_ALL_ACCESS,
1605                              NULL,
1606                              &hPropKey,
1607                              NULL);
1608     if (lError != ERROR_SUCCESS)
1609     {
1610         ret = CR_REGISTRY_ERROR;
1611         goto done;
1612     }
1613 
1614     if (ulLength == 0)
1615     {
1616         if (RegDeleteValueW(hPropKey,
1617                             lpValueName))
1618             ret = CR_REGISTRY_ERROR;
1619     }
1620     else
1621     {
1622         if (RegSetValueExW(hPropKey,
1623                            lpValueName,
1624                            0,
1625                            ulDataType,
1626                            Buffer,
1627                            ulLength))
1628             ret = CR_REGISTRY_ERROR;
1629     }
1630 
1631 done:
1632     if (hPropKey != NULL)
1633         RegCloseKey(hPropKey);
1634 
1635     if (hInstKey != NULL)
1636         RegCloseKey(hInstKey);
1637 
1638     return ret;
1639 }
1640 
1641 
1642 static VOID
1643 SplitDeviceInstanceID(IN LPWSTR pszDeviceInstanceID,
1644                       OUT LPWSTR pszEnumerator,
1645                       OUT LPWSTR pszDevice,
1646                       OUT LPWSTR pszInstance)
1647 {
1648     WCHAR szLocalDeviceInstanceID[MAX_DEVICE_ID_LEN];
1649     LPWSTR lpEnumerator = NULL;
1650     LPWSTR lpDevice = NULL;
1651     LPWSTR lpInstance = NULL;
1652     LPWSTR ptr;
1653 
1654     wcscpy(szLocalDeviceInstanceID, pszDeviceInstanceID);
1655 
1656     *pszEnumerator = 0;
1657     *pszDevice = 0;
1658     *pszInstance = 0;
1659 
1660     lpEnumerator = szLocalDeviceInstanceID;
1661 
1662     ptr = wcschr(lpEnumerator, L'\\');
1663     if (ptr != NULL)
1664     {
1665         *ptr = 0;
1666         lpDevice = ++ptr;
1667 
1668         ptr = wcschr(lpDevice, L'\\');
1669         if (ptr != NULL)
1670         {
1671             *ptr = 0;
1672             lpInstance = ++ptr;
1673         }
1674     }
1675 
1676     if (lpEnumerator != NULL)
1677         wcscpy(pszEnumerator, lpEnumerator);
1678 
1679     if (lpDevice != NULL)
1680         wcscpy(pszDevice, lpDevice);
1681 
1682     if (lpInstance != NULL)
1683         wcscpy(pszInstance, lpInstance);
1684 }
1685 
1686 
1687 static CONFIGRET
1688 CreateDeviceInstance(LPWSTR pszDeviceID)
1689 {
1690     WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
1691     WCHAR szDevice[MAX_DEVICE_ID_LEN];
1692     WCHAR szInstance[MAX_DEVICE_ID_LEN];
1693     HKEY hKeyEnumerator;
1694     HKEY hKeyDevice;
1695     HKEY hKeyInstance;
1696     HKEY hKeyControl;
1697     LONG lError;
1698 
1699     /* Split the instance ID */
1700     SplitDeviceInstanceID(pszDeviceID,
1701                           szEnumerator,
1702                           szDevice,
1703                           szInstance);
1704 
1705     /* Open or create the enumerator key */
1706     lError = RegCreateKeyExW(hEnumKey,
1707                              szEnumerator,
1708                              0,
1709                              NULL,
1710                              REG_OPTION_NON_VOLATILE,
1711                              KEY_ALL_ACCESS,
1712                              NULL,
1713                              &hKeyEnumerator,
1714                              NULL);
1715     if (lError != ERROR_SUCCESS)
1716     {
1717         return CR_REGISTRY_ERROR;
1718     }
1719 
1720     /* Open or create the device key */
1721     lError = RegCreateKeyExW(hKeyEnumerator,
1722                              szDevice,
1723                              0,
1724                              NULL,
1725                              REG_OPTION_NON_VOLATILE,
1726                              KEY_ALL_ACCESS,
1727                              NULL,
1728                              &hKeyDevice,
1729                              NULL);
1730 
1731     /* Close the enumerator key */
1732     RegCloseKey(hKeyEnumerator);
1733 
1734     if (lError != ERROR_SUCCESS)
1735     {
1736         return CR_REGISTRY_ERROR;
1737     }
1738 
1739     /* Try to open the instance key and fail if it exists */
1740     lError = RegOpenKeyExW(hKeyDevice,
1741                            szInstance,
1742                            0,
1743                            KEY_SET_VALUE,
1744                            &hKeyInstance);
1745     if (lError == ERROR_SUCCESS)
1746     {
1747         DPRINT1("Instance %S already exists!\n", szInstance);
1748         RegCloseKey(hKeyInstance);
1749         RegCloseKey(hKeyDevice);
1750         return CR_ALREADY_SUCH_DEVINST;
1751     }
1752 
1753     /* Create a new instance key */
1754     lError = RegCreateKeyExW(hKeyDevice,
1755                              szInstance,
1756                              0,
1757                              NULL,
1758                              REG_OPTION_NON_VOLATILE,
1759                              KEY_ALL_ACCESS,
1760                              NULL,
1761                              &hKeyInstance,
1762                              NULL);
1763 
1764     /* Close the device key */
1765     RegCloseKey(hKeyDevice);
1766 
1767     if (lError != ERROR_SUCCESS)
1768     {
1769         return CR_REGISTRY_ERROR;
1770     }
1771 
1772     /* Create the 'Control' sub key */
1773     lError = RegCreateKeyExW(hKeyInstance,
1774                              L"Control",
1775                              0,
1776                              NULL,
1777                              REG_OPTION_NON_VOLATILE,
1778                              KEY_ALL_ACCESS,
1779                              NULL,
1780                              &hKeyControl,
1781                              NULL);
1782     if (lError == ERROR_SUCCESS)
1783     {
1784         RegCloseKey(hKeyControl);
1785     }
1786 
1787     RegCloseKey(hKeyInstance);
1788 
1789     return (lError == ERROR_SUCCESS) ? CR_SUCCESS : CR_REGISTRY_ERROR;
1790 }
1791 
1792 
1793 /* Function 28 */
1794 DWORD
1795 WINAPI
1796 PNP_CreateDevInst(
1797     handle_t hBinding,
1798     LPWSTR pszDeviceID,
1799     LPWSTR pszParentDeviceID,
1800     PNP_RPC_STRING_LEN ulLength,
1801     DWORD ulFlags)
1802 {
1803     CONFIGRET ret = CR_SUCCESS;
1804 
1805     DPRINT("PNP_CreateDevInst: %S\n", pszDeviceID);
1806 
1807     if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID)
1808     {
1809         WCHAR szGeneratedInstance[MAX_DEVICE_ID_LEN];
1810         DWORD dwInstanceNumber;
1811 
1812         /* Generated ID is: Root\<Device ID>\<Instance number> */
1813         dwInstanceNumber = 0;
1814         do
1815         {
1816             swprintf(szGeneratedInstance, L"Root\\%ls\\%04lu",
1817                      pszDeviceID, dwInstanceNumber);
1818 
1819             /* Try to create a device instance with this ID */
1820             ret = CreateDeviceInstance(szGeneratedInstance);
1821 
1822             dwInstanceNumber++;
1823         }
1824         while (ret == CR_ALREADY_SUCH_DEVINST);
1825 
1826         if (ret == CR_SUCCESS)
1827         {
1828             /* pszDeviceID is an out parameter too for generated IDs */
1829             if (wcslen(szGeneratedInstance) > ulLength)
1830             {
1831                 ret = CR_BUFFER_SMALL;
1832             }
1833             else
1834             {
1835                 wcscpy(pszDeviceID, szGeneratedInstance);
1836             }
1837         }
1838     }
1839     else
1840     {
1841         /* Create the device instance */
1842         ret = CreateDeviceInstance(pszDeviceID);
1843     }
1844 
1845     DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
1846 
1847     return ret;
1848 }
1849 
1850 
1851 static CONFIGRET
1852 MoveDeviceInstance(LPWSTR pszDeviceInstanceDestination,
1853                    LPWSTR pszDeviceInstanceSource)
1854 {
1855     DPRINT("MoveDeviceInstance: not implemented\n");
1856     /* FIXME */
1857     return CR_CALL_NOT_IMPLEMENTED;
1858 }
1859 
1860 
1861 static CONFIGRET
1862 SetupDeviceInstance(LPWSTR pszDeviceInstance,
1863                     DWORD ulFlags)
1864 {
1865     DPRINT("SetupDeviceInstance: not implemented\n");
1866     /* FIXME */
1867     return CR_CALL_NOT_IMPLEMENTED;
1868 }
1869 
1870 
1871 static CONFIGRET
1872 EnableDeviceInstance(LPWSTR pszDeviceInstance)
1873 {
1874     PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
1875     CONFIGRET ret = CR_SUCCESS;
1876     NTSTATUS Status;
1877 
1878     DPRINT("Enable device instance %S\n", pszDeviceInstance);
1879 
1880     RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, pszDeviceInstance);
1881     Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
1882     if (!NT_SUCCESS(Status))
1883         ret = NtStatusToCrError(Status);
1884 
1885     return ret;
1886 }
1887 
1888 
1889 static CONFIGRET
1890 DisableDeviceInstance(LPWSTR pszDeviceInstance)
1891 {
1892     DPRINT("DisableDeviceInstance: not implemented\n");
1893     /* FIXME */
1894     return CR_CALL_NOT_IMPLEMENTED;
1895 }
1896 
1897 
1898 static CONFIGRET
1899 ReenumerateDeviceInstance(
1900     _In_ LPWSTR pszDeviceInstance,
1901     _In_ ULONG ulFlags)
1902 {
1903     PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA EnumerateDeviceData;
1904     CONFIGRET ret = CR_SUCCESS;
1905     NTSTATUS Status;
1906 
1907     DPRINT1("ReenumerateDeviceInstance(%S 0x%08lx)\n",
1908            pszDeviceInstance, ulFlags);
1909 
1910     if (ulFlags & ~CM_REENUMERATE_BITS)
1911         return CR_INVALID_FLAG;
1912 
1913     if (ulFlags & CM_REENUMERATE_RETRY_INSTALLATION)
1914     {
1915         DPRINT1("CM_REENUMERATE_RETRY_INSTALLATION not implemented!\n");
1916     }
1917 
1918     RtlInitUnicodeString(&EnumerateDeviceData.DeviceInstance,
1919                          pszDeviceInstance);
1920     EnumerateDeviceData.Flags = 0;
1921 
1922     Status = NtPlugPlayControl(PlugPlayControlEnumerateDevice,
1923                                &EnumerateDeviceData,
1924                                sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA));
1925     if (!NT_SUCCESS(Status))
1926         ret = NtStatusToCrError(Status);
1927 
1928     return ret;
1929 }
1930 
1931 
1932 /* Function 29 */
1933 DWORD
1934 WINAPI
1935 PNP_DeviceInstanceAction(
1936     handle_t hBinding,
1937     DWORD ulAction,
1938     DWORD ulFlags,
1939     LPWSTR pszDeviceInstance1,
1940     LPWSTR pszDeviceInstance2)
1941 {
1942     CONFIGRET ret = CR_SUCCESS;
1943 
1944     UNREFERENCED_PARAMETER(hBinding);
1945 
1946     DPRINT("PNP_DeviceInstanceAction() called\n");
1947 
1948     switch (ulAction)
1949     {
1950         case PNP_DEVINST_MOVE:
1951             ret = MoveDeviceInstance(pszDeviceInstance1,
1952                                      pszDeviceInstance2);
1953             break;
1954 
1955         case PNP_DEVINST_SETUP:
1956             ret = SetupDeviceInstance(pszDeviceInstance1,
1957                                       ulFlags);
1958             break;
1959 
1960         case PNP_DEVINST_ENABLE:
1961             ret = EnableDeviceInstance(pszDeviceInstance1);
1962             break;
1963 
1964         case PNP_DEVINST_DISABLE:
1965             ret = DisableDeviceInstance(pszDeviceInstance1);
1966             break;
1967 
1968         case PNP_DEVINST_REENUMERATE:
1969             ret = ReenumerateDeviceInstance(pszDeviceInstance1,
1970                                             ulFlags);
1971             break;
1972 
1973         default:
1974             DPRINT1("Unknown device action %lu: not implemented\n", ulAction);
1975             ret = CR_CALL_NOT_IMPLEMENTED;
1976     }
1977 
1978     DPRINT("PNP_DeviceInstanceAction() done (returns %lx)\n", ret);
1979 
1980     return ret;
1981 }
1982 
1983 
1984 /* Function 30 */
1985 DWORD
1986 WINAPI
1987 PNP_GetDeviceStatus(
1988     handle_t hBinding,
1989     LPWSTR pDeviceID,
1990     DWORD *pulStatus,
1991     DWORD *pulProblem,
1992     DWORD ulFlags)
1993 {
1994     PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
1995     CONFIGRET ret = CR_SUCCESS;
1996     NTSTATUS Status;
1997 
1998     UNREFERENCED_PARAMETER(hBinding);
1999     UNREFERENCED_PARAMETER(ulFlags);
2000 
2001     DPRINT("PNP_GetDeviceStatus() called\n");
2002 
2003     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
2004                          pDeviceID);
2005     PlugPlayData.Operation = 0; /* Get status */
2006 
2007     Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
2008                                (PVOID)&PlugPlayData,
2009                                sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
2010     if (NT_SUCCESS(Status))
2011     {
2012         *pulStatus = PlugPlayData.DeviceStatus;
2013         *pulProblem = PlugPlayData.DeviceProblem;
2014     }
2015     else
2016     {
2017         ret = NtStatusToCrError(Status);
2018     }
2019 
2020     DPRINT("PNP_GetDeviceStatus() done (returns %lx)\n", ret);
2021 
2022     return ret;
2023 }
2024 
2025 
2026 /* Function 31 */
2027 DWORD
2028 WINAPI
2029 PNP_SetDeviceProblem(
2030     handle_t hBinding,
2031     LPWSTR pDeviceID,
2032     DWORD ulProblem,
2033     DWORD ulFlags)
2034 {
2035     UNIMPLEMENTED;
2036     return CR_CALL_NOT_IMPLEMENTED;
2037 }
2038 
2039 
2040 /* Function 32 */
2041 DWORD
2042 WINAPI
2043 PNP_DisableDevInst(
2044     handle_t hBinding,
2045     LPWSTR pDeviceID,
2046     PPNP_VETO_TYPE pVetoType,
2047     LPWSTR pszVetoName,
2048     DWORD ulNameLength,
2049     DWORD ulFlags)
2050 {
2051     UNIMPLEMENTED;
2052     return CR_CALL_NOT_IMPLEMENTED;
2053 }
2054 
2055 /* Function 33 */
2056 DWORD
2057 WINAPI
2058 PNP_UninstallDevInst(
2059     handle_t hBinding,
2060     LPWSTR pDeviceID,
2061     DWORD ulFlags)
2062 {
2063     UNIMPLEMENTED;
2064     return CR_CALL_NOT_IMPLEMENTED;
2065 }
2066 
2067 
2068 static BOOL
2069 CheckForDeviceId(LPWSTR lpDeviceIdList,
2070                  LPWSTR lpDeviceId)
2071 {
2072     LPWSTR lpPtr;
2073     DWORD dwLength;
2074 
2075     lpPtr = lpDeviceIdList;
2076     while (*lpPtr != 0)
2077     {
2078         dwLength = wcslen(lpPtr);
2079         if (0 == _wcsicmp(lpPtr, lpDeviceId))
2080             return TRUE;
2081 
2082         lpPtr += (dwLength + 1);
2083     }
2084 
2085     return FALSE;
2086 }
2087 
2088 
2089 static VOID
2090 AppendDeviceId(LPWSTR lpDeviceIdList,
2091                LPDWORD lpDeviceIdListSize,
2092                LPWSTR lpDeviceId)
2093 {
2094     DWORD dwLen;
2095     DWORD dwPos;
2096 
2097     dwLen = wcslen(lpDeviceId);
2098     dwPos = (*lpDeviceIdListSize / sizeof(WCHAR)) - 1;
2099 
2100     wcscpy(&lpDeviceIdList[dwPos], lpDeviceId);
2101 
2102     dwPos += (dwLen + 1);
2103 
2104     lpDeviceIdList[dwPos] = 0;
2105 
2106     *lpDeviceIdListSize = dwPos * sizeof(WCHAR);
2107 }
2108 
2109 
2110 /* Function 34 */
2111 DWORD
2112 WINAPI
2113 PNP_AddID(
2114     handle_t hBinding,
2115     LPWSTR pszDeviceID,
2116     LPWSTR pszID,
2117     DWORD ulFlags)
2118 {
2119     CONFIGRET ret = CR_SUCCESS;
2120     HKEY hDeviceKey;
2121     LPWSTR pszSubKey;
2122     DWORD dwDeviceIdListSize;
2123     DWORD dwNewDeviceIdSize;
2124     WCHAR * pszDeviceIdList = NULL;
2125 
2126     UNREFERENCED_PARAMETER(hBinding);
2127 
2128     DPRINT("PNP_AddID() called\n");
2129     DPRINT("  DeviceInstance: %S\n", pszDeviceID);
2130     DPRINT("  DeviceId: %S\n", pszID);
2131     DPRINT("  Flags: %lx\n", ulFlags);
2132 
2133     if (RegOpenKeyExW(hEnumKey,
2134                       pszDeviceID,
2135                       0,
2136                       KEY_QUERY_VALUE | KEY_SET_VALUE,
2137                       &hDeviceKey) != ERROR_SUCCESS)
2138     {
2139         DPRINT("Failed to open the device key!\n");
2140         return CR_INVALID_DEVNODE;
2141     }
2142 
2143     pszSubKey = (ulFlags & CM_ADD_ID_COMPATIBLE) ? L"CompatibleIDs" : L"HardwareID";
2144 
2145     if (RegQueryValueExW(hDeviceKey,
2146                          pszSubKey,
2147                          NULL,
2148                          NULL,
2149                          NULL,
2150                          &dwDeviceIdListSize) != ERROR_SUCCESS)
2151     {
2152         DPRINT("Failed to query the desired ID string!\n");
2153         ret = CR_REGISTRY_ERROR;
2154         goto Done;
2155     }
2156 
2157     dwNewDeviceIdSize = lstrlenW(pszDeviceID);
2158     if (!dwNewDeviceIdSize)
2159     {
2160         ret = CR_INVALID_POINTER;
2161         goto Done;
2162     }
2163 
2164     dwDeviceIdListSize += (dwNewDeviceIdSize + 2) * sizeof(WCHAR);
2165 
2166     pszDeviceIdList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDeviceIdListSize);
2167     if (!pszDeviceIdList)
2168     {
2169         DPRINT("Failed to allocate memory for the desired ID string!\n");
2170         ret = CR_OUT_OF_MEMORY;
2171         goto Done;
2172     }
2173 
2174     if (RegQueryValueExW(hDeviceKey,
2175                          pszSubKey,
2176                          NULL,
2177                          NULL,
2178                          (LPBYTE)pszDeviceIdList,
2179                          &dwDeviceIdListSize) != ERROR_SUCCESS)
2180     {
2181         DPRINT("Failed to query the desired ID string!\n");
2182         ret = CR_REGISTRY_ERROR;
2183         goto Done;
2184     }
2185 
2186     /* Check whether the device ID is already in use */
2187     if (CheckForDeviceId(pszDeviceIdList, pszDeviceID))
2188     {
2189         DPRINT("Device ID was found in the ID string!\n");
2190         ret = CR_SUCCESS;
2191         goto Done;
2192     }
2193 
2194     /* Append the Device ID */
2195     AppendDeviceId(pszDeviceIdList, &dwDeviceIdListSize, pszID);
2196 
2197     if (RegSetValueExW(hDeviceKey,
2198                        pszSubKey,
2199                        0,
2200                        REG_MULTI_SZ,
2201                        (LPBYTE)pszDeviceIdList,
2202                        dwDeviceIdListSize) != ERROR_SUCCESS)
2203     {
2204         DPRINT("Failed to set the desired ID string!\n");
2205         ret = CR_REGISTRY_ERROR;
2206     }
2207 
2208 Done:
2209     RegCloseKey(hDeviceKey);
2210     if (pszDeviceIdList)
2211         HeapFree(GetProcessHeap(), 0, pszDeviceIdList);
2212 
2213     DPRINT("PNP_AddID() done (returns %lx)\n", ret);
2214 
2215     return ret;
2216 }
2217 
2218 
2219 /* Function 35 */
2220 DWORD
2221 WINAPI
2222 PNP_RegisterDriver(
2223     handle_t hBinding,
2224     LPWSTR pszDeviceID,
2225     DWORD ulFlags)
2226 {
2227     UNIMPLEMENTED;
2228     return CR_CALL_NOT_IMPLEMENTED;
2229 }
2230 
2231 
2232 /* Function 36 */
2233 DWORD
2234 WINAPI
2235 PNP_QueryRemove(
2236     handle_t hBinding,
2237     LPWSTR pszDeviceID,
2238     PPNP_VETO_TYPE pVetoType,
2239     LPWSTR pszVetoName,
2240     DWORD ulNameLength,
2241     DWORD ulFlags)
2242 {
2243     UNIMPLEMENTED;
2244     return CR_CALL_NOT_IMPLEMENTED;
2245 }
2246 
2247 
2248 /* Function 37 */
2249 DWORD
2250 WINAPI
2251 PNP_RequestDeviceEject(
2252     handle_t hBinding,
2253     LPWSTR pszDeviceID,
2254     PPNP_VETO_TYPE pVetoType,
2255     LPWSTR pszVetoName,
2256     DWORD ulNameLength,
2257     DWORD ulFlags)
2258 {
2259     UNIMPLEMENTED;
2260     return CR_CALL_NOT_IMPLEMENTED;
2261 }
2262 
2263 
2264 /* Function 38 */
2265 CONFIGRET
2266 WINAPI
2267 PNP_IsDockStationPresent(
2268     handle_t hBinding,
2269     BOOL *Present)
2270 {
2271     HKEY hKey;
2272     DWORD dwType;
2273     DWORD dwValue;
2274     DWORD dwSize;
2275     CONFIGRET ret = CR_SUCCESS;
2276 
2277     UNREFERENCED_PARAMETER(hBinding);
2278 
2279     DPRINT1("PNP_IsDockStationPresent() called\n");
2280 
2281     *Present = FALSE;
2282 
2283     if (RegOpenKeyExW(HKEY_CURRENT_CONFIG,
2284                       L"CurrentDockInfo",
2285                       0,
2286                       KEY_READ,
2287                       &hKey) != ERROR_SUCCESS)
2288         return CR_REGISTRY_ERROR;
2289 
2290     dwSize = sizeof(DWORD);
2291     if (RegQueryValueExW(hKey,
2292                          L"DockingState",
2293                          NULL,
2294                          &dwType,
2295                          (LPBYTE)&dwValue,
2296                          &dwSize) != ERROR_SUCCESS)
2297         ret = CR_REGISTRY_ERROR;
2298 
2299     RegCloseKey(hKey);
2300 
2301     if (ret == CR_SUCCESS)
2302     {
2303         if (dwType != REG_DWORD || dwSize != sizeof(DWORD))
2304         {
2305             ret = CR_REGISTRY_ERROR;
2306         }
2307         else if (dwValue != 0)
2308         {
2309             *Present = TRUE;
2310         }
2311     }
2312 
2313     DPRINT1("PNP_IsDockStationPresent() done (returns %lx)\n", ret);
2314 
2315     return ret;
2316 }
2317 
2318 
2319 /* Function 39 */
2320 DWORD
2321 WINAPI
2322 PNP_RequestEjectPC(
2323     handle_t hBinding)
2324 {
2325     UNIMPLEMENTED;
2326     return CR_CALL_NOT_IMPLEMENTED;
2327 }
2328 
2329 
2330 /* Function 40 */
2331 DWORD
2332 WINAPI
2333 PNP_HwProfFlags(
2334     handle_t hBinding,
2335     DWORD ulAction,
2336     LPWSTR pDeviceID,
2337     DWORD ulConfig,
2338     DWORD *pulValue,
2339     PPNP_VETO_TYPE pVetoType,
2340     LPWSTR pszVetoName,
2341     DWORD ulNameLength,
2342     DWORD ulFlags)
2343 {
2344     CONFIGRET ret = CR_SUCCESS;
2345     WCHAR szKeyName[MAX_PATH];
2346     HKEY hKey;
2347     HKEY hDeviceKey;
2348     DWORD dwSize;
2349 
2350     UNREFERENCED_PARAMETER(hBinding);
2351 
2352     DPRINT("PNP_HwProfFlags() called\n");
2353 
2354     if (ulConfig == 0)
2355     {
2356         wcscpy(szKeyName,
2357                L"System\\CurrentControlSet\\HardwareProfiles\\Current\\System\\CurrentControlSet\\Enum");
2358     }
2359     else
2360     {
2361         swprintf(szKeyName,
2362                  L"System\\CurrentControlSet\\HardwareProfiles\\%04lu\\System\\CurrentControlSet\\Enum",
2363                  ulConfig);
2364     }
2365 
2366     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2367                       szKeyName,
2368                       0,
2369                       KEY_QUERY_VALUE,
2370                       &hKey) != ERROR_SUCCESS)
2371         return CR_REGISTRY_ERROR;
2372 
2373     if (ulAction == PNP_GET_HWPROFFLAGS)
2374     {
2375          if (RegOpenKeyExW(hKey,
2376                            pDeviceID,
2377                            0,
2378                            KEY_QUERY_VALUE,
2379                            &hDeviceKey) != ERROR_SUCCESS)
2380          {
2381             *pulValue = 0;
2382          }
2383          else
2384          {
2385              dwSize = sizeof(DWORD);
2386              if (RegQueryValueExW(hDeviceKey,
2387                                   L"CSConfigFlags",
2388                                   NULL,
2389                                   NULL,
2390                                   (LPBYTE)pulValue,
2391                                   &dwSize) != ERROR_SUCCESS)
2392              {
2393                  *pulValue = 0;
2394              }
2395 
2396              RegCloseKey(hDeviceKey);
2397          }
2398     }
2399     else if (ulAction == PNP_SET_HWPROFFLAGS)
2400     {
2401         /* FIXME: not implemented yet */
2402         ret = CR_CALL_NOT_IMPLEMENTED;
2403     }
2404 
2405     RegCloseKey(hKey);
2406 
2407     return ret;
2408 }
2409 
2410 
2411 /* Function 41 */
2412 DWORD
2413 WINAPI
2414 PNP_GetHwProfInfo(
2415     handle_t hBinding,
2416     DWORD ulIndex,
2417     HWPROFILEINFO *pHWProfileInfo,
2418     DWORD ulProfileInfoSize,
2419     DWORD ulFlags)
2420 {
2421     WCHAR szProfileName[5];
2422     HKEY hKeyConfig = NULL;
2423     HKEY hKeyProfiles = NULL;
2424     HKEY hKeyProfile = NULL;
2425     DWORD dwDisposition;
2426     DWORD dwSize;
2427     LONG lError;
2428     CONFIGRET ret = CR_SUCCESS;
2429 
2430     UNREFERENCED_PARAMETER(hBinding);
2431 
2432     DPRINT("PNP_GetHwProfInfo() called\n");
2433 
2434     if (ulProfileInfoSize == 0)
2435     {
2436         ret = CR_INVALID_DATA;
2437         goto done;
2438     }
2439 
2440     if (ulFlags != 0)
2441     {
2442         ret = CR_INVALID_FLAG;
2443         goto done;
2444     }
2445 
2446     /* Initialize the profile information */
2447     pHWProfileInfo->HWPI_ulHWProfile = 0;
2448     pHWProfileInfo->HWPI_szFriendlyName[0] = 0;
2449     pHWProfileInfo->HWPI_dwFlags = 0;
2450 
2451     /* Open the 'IDConfigDB' key */
2452     lError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
2453                              L"System\\CurrentControlSet\\Control\\IDConfigDB",
2454                              0,
2455                              NULL,
2456                              REG_OPTION_NON_VOLATILE,
2457                              KEY_QUERY_VALUE,
2458                              NULL,
2459                              &hKeyConfig,
2460                              &dwDisposition);
2461     if (lError != ERROR_SUCCESS)
2462     {
2463         ret = CR_REGISTRY_ERROR;
2464         goto done;
2465     }
2466 
2467     /* Open the 'Hardware Profiles' subkey */
2468     lError = RegCreateKeyExW(hKeyConfig,
2469                              L"Hardware Profiles",
2470                              0,
2471                              NULL,
2472                              REG_OPTION_NON_VOLATILE,
2473                              KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
2474                              NULL,
2475                              &hKeyProfiles,
2476                              &dwDisposition);
2477     if (lError != ERROR_SUCCESS)
2478     {
2479         ret = CR_REGISTRY_ERROR;
2480         goto done;
2481     }
2482 
2483     if (ulIndex == (ULONG)-1)
2484     {
2485         dwSize = sizeof(ULONG);
2486         lError = RegQueryValueExW(hKeyConfig,
2487                                   L"CurrentConfig",
2488                                   NULL,
2489                                   NULL,
2490                                   (LPBYTE)&pHWProfileInfo->HWPI_ulHWProfile,
2491                                   &dwSize);
2492         if (lError != ERROR_SUCCESS)
2493         {
2494             pHWProfileInfo->HWPI_ulHWProfile = 0;
2495             ret = CR_REGISTRY_ERROR;
2496             goto done;
2497         }
2498     }
2499     else
2500     {
2501         /* FIXME: not implemented yet */
2502         ret = CR_CALL_NOT_IMPLEMENTED;
2503         goto done;
2504     }
2505 
2506     swprintf(szProfileName, L"%04lu", pHWProfileInfo->HWPI_ulHWProfile);
2507 
2508     lError = RegOpenKeyExW(hKeyProfiles,
2509                            szProfileName,
2510                            0,
2511                            KEY_QUERY_VALUE,
2512                            &hKeyProfile);
2513     if (lError != ERROR_SUCCESS)
2514     {
2515         ret = CR_REGISTRY_ERROR;
2516         goto done;
2517     }
2518 
2519     dwSize = sizeof(pHWProfileInfo->HWPI_szFriendlyName);
2520     lError = RegQueryValueExW(hKeyProfile,
2521                               L"FriendlyName",
2522                               NULL,
2523                               NULL,
2524                               (LPBYTE)&pHWProfileInfo->HWPI_szFriendlyName,
2525                               &dwSize);
2526     if (lError != ERROR_SUCCESS)
2527     {
2528         ret = CR_REGISTRY_ERROR;
2529         goto done;
2530     }
2531 
2532 done:
2533     if (hKeyProfile != NULL)
2534         RegCloseKey(hKeyProfile);
2535 
2536     if (hKeyProfiles != NULL)
2537         RegCloseKey(hKeyProfiles);
2538 
2539     if (hKeyConfig != NULL)
2540         RegCloseKey(hKeyConfig);
2541 
2542     return ret;
2543 }
2544 
2545 
2546 /* Function 42 */
2547 DWORD
2548 WINAPI
2549 PNP_AddEmptyLogConf(
2550     handle_t hBinding,
2551     LPWSTR pDeviceID,
2552     DWORD ulPriority,
2553     DWORD *pulLogConfTag,
2554     DWORD ulFlags)
2555 {
2556     UNIMPLEMENTED;
2557     return CR_CALL_NOT_IMPLEMENTED;
2558 }
2559 
2560 
2561 /* Function 43 */
2562 DWORD
2563 WINAPI
2564 PNP_FreeLogConf(
2565     handle_t hBinding,
2566     LPWSTR pDeviceID,
2567     DWORD ulLogConfType,
2568     DWORD ulLogConfTag,
2569     DWORD ulFlags)
2570 {
2571     UNIMPLEMENTED;
2572     return CR_CALL_NOT_IMPLEMENTED;
2573 }
2574 
2575 
2576 /* Function 44 */
2577 DWORD
2578 WINAPI
2579 PNP_GetFirstLogConf(
2580     handle_t hBinding,
2581     LPWSTR pDeviceID,
2582     DWORD ulLogConfType,
2583     DWORD *pulLogConfTag,
2584     DWORD ulFlags)
2585 {
2586     UNIMPLEMENTED;
2587     return CR_CALL_NOT_IMPLEMENTED;
2588 }
2589 
2590 
2591 /* Function 45 */
2592 DWORD
2593 WINAPI
2594 PNP_GetNextLogConf(
2595     handle_t hBinding,
2596     LPWSTR pDeviceID,
2597     DWORD ulLogConfType,
2598     DWORD ulCurrentTag,
2599     DWORD *pulNextTag,
2600     DWORD ulFlags)
2601 {
2602     UNIMPLEMENTED;
2603     return CR_CALL_NOT_IMPLEMENTED;
2604 }
2605 
2606 
2607 /* Function 46 */
2608 DWORD
2609 WINAPI
2610 PNP_GetLogConfPriority(
2611     handle_t hBinding,
2612     LPWSTR pDeviceID,
2613     DWORD ulType,
2614     DWORD ulTag,
2615     DWORD *pPriority,
2616     DWORD ulFlags)
2617 {
2618     UNIMPLEMENTED;
2619     return CR_CALL_NOT_IMPLEMENTED;
2620 }
2621 
2622 
2623 /* Function 47 */
2624 DWORD
2625 WINAPI
2626 PNP_AddResDes(
2627     handle_t hBinding,
2628     LPWSTR pDeviceID,
2629     DWORD ulLogConfTag,
2630     DWORD ulLogConfType,
2631     RESOURCEID ResourceID,
2632     DWORD *pulResourceTag,
2633     BYTE *ResourceData,
2634     PNP_RPC_BUFFER_SIZE ResourceLen,
2635     DWORD ulFlags)
2636 {
2637     UNIMPLEMENTED;
2638     return CR_CALL_NOT_IMPLEMENTED;
2639 }
2640 
2641 
2642 /* Function 48 */
2643 DWORD
2644 WINAPI
2645 PNP_FreeResDes(
2646     handle_t hBinding,
2647     LPWSTR pDeviceID,
2648     DWORD ulLogConfTag,
2649     DWORD ulLogConfType,
2650     RESOURCEID ResourceID,
2651     DWORD ulResourceTag,
2652     DWORD *pulPreviousResType,
2653     DWORD *pulPreviousResTag,
2654     DWORD ulFlags)
2655 {
2656     UNIMPLEMENTED;
2657     return CR_CALL_NOT_IMPLEMENTED;
2658 }
2659 
2660 
2661 /* Function 49 */
2662 DWORD
2663 WINAPI
2664 PNP_GetNextResDes(
2665     handle_t hBinding,
2666     LPWSTR pDeviceID,
2667     DWORD ulLogConfTag,
2668     DWORD ulLogConfType,
2669     RESOURCEID ResourceID,
2670     DWORD ulResourceTag,
2671     DWORD *pulNextResType,
2672     DWORD *pulNextResTag,
2673     DWORD ulFlags)
2674 {
2675     UNIMPLEMENTED;
2676     return CR_CALL_NOT_IMPLEMENTED;
2677 }
2678 
2679 
2680 /* Function 50 */
2681 DWORD
2682 WINAPI
2683 PNP_GetResDesData(
2684     handle_t hBinding,
2685     LPWSTR pDeviceID,
2686     DWORD ulLogConfTag,
2687     DWORD ulLogConfType,
2688     RESOURCEID ResourceID,
2689     DWORD ulResourceTag,
2690     BYTE *Buffer,
2691     PNP_RPC_BUFFER_SIZE BufferLen,
2692     DWORD ulFlags)
2693 {
2694     UNIMPLEMENTED;
2695     return CR_CALL_NOT_IMPLEMENTED;
2696 }
2697 
2698 
2699 /* Function 51 */
2700 DWORD
2701 WINAPI
2702 PNP_GetResDesDataSize(
2703     handle_t hBinding,
2704     LPWSTR pDeviceID,
2705     DWORD ulLogConfTag,
2706     DWORD ulLogConfType,
2707     RESOURCEID ResourceID,
2708     DWORD ulResourceTag,
2709     DWORD *pulSize,
2710     DWORD ulFlags)
2711 {
2712     UNIMPLEMENTED;
2713     return CR_CALL_NOT_IMPLEMENTED;
2714 }
2715 
2716 
2717 /* Function 52 */
2718 DWORD
2719 WINAPI
2720 PNP_ModifyResDes(
2721     handle_t hBinding,
2722     LPWSTR pDeviceID,
2723     DWORD ulLogConfTag,
2724     DWORD ulLogConfType,
2725     RESOURCEID CurrentResourceID,
2726     RESOURCEID NewResourceID,
2727     DWORD ulResourceTag,
2728     BYTE *ResourceData,
2729     PNP_RPC_BUFFER_SIZE ResourceLen,
2730     DWORD ulFlags)
2731 {
2732     UNIMPLEMENTED;
2733     return CR_CALL_NOT_IMPLEMENTED;
2734 }
2735 
2736 
2737 /* Function 53 */
2738 DWORD
2739 WINAPI
2740 PNP_DetectResourceConflict(
2741     handle_t hBinding,
2742     LPWSTR pDeviceID,
2743     RESOURCEID ResourceID,
2744     BYTE *ResourceData,
2745     PNP_RPC_BUFFER_SIZE ResourceLen,
2746     BOOL *pbConflictDetected,
2747     DWORD ulFlags)
2748 {
2749     DPRINT("PNP_DetectResourceConflict()\n");
2750 
2751     if (pbConflictDetected != NULL)
2752         *pbConflictDetected = FALSE;
2753 
2754     return CR_CALL_NOT_IMPLEMENTED;
2755 }
2756 
2757 
2758 /* Function 54 */
2759 DWORD
2760 WINAPI
2761 PNP_QueryResConfList(
2762     handle_t hBinding,
2763     LPWSTR pDeviceID,
2764     RESOURCEID ResourceID,
2765     BYTE *ResourceData,
2766     PNP_RPC_BUFFER_SIZE ResourceLen,
2767     BYTE *Buffer,
2768     PNP_RPC_BUFFER_SIZE BufferLen,
2769     DWORD ulFlags)
2770 {
2771     UNIMPLEMENTED;
2772     return CR_CALL_NOT_IMPLEMENTED;
2773 }
2774 
2775 
2776 /* Function 55 */
2777 DWORD
2778 WINAPI
2779 PNP_SetHwProf(
2780     handle_t hBinding,
2781     DWORD ulHardwareProfile,
2782     DWORD ulFlags)
2783 {
2784     UNIMPLEMENTED;
2785     return CR_CALL_NOT_IMPLEMENTED;
2786 }
2787 
2788 
2789 /* Function 56 */
2790 DWORD
2791 WINAPI
2792 PNP_QueryArbitratorFreeData(
2793     handle_t hBinding,
2794     BYTE *pData,
2795     DWORD DataLen,
2796     LPWSTR pDeviceID,
2797     RESOURCEID ResourceID,
2798     DWORD ulFlags)
2799 {
2800     UNIMPLEMENTED;
2801     return CR_CALL_NOT_IMPLEMENTED;
2802 }
2803 
2804 
2805 /* Function 57 */
2806 DWORD
2807 WINAPI
2808 PNP_QueryArbitratorFreeSize(
2809     handle_t hBinding,
2810     DWORD *pulSize,
2811     LPWSTR pDeviceID,
2812     RESOURCEID ResourceID,
2813     DWORD ulFlags)
2814 {
2815     UNIMPLEMENTED;
2816     return CR_CALL_NOT_IMPLEMENTED;
2817 }
2818 
2819 
2820 /* Function 58 */
2821 CONFIGRET
2822 WINAPI
2823 PNP_RunDetection(
2824     handle_t hBinding,
2825     DWORD ulFlags)
2826 {
2827     return CR_CALL_NOT_IMPLEMENTED;
2828 }
2829 
2830 
2831 /* Function 59 */
2832 DWORD
2833 WINAPI
2834 PNP_RegisterNotification(
2835     handle_t hBinding,
2836     DWORD ulFlags,
2837     DWORD *pulNotify)
2838 {
2839 #if 0
2840     PNOTIFY_DATA pNotifyData;
2841 #endif
2842 
2843     DPRINT1("PNP_RegisterNotification(%p 0x%lx %p)\n",
2844            hBinding, ulFlags, pulNotify);
2845 
2846 #if 0
2847     pNotifyData = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFY_DATA));
2848     if (pNotifyData == NULL)
2849         return CR_OUT_OF_MEMORY;
2850 
2851     *pulNotify = (DWORD)pNotifyData;
2852 #endif
2853 
2854     *pulNotify = 1;
2855 
2856     return CR_SUCCESS;
2857 }
2858 
2859 
2860 /* Function 60 */
2861 DWORD
2862 WINAPI
2863 PNP_UnregisterNotification(
2864     handle_t hBinding,
2865     DWORD ulNotify)
2866 {
2867     DPRINT1("PNP_UnregisterNotification(%p 0x%lx)\n",
2868            hBinding, ulNotify);
2869 
2870 #if 0
2871     UNIMPLEMENTED;
2872     return CR_CALL_NOT_IMPLEMENTED;
2873 #endif
2874 
2875     return CR_SUCCESS;
2876 }
2877 
2878 
2879 /* Function 61 */
2880 DWORD
2881 WINAPI
2882 PNP_GetCustomDevProp(
2883     handle_t hBinding,
2884     LPWSTR pDeviceID,
2885     LPWSTR CustomPropName,
2886     DWORD *pulRegDataType,
2887     BYTE *Buffer,
2888     PNP_RPC_STRING_LEN *pulTransferLen,
2889     PNP_RPC_STRING_LEN *pulLength,
2890     DWORD ulFlags)
2891 {
2892     HKEY hDeviceKey = NULL;
2893     HKEY hParamKey = NULL;
2894     LONG lError;
2895     CONFIGRET ret = CR_SUCCESS;
2896 
2897     UNREFERENCED_PARAMETER(hBinding);
2898 
2899     DPRINT("PNP_GetCustomDevProp() called\n");
2900 
2901     if (pulTransferLen == NULL || pulLength == NULL)
2902     {
2903         ret = CR_INVALID_POINTER;
2904         goto done;
2905     }
2906 
2907     if (ulFlags & ~CM_CUSTOMDEVPROP_BITS)
2908     {
2909         ret = CR_INVALID_FLAG;
2910         goto done;
2911     }
2912 
2913     if (*pulLength < *pulTransferLen)
2914         *pulLength = *pulTransferLen;
2915 
2916     *pulTransferLen = 0;
2917 
2918     lError = RegOpenKeyExW(hEnumKey,
2919                            pDeviceID,
2920                            0,
2921                            KEY_READ,
2922                            &hDeviceKey);
2923     if (lError != ERROR_SUCCESS)
2924     {
2925         ret = CR_REGISTRY_ERROR;
2926         goto done;
2927     }
2928 
2929     lError = RegOpenKeyExW(hDeviceKey,
2930                            L"Device Parameters",
2931                            0,
2932                            KEY_READ,
2933                            &hParamKey);
2934     if (lError != ERROR_SUCCESS)
2935     {
2936         ret = CR_REGISTRY_ERROR;
2937         goto done;
2938     }
2939 
2940     lError = RegQueryValueExW(hParamKey,
2941                               CustomPropName,
2942                               NULL,
2943                               pulRegDataType,
2944                               Buffer,
2945                               pulLength);
2946     if (lError != ERROR_SUCCESS)
2947     {
2948         if (lError == ERROR_MORE_DATA)
2949         {
2950             ret = CR_BUFFER_SMALL;
2951         }
2952         else
2953         {
2954             *pulLength = 0;
2955             ret = CR_NO_SUCH_VALUE;
2956         }
2957     }
2958 
2959 done:
2960     if (ret == CR_SUCCESS)
2961         *pulTransferLen = *pulLength;
2962 
2963     if (hParamKey != NULL)
2964         RegCloseKey(hParamKey);
2965 
2966     if (hDeviceKey != NULL)
2967         RegCloseKey(hDeviceKey);
2968 
2969     DPRINT("PNP_GetCustomDevProp() done (returns %lx)\n", ret);
2970 
2971     return ret;
2972 }
2973 
2974 
2975 /* Function 62 */
2976 DWORD
2977 WINAPI
2978 PNP_GetVersionInternal(
2979     handle_t hBinding,
2980     WORD *pwVersion)
2981 {
2982     UNREFERENCED_PARAMETER(hBinding);
2983 
2984     *pwVersion = 0x501;
2985     return CR_SUCCESS;
2986 }
2987 
2988 
2989 /* Function 63 */
2990 DWORD
2991 WINAPI
2992 PNP_GetBlockedDriverInfo(
2993     handle_t hBinding,
2994     BYTE *Buffer,
2995     PNP_RPC_BUFFER_SIZE *pulTransferLen,
2996     PNP_RPC_BUFFER_SIZE *pulLength,
2997     DWORD ulFlags)
2998 {
2999     UNIMPLEMENTED;
3000     return CR_CALL_NOT_IMPLEMENTED;
3001 }
3002 
3003 
3004 /* Function 64 */
3005 DWORD
3006 WINAPI
3007 PNP_GetServerSideDeviceInstallFlags(
3008     handle_t hBinding,
3009     DWORD *pulSSDIFlags,
3010     DWORD ulFlags)
3011 {
3012     UNREFERENCED_PARAMETER(hBinding);
3013 
3014     DPRINT1("PNP_GetServerSideDeviceInstallFlags(%p %p %lu)\n",
3015             hBinding, pulSSDIFlags, ulFlags);
3016 
3017     if (pulSSDIFlags == NULL)
3018         return CR_INVALID_POINTER;
3019 
3020     if (ulFlags != 0)
3021         return CR_INVALID_FLAG;
3022 
3023     /* FIXME */
3024     *pulSSDIFlags = 0;
3025 
3026     return CR_SUCCESS;
3027 }
3028 
3029 
3030 /* Function 65 */
3031 DWORD
3032 WINAPI
3033 PNP_GetObjectPropKeys(
3034     handle_t hBinding,
3035     LPWSTR ObjectName,
3036     DWORD ObjectType,
3037     LPWSTR PropertyCultureName,
3038     PNP_PROP_COUNT *PropertyCount,
3039     PNP_PROP_COUNT *TransferLen,
3040     DEVPROPKEY *PropertyKeys,
3041     DWORD Flags)
3042 {
3043     UNIMPLEMENTED;
3044     return CR_CALL_NOT_IMPLEMENTED;
3045 }
3046 
3047 
3048 /* Function 66 */
3049 DWORD
3050 WINAPI
3051 PNP_GetObjectProp(
3052     handle_t hBinding,
3053     LPWSTR ObjectName,
3054     DWORD ObjectType,
3055     LPWSTR PropertyCultureName,
3056     const DEVPROPKEY *PropertyKey,
3057     DEVPROPTYPE *PropertyType,
3058     PNP_PROP_SIZE *PropertySize,
3059     PNP_PROP_SIZE *TransferLen,
3060     BYTE *PropertyBuffer,
3061     DWORD Flags)
3062 {
3063     UNIMPLEMENTED;
3064     return CR_CALL_NOT_IMPLEMENTED;
3065 }
3066 
3067 
3068 /* Function 67 */
3069 DWORD
3070 WINAPI
3071 PNP_SetObjectProp(
3072     handle_t hBinding,
3073     LPWSTR ObjectName,
3074     DWORD ObjectType,
3075     LPWSTR PropertyCultureName,
3076     const DEVPROPKEY *PropertyKey,
3077     DEVPROPTYPE PropertyType,
3078     PNP_PROP_SIZE PropertySize,
3079     BYTE *PropertyBuffer,
3080     DWORD Flags)
3081 {
3082     UNIMPLEMENTED;
3083     return CR_CALL_NOT_IMPLEMENTED;
3084 }
3085 
3086 
3087 /* Function 68 */
3088 DWORD
3089 WINAPI
3090 PNP_InstallDevInst(
3091     handle_t hBinding)
3092 {
3093     UNIMPLEMENTED;
3094     return CR_CALL_NOT_IMPLEMENTED;
3095 }
3096 
3097 
3098 /* Function 69 */
3099 DWORD
3100 WINAPI
3101 PNP_ApplyPowerSettings(
3102     handle_t hBinding)
3103 {
3104     UNIMPLEMENTED;
3105     return CR_CALL_NOT_IMPLEMENTED;
3106 }
3107 
3108 
3109 /* Function 70 */
3110 DWORD
3111 WINAPI
3112 PNP_DriverStoreAddDriverPackage(
3113     handle_t hBinding)
3114 {
3115     UNIMPLEMENTED;
3116     return CR_CALL_NOT_IMPLEMENTED;
3117 }
3118 
3119 
3120 /* Function 71 */
3121 DWORD
3122 WINAPI
3123 PNP_DriverStoreDeleteDriverPackage(
3124     handle_t hBinding)
3125 {
3126     UNIMPLEMENTED;
3127     return CR_CALL_NOT_IMPLEMENTED;
3128 }
3129 
3130 
3131 /* Function 72 */
3132 DWORD
3133 WINAPI
3134 PNP_RegisterServiceNotification(
3135     handle_t hBinding)
3136 {
3137     UNIMPLEMENTED;
3138     return CR_CALL_NOT_IMPLEMENTED;
3139 }
3140 
3141 
3142 /* Function 73 */
3143 DWORD
3144 WINAPI
3145 PNP_SetActiveService(
3146     handle_t hBinding,
3147     LPWSTR pszFilter,
3148     DWORD ulFlags)
3149 {
3150     UNIMPLEMENTED;
3151     return CR_CALL_NOT_IMPLEMENTED;
3152 }
3153 
3154 
3155 /* Function 74 */
3156 DWORD
3157 WINAPI
3158 PNP_DeleteServiceDevices(
3159     handle_t hBinding)
3160 {
3161     UNIMPLEMENTED;
3162     return CR_CALL_NOT_IMPLEMENTED;
3163 }
3164 
3165 
3166 static BOOL
3167 InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
3168 {
3169     BOOL DeviceInstalled = FALSE;
3170     DWORD BytesWritten;
3171     DWORD Value;
3172     HANDLE hInstallEvent;
3173     HANDLE hPipe = INVALID_HANDLE_VALUE;
3174     LPVOID Environment = NULL;
3175     PROCESS_INFORMATION ProcessInfo;
3176     STARTUPINFOW StartupInfo;
3177     UUID RandomUuid;
3178     HKEY DeviceKey;
3179 
3180     /* The following lengths are constant (see below), they cannot overflow */
3181     WCHAR CommandLine[116];
3182     WCHAR InstallEventName[73];
3183     WCHAR PipeName[74];
3184     WCHAR UuidString[39];
3185 
3186     DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
3187 
3188     ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
3189 
3190     if (RegOpenKeyExW(hEnumKey,
3191                       DeviceInstance,
3192                       0,
3193                       KEY_QUERY_VALUE,
3194                       &DeviceKey) == ERROR_SUCCESS)
3195     {
3196         if (RegQueryValueExW(DeviceKey,
3197                              L"Class",
3198                              NULL,
3199                              NULL,
3200                              NULL,
3201                              NULL) == ERROR_SUCCESS)
3202         {
3203             DPRINT("No need to install: %S\n", DeviceInstance);
3204             RegCloseKey(DeviceKey);
3205             return TRUE;
3206         }
3207 
3208         BytesWritten = sizeof(DWORD);
3209         if (RegQueryValueExW(DeviceKey,
3210                              L"ConfigFlags",
3211                              NULL,
3212                              NULL,
3213                              (PBYTE)&Value,
3214                              &BytesWritten) == ERROR_SUCCESS)
3215         {
3216             if (Value & CONFIGFLAG_FAILEDINSTALL)
3217             {
3218                 DPRINT("No need to install: %S\n", DeviceInstance);
3219                 RegCloseKey(DeviceKey);
3220                 return TRUE;
3221             }
3222         }
3223 
3224         RegCloseKey(DeviceKey);
3225     }
3226 
3227     DPRINT1("Installing: %S\n", DeviceInstance);
3228 
3229     /* Create a random UUID for the named pipe & event*/
3230     UuidCreate(&RandomUuid);
3231     swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
3232         RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
3233         RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
3234         RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
3235         RandomUuid.Data4[6], RandomUuid.Data4[7]);
3236 
3237     /* Create the event */
3238     wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
3239     wcscat(InstallEventName, UuidString);
3240     hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
3241     if (!hInstallEvent)
3242     {
3243         DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
3244         goto cleanup;
3245     }
3246 
3247     /* Create the named pipe */
3248     wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
3249     wcscat(PipeName, UuidString);
3250     hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512, 0, NULL);
3251     if (hPipe == INVALID_HANDLE_VALUE)
3252     {
3253         DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
3254         goto cleanup;
3255     }
3256 
3257     /* Launch rundll32 to call ClientSideInstallW */
3258     wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
3259     wcscat(CommandLine, PipeName);
3260 
3261     ZeroMemory(&StartupInfo, sizeof(StartupInfo));
3262     StartupInfo.cb = sizeof(StartupInfo);
3263 
3264     if (hUserToken)
3265     {
3266         /* newdev has to run under the environment of the current user */
3267         if (!CreateEnvironmentBlock(&Environment, hUserToken, FALSE))
3268         {
3269             DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
3270             goto cleanup;
3271         }
3272 
3273         if (!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
3274         {
3275             DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
3276             goto cleanup;
3277         }
3278     }
3279     else
3280     {
3281         /* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
3282 
3283            Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
3284            (ShowWizard is only set to FALSE for these two modes) */
3285         ASSERT(!ShowWizard);
3286 
3287         if (!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
3288         {
3289             DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
3290             goto cleanup;
3291         }
3292     }
3293 
3294     /* Wait for the function to connect to our pipe */
3295     if (!ConnectNamedPipe(hPipe, NULL))
3296     {
3297         if (GetLastError() != ERROR_PIPE_CONNECTED)
3298         {
3299             DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
3300             goto cleanup;
3301         }
3302     }
3303 
3304     /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
3305     Value = sizeof(InstallEventName);
3306     WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
3307     WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
3308 
3309     /* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
3310        Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
3311     WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
3312 
3313     Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
3314     WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
3315     WriteFile(hPipe, DeviceInstance, Value, &BytesWritten, NULL);
3316 
3317     /* Wait for newdev.dll to finish processing */
3318     WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
3319 
3320     /* If the event got signalled, this is success */
3321     DeviceInstalled = WaitForSingleObject(hInstallEvent, 0) == WAIT_OBJECT_0;
3322 
3323 cleanup:
3324     if (hInstallEvent)
3325         CloseHandle(hInstallEvent);
3326 
3327     if (hPipe != INVALID_HANDLE_VALUE)
3328         CloseHandle(hPipe);
3329 
3330     if (Environment)
3331         DestroyEnvironmentBlock(Environment);
3332 
3333     if (ProcessInfo.hProcess)
3334         CloseHandle(ProcessInfo.hProcess);
3335 
3336     if (ProcessInfo.hThread)
3337         CloseHandle(ProcessInfo.hThread);
3338 
3339     if (!DeviceInstalled)
3340     {
3341         DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance);
3342     }
3343 
3344     return DeviceInstalled;
3345 }
3346 
3347 
3348 static LONG
3349 ReadRegSzKey(
3350     IN HKEY hKey,
3351     IN LPCWSTR pszKey,
3352     OUT LPWSTR* pValue)
3353 {
3354     LONG rc;
3355     DWORD dwType;
3356     DWORD cbData = 0;
3357     LPWSTR Value;
3358 
3359     if (!pValue)
3360         return ERROR_INVALID_PARAMETER;
3361 
3362     *pValue = NULL;
3363     rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
3364     if (rc != ERROR_SUCCESS)
3365         return rc;
3366     if (dwType != REG_SZ)
3367         return ERROR_FILE_NOT_FOUND;
3368     Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
3369     if (!Value)
3370         return ERROR_NOT_ENOUGH_MEMORY;
3371     rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
3372     if (rc != ERROR_SUCCESS)
3373     {
3374         HeapFree(GetProcessHeap(), 0, Value);
3375         return rc;
3376     }
3377     /* NULL-terminate the string */
3378     Value[cbData / sizeof(WCHAR)] = '\0';
3379 
3380     *pValue = Value;
3381     return ERROR_SUCCESS;
3382 }
3383 
3384 
3385 static BOOL
3386 SetupIsActive(VOID)
3387 {
3388     HKEY hKey = NULL;
3389     DWORD regType, active, size;
3390     LONG rc;
3391     BOOL ret = FALSE;
3392 
3393     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey);
3394     if (rc != ERROR_SUCCESS)
3395         goto cleanup;
3396 
3397     size = sizeof(DWORD);
3398     rc = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, &regType, (LPBYTE)&active, &size);
3399     if (rc != ERROR_SUCCESS)
3400         goto cleanup;
3401     if (regType != REG_DWORD || size != sizeof(DWORD))
3402         goto cleanup;
3403 
3404     ret = (active != 0);
3405 
3406 cleanup:
3407     if (hKey != NULL)
3408         RegCloseKey(hKey);
3409 
3410     DPRINT("System setup in progress? %S\n", ret ? L"YES" : L"NO");
3411 
3412     return ret;
3413 }
3414 
3415 
3416 static BOOL
3417 IsConsoleBoot(VOID)
3418 {
3419     HKEY ControlKey = NULL;
3420     LPWSTR SystemStartOptions = NULL;
3421     LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
3422     BOOL ConsoleBoot = FALSE;
3423     LONG rc;
3424 
3425     rc = RegOpenKeyExW(
3426         HKEY_LOCAL_MACHINE,
3427         L"SYSTEM\\CurrentControlSet\\Control",
3428         0,
3429         KEY_QUERY_VALUE,
3430         &ControlKey);
3431 
3432     rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
3433     if (rc != ERROR_SUCCESS)
3434         goto cleanup;
3435 
3436     /* Check for CONSOLE switch in SystemStartOptions */
3437     CurrentOption = SystemStartOptions;
3438     while (CurrentOption)
3439     {
3440         NextOption = wcschr(CurrentOption, L' ');
3441         if (NextOption)
3442             *NextOption = L'\0';
3443         if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
3444         {
3445             DPRINT("Found %S. Switching to console boot\n", CurrentOption);
3446             ConsoleBoot = TRUE;
3447             goto cleanup;
3448         }
3449         CurrentOption = NextOption ? NextOption + 1 : NULL;
3450     }
3451 
3452 cleanup:
3453     if (ControlKey != NULL)
3454         RegCloseKey(ControlKey);
3455     HeapFree(GetProcessHeap(), 0, SystemStartOptions);
3456     return ConsoleBoot;
3457 }
3458 
3459 
3460 /* Loop to install all queued devices installations */
3461 static DWORD WINAPI
3462 DeviceInstallThread(LPVOID lpParameter)
3463 {
3464 #ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
3465     PSLIST_ENTRY ListEntry;
3466 #else
3467     PLIST_ENTRY ListEntry;
3468 #endif
3469     DeviceInstallParams* Params;
3470     BOOL showWizard;
3471 
3472     UNREFERENCED_PARAMETER(lpParameter);
3473 
3474     WaitForSingleObject(hInstallEvent, INFINITE);
3475 
3476     showWizard = !SetupIsActive() && !IsConsoleBoot();
3477 
3478     while (TRUE)
3479     {
3480 #ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
3481         ListEntry = InterlockedPopEntrySList(&DeviceInstallListHead);
3482 #else
3483         if ((BOOL)IsListEmpty(&DeviceInstallListHead))
3484             ListEntry = NULL;
3485         else
3486             ListEntry = RemoveHeadList(&DeviceInstallListHead);
3487 #endif
3488         if (ListEntry == NULL)
3489         {
3490             SetEvent(hNoPendingInstalls);
3491             WaitForSingleObject(hDeviceInstallListNotEmpty, INFINITE);
3492         }
3493         else
3494         {
3495             ResetEvent(hNoPendingInstalls);
3496             Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
3497             InstallDevice(Params->DeviceIds, showWizard);
3498         }
3499     }
3500 
3501     return 0;
3502 }
3503 
3504 
3505 static DWORD WINAPI
3506 PnpEventThread(LPVOID lpParameter)
3507 {
3508     PPLUGPLAY_EVENT_BLOCK PnpEvent;
3509     ULONG PnpEventSize;
3510     NTSTATUS Status;
3511     RPC_STATUS RpcStatus;
3512 
3513     UNREFERENCED_PARAMETER(lpParameter);
3514 
3515     PnpEventSize = 0x1000;
3516     PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize);
3517     if (PnpEvent == NULL)
3518         return ERROR_OUTOFMEMORY;
3519 
3520     for (;;)
3521     {
3522         DPRINT("Calling NtGetPlugPlayEvent()\n");
3523 
3524         /* Wait for the next pnp event */
3525         Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
3526 
3527         /* Resize the buffer for the PnP event if it's too small. */
3528         if (Status == STATUS_BUFFER_TOO_SMALL)
3529         {
3530             PnpEventSize += 0x400;
3531             HeapFree(GetProcessHeap(), 0, PnpEvent);
3532             PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize);
3533             if (PnpEvent == NULL)
3534                 return ERROR_OUTOFMEMORY;
3535             continue;
3536         }
3537 
3538         if (!NT_SUCCESS(Status))
3539         {
3540             DPRINT("NtGetPlugPlayEvent() failed (Status %lx)\n", Status);
3541             break;
3542         }
3543 
3544         /* Process the pnp event */
3545         DPRINT("Received PnP Event\n");
3546         if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ENUMERATED, &RpcStatus))
3547         {
3548             DeviceInstallParams* Params;
3549             DWORD len;
3550             DWORD DeviceIdLength;
3551 
3552             DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
3553 
3554             DeviceIdLength = lstrlenW(PnpEvent->TargetDevice.DeviceIds);
3555             if (DeviceIdLength)
3556             {
3557                 /* Queue device install (will be dequeued by DeviceInstallThread */
3558                 len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR);
3559                 Params = HeapAlloc(GetProcessHeap(), 0, len);
3560                 if (Params)
3561                 {
3562                     wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds);
3563 #ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
3564                     InterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry);
3565 #else
3566                     InsertTailList(&DeviceInstallListHead, &Params->ListEntry);
3567 #endif
3568                     SetEvent(hDeviceInstallListNotEmpty);
3569                 }
3570             }
3571         }
3572         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
3573         {
3574 //            DWORD dwRecipient;
3575 
3576             DPRINT("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
3577 
3578 //            dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
3579 //            BroadcastSystemMessageW(BSF_POSTMESSAGE,
3580 //                                    &dwRecipient,
3581 //                                    WM_DEVICECHANGE,
3582 //                                    DBT_DEVNODES_CHANGED,
3583 //                                    0);
3584             SendMessageW(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0);
3585         }
3586         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_EJECT_VETOED, &RpcStatus))
3587         {
3588             DPRINT1("Eject vetoed: %S\n", PnpEvent->TargetDevice.DeviceIds);
3589         }
3590         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_KERNEL_INITIATED_EJECT, &RpcStatus))
3591         {
3592             DPRINT1("Kernel initiated eject: %S\n", PnpEvent->TargetDevice.DeviceIds);
3593         }
3594         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_SAFE_REMOVAL, &RpcStatus))
3595         {
3596 //            DWORD dwRecipient;
3597 
3598             DPRINT1("Safe removal: %S\n", PnpEvent->TargetDevice.DeviceIds);
3599 
3600 //            dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
3601 //            BroadcastSystemMessageW(BSF_POSTMESSAGE,
3602 //                                    &dwRecipient,
3603 //                                    WM_DEVICECHANGE,
3604 //                                    DBT_DEVNODES_CHANGED,
3605 //                                    0);
3606             SendMessageW(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0);
3607         }
3608         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_SURPRISE_REMOVAL, &RpcStatus))
3609         {
3610 //            DWORD dwRecipient;
3611 
3612             DPRINT1("Surprise removal: %S\n", PnpEvent->TargetDevice.DeviceIds);
3613 
3614 //            dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
3615 //            BroadcastSystemMessageW(BSF_POSTMESSAGE,
3616 //                                    &dwRecipient,
3617 //                                    WM_DEVICECHANGE,
3618 //                                    DBT_DEVNODES_CHANGED,
3619 //                                    0);
3620             SendMessageW(HWND_BROADCAST, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0);
3621         }
3622         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_REMOVAL_VETOED, &RpcStatus))
3623         {
3624             DPRINT1("Removal vetoed: %S\n", PnpEvent->TargetDevice.DeviceIds);
3625         }
3626         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_REMOVE_PENDING, &RpcStatus))
3627         {
3628             DPRINT1("Removal pending: %S\n", PnpEvent->TargetDevice.DeviceIds);
3629         }
3630         else
3631         {
3632             DPRINT1("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
3633                 PnpEvent->EventGuid.Data1, PnpEvent->EventGuid.Data2, PnpEvent->EventGuid.Data3,
3634                 PnpEvent->EventGuid.Data4[0], PnpEvent->EventGuid.Data4[1], PnpEvent->EventGuid.Data4[2],
3635                 PnpEvent->EventGuid.Data4[3], PnpEvent->EventGuid.Data4[4], PnpEvent->EventGuid.Data4[5],
3636                 PnpEvent->EventGuid.Data4[6], PnpEvent->EventGuid.Data4[7]);
3637         }
3638 
3639         /* Dequeue the current pnp event and signal the next one */
3640         NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
3641     }
3642 
3643     HeapFree(GetProcessHeap(), 0, PnpEvent);
3644 
3645     return ERROR_SUCCESS;
3646 }
3647 
3648 
3649 static VOID
3650 UpdateServiceStatus(DWORD dwState)
3651 {
3652     ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3653     ServiceStatus.dwCurrentState = dwState;
3654     ServiceStatus.dwControlsAccepted = 0;
3655     ServiceStatus.dwWin32ExitCode = 0;
3656     ServiceStatus.dwServiceSpecificExitCode = 0;
3657     ServiceStatus.dwCheckPoint = 0;
3658 
3659     if (dwState == SERVICE_START_PENDING ||
3660         dwState == SERVICE_STOP_PENDING ||
3661         dwState == SERVICE_PAUSE_PENDING ||
3662         dwState == SERVICE_CONTINUE_PENDING)
3663         ServiceStatus.dwWaitHint = 10000;
3664     else
3665         ServiceStatus.dwWaitHint = 0;
3666 
3667     SetServiceStatus(ServiceStatusHandle,
3668                      &ServiceStatus);
3669 }
3670 
3671 
3672 static DWORD WINAPI
3673 ServiceControlHandler(DWORD dwControl,
3674                       DWORD dwEventType,
3675                       LPVOID lpEventData,
3676                       LPVOID lpContext)
3677 {
3678     DPRINT1("ServiceControlHandler() called\n");
3679 
3680     switch (dwControl)
3681     {
3682         case SERVICE_CONTROL_STOP:
3683             DPRINT1("  SERVICE_CONTROL_STOP received\n");
3684             /* Stop listening to RPC Messages */
3685             RpcMgmtStopServerListening(NULL);
3686             UpdateServiceStatus(SERVICE_STOPPED);
3687             return ERROR_SUCCESS;
3688 
3689         case SERVICE_CONTROL_PAUSE:
3690             DPRINT1("  SERVICE_CONTROL_PAUSE received\n");
3691             UpdateServiceStatus(SERVICE_PAUSED);
3692             return ERROR_SUCCESS;
3693 
3694         case SERVICE_CONTROL_CONTINUE:
3695             DPRINT1("  SERVICE_CONTROL_CONTINUE received\n");
3696             UpdateServiceStatus(SERVICE_RUNNING);
3697             return ERROR_SUCCESS;
3698 
3699         case SERVICE_CONTROL_INTERROGATE:
3700             DPRINT1("  SERVICE_CONTROL_INTERROGATE received\n");
3701             SetServiceStatus(ServiceStatusHandle,
3702                              &ServiceStatus);
3703             return ERROR_SUCCESS;
3704 
3705         case SERVICE_CONTROL_SHUTDOWN:
3706             DPRINT1("  SERVICE_CONTROL_SHUTDOWN received\n");
3707             /* Stop listening to RPC Messages */
3708             RpcMgmtStopServerListening(NULL);
3709             UpdateServiceStatus(SERVICE_STOPPED);
3710             return ERROR_SUCCESS;
3711 
3712         default :
3713             DPRINT1("  Control %lu received\n", dwControl);
3714             return ERROR_CALL_NOT_IMPLEMENTED;
3715     }
3716 }
3717 
3718 
3719 VOID WINAPI
3720 ServiceMain(DWORD argc, LPTSTR *argv)
3721 {
3722     HANDLE hThread;
3723     DWORD dwThreadId;
3724 
3725     UNREFERENCED_PARAMETER(argc);
3726     UNREFERENCED_PARAMETER(argv);
3727 
3728     DPRINT("ServiceMain() called\n");
3729 
3730     ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
3731                                                         ServiceControlHandler,
3732                                                         NULL);
3733     if (!ServiceStatusHandle)
3734     {
3735         DPRINT1("RegisterServiceCtrlHandlerExW() failed! (Error %lu)\n", GetLastError());
3736         return;
3737     }
3738 
3739     UpdateServiceStatus(SERVICE_START_PENDING);
3740 
3741     hThread = CreateThread(NULL,
3742                            0,
3743                            PnpEventThread,
3744                            NULL,
3745                            0,
3746                            &dwThreadId);
3747     if (hThread != NULL)
3748         CloseHandle(hThread);
3749 
3750     hThread = CreateThread(NULL,
3751                            0,
3752                            RpcServerThread,
3753                            NULL,
3754                            0,
3755                            &dwThreadId);
3756     if (hThread != NULL)
3757         CloseHandle(hThread);
3758 
3759     hThread = CreateThread(NULL,
3760                            0,
3761                            DeviceInstallThread,
3762                            NULL,
3763                            0,
3764                            &dwThreadId);
3765     if (hThread != NULL)
3766         CloseHandle(hThread);
3767 
3768     UpdateServiceStatus(SERVICE_RUNNING);
3769 
3770     DPRINT("ServiceMain() done\n");
3771 }
3772 
3773 static DWORD
3774 InitializePnPManager(VOID)
3775 {
3776     BOOLEAN OldValue;
3777     DWORD dwError;
3778 
3779     DPRINT("UMPNPMGR: InitializePnPManager() started\n");
3780 
3781     /* We need this privilege for using CreateProcessAsUserW */
3782     RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
3783 
3784     hInstallEvent = CreateEventW(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
3785     if (hInstallEvent == NULL)
3786     {
3787         dwError = GetLastError();
3788         DPRINT1("Could not create the Install Event! (Error %lu)\n", dwError);
3789         return dwError;
3790     }
3791 
3792     hDeviceInstallListNotEmpty = CreateEventW(NULL, FALSE, FALSE, NULL);
3793     if (hDeviceInstallListNotEmpty == NULL)
3794     {
3795         dwError = GetLastError();
3796         DPRINT1("Could not create the Event! (Error %lu)\n", dwError);
3797         return dwError;
3798     }
3799 
3800     hNoPendingInstalls = CreateEventW(NULL,
3801                                       TRUE,
3802                                       FALSE,
3803                                       L"Global\\PnP_No_Pending_Install_Events");
3804     if (hNoPendingInstalls == NULL)
3805     {
3806         dwError = GetLastError();
3807         DPRINT1("Could not create the Event! (Error %lu)\n", dwError);
3808         return dwError;
3809     }
3810 
3811 #ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
3812     InitializeSListHead(&DeviceInstallListHead);
3813 #else
3814     InitializeListHead(&DeviceInstallListHead);
3815 #endif
3816 
3817     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3818                             L"System\\CurrentControlSet\\Enum",
3819                             0,
3820                             KEY_ALL_ACCESS,
3821                             &hEnumKey);
3822     if (dwError != ERROR_SUCCESS)
3823     {
3824         DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
3825         return dwError;
3826     }
3827 
3828     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3829                             L"System\\CurrentControlSet\\Control\\Class",
3830                             0,
3831                             KEY_ALL_ACCESS,
3832                             &hClassKey);
3833     if (dwError != ERROR_SUCCESS)
3834     {
3835         DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
3836         return dwError;
3837     }
3838 
3839     DPRINT("UMPNPMGR: InitializePnPManager() done\n");
3840 
3841     return 0;
3842 }
3843 
3844 BOOL WINAPI
3845 DllMain(HINSTANCE hinstDLL,
3846         DWORD fdwReason,
3847         LPVOID lpvReserved)
3848 {
3849     switch (fdwReason)
3850     {
3851         case DLL_PROCESS_ATTACH:
3852             DisableThreadLibraryCalls(hinstDLL);
3853             InitializePnPManager();
3854             break;
3855 
3856         case DLL_PROCESS_DETACH:
3857             break;
3858     }
3859 
3860     return TRUE;
3861 }
3862 
3863 /* EOF */
3864