xref: /reactos/base/services/umpnpmgr/rpcserver.c (revision 57d7f6f6)
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/rpcserver.c
23  * PURPOSE:          RPC server
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 #include "precomp.h"
32 
33 #define NDEBUG
34 #include <debug.h>
35 
36 
37 /* GLOBALS ******************************************************************/
38 
39 static WCHAR szRootDeviceInstanceID[] = L"HTREE\\ROOT\\0";
40 
41 LIST_ENTRY NotificationListHead;
42 
43 /* FUNCTIONS *****************************************************************/
44 
45 DWORD WINAPI
46 RpcServerThread(LPVOID lpParameter)
47 {
48     RPC_STATUS Status;
49     BOOLEAN RegisteredProtSeq = FALSE;
50 
51     UNREFERENCED_PARAMETER(lpParameter);
52 
53     DPRINT("RpcServerThread() called\n");
54 
55     InitializeListHead(&NotificationListHead);
56 
57 #if 0
58     /* 2k/XP/2k3-compatible protocol sequence/endpoint */
59     Status = RpcServerUseProtseqEpW(L"ncacn_np",
60                                     20,
61                                     L"\\pipe\\ntsvcs",
62                                     NULL);  // Security descriptor
63     if (Status == RPC_S_OK)
64         RegisteredProtSeq = TRUE;
65     else
66         DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
67 #endif
68 
69     /* Vista/7-compatible protocol sequence/endpoint */
70     Status = RpcServerUseProtseqEpW(L"ncacn_np",
71                                     20,
72                                     L"\\pipe\\plugplay",
73                                     NULL);  // Security descriptor
74     if (Status == RPC_S_OK)
75         RegisteredProtSeq = TRUE;
76     else
77         DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
78 
79     /* Make sure there's a usable endpoint */
80     if (RegisteredProtSeq == FALSE)
81         return 0;
82 
83     Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec,
84                                  NULL,
85                                  NULL);
86     if (Status != RPC_S_OK)
87     {
88         DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
89         return 0;
90     }
91 
92     Status = RpcServerListen(1,
93                              20,
94                              FALSE);
95     if (Status != RPC_S_OK)
96     {
97         DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
98         return 0;
99     }
100 
101     /* ROS HACK (this should never happen...) */
102     DPRINT1("*** Other devices won't be installed correctly. If something\n");
103     DPRINT1("*** doesn't work, try to reboot to get a new chance.\n");
104 
105     DPRINT("RpcServerThread() done\n");
106 
107     return 0;
108 }
109 
110 
111 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
112 {
113     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
114 }
115 
116 
117 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
118 {
119     HeapFree(GetProcessHeap(), 0, ptr);
120 }
121 
122 
123 static CONFIGRET WINAPI
124 NtStatusToCrError(NTSTATUS Status)
125 {
126     switch (Status)
127     {
128         case STATUS_NOT_IMPLEMENTED:
129             return CR_CALL_NOT_IMPLEMENTED;
130 
131         case STATUS_INVALID_PARAMETER:
132             return CR_INVALID_DATA;
133 
134         case STATUS_NO_SUCH_DEVICE:
135             return CR_NO_SUCH_DEVINST;
136 
137         case STATUS_ACCESS_DENIED:
138             return CR_ACCESS_DENIED;
139 
140         case STATUS_BUFFER_TOO_SMALL:
141             return CR_BUFFER_SMALL;
142 
143         case STATUS_OBJECT_NAME_NOT_FOUND:
144             return CR_NO_SUCH_VALUE;
145 
146         default:
147             return CR_FAILURE;
148     }
149 }
150 
151 
152 static VOID
153 SplitDeviceInstanceID(IN LPWSTR pszDeviceInstanceID,
154                       OUT LPWSTR pszEnumerator,
155                       OUT LPWSTR pszDevice,
156                       OUT LPWSTR pszInstance)
157 {
158     WCHAR szLocalDeviceInstanceID[MAX_DEVICE_ID_LEN];
159     LPWSTR lpEnumerator = NULL;
160     LPWSTR lpDevice = NULL;
161     LPWSTR lpInstance = NULL;
162     LPWSTR ptr;
163 
164     wcscpy(szLocalDeviceInstanceID, pszDeviceInstanceID);
165 
166     *pszEnumerator = 0;
167     *pszDevice = 0;
168     *pszInstance = 0;
169 
170     lpEnumerator = szLocalDeviceInstanceID;
171 
172     ptr = wcschr(lpEnumerator, L'\\');
173     if (ptr != NULL)
174     {
175         *ptr = 0;
176         lpDevice = ++ptr;
177 
178         ptr = wcschr(lpDevice, L'\\');
179         if (ptr != NULL)
180         {
181             *ptr = 0;
182             lpInstance = ++ptr;
183         }
184     }
185 
186     if (lpEnumerator != NULL)
187         wcscpy(pszEnumerator, lpEnumerator);
188 
189     if (lpDevice != NULL)
190         wcscpy(pszDevice, lpDevice);
191 
192     if (lpInstance != NULL)
193         wcscpy(pszInstance, lpInstance);
194 }
195 
196 
197 static
198 CONFIGRET
199 ClearDeviceStatus(
200     _In_ LPWSTR pszDeviceID,
201     _In_ DWORD ulStatus,
202     _In_ DWORD ulProblem)
203 {
204     PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
205     CONFIGRET ret = CR_SUCCESS;
206     NTSTATUS Status;
207 
208     DPRINT1("ClearDeviceStatus(%S 0x%lx 0x%lx)\n",
209             pszDeviceID, ulStatus, ulProblem);
210 
211     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
212                          pszDeviceID);
213     PlugPlayData.Operation = PNP_CLEAR_DEVICE_STATUS;
214     PlugPlayData.DeviceStatus = ulStatus;
215     PlugPlayData.DeviceProblem = ulProblem;
216 
217     Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
218                                (PVOID)&PlugPlayData,
219                                sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
220     if (!NT_SUCCESS(Status))
221         ret = NtStatusToCrError(Status);
222 
223     return ret;
224 }
225 
226 
227 static
228 CONFIGRET
229 GetDeviceStatus(
230     _In_ LPWSTR pszDeviceID,
231     _Out_ DWORD *pulStatus,
232     _Out_ DWORD *pulProblem)
233 {
234     PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
235     CONFIGRET ret = CR_SUCCESS;
236     NTSTATUS Status;
237 
238     DPRINT("GetDeviceStatus(%S %p %p)\n",
239            pszDeviceID, pulStatus, pulProblem);
240 
241     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
242                          pszDeviceID);
243     PlugPlayData.Operation = PNP_GET_DEVICE_STATUS;
244 
245     Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
246                                (PVOID)&PlugPlayData,
247                                sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
248     if (NT_SUCCESS(Status))
249     {
250         *pulStatus = PlugPlayData.DeviceStatus;
251         *pulProblem = PlugPlayData.DeviceProblem;
252     }
253     else
254     {
255         ret = NtStatusToCrError(Status);
256     }
257 
258     return ret;
259 }
260 
261 
262 static
263 CONFIGRET
264 SetDeviceStatus(
265     _In_ LPWSTR pszDeviceID,
266     _In_ DWORD ulStatus,
267     _In_ DWORD ulProblem)
268 {
269     PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
270     CONFIGRET ret = CR_SUCCESS;
271     NTSTATUS Status;
272 
273     DPRINT1("SetDeviceStatus(%S 0x%lx 0x%lx)\n",
274             pszDeviceID, ulStatus, ulProblem);
275 
276     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
277                          pszDeviceID);
278     PlugPlayData.Operation = PNP_SET_DEVICE_STATUS;
279     PlugPlayData.DeviceStatus = ulStatus;
280     PlugPlayData.DeviceProblem = ulProblem;
281 
282     Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
283                                (PVOID)&PlugPlayData,
284                                sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
285     if (!NT_SUCCESS(Status))
286         ret = NtStatusToCrError(Status);
287 
288     return ret;
289 }
290 
291 
292 static
293 CONFIGRET
294 DisableDeviceInstance(
295     _In_ LPWSTR pszDeviceInstance,
296     _Inout_opt_ PPNP_VETO_TYPE pVetoType,
297     _Inout_opt_ LPWSTR pszVetoName,
298     _In_ DWORD ulNameLength)
299 {
300     PLUGPLAY_CONTROL_QUERY_REMOVE_DATA QueryRemoveData;
301     CONFIGRET ret = CR_SUCCESS;
302     NTSTATUS Status;
303 
304     DPRINT1("DisableDeviceInstance(%S %p %p %lu)\n",
305             pszDeviceInstance, pVetoType, pszVetoName, ulNameLength);
306 
307     RtlInitUnicodeString(&QueryRemoveData.DeviceInstance,
308                          pszDeviceInstance);
309 
310     QueryRemoveData.Flags = 0;
311     QueryRemoveData.VetoType = 0;
312     QueryRemoveData.VetoName = pszVetoName;
313     QueryRemoveData.NameLength = ulNameLength;
314 
315     Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
316                                &QueryRemoveData,
317                                sizeof(PLUGPLAY_CONTROL_QUERY_REMOVE_DATA));
318     if (Status == STATUS_NO_SUCH_DEVICE)
319     {
320         ret = CR_INVALID_DEVNODE;
321     }
322     else if (Status == STATUS_PLUGPLAY_QUERY_VETOED)
323     {
324         if (pVetoType != NULL)
325             *pVetoType = QueryRemoveData.VetoType;
326 
327         ret = CR_REMOVE_VETOED;
328     }
329     else if (!NT_SUCCESS(Status))
330     {
331         ret = NtStatusToCrError(Status);
332     }
333 
334     return ret;
335 }
336 
337 
338 static
339 BOOL
340 IsValidDeviceInstanceID(
341     _In_ PWSTR pszDeviceInstanceID)
342 {
343     INT nPartLength[3] = {0, 0, 0};
344     INT nLength = 0, nParts = 0;
345     PWCHAR p;
346 
347     DPRINT("IsValidDeviceInstanceID(%S)\n",
348            pszDeviceInstanceID);
349 
350     if (pszDeviceInstanceID == NULL)
351     {
352         DPRINT("Device instance ID is NULL!\n");
353         return FALSE;
354     }
355 
356     p = pszDeviceInstanceID;
357     while (*p != UNICODE_NULL)
358     {
359         if (*p == L'\\')
360         {
361             nParts++;
362             if (nParts >= 3)
363             {
364                 DPRINT("Too many separators: %d\n", nParts);
365                 return FALSE;
366             }
367         }
368         else
369         {
370             nPartLength[nParts]++;
371         }
372 
373         nLength++;
374         if (nLength >= MAX_DEVICE_ID_LEN)
375         {
376             DPRINT("Too long: %d\n", nLength);
377             return FALSE;
378         }
379 
380         p++;
381     }
382 
383     if (nParts != 2)
384     {
385         DPRINT("Invalid number of separtors: %d\n", nParts);
386         return FALSE;
387     }
388 
389     if ((nPartLength[0] == 0) ||
390         (nPartLength[1] == 0) ||
391         (nPartLength[2] == 0))
392     {
393         DPRINT("Invalid part lengths: %d %d %d\n",
394                nPartLength[0], nPartLength[1], nPartLength[2]);
395         return FALSE;
396     }
397 
398     DPRINT("Valid device instance ID!\n");
399 
400     return TRUE;
401 }
402 
403 
404 static
405 BOOL
406 IsRootDeviceInstanceID(
407     _In_ PWSTR pszDeviceInstanceID)
408 {
409     if (_wcsicmp(pszDeviceInstanceID, szRootDeviceInstanceID) == 0)
410         return TRUE;
411 
412     return FALSE;
413 }
414 
415 
416 static
417 BOOL
418 IsPresentDeviceInstanceID(
419     _In_ LPWSTR pszDeviceInstanceID)
420 {
421     DWORD ulStatus, ulProblem;
422 
423     return (GetDeviceStatus(pszDeviceInstanceID, &ulStatus, &ulProblem) == CR_SUCCESS);
424 }
425 
426 
427 static
428 CONFIGRET
429 OpenConfigurationKey(
430     _In_ LPCWSTR pszDeviceID,
431     _Out_ PHKEY phKey)
432 {
433     WCHAR szKeyName[MAX_PATH];
434     HKEY hInstanceKey;
435     DWORD dwError;
436 
437     /* Build the full device instance key name */
438     wcscpy(szKeyName, L"System\\CurrentControlSet\\Enum\\");
439     wcscat(szKeyName, pszDeviceID);
440 
441     /* Open the device instance key */
442     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
443                             szKeyName,
444                             0,
445                             KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
446                             &hInstanceKey);
447     if (dwError != ERROR_SUCCESS)
448         return CR_INVALID_DEVINST;
449 
450     /* Create or open the LogConf key */
451     dwError = RegCreateKeyExW(hInstanceKey,
452                               L"LogConf",
453                               0,
454                               NULL,
455                               REG_OPTION_NON_VOLATILE,
456                               KEY_ALL_ACCESS,
457                               NULL,
458                               phKey,
459                               NULL);
460 
461     /* Close the device instance key */
462     RegCloseKey(hInstanceKey);
463 
464     if (dwError != ERROR_SUCCESS)
465         return CR_REGISTRY_ERROR;
466 
467     return CR_SUCCESS;
468 }
469 
470 
471 static
472 CONFIGRET
473 GetConfigurationData(
474     _In_ HKEY hKey,
475     _In_ ULONG ulLogConfType,
476     _Out_ PULONG pulRegDataType,
477     _Out_ PULONG pulDataSize,
478     _Out_ LPBYTE *ppBuffer)
479 {
480     LPCWSTR pszValueName;
481 
482     switch (ulLogConfType)
483     {
484         case BOOT_LOG_CONF:
485             pszValueName = L"BootConfig";
486             *pulRegDataType = REG_RESOURCE_LIST;
487             break;
488 
489         case ALLOC_LOG_CONF:
490             pszValueName = L"AllocConfig";
491             *pulRegDataType = REG_RESOURCE_LIST;
492             break;
493 
494         case FORCED_LOG_CONF:
495             pszValueName = L"ForcedConfig";
496             *pulRegDataType = REG_RESOURCE_LIST;
497             break;
498 
499         case FILTERED_LOG_CONF:
500             pszValueName = L"FilteredConfigVector";
501             *pulRegDataType = REG_RESOURCE_REQUIREMENTS_LIST;
502             break;
503 
504         case BASIC_LOG_CONF:
505             pszValueName = L"BasicConfigVector";
506             *pulRegDataType = REG_RESOURCE_REQUIREMENTS_LIST;
507             break;
508 
509         case OVERRIDE_LOG_CONF:
510             pszValueName = L"OverrideConfigVector";
511             *pulRegDataType = REG_RESOURCE_REQUIREMENTS_LIST;
512             break;
513 
514         default:
515             DPRINT1("Unsupported configuration type!\n");
516             return CR_FAILURE;
517     }
518 
519     /* Get the configuration data size */
520     if (RegQueryValueExW(hKey,
521                          pszValueName,
522                          NULL,
523                          NULL,
524                          NULL,
525                          pulDataSize) != ERROR_SUCCESS)
526     {
527         return CR_INVALID_LOG_CONF;
528     }
529 
530     /* Allocate the buffer */
531     *ppBuffer = HeapAlloc(GetProcessHeap(), 0, *pulDataSize);
532     if (*ppBuffer == NULL)
533     {
534         return CR_OUT_OF_MEMORY;
535     }
536 
537     /* Retrieve the configuration data */
538     if (RegQueryValueExW(hKey,
539                          pszValueName,
540                          NULL,
541                          NULL,
542                          (LPBYTE)*ppBuffer,
543                          pulDataSize) != ERROR_SUCCESS)
544     {
545         return CR_INVALID_LOG_CONF;
546     }
547 
548     return CR_SUCCESS;
549 }
550 
551 
552 VOID
553 __RPC_USER
554 PNP_NOTIFY_HANDLE_rundown(
555     PNP_NOTIFY_HANDLE pHandle)
556 {
557     DPRINT1("PNP_NOTIFY_HANDLE_rundown(%p)\n", pHandle);
558 }
559 
560 
561 /* PUBLIC FUNCTIONS **********************************************************/
562 
563 /* Function 0 */
564 DWORD
565 WINAPI
566 PNP_Disconnect(
567     handle_t hBinding)
568 {
569     UNREFERENCED_PARAMETER(hBinding);
570     return CR_SUCCESS;
571 }
572 
573 
574 /* Function 1 */
575 DWORD
576 WINAPI
577 PNP_Connect(
578     handle_t hBinding)
579 {
580     UNREFERENCED_PARAMETER(hBinding);
581     return CR_SUCCESS;
582 }
583 
584 
585 /* Function 2 */
586 DWORD
587 WINAPI
588 PNP_GetVersion(
589     handle_t hBinding,
590     WORD *pVersion)
591 {
592     UNREFERENCED_PARAMETER(hBinding);
593 
594     DPRINT("PNP_GetVersion(%p %p)\n",
595            hBinding, pVersion);
596 
597     *pVersion = 0x0400;
598 
599     return CR_SUCCESS;
600 }
601 
602 
603 /* Function 3 */
604 DWORD
605 WINAPI
606 PNP_GetGlobalState(
607     handle_t hBinding,
608     DWORD *pulState,
609     DWORD ulFlags)
610 {
611     UNREFERENCED_PARAMETER(hBinding);
612     UNREFERENCED_PARAMETER(ulFlags);
613 
614     DPRINT("PNP_GetGlobalState(%p %p 0x%08lx)\n",
615            hBinding, pulState, ulFlags);
616 
617     *pulState = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
618 
619     return CR_SUCCESS;
620 }
621 
622 
623 /* Function 4 */
624 DWORD
625 WINAPI
626 PNP_InitDetection(
627     handle_t hBinding)
628 {
629     UNREFERENCED_PARAMETER(hBinding);
630 
631     DPRINT("PNP_InitDetection(%p)\n",
632            hBinding);
633 
634     return CR_SUCCESS;
635 }
636 
637 
638 /* Function 5 */
639 DWORD
640 WINAPI
641 PNP_ReportLogOn(
642     handle_t hBinding,
643     BOOL Admin,
644     DWORD ProcessId)
645 {
646     DWORD ReturnValue = CR_FAILURE;
647     HANDLE hProcess;
648 
649     UNREFERENCED_PARAMETER(hBinding);
650     UNREFERENCED_PARAMETER(Admin);
651 
652     DPRINT("PNP_ReportLogOn(%p %u, %u)\n",
653            hBinding, Admin, ProcessId);
654 
655     /* Get the users token */
656     hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
657 
658     if (!hProcess)
659     {
660         DPRINT1("OpenProcess failed with error %u\n", GetLastError());
661         goto cleanup;
662     }
663 
664     if (hUserToken)
665     {
666         CloseHandle(hUserToken);
667         hUserToken = NULL;
668     }
669 
670     if (!OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY, &hUserToken))
671     {
672         DPRINT1("OpenProcessToken failed with error %u\n", GetLastError());
673         goto cleanup;
674     }
675 
676     /* Trigger the installer thread */
677     if (hInstallEvent)
678         SetEvent(hInstallEvent);
679 
680     ReturnValue = CR_SUCCESS;
681 
682 cleanup:
683     if (hProcess)
684         CloseHandle(hProcess);
685 
686     return ReturnValue;
687 }
688 
689 
690 /* Function 6 */
691 DWORD
692 WINAPI
693 PNP_ValidateDeviceInstance(
694     handle_t hBinding,
695     LPWSTR pDeviceID,
696     DWORD ulFlags)
697 {
698     CONFIGRET ret = CR_SUCCESS;
699     HKEY hDeviceKey = NULL;
700 
701     UNREFERENCED_PARAMETER(hBinding);
702     UNREFERENCED_PARAMETER(ulFlags);
703 
704     DPRINT("PNP_ValidateDeviceInstance(%p %S 0x%08lx)\n",
705            hBinding, pDeviceID, ulFlags);
706 
707     if (!IsValidDeviceInstanceID(pDeviceID))
708         return CR_INVALID_DEVINST;
709 
710     if (RegOpenKeyExW(hEnumKey,
711                       pDeviceID,
712                       0,
713                       KEY_READ,
714                       &hDeviceKey))
715     {
716         DPRINT("Could not open the Device Key!\n");
717         ret = CR_NO_SUCH_DEVNODE;
718         goto Done;
719     }
720 
721     /* FIXME: add more tests */
722 
723 Done:
724     if (hDeviceKey != NULL)
725         RegCloseKey(hDeviceKey);
726 
727     DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret);
728 
729     return ret;
730 }
731 
732 
733 /* Function 7 */
734 DWORD
735 WINAPI
736 PNP_GetRootDeviceInstance(
737     handle_t hBinding,
738     LPWSTR pDeviceID,
739     PNP_RPC_STRING_LEN ulLength)
740 {
741     CONFIGRET ret = CR_SUCCESS;
742 
743     UNREFERENCED_PARAMETER(hBinding);
744 
745     DPRINT("PNP_GetRootDeviceInstance(%p %S %lu)\n",
746            hBinding, pDeviceID, ulLength);
747 
748     if (!pDeviceID)
749     {
750         ret = CR_INVALID_POINTER;
751         goto Done;
752     }
753 
754     if (ulLength < lstrlenW(szRootDeviceInstanceID) + 1)
755     {
756         ret = CR_BUFFER_SMALL;
757         goto Done;
758     }
759 
760     lstrcpyW(pDeviceID,
761              szRootDeviceInstanceID);
762 
763 Done:
764     DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret);
765 
766     return ret;
767 }
768 
769 
770 /* Function 8 */
771 DWORD
772 WINAPI
773 PNP_GetRelatedDeviceInstance(
774     handle_t hBinding,
775     DWORD ulRelationship,
776     LPWSTR pDeviceID,
777     LPWSTR pRelatedDeviceId,
778     PNP_RPC_STRING_LEN *pulLength,
779     DWORD ulFlags)
780 {
781     PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData;
782     CONFIGRET ret = CR_SUCCESS;
783     NTSTATUS Status;
784 
785     UNREFERENCED_PARAMETER(hBinding);
786     UNREFERENCED_PARAMETER(ulFlags);
787 
788     DPRINT("PNP_GetRelatedDeviceInstance(%p %lu %S %p %p 0x%lx)\n",
789            hBinding, ulRelationship, pDeviceID, pRelatedDeviceId,
790            pulLength, ulFlags);
791 
792     if (!IsValidDeviceInstanceID(pDeviceID))
793         return CR_INVALID_DEVINST;
794 
795     if (ulRelationship == PNP_GET_PARENT_DEVICE_INSTANCE)
796     {
797         /* The root device does not have a parent */
798         if (IsRootDeviceInstanceID(pDeviceID))
799             return CR_NO_SUCH_DEVINST;
800 
801         /* Return the root device for non existing devices */
802         if (!IsPresentDeviceInstanceID(pDeviceID))
803         {
804             if ((wcslen(szRootDeviceInstanceID) + 1) > *pulLength)
805             {
806                 *pulLength = wcslen(szRootDeviceInstanceID) + 1;
807                 return CR_BUFFER_SMALL;
808             }
809 
810             wcscpy(pRelatedDeviceId, szRootDeviceInstanceID);
811             *pulLength = wcslen(szRootDeviceInstanceID) + 1;
812             return CR_SUCCESS;
813         }
814     }
815     else if (ulRelationship == PNP_GET_SIBLING_DEVICE_INSTANCE)
816     {
817         /* The root device does not have siblings */
818         if (IsRootDeviceInstanceID(pDeviceID))
819             return CR_NO_SUCH_DEVINST;
820     }
821 
822     RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance,
823                          pDeviceID);
824 
825     PlugPlayData.Relation = ulRelationship;
826 
827     PlugPlayData.RelatedDeviceInstanceLength = *pulLength;
828     PlugPlayData.RelatedDeviceInstance = pRelatedDeviceId;
829 
830     Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice,
831                                (PVOID)&PlugPlayData,
832                                sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
833     if (!NT_SUCCESS(Status))
834     {
835         ret = NtStatusToCrError(Status);
836     }
837 
838     DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret);
839     if (ret == CR_SUCCESS)
840     {
841         DPRINT("RelatedDevice: %wZ\n", &PlugPlayData.RelatedDeviceInstance);
842     }
843 
844     return ret;
845 }
846 
847 
848 /* Function 9 */
849 DWORD
850 WINAPI
851 PNP_EnumerateSubKeys(
852     handle_t hBinding,
853     DWORD ulBranch,
854     DWORD ulIndex,
855     LPWSTR Buffer,
856     PNP_RPC_STRING_LEN ulLength,
857     PNP_RPC_STRING_LEN *pulRequiredLen,
858     DWORD ulFlags)
859 {
860     CONFIGRET ret = CR_SUCCESS;
861     HKEY hKey;
862     DWORD dwError;
863 
864     UNREFERENCED_PARAMETER(hBinding);
865     UNREFERENCED_PARAMETER(ulFlags);
866 
867     DPRINT("PNP_EnumerateSubKeys(%p %lu %lu %p %lu %p 0x%08lx)\n",
868            hBinding, ulBranch, ulIndex, Buffer, ulLength,
869            pulRequiredLen, ulFlags);
870 
871     switch (ulBranch)
872     {
873         case PNP_ENUMERATOR_SUBKEYS:
874             hKey = hEnumKey;
875             break;
876 
877         case PNP_CLASS_SUBKEYS:
878             hKey = hClassKey;
879             break;
880 
881         default:
882             return CR_FAILURE;
883     }
884 
885     *pulRequiredLen = ulLength;
886     dwError = RegEnumKeyExW(hKey,
887                             ulIndex,
888                             Buffer,
889                             pulRequiredLen,
890                             NULL,
891                             NULL,
892                             NULL,
893                             NULL);
894     if (dwError != ERROR_SUCCESS)
895     {
896         ret = (dwError == ERROR_NO_MORE_ITEMS) ? CR_NO_SUCH_VALUE : CR_FAILURE;
897     }
898     else
899     {
900         (*pulRequiredLen)++;
901     }
902 
903     DPRINT("PNP_EnumerateSubKeys() done (returns %lx)\n", ret);
904 
905     return ret;
906 }
907 
908 
909 static
910 CONFIGRET
911 GetRelationsInstanceList(
912     _In_ PWSTR pszDevice,
913     _In_ DWORD ulFlags,
914     _Inout_ PWSTR pszBuffer,
915     _Inout_ PDWORD pulLength)
916 {
917     PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
918     NTSTATUS Status;
919     CONFIGRET ret = CR_SUCCESS;
920 
921     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
922                          pszDevice);
923 
924     if (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)
925     {
926         PlugPlayData.Relations = 3;
927     }
928     else if (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS)
929     {
930         PlugPlayData.Relations = 2;
931     }
932     else if (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS)
933     {
934         PlugPlayData.Relations = 1;
935     }
936     else if (ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS)
937     {
938         PlugPlayData.Relations = 0;
939     }
940 
941     PlugPlayData.BufferSize = *pulLength * sizeof(WCHAR);
942     PlugPlayData.Buffer = pszBuffer;
943 
944     Status = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
945                                (PVOID)&PlugPlayData,
946                                sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
947     if (NT_SUCCESS(Status))
948     {
949         *pulLength = PlugPlayData.BufferSize / sizeof(WCHAR);
950     }
951     else
952     {
953         ret = NtStatusToCrError(Status);
954     }
955 
956     return ret;
957 }
958 
959 
960 static
961 CONFIGRET
962 GetServiceInstanceList(
963     _In_ PWSTR pszService,
964     _Inout_ PWSTR pszBuffer,
965     _Inout_ PDWORD pulLength)
966 {
967     WCHAR szPathBuffer[512];
968     WCHAR szName[16];
969     HKEY hServicesKey = NULL, hServiceKey = NULL, hEnumKey = NULL;
970     DWORD dwValues, dwSize, dwIndex, dwUsedLength, dwPathLength;
971     DWORD dwError;
972     PWSTR pPtr;
973     CONFIGRET ret = CR_SUCCESS;
974 
975     /* Open the device key */
976     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
977                             L"System\\CurrentControlSet\\Services",
978                             0,
979                             KEY_READ,
980                             &hServicesKey);
981     if (dwError != ERROR_SUCCESS)
982     {
983         DPRINT("Failed to open the services key (Error %lu)\n", dwError);
984         return CR_REGISTRY_ERROR;
985     }
986 
987     dwError = RegOpenKeyExW(hServicesKey,
988                             pszService,
989                             0,
990                             KEY_READ,
991                             &hServiceKey);
992     if (dwError != ERROR_SUCCESS)
993     {
994         DPRINT("Failed to open the service key (Error %lu)\n", dwError);
995         ret = CR_REGISTRY_ERROR;
996         goto Done;
997     }
998 
999     dwError = RegOpenKeyExW(hServiceKey,
1000                             L"Enum",
1001                             0,
1002                             KEY_READ,
1003                             &hEnumKey);
1004     if (dwError != ERROR_SUCCESS)
1005     {
1006         DPRINT("Failed to open the service enum key (Error %lu)\n", dwError);
1007         ret = CR_REGISTRY_ERROR;
1008         goto Done;
1009     }
1010 
1011     /* Retrieve the number of device instances */
1012     dwSize = sizeof(DWORD);
1013     dwError = RegQueryValueExW(hEnumKey,
1014                                L"Count",
1015                                NULL,
1016                                NULL,
1017                                (LPBYTE)&dwValues,
1018                                &dwSize);
1019     if (dwError != ERROR_SUCCESS)
1020     {
1021         DPRINT("RegQueryValueExW failed (Error %lu)\n", dwError);
1022         dwValues = 1;
1023     }
1024 
1025     DPRINT("dwValues %lu\n", dwValues);
1026 
1027     dwUsedLength = 0;
1028     pPtr = pszBuffer;
1029 
1030     for (dwIndex = 0; dwIndex < dwValues; dwIndex++)
1031     {
1032         wsprintf(szName, L"%lu", dwIndex);
1033 
1034         dwSize = sizeof(szPathBuffer);
1035         dwError = RegQueryValueExW(hEnumKey,
1036                                    szName,
1037                                    NULL,
1038                                    NULL,
1039                                    (LPBYTE)szPathBuffer,
1040                                    &dwSize);
1041         if (dwError != ERROR_SUCCESS)
1042             break;
1043 
1044         DPRINT("Path: %S\n", szPathBuffer);
1045 
1046         dwPathLength = wcslen(szPathBuffer) + 1;
1047         if (dwUsedLength + dwPathLength + 1 > *pulLength)
1048         {
1049             ret = CR_BUFFER_SMALL;
1050             break;
1051         }
1052 
1053         wcscpy(pPtr, szPathBuffer);
1054         dwUsedLength += dwPathLength;
1055         pPtr += dwPathLength;
1056 
1057         *pPtr = UNICODE_NULL;
1058     }
1059 
1060 Done:
1061     if (hEnumKey != NULL)
1062         RegCloseKey(hEnumKey);
1063 
1064     if (hServiceKey != NULL)
1065         RegCloseKey(hServiceKey);
1066 
1067     if (hServicesKey != NULL)
1068         RegCloseKey(hServicesKey);
1069 
1070     if (ret == CR_SUCCESS)
1071         *pulLength = dwUsedLength + 1;
1072     else
1073         *pulLength = 0;
1074 
1075     return ret;
1076 }
1077 
1078 
1079 static
1080 CONFIGRET
1081 GetDeviceInstanceList(
1082     _In_ PWSTR pszDevice,
1083     _Inout_ PWSTR pszBuffer,
1084     _Inout_ PDWORD pulLength)
1085 {
1086     WCHAR szInstanceBuffer[MAX_DEVICE_ID_LEN];
1087     WCHAR szPathBuffer[512];
1088     HKEY hDeviceKey;
1089     DWORD dwInstanceLength, dwPathLength, dwUsedLength;
1090     DWORD dwIndex, dwError;
1091     PWSTR pPtr;
1092     CONFIGRET ret = CR_SUCCESS;
1093 
1094     /* Open the device key */
1095     dwError = RegOpenKeyExW(hEnumKey,
1096                             pszDevice,
1097                             0,
1098                             KEY_ENUMERATE_SUB_KEYS,
1099                             &hDeviceKey);
1100     if (dwError != ERROR_SUCCESS)
1101     {
1102         DPRINT("Failed to open the device key (Error %lu)\n", dwError);
1103         return CR_REGISTRY_ERROR;
1104     }
1105 
1106     dwUsedLength = 0;
1107     pPtr = pszBuffer;
1108 
1109     for (dwIndex = 0; ; dwIndex++)
1110     {
1111         dwInstanceLength = MAX_DEVICE_ID_LEN;
1112         dwError = RegEnumKeyExW(hDeviceKey,
1113                                 dwIndex,
1114                                 szInstanceBuffer,
1115                                 &dwInstanceLength,
1116                                 NULL,
1117                                 NULL,
1118                                 NULL,
1119                                 NULL);
1120         if (dwError != ERROR_SUCCESS)
1121             break;
1122 
1123         wsprintf(szPathBuffer, L"%s\\%s", pszDevice, szInstanceBuffer);
1124         DPRINT("Path: %S\n", szPathBuffer);
1125 
1126         dwPathLength = wcslen(szPathBuffer) + 1;
1127         if (dwUsedLength + dwPathLength + 1 > *pulLength)
1128         {
1129             ret = CR_BUFFER_SMALL;
1130             break;
1131         }
1132 
1133         wcscpy(pPtr, szPathBuffer);
1134         dwUsedLength += dwPathLength;
1135         pPtr += dwPathLength;
1136 
1137         *pPtr = UNICODE_NULL;
1138     }
1139 
1140     RegCloseKey(hDeviceKey);
1141 
1142     if (ret == CR_SUCCESS)
1143         *pulLength = dwUsedLength + 1;
1144     else
1145         *pulLength = 0;
1146 
1147     return ret;
1148 }
1149 
1150 
1151 CONFIGRET
1152 GetEnumeratorInstanceList(
1153     _In_ PWSTR pszEnumerator,
1154     _Inout_ PWSTR pszBuffer,
1155     _Inout_ PDWORD pulLength)
1156 {
1157     WCHAR szDeviceBuffer[MAX_DEVICE_ID_LEN];
1158     WCHAR szPathBuffer[512];
1159     HKEY hEnumeratorKey;
1160     PWSTR pPtr;
1161     DWORD dwIndex, dwDeviceLength, dwUsedLength, dwRemainingLength, dwPathLength;
1162     DWORD dwError;
1163     CONFIGRET ret = CR_SUCCESS;
1164 
1165     /* Open the enumerator key */
1166     dwError = RegOpenKeyExW(hEnumKey,
1167                             pszEnumerator,
1168                             0,
1169                             KEY_ENUMERATE_SUB_KEYS,
1170                             &hEnumeratorKey);
1171     if (dwError != ERROR_SUCCESS)
1172     {
1173         DPRINT("Failed to open the enumerator key (Error %lu)\n", dwError);
1174         return CR_REGISTRY_ERROR;
1175     }
1176 
1177     dwUsedLength = 0;
1178     dwRemainingLength = *pulLength;
1179     pPtr = pszBuffer;
1180 
1181     for (dwIndex = 0; ; dwIndex++)
1182     {
1183         dwDeviceLength = MAX_DEVICE_ID_LEN;
1184         dwError = RegEnumKeyExW(hEnumeratorKey,
1185                                 dwIndex,
1186                                 szDeviceBuffer,
1187                                 &dwDeviceLength,
1188                                 NULL,
1189                                 NULL,
1190                                 NULL,
1191                                 NULL);
1192         if (dwError != ERROR_SUCCESS)
1193             break;
1194 
1195         wsprintf(szPathBuffer, L"%s\\%s", pszEnumerator, szDeviceBuffer);
1196         DPRINT("Path: %S\n", szPathBuffer);
1197 
1198         dwPathLength = dwRemainingLength;
1199         ret = GetDeviceInstanceList(szPathBuffer,
1200                                     pPtr,
1201                                     &dwPathLength);
1202         if (ret != CR_SUCCESS)
1203             break;
1204 
1205         dwUsedLength += dwPathLength - 1;
1206         dwRemainingLength -= dwPathLength - 1;
1207         pPtr += dwPathLength - 1;
1208     }
1209 
1210     RegCloseKey(hEnumeratorKey);
1211 
1212     if (ret == CR_SUCCESS)
1213         *pulLength = dwUsedLength + 1;
1214     else
1215         *pulLength = 0;
1216 
1217     return ret;
1218 }
1219 
1220 
1221 static
1222 CONFIGRET
1223 GetAllInstanceList(
1224     _Inout_ PWSTR pszBuffer,
1225     _Inout_ PDWORD pulLength)
1226 {
1227     WCHAR szEnumeratorBuffer[MAX_DEVICE_ID_LEN];
1228     PWSTR pPtr;
1229     DWORD dwIndex, dwEnumeratorLength, dwUsedLength, dwRemainingLength, dwPathLength;
1230     DWORD dwError;
1231     CONFIGRET ret = CR_SUCCESS;
1232 
1233     dwUsedLength = 0;
1234     dwRemainingLength = *pulLength;
1235     pPtr = pszBuffer;
1236 
1237     for (dwIndex = 0; ; dwIndex++)
1238     {
1239         dwEnumeratorLength = MAX_DEVICE_ID_LEN;
1240         dwError = RegEnumKeyExW(hEnumKey,
1241                                 dwIndex,
1242                                 szEnumeratorBuffer,
1243                                 &dwEnumeratorLength,
1244                                 NULL, NULL, NULL, NULL);
1245         if (dwError != ERROR_SUCCESS)
1246             break;
1247 
1248         dwPathLength = dwRemainingLength;
1249         ret = GetEnumeratorInstanceList(szEnumeratorBuffer,
1250                                         pPtr,
1251                                         &dwPathLength);
1252         if (ret != CR_SUCCESS)
1253             break;
1254 
1255         dwUsedLength += dwPathLength - 1;
1256         dwRemainingLength -= dwPathLength - 1;
1257         pPtr += dwPathLength - 1;
1258     }
1259 
1260     if (ret == CR_SUCCESS)
1261         *pulLength = dwUsedLength + 1;
1262     else
1263         *pulLength = 0;
1264 
1265     return ret;
1266 }
1267 
1268 
1269 /* Function 10 */
1270 DWORD
1271 WINAPI
1272 PNP_GetDeviceList(
1273     handle_t hBinding,
1274     LPWSTR pszFilter,
1275     LPWSTR Buffer,
1276     PNP_RPC_STRING_LEN *pulLength,
1277     DWORD ulFlags)
1278 {
1279     WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
1280     WCHAR szDevice[MAX_DEVICE_ID_LEN];
1281     WCHAR szInstance[MAX_DEVICE_ID_LEN];
1282     CONFIGRET ret = CR_SUCCESS;
1283 
1284     DPRINT("PNP_GetDeviceList(%p %S %p %p 0x%08lx)\n",
1285            hBinding, pszFilter, Buffer, pulLength, ulFlags);
1286 
1287     if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
1288         return CR_INVALID_FLAG;
1289 
1290     if (pulLength == NULL)
1291         return CR_INVALID_POINTER;
1292 
1293     if ((ulFlags != CM_GETIDLIST_FILTER_NONE) &&
1294         (pszFilter == NULL))
1295         return CR_INVALID_POINTER;
1296 
1297     if (ulFlags &
1298         (CM_GETIDLIST_FILTER_BUSRELATIONS |
1299          CM_GETIDLIST_FILTER_POWERRELATIONS |
1300          CM_GETIDLIST_FILTER_REMOVALRELATIONS |
1301          CM_GETIDLIST_FILTER_EJECTRELATIONS))
1302     {
1303         ret = GetRelationsInstanceList(pszFilter,
1304                                        ulFlags,
1305                                        Buffer,
1306                                        pulLength);
1307     }
1308     else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
1309     {
1310         ret = GetServiceInstanceList(pszFilter,
1311                                      Buffer,
1312                                      pulLength);
1313     }
1314     else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
1315     {
1316         SplitDeviceInstanceID(pszFilter,
1317                               szEnumerator,
1318                               szDevice,
1319                               szInstance);
1320 
1321         if (*szEnumerator != UNICODE_NULL && *szDevice != UNICODE_NULL)
1322         {
1323             ret = GetDeviceInstanceList(pszFilter,
1324                                         Buffer,
1325                                         pulLength);
1326         }
1327         else
1328         {
1329             ret = GetEnumeratorInstanceList(pszFilter,
1330                                             Buffer,
1331                                             pulLength);
1332         }
1333     }
1334     else /* CM_GETIDLIST_FILTER_NONE */
1335     {
1336         ret = GetAllInstanceList(Buffer,
1337                                  pulLength);
1338     }
1339 
1340     return ret;
1341 }
1342 
1343 
1344 static
1345 CONFIGRET
1346 GetRelationsInstanceListSize(
1347     _In_ PWSTR pszDevice,
1348     _In_ DWORD ulFlags,
1349     _Inout_ PDWORD pulLength)
1350 {
1351     PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData;
1352     NTSTATUS Status;
1353     CONFIGRET ret = CR_SUCCESS;
1354 
1355     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
1356                          pszDevice);
1357 
1358     if (ulFlags & CM_GETIDLIST_FILTER_BUSRELATIONS)
1359     {
1360         PlugPlayData.Relations = 3;
1361     }
1362     else if (ulFlags & CM_GETIDLIST_FILTER_POWERRELATIONS)
1363     {
1364         PlugPlayData.Relations = 2;
1365     }
1366     else if (ulFlags & CM_GETIDLIST_FILTER_REMOVALRELATIONS)
1367     {
1368         PlugPlayData.Relations = 1;
1369     }
1370     else if (ulFlags & CM_GETIDLIST_FILTER_EJECTRELATIONS)
1371     {
1372         PlugPlayData.Relations = 0;
1373     }
1374 
1375     PlugPlayData.BufferSize = 0;
1376     PlugPlayData.Buffer = NULL;
1377 
1378     Status = NtPlugPlayControl(PlugPlayControlQueryDeviceRelations,
1379                                (PVOID)&PlugPlayData,
1380                                sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA));
1381     if (NT_SUCCESS(Status))
1382     {
1383         *pulLength = PlugPlayData.BufferSize / sizeof(WCHAR);
1384     }
1385     else
1386     {
1387         ret = NtStatusToCrError(Status);
1388     }
1389 
1390     return ret;
1391 }
1392 
1393 
1394 static
1395 CONFIGRET
1396 GetServiceInstanceListSize(
1397     _In_ PWSTR pszService,
1398     _Out_ PDWORD pulLength)
1399 {
1400     HKEY hServicesKey = NULL, hServiceKey = NULL, hEnumKey = NULL;
1401     DWORD dwValues, dwMaxValueLength, dwSize;
1402     DWORD dwError;
1403     CONFIGRET ret = CR_SUCCESS;
1404 
1405     /* Open the device key */
1406     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1407                             L"System\\CurrentControlSet\\Services",
1408                             0,
1409                             KEY_READ,
1410                             &hServicesKey);
1411     if (dwError != ERROR_SUCCESS)
1412     {
1413         DPRINT("Failed to open the services key (Error %lu)\n", dwError);
1414         return CR_REGISTRY_ERROR;
1415     }
1416 
1417     dwError = RegOpenKeyExW(hServicesKey,
1418                             pszService,
1419                             0,
1420                             KEY_READ,
1421                             &hServiceKey);
1422     if (dwError != ERROR_SUCCESS)
1423     {
1424         DPRINT("Failed to open the service key (Error %lu)\n", dwError);
1425         ret = CR_REGISTRY_ERROR;
1426         goto Done;
1427     }
1428 
1429     dwError = RegOpenKeyExW(hServiceKey,
1430                             L"Enum",
1431                             0,
1432                             KEY_READ,
1433                             &hEnumKey);
1434     if (dwError != ERROR_SUCCESS)
1435     {
1436         DPRINT("Failed to open the service enum key (Error %lu)\n", dwError);
1437         ret = CR_REGISTRY_ERROR;
1438         goto Done;
1439     }
1440 
1441     /* Retrieve the number of device instances */
1442     dwSize = sizeof(DWORD);
1443     dwError = RegQueryValueExW(hEnumKey,
1444                                L"Count",
1445                                NULL,
1446                                NULL,
1447                                (LPBYTE)&dwValues,
1448                                &dwSize);
1449     if (dwError != ERROR_SUCCESS)
1450     {
1451         DPRINT("RegQueryValueExW failed (Error %lu)\n", dwError);
1452         dwValues = 1;
1453     }
1454 
1455     /* Retrieve the maximum instance name length */
1456     dwError = RegQueryInfoKeyW(hEnumKey,
1457                                NULL,
1458                                NULL,
1459                                NULL,
1460                                NULL,
1461                                NULL,
1462                                NULL,
1463                                NULL,
1464                                NULL,
1465                                &dwMaxValueLength,
1466                                NULL,
1467                                NULL);
1468     if (dwError != ERROR_SUCCESS)
1469     {
1470         DPRINT("RegQueryInfoKeyW failed (Error %lu)\n", dwError);
1471         dwMaxValueLength = MAX_DEVICE_ID_LEN;
1472     }
1473 
1474     DPRINT("dwValues %lu  dwMaxValueLength %lu\n", dwValues, dwMaxValueLength / sizeof(WCHAR));
1475 
1476     /* Return the largest possible buffer size */
1477     *pulLength = dwValues * dwMaxValueLength / sizeof(WCHAR) + 2;
1478 
1479 Done:
1480     if (hEnumKey != NULL)
1481         RegCloseKey(hEnumKey);
1482 
1483     if (hServiceKey != NULL)
1484         RegCloseKey(hServiceKey);
1485 
1486     if (hServicesKey != NULL)
1487         RegCloseKey(hServicesKey);
1488 
1489     return ret;
1490 }
1491 
1492 
1493 static
1494 CONFIGRET
1495 GetDeviceInstanceListSize(
1496     _In_ LPCWSTR pszDevice,
1497     _Out_ PULONG pulLength)
1498 {
1499     HKEY hDeviceKey;
1500     DWORD dwSubKeys, dwMaxSubKeyLength;
1501     DWORD dwError;
1502 
1503     /* Open the device key */
1504     dwError = RegOpenKeyExW(hEnumKey,
1505                             pszDevice,
1506                             0,
1507                             KEY_READ,
1508                             &hDeviceKey);
1509     if (dwError != ERROR_SUCCESS)
1510     {
1511         DPRINT("Failed to open the device key (Error %lu)\n", dwError);
1512         return CR_REGISTRY_ERROR;
1513     }
1514 
1515     /* Retrieve the number of device instances and the maximum name length */
1516     dwError = RegQueryInfoKeyW(hDeviceKey,
1517                                NULL,
1518                                NULL,
1519                                NULL,
1520                                &dwSubKeys,
1521                                &dwMaxSubKeyLength,
1522                                NULL,
1523                                NULL,
1524                                NULL,
1525                                NULL,
1526                                NULL,
1527                                NULL);
1528     if (dwError != ERROR_SUCCESS)
1529     {
1530         DPRINT("RegQueryInfoKeyW failed (Error %lu)\n", dwError);
1531         dwSubKeys = 0;
1532         dwMaxSubKeyLength = 0;
1533     }
1534 
1535     /* Close the device key */
1536     RegCloseKey(hDeviceKey);
1537 
1538     /* Return the largest possible buffer size */
1539     *pulLength = dwSubKeys * (wcslen(pszDevice) + 1 + dwMaxSubKeyLength + 1);
1540 
1541     return CR_SUCCESS;
1542 }
1543 
1544 
1545 static
1546 CONFIGRET
1547 GetEnumeratorInstanceListSize(
1548     _In_ LPCWSTR pszEnumerator,
1549     _Out_ PULONG pulLength)
1550 {
1551     WCHAR szDeviceBuffer[MAX_DEVICE_ID_LEN];
1552     WCHAR szPathBuffer[512];
1553     HKEY hEnumeratorKey;
1554     DWORD dwIndex, dwDeviceLength, dwBufferLength;
1555     DWORD dwError;
1556     CONFIGRET ret = CR_SUCCESS;
1557 
1558     *pulLength = 0;
1559 
1560     /* Open the enumerator key */
1561     dwError = RegOpenKeyExW(hEnumKey,
1562                             pszEnumerator,
1563                             0,
1564                             KEY_ENUMERATE_SUB_KEYS,
1565                             &hEnumeratorKey);
1566     if (dwError != ERROR_SUCCESS)
1567     {
1568         DPRINT("Failed to open the enumerator key (Error %lu)\n", dwError);
1569         return CR_REGISTRY_ERROR;
1570     }
1571 
1572     for (dwIndex = 0; ; dwIndex++)
1573     {
1574         dwDeviceLength = MAX_DEVICE_ID_LEN;
1575         dwError = RegEnumKeyExW(hEnumeratorKey,
1576                                 dwIndex,
1577                                 szDeviceBuffer,
1578                                 &dwDeviceLength,
1579                                 NULL,
1580                                 NULL,
1581                                 NULL,
1582                                 NULL);
1583         if (dwError != ERROR_SUCCESS)
1584             break;
1585 
1586         wsprintf(szPathBuffer, L"%s\\%s", pszEnumerator, szDeviceBuffer);
1587         DPRINT("Path: %S\n", szPathBuffer);
1588 
1589         ret = GetDeviceInstanceListSize(szPathBuffer, &dwBufferLength);
1590         if (ret != CR_SUCCESS)
1591         {
1592             *pulLength = 0;
1593             break;
1594         }
1595 
1596         *pulLength += dwBufferLength;
1597     }
1598 
1599     /* Close the enumerator key */
1600     RegCloseKey(hEnumeratorKey);
1601 
1602     return ret;
1603 }
1604 
1605 
1606 static
1607 CONFIGRET
1608 GetAllInstanceListSize(
1609     _Out_ PULONG pulLength)
1610 {
1611     WCHAR szEnumeratorBuffer[MAX_DEVICE_ID_LEN];
1612     DWORD dwIndex, dwEnumeratorLength, dwBufferLength;
1613     DWORD dwError;
1614     CONFIGRET ret = CR_SUCCESS;
1615 
1616     for (dwIndex = 0; ; dwIndex++)
1617     {
1618         dwEnumeratorLength = MAX_DEVICE_ID_LEN;
1619         dwError = RegEnumKeyExW(hEnumKey,
1620                                 dwIndex,
1621                                 szEnumeratorBuffer,
1622                                 &dwEnumeratorLength,
1623                                 NULL, NULL, NULL, NULL);
1624         if (dwError != ERROR_SUCCESS)
1625             break;
1626 
1627         /* Get the size of all device instances for the enumerator */
1628         ret = GetEnumeratorInstanceListSize(szEnumeratorBuffer,
1629                                             &dwBufferLength);
1630         if (ret != CR_SUCCESS)
1631             break;
1632 
1633         *pulLength += dwBufferLength;
1634     }
1635 
1636     return ret;
1637 }
1638 
1639 
1640 /* Function 11 */
1641 DWORD
1642 WINAPI
1643 PNP_GetDeviceListSize(
1644     handle_t hBinding,
1645     LPWSTR pszFilter,
1646     PNP_RPC_BUFFER_SIZE *pulLength,
1647     DWORD ulFlags)
1648 {
1649     WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
1650     WCHAR szDevice[MAX_DEVICE_ID_LEN];
1651     WCHAR szInstance[MAX_DEVICE_ID_LEN];
1652     CONFIGRET ret = CR_SUCCESS;
1653 
1654     DPRINT("PNP_GetDeviceListSize(%p %S %p 0x%08lx)\n",
1655            hBinding, pszFilter, pulLength, ulFlags);
1656 
1657     if (ulFlags & ~CM_GETIDLIST_FILTER_BITS)
1658         return CR_INVALID_FLAG;
1659 
1660     if (pulLength == NULL)
1661         return CR_INVALID_POINTER;
1662 
1663     if ((ulFlags != CM_GETIDLIST_FILTER_NONE) &&
1664         (pszFilter == NULL))
1665         return CR_INVALID_POINTER;
1666 
1667     *pulLength = 0;
1668 
1669     if (ulFlags &
1670         (CM_GETIDLIST_FILTER_BUSRELATIONS |
1671          CM_GETIDLIST_FILTER_POWERRELATIONS |
1672          CM_GETIDLIST_FILTER_REMOVALRELATIONS |
1673          CM_GETIDLIST_FILTER_EJECTRELATIONS))
1674     {
1675         ret = GetRelationsInstanceListSize(pszFilter,
1676                                            ulFlags,
1677                                            pulLength);
1678     }
1679     else if (ulFlags & CM_GETIDLIST_FILTER_SERVICE)
1680     {
1681         ret = GetServiceInstanceListSize(pszFilter,
1682                                          pulLength);
1683     }
1684     else if (ulFlags & CM_GETIDLIST_FILTER_ENUMERATOR)
1685     {
1686         SplitDeviceInstanceID(pszFilter,
1687                               szEnumerator,
1688                               szDevice,
1689                               szInstance);
1690 
1691         if (*szEnumerator != UNICODE_NULL && *szDevice != UNICODE_NULL)
1692         {
1693             ret = GetDeviceInstanceListSize(pszFilter,
1694                                             pulLength);
1695         }
1696         else
1697         {
1698             ret = GetEnumeratorInstanceListSize(pszFilter,
1699                                                 pulLength);
1700         }
1701     }
1702     else /* CM_GETIDLIST_FILTER_NONE */
1703     {
1704         ret = GetAllInstanceListSize(pulLength);
1705     }
1706 
1707     /* Add one character for the terminating double UNICODE_NULL */
1708     if (ret == CR_SUCCESS)
1709         (*pulLength) += 1;
1710 
1711     return ret;
1712 }
1713 
1714 
1715 /* Function 12 */
1716 DWORD
1717 WINAPI
1718 PNP_GetDepth(
1719     handle_t hBinding,
1720     LPWSTR pszDeviceID,
1721     DWORD *pulDepth,
1722     DWORD ulFlags)
1723 {
1724     PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData;
1725     CONFIGRET ret = CR_SUCCESS;
1726     NTSTATUS Status;
1727 
1728     UNREFERENCED_PARAMETER(hBinding);
1729     UNREFERENCED_PARAMETER(ulFlags);
1730 
1731     DPRINT("PNP_GetDepth(%p %S %p 0x%08lx)\n",
1732            hBinding, pszDeviceID, pulDepth, ulFlags);
1733 
1734     if (!IsValidDeviceInstanceID(pszDeviceID))
1735         return CR_INVALID_DEVINST;
1736 
1737     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
1738                          pszDeviceID);
1739 
1740     Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth,
1741                                (PVOID)&PlugPlayData,
1742                                sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
1743     if (NT_SUCCESS(Status))
1744     {
1745         *pulDepth = PlugPlayData.Depth;
1746     }
1747     else
1748     {
1749         ret = NtStatusToCrError(Status);
1750     }
1751 
1752     DPRINT("PNP_GetDepth() done (returns %lx)\n", ret);
1753 
1754     return ret;
1755 }
1756 
1757 
1758 /* Function 13 */
1759 DWORD
1760 WINAPI
1761 PNP_GetDeviceRegProp(
1762     handle_t hBinding,
1763     LPWSTR pDeviceID,
1764     DWORD ulProperty,
1765     DWORD *pulRegDataType,
1766     BYTE *Buffer,
1767     PNP_PROP_SIZE *pulTransferLen,
1768     PNP_PROP_SIZE *pulLength,
1769     DWORD ulFlags)
1770 {
1771     PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData;
1772     CONFIGRET ret = CR_SUCCESS;
1773     LPWSTR lpValueName = NULL;
1774     HKEY hKey = NULL;
1775     LONG lError;
1776     NTSTATUS Status;
1777 
1778     UNREFERENCED_PARAMETER(hBinding);
1779 
1780     DPRINT("PNP_GetDeviceRegProp(%p %S %lu %p %p %p %p 0x%08lx)\n",
1781            hBinding, pDeviceID, ulProperty, pulRegDataType, Buffer,
1782            pulTransferLen, pulLength, ulFlags);
1783 
1784     if (pulTransferLen == NULL || pulLength == NULL)
1785     {
1786         ret = CR_INVALID_POINTER;
1787         goto done;
1788     }
1789 
1790     if (ulFlags != 0)
1791     {
1792         ret = CR_INVALID_FLAG;
1793         goto done;
1794     }
1795 
1796     /* Check pDeviceID */
1797     if (!IsValidDeviceInstanceID(pDeviceID))
1798     {
1799         ret = CR_INVALID_DEVINST;
1800         goto done;
1801     }
1802 
1803     if (*pulLength < *pulTransferLen)
1804         *pulLength = *pulTransferLen;
1805 
1806     *pulTransferLen = 0;
1807 
1808     switch (ulProperty)
1809     {
1810         case CM_DRP_DEVICEDESC:
1811             lpValueName = L"DeviceDesc";
1812             break;
1813 
1814         case CM_DRP_HARDWAREID:
1815             lpValueName = L"HardwareID";
1816             break;
1817 
1818         case CM_DRP_COMPATIBLEIDS:
1819             lpValueName = L"CompatibleIDs";
1820             break;
1821 
1822         case CM_DRP_SERVICE:
1823             lpValueName = L"Service";
1824             break;
1825 
1826         case CM_DRP_CLASS:
1827             lpValueName = L"Class";
1828             break;
1829 
1830         case CM_DRP_CLASSGUID:
1831             lpValueName = L"ClassGUID";
1832             break;
1833 
1834         case CM_DRP_DRIVER:
1835             lpValueName = L"Driver";
1836             break;
1837 
1838         case CM_DRP_CONFIGFLAGS:
1839             lpValueName = L"ConfigFlags";
1840             break;
1841 
1842         case CM_DRP_MFG:
1843             lpValueName = L"Mfg";
1844             break;
1845 
1846         case CM_DRP_FRIENDLYNAME:
1847             lpValueName = L"FriendlyName";
1848             break;
1849 
1850         case CM_DRP_LOCATION_INFORMATION:
1851             lpValueName = L"LocationInformation";
1852             break;
1853 
1854         case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
1855             PlugPlayData.Property = PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME;
1856             *pulRegDataType = REG_SZ;
1857             break;
1858 
1859         case CM_DRP_CAPABILITIES:
1860             lpValueName = L"Capabilities";
1861             break;
1862 
1863         case CM_DRP_UI_NUMBER:
1864             PlugPlayData.Property = PNP_PROPERTY_UI_NUMBER;
1865             break;
1866 
1867         case CM_DRP_UPPERFILTERS:
1868             lpValueName = L"UpperFilters";
1869             break;
1870 
1871         case CM_DRP_LOWERFILTERS:
1872             lpValueName = L"LowerFilters";
1873             break;
1874 
1875         case CM_DRP_BUSTYPEGUID:
1876             PlugPlayData.Property = PNP_PROPERTY_BUSTYPEGUID;
1877             *pulRegDataType = REG_BINARY;
1878             break;
1879 
1880         case CM_DRP_LEGACYBUSTYPE:
1881             PlugPlayData.Property = PNP_PROPERTY_LEGACYBUSTYPE;
1882             *pulRegDataType = REG_DWORD;
1883             break;
1884 
1885         case CM_DRP_BUSNUMBER:
1886             PlugPlayData.Property = PNP_PROPERTY_BUSNUMBER;
1887             *pulRegDataType = REG_DWORD;
1888             break;
1889 
1890         case CM_DRP_ENUMERATOR_NAME:
1891             PlugPlayData.Property = PNP_PROPERTY_ENUMERATOR_NAME;
1892             *pulRegDataType = REG_SZ;
1893             break;
1894 
1895         case CM_DRP_SECURITY:
1896             lpValueName = L"Security";
1897             break;
1898 
1899         case CM_DRP_DEVTYPE:
1900             lpValueName = L"DeviceType";
1901             break;
1902 
1903         case CM_DRP_EXCLUSIVE:
1904             lpValueName = L"Exclusive";
1905             break;
1906 
1907         case CM_DRP_CHARACTERISTICS:
1908             lpValueName = L"DeviceCharacteristics";
1909             break;
1910 
1911         case CM_DRP_ADDRESS:
1912             PlugPlayData.Property = PNP_PROPERTY_ADDRESS;
1913             *pulRegDataType = REG_DWORD;
1914             break;
1915 
1916         case CM_DRP_UI_NUMBER_DESC_FORMAT:
1917             lpValueName = L"UINumberDescFormat";
1918             break;
1919 
1920         case CM_DRP_DEVICE_POWER_DATA:
1921             PlugPlayData.Property = PNP_PROPERTY_POWER_DATA;
1922             *pulRegDataType = REG_BINARY;
1923             break;
1924 
1925         case CM_DRP_REMOVAL_POLICY:
1926             PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY;
1927             *pulRegDataType = REG_DWORD;
1928             break;
1929 
1930         case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
1931             PlugPlayData.Property = PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT;
1932             *pulRegDataType = REG_DWORD;
1933             break;
1934 
1935         case CM_DRP_REMOVAL_POLICY_OVERRIDE:
1936             lpValueName = L"RemovalPolicy";
1937             *pulRegDataType = REG_DWORD;
1938             break;
1939 
1940         case CM_DRP_INSTALL_STATE:
1941             PlugPlayData.Property = PNP_PROPERTY_INSTALL_STATE;
1942             *pulRegDataType = REG_DWORD;
1943             break;
1944 
1945 #if (WINVER >= _WIN32_WINNT_WS03)
1946         case CM_DRP_LOCATION_PATHS:
1947             PlugPlayData.Property = PNP_PROPERTY_LOCATION_PATHS;
1948             *pulRegDataType = REG_MULTI_SZ;
1949             break;
1950 #endif
1951 
1952 #if (WINVER >= _WIN32_WINNT_WIN7)
1953         case CM_DRP_BASE_CONTAINERID:
1954             PlugPlayData.Property = PNP_PROPERTY_CONTAINERID;
1955             *pulRegDataType = REG_SZ;
1956             break;
1957 #endif
1958 
1959         default:
1960             ret = CR_INVALID_PROPERTY;
1961             goto done;
1962     }
1963 
1964     DPRINT("Value name: %S\n", lpValueName);
1965 
1966     if (lpValueName)
1967     {
1968         /* Retrieve information from the Registry */
1969         lError = RegOpenKeyExW(hEnumKey,
1970                                pDeviceID,
1971                                0,
1972                                KEY_QUERY_VALUE,
1973                                &hKey);
1974         if (lError != ERROR_SUCCESS)
1975         {
1976             hKey = NULL;
1977             *pulLength = 0;
1978             ret = CR_INVALID_DEVNODE;
1979             goto done;
1980         }
1981 
1982         lError = RegQueryValueExW(hKey,
1983                                   lpValueName,
1984                                   NULL,
1985                                   pulRegDataType,
1986                                   Buffer,
1987                                   pulLength);
1988         if (lError != ERROR_SUCCESS)
1989         {
1990             if (lError == ERROR_MORE_DATA)
1991             {
1992                 ret = CR_BUFFER_SMALL;
1993             }
1994             else
1995             {
1996                 *pulLength = 0;
1997                 ret = CR_NO_SUCH_VALUE;
1998             }
1999         }
2000     }
2001     else
2002     {
2003         /* Retrieve information from the Device Node */
2004         RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
2005                              pDeviceID);
2006         PlugPlayData.Buffer = Buffer;
2007         PlugPlayData.BufferSize = *pulLength;
2008 
2009         Status = NtPlugPlayControl(PlugPlayControlProperty,
2010                                    (PVOID)&PlugPlayData,
2011                                    sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA));
2012         if (NT_SUCCESS(Status))
2013         {
2014             *pulLength = PlugPlayData.BufferSize;
2015         }
2016         else
2017         {
2018             ret = NtStatusToCrError(Status);
2019         }
2020     }
2021 
2022 done:
2023     if (pulTransferLen)
2024         *pulTransferLen = (ret == CR_SUCCESS) ? *pulLength : 0;
2025 
2026     if (hKey != NULL)
2027         RegCloseKey(hKey);
2028 
2029     DPRINT("PNP_GetDeviceRegProp() done (returns %lx)\n", ret);
2030 
2031     return ret;
2032 }
2033 
2034 
2035 /* Function 14 */
2036 DWORD
2037 WINAPI
2038 PNP_SetDeviceRegProp(
2039     handle_t hBinding,
2040     LPWSTR pDeviceId,
2041     DWORD ulProperty,
2042     DWORD ulDataType,
2043     BYTE *Buffer,
2044     PNP_PROP_SIZE ulLength,
2045     DWORD ulFlags)
2046 {
2047     CONFIGRET ret = CR_SUCCESS;
2048     LPWSTR lpValueName = NULL;
2049     HKEY hKey = 0;
2050 
2051     UNREFERENCED_PARAMETER(hBinding);
2052     UNREFERENCED_PARAMETER(ulFlags);
2053 
2054     DPRINT("PNP_SetDeviceRegProp(%p %S %lu %lu %p %lu 0x%08lx)\n",
2055            hBinding, pDeviceId, ulProperty, ulDataType, Buffer,
2056            ulLength, ulFlags);
2057 
2058     if (!IsValidDeviceInstanceID(pDeviceId))
2059         return CR_INVALID_DEVINST;
2060 
2061     switch (ulProperty)
2062     {
2063         case CM_DRP_DEVICEDESC:
2064             lpValueName = L"DeviceDesc";
2065             break;
2066 
2067         case CM_DRP_HARDWAREID:
2068             lpValueName = L"HardwareID";
2069             break;
2070 
2071         case CM_DRP_COMPATIBLEIDS:
2072             lpValueName = L"CompatibleIDs";
2073             break;
2074 
2075         case CM_DRP_SERVICE:
2076             lpValueName = L"Service";
2077             break;
2078 
2079         case CM_DRP_CLASS:
2080             lpValueName = L"Class";
2081             break;
2082 
2083         case CM_DRP_CLASSGUID:
2084             lpValueName = L"ClassGUID";
2085             break;
2086 
2087         case CM_DRP_DRIVER:
2088             lpValueName = L"Driver";
2089             break;
2090 
2091         case CM_DRP_CONFIGFLAGS:
2092             lpValueName = L"ConfigFlags";
2093             break;
2094 
2095         case CM_DRP_MFG:
2096             lpValueName = L"Mfg";
2097             break;
2098 
2099         case CM_DRP_FRIENDLYNAME:
2100             lpValueName = L"FriendlyName";
2101             break;
2102 
2103         case CM_DRP_LOCATION_INFORMATION:
2104             lpValueName = L"LocationInformation";
2105             break;
2106 
2107         case CM_DRP_UPPERFILTERS:
2108             lpValueName = L"UpperFilters";
2109             break;
2110 
2111         case CM_DRP_LOWERFILTERS:
2112             lpValueName = L"LowerFilters";
2113             break;
2114 
2115         case CM_DRP_SECURITY:
2116             lpValueName = L"Security";
2117             break;
2118 
2119         case CM_DRP_DEVTYPE:
2120             lpValueName = L"DeviceType";
2121             break;
2122 
2123         case CM_DRP_EXCLUSIVE:
2124             lpValueName = L"Exclusive";
2125             break;
2126 
2127         case CM_DRP_CHARACTERISTICS:
2128             lpValueName = L"DeviceCharacteristics";
2129             break;
2130 
2131         case CM_DRP_UI_NUMBER_DESC_FORMAT:
2132             lpValueName = L"UINumberDescFormat";
2133             break;
2134 
2135         case CM_DRP_REMOVAL_POLICY_OVERRIDE:
2136             lpValueName = L"RemovalPolicy";
2137             break;
2138 
2139         default:
2140             return CR_INVALID_PROPERTY;
2141     }
2142 
2143     DPRINT("Value name: %S\n", lpValueName);
2144 
2145     if (RegOpenKeyExW(hEnumKey,
2146                       pDeviceId,
2147                       0,
2148                       KEY_SET_VALUE,
2149                       &hKey))
2150         return CR_INVALID_DEVNODE;
2151 
2152     if (ulLength == 0)
2153     {
2154         if (RegDeleteValueW(hKey,
2155                             lpValueName))
2156             ret = CR_REGISTRY_ERROR;
2157     }
2158     else
2159     {
2160         if (RegSetValueExW(hKey,
2161                            lpValueName,
2162                            0,
2163                            ulDataType,
2164                            Buffer,
2165                            ulLength))
2166             ret = CR_REGISTRY_ERROR;
2167     }
2168 
2169     RegCloseKey(hKey);
2170 
2171     DPRINT("PNP_SetDeviceRegProp() done (returns %lx)\n", ret);
2172 
2173     return ret;
2174 }
2175 
2176 
2177 /* Function 15 */
2178 DWORD
2179 WINAPI
2180 PNP_GetClassInstance(
2181     handle_t hBinding,
2182     LPWSTR pDeviceId,
2183     LPWSTR pszClassInstance,
2184     PNP_RPC_STRING_LEN ulLength)
2185 {
2186     WCHAR szClassGuid[40];
2187     WCHAR szClassInstance[5];
2188     HKEY hDeviceClassKey = NULL;
2189     HKEY hClassInstanceKey;
2190     ULONG ulTransferLength, ulDataLength;
2191     DWORD dwDataType, dwDisposition, i;
2192     DWORD dwError;
2193     CONFIGRET ret = CR_SUCCESS;
2194 
2195     DPRINT("PNP_GetClassInstance(%p %S %p %lu)\n",
2196            hBinding, pDeviceId, pszClassInstance, ulLength);
2197 
2198     if (!IsValidDeviceInstanceID(pDeviceId))
2199         return CR_INVALID_DEVINST;
2200 
2201     ulTransferLength = ulLength;
2202     ret = PNP_GetDeviceRegProp(hBinding,
2203                                pDeviceId,
2204                                CM_DRP_DRIVER,
2205                                &dwDataType,
2206                                (BYTE *)pszClassInstance,
2207                                &ulTransferLength,
2208                                &ulLength,
2209                                0);
2210     if (ret == CR_SUCCESS)
2211         return ret;
2212 
2213     ulTransferLength = sizeof(szClassGuid);
2214     ulDataLength = sizeof(szClassGuid);
2215     ret = PNP_GetDeviceRegProp(hBinding,
2216                                pDeviceId,
2217                                CM_DRP_CLASSGUID,
2218                                &dwDataType,
2219                                (BYTE *)szClassGuid,
2220                                &ulTransferLength,
2221                                &ulDataLength,
2222                                0);
2223     if (ret != CR_SUCCESS)
2224     {
2225         DPRINT1("PNP_GetDeviceRegProp() failed (Error %lu)\n", ret);
2226         goto done;
2227     }
2228 
2229     dwError = RegOpenKeyExW(hClassKey,
2230                             szClassGuid,
2231                             0,
2232                             KEY_READ,
2233                             &hDeviceClassKey);
2234     if (dwError != ERROR_SUCCESS)
2235     {
2236         DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
2237         ret = CR_FAILURE;
2238         goto done;
2239     }
2240 
2241     for (i = 0; i < 10000; i++)
2242     {
2243         wsprintf(szClassInstance, L"%04lu", i);
2244 
2245         dwError = RegCreateKeyExW(hDeviceClassKey,
2246                                   szClassInstance,
2247                                   0,
2248                                   NULL,
2249                                   REG_OPTION_NON_VOLATILE,
2250                                   KEY_ALL_ACCESS,
2251                                   NULL,
2252                                   &hClassInstanceKey,
2253                                   &dwDisposition);
2254         if (dwError == ERROR_SUCCESS)
2255         {
2256             RegCloseKey(hClassInstanceKey);
2257 
2258             if (dwDisposition == REG_CREATED_NEW_KEY)
2259             {
2260                 wsprintf(pszClassInstance,
2261                          L"%s\\%s",
2262                          szClassGuid,
2263                          szClassInstance);
2264 
2265                 ulDataLength = (wcslen(pszClassInstance) + 1) * sizeof(WCHAR);
2266                 ret = PNP_SetDeviceRegProp(hBinding,
2267                                            pDeviceId,
2268                                            CM_DRP_DRIVER,
2269                                            REG_SZ,
2270                                            (BYTE *)pszClassInstance,
2271                                            ulDataLength,
2272                                            0);
2273                 if (ret != CR_SUCCESS)
2274                 {
2275                     DPRINT1("PNP_SetDeviceRegProp() failed (Error %lu)\n", ret);
2276                     RegDeleteKeyW(hDeviceClassKey,
2277                                   szClassInstance);
2278                 }
2279 
2280                 break;
2281             }
2282         }
2283     }
2284 
2285 done:
2286     if (hDeviceClassKey != NULL)
2287         RegCloseKey(hDeviceClassKey);
2288 
2289     return ret;
2290 }
2291 
2292 
2293 /* Function 16 */
2294 DWORD
2295 WINAPI
2296 PNP_CreateKey(
2297     handle_t hBinding,
2298     LPWSTR pszSubKey,
2299     DWORD samDesired,
2300     DWORD ulFlags)
2301 {
2302     HKEY hDeviceKey = NULL, hParametersKey = NULL;
2303     DWORD dwError;
2304     CONFIGRET ret = CR_SUCCESS;
2305 
2306     UNREFERENCED_PARAMETER(hBinding);
2307     UNREFERENCED_PARAMETER(samDesired);
2308 
2309     DPRINT("PNP_CreateKey(%p %S 0x%lx 0x%08lx)\n",
2310            hBinding, pszSubKey, samDesired, ulFlags);
2311 
2312     if (ulFlags != 0)
2313         return CR_INVALID_FLAG;
2314 
2315     if (!IsValidDeviceInstanceID(pszSubKey))
2316         return CR_INVALID_DEVINST;
2317 
2318     dwError = RegOpenKeyExW(hEnumKey,
2319                             pszSubKey,
2320                             0,
2321                             KEY_WRITE,
2322                             &hDeviceKey);
2323     if (dwError != ERROR_SUCCESS)
2324     {
2325         ret = CR_INVALID_DEVNODE;
2326         goto done;
2327     }
2328 
2329     dwError = RegCreateKeyExW(hDeviceKey,
2330                               L"Device Parameters",
2331                               0,
2332                               NULL,
2333                               REG_OPTION_NON_VOLATILE,
2334                               KEY_ALL_ACCESS,
2335                               NULL,
2336                               &hParametersKey,
2337                               NULL);
2338     if (dwError != ERROR_SUCCESS)
2339     {
2340         ret = CR_REGISTRY_ERROR;
2341         goto done;
2342     }
2343 
2344     /* FIXME: Set key security */
2345 
2346 done:
2347     if (hParametersKey != NULL)
2348         RegCloseKey(hParametersKey);
2349 
2350     if (hDeviceKey != NULL)
2351         RegCloseKey(hDeviceKey);
2352 
2353     return ret;
2354 }
2355 
2356 
2357 /* Function 17 */
2358 DWORD
2359 WINAPI
2360 PNP_DeleteRegistryKey(
2361     handle_t hBinding,
2362     LPWSTR pszDeviceID,
2363     LPWSTR pszParentKey,
2364     LPWSTR pszChildKey,
2365     DWORD ulFlags)
2366 {
2367     UNIMPLEMENTED;
2368     return CR_CALL_NOT_IMPLEMENTED;
2369 }
2370 
2371 
2372 /* Function 18 */
2373 DWORD
2374 WINAPI
2375 PNP_GetClassCount(
2376     handle_t hBinding,
2377     DWORD *pulClassCount,
2378     DWORD ulFlags)
2379 {
2380     HKEY hKey;
2381     DWORD dwError;
2382 
2383     UNREFERENCED_PARAMETER(hBinding);
2384     UNREFERENCED_PARAMETER(ulFlags);
2385 
2386     DPRINT("PNP_GetClassCount(%p %p 0x%08lx)\n",
2387            hBinding, pulClassCount, ulFlags);
2388 
2389     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2390                             REGSTR_PATH_CLASS,
2391                             0,
2392                             KEY_QUERY_VALUE,
2393                             &hKey);
2394     if (dwError != ERROR_SUCCESS)
2395         return CR_INVALID_DATA;
2396 
2397     dwError = RegQueryInfoKeyW(hKey,
2398                                NULL,
2399                                NULL,
2400                                NULL,
2401                                pulClassCount,
2402                                NULL,
2403                                NULL,
2404                                NULL,
2405                                NULL,
2406                                NULL,
2407                                NULL,
2408                                NULL);
2409     RegCloseKey(hKey);
2410     if (dwError != ERROR_SUCCESS)
2411         return CR_INVALID_DATA;
2412 
2413     return CR_SUCCESS;
2414 }
2415 
2416 
2417 /* Function 19 */
2418 DWORD
2419 WINAPI
2420 PNP_GetClassName(
2421     handle_t hBinding,
2422     LPWSTR pszClassGuid,
2423     LPWSTR Buffer,
2424     PNP_RPC_STRING_LEN *pulLength,
2425     DWORD ulFlags)
2426 {
2427     WCHAR szKeyName[MAX_PATH];
2428     CONFIGRET ret = CR_SUCCESS;
2429     HKEY hKey;
2430     DWORD dwSize;
2431 
2432     UNREFERENCED_PARAMETER(hBinding);
2433     UNREFERENCED_PARAMETER(ulFlags);
2434 
2435     DPRINT("PNP_GetClassName(%p %S %p %p 0x%08lx)\n",
2436            hBinding, pszClassGuid, Buffer, pulLength, ulFlags);
2437 
2438     lstrcpyW(szKeyName, L"System\\CurrentControlSet\\Control\\Class\\");
2439     if (lstrlenW(pszClassGuid) + 1 < sizeof(szKeyName)/sizeof(WCHAR)-(lstrlenW(szKeyName) * sizeof(WCHAR)))
2440         lstrcatW(szKeyName, pszClassGuid);
2441     else
2442         return CR_INVALID_DATA;
2443 
2444     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2445                       szKeyName,
2446                       0,
2447                       KEY_QUERY_VALUE,
2448                       &hKey))
2449         return CR_REGISTRY_ERROR;
2450 
2451     dwSize = *pulLength * sizeof(WCHAR);
2452     if (RegQueryValueExW(hKey,
2453                          L"Class",
2454                          NULL,
2455                          NULL,
2456                          (LPBYTE)Buffer,
2457                          &dwSize))
2458     {
2459         *pulLength = 0;
2460         ret = CR_REGISTRY_ERROR;
2461     }
2462     else
2463     {
2464         *pulLength = dwSize / sizeof(WCHAR);
2465     }
2466 
2467     RegCloseKey(hKey);
2468 
2469     DPRINT("PNP_GetClassName() done (returns %lx)\n", ret);
2470 
2471     return ret;
2472 }
2473 
2474 
2475 /* Function 20 */
2476 DWORD
2477 WINAPI
2478 PNP_DeleteClassKey(
2479     handle_t hBinding,
2480     LPWSTR pszClassGuid,
2481     DWORD ulFlags)
2482 {
2483     CONFIGRET ret = CR_SUCCESS;
2484 
2485     UNREFERENCED_PARAMETER(hBinding);
2486 
2487     DPRINT("PNP_DeleteClassKey(%p %S 0x%08lx)\n",
2488            hBinding, pszClassGuid, ulFlags);
2489 
2490     if (ulFlags & CM_DELETE_CLASS_SUBKEYS)
2491     {
2492         if (SHDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
2493             ret = CR_REGISTRY_ERROR;
2494     }
2495     else
2496     {
2497         if (RegDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
2498             ret = CR_REGISTRY_ERROR;
2499     }
2500 
2501     DPRINT("PNP_DeleteClassKey() done (returns %lx)\n", ret);
2502 
2503     return ret;
2504 }
2505 
2506 
2507 /* Function 21 */
2508 DWORD
2509 WINAPI
2510 PNP_GetInterfaceDeviceAlias(
2511     handle_t hBinding,
2512     LPWSTR pszInterfaceDevice,
2513     GUID *AliasInterfaceGuid,
2514     LPWSTR pszAliasInterfaceDevice,
2515     PNP_RPC_STRING_LEN *pulLength,
2516     PNP_RPC_STRING_LEN *pulTransferLen,
2517     DWORD ulFlags)
2518 {
2519     UNIMPLEMENTED;
2520     return CR_CALL_NOT_IMPLEMENTED;
2521 }
2522 
2523 
2524 /* Function 22 */
2525 DWORD
2526 WINAPI
2527 PNP_GetInterfaceDeviceList(
2528     handle_t hBinding,
2529     GUID *InterfaceGuid,
2530     LPWSTR pszDeviceID,
2531     BYTE *Buffer,
2532     PNP_RPC_BUFFER_SIZE *pulLength,
2533     DWORD ulFlags)
2534 {
2535     NTSTATUS Status;
2536     PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData;
2537     DWORD ret = CR_SUCCESS;
2538 
2539     UNREFERENCED_PARAMETER(hBinding);
2540 
2541     DPRINT("PNP_GetInterfaceDeviceList(%p %p %S %p %p 0x%08lx)\n",
2542            hBinding, InterfaceGuid, pszDeviceID, Buffer, pulLength, ulFlags);
2543 
2544     if (!IsValidDeviceInstanceID(pszDeviceID))
2545         return CR_INVALID_DEVINST;
2546 
2547     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
2548                          pszDeviceID);
2549 
2550     PlugPlayData.Flags = ulFlags;
2551     PlugPlayData.FilterGuid = InterfaceGuid;
2552     PlugPlayData.Buffer = Buffer;
2553     PlugPlayData.BufferSize = *pulLength;
2554 
2555     Status = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
2556                                (PVOID)&PlugPlayData,
2557                                sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
2558     if (NT_SUCCESS(Status))
2559     {
2560         *pulLength = PlugPlayData.BufferSize;
2561     }
2562     else
2563     {
2564         ret = NtStatusToCrError(Status);
2565     }
2566 
2567     DPRINT("PNP_GetInterfaceDeviceList() done (returns %lx)\n", ret);
2568     return ret;
2569 }
2570 
2571 
2572 /* Function 23 */
2573 DWORD
2574 WINAPI
2575 PNP_GetInterfaceDeviceListSize(
2576     handle_t hBinding,
2577     PNP_RPC_BUFFER_SIZE *pulLen,
2578     GUID *InterfaceGuid,
2579     LPWSTR pszDeviceID,
2580     DWORD ulFlags)
2581 {
2582     NTSTATUS Status;
2583     PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData;
2584     DWORD ret = CR_SUCCESS;
2585 
2586     UNREFERENCED_PARAMETER(hBinding);
2587 
2588     DPRINT("PNP_GetInterfaceDeviceListSize(%p %p %p %S 0x%08lx)\n",
2589            hBinding, pulLen, InterfaceGuid, pszDeviceID, ulFlags);
2590 
2591     if (!IsValidDeviceInstanceID(pszDeviceID))
2592         return CR_INVALID_DEVINST;
2593 
2594     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
2595                          pszDeviceID);
2596 
2597     PlugPlayData.FilterGuid = InterfaceGuid;
2598     PlugPlayData.Buffer = NULL;
2599     PlugPlayData.BufferSize = 0;
2600     PlugPlayData.Flags = ulFlags;
2601 
2602     Status = NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList,
2603                                (PVOID)&PlugPlayData,
2604                                sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
2605     if (NT_SUCCESS(Status))
2606     {
2607         *pulLen = PlugPlayData.BufferSize;
2608     }
2609     else
2610     {
2611         ret = NtStatusToCrError(Status);
2612     }
2613 
2614     DPRINT("PNP_GetInterfaceDeviceListSize() done (returns %lx)\n", ret);
2615     return ret;
2616 }
2617 
2618 
2619 /* Function 24 */
2620 DWORD
2621 WINAPI
2622 PNP_RegisterDeviceClassAssociation(
2623     handle_t hBinding,
2624     LPWSTR pszDeviceID,
2625     GUID *InterfaceGuid,
2626     LPWSTR pszReference,
2627     LPWSTR pszSymLink,
2628     PNP_RPC_STRING_LEN *pulLength,
2629     PNP_RPC_STRING_LEN *pulTransferLen,
2630     DWORD ulFlags)
2631 {
2632     UNIMPLEMENTED;
2633     return CR_CALL_NOT_IMPLEMENTED;
2634 }
2635 
2636 
2637 /* Function 25 */
2638 DWORD
2639 WINAPI
2640 PNP_UnregisterDeviceClassAssociation(
2641     handle_t hBinding,
2642     LPWSTR pszInterfaceDevice,
2643     DWORD ulFlags)
2644 {
2645     UNIMPLEMENTED;
2646     return CR_CALL_NOT_IMPLEMENTED;
2647 }
2648 
2649 
2650 /* Function 26 */
2651 DWORD
2652 WINAPI
2653 PNP_GetClassRegProp(
2654     handle_t hBinding,
2655     LPWSTR pszClassGuid,
2656     DWORD ulProperty,
2657     DWORD *pulRegDataType,
2658     BYTE *Buffer,
2659     PNP_RPC_STRING_LEN *pulTransferLen,
2660     PNP_RPC_STRING_LEN *pulLength,
2661     DWORD ulFlags)
2662 {
2663     CONFIGRET ret = CR_SUCCESS;
2664     LPWSTR lpValueName = NULL;
2665     HKEY hInstKey = NULL;
2666     HKEY hPropKey = NULL;
2667     LONG lError;
2668 
2669     UNREFERENCED_PARAMETER(hBinding);
2670 
2671     DPRINT("PNP_GetClassRegProp(%p %S %lu %p %p %p %p 0x%08lx)\n",
2672            hBinding, pszClassGuid, ulProperty, pulRegDataType,
2673            Buffer, pulTransferLen, pulLength, ulFlags);
2674 
2675     if (pulTransferLen == NULL || pulLength == NULL)
2676     {
2677         ret = CR_INVALID_POINTER;
2678         goto done;
2679     }
2680 
2681     if (ulFlags != 0)
2682     {
2683         ret = CR_INVALID_FLAG;
2684         goto done;
2685     }
2686 
2687     if (*pulLength < *pulTransferLen)
2688         *pulLength = *pulTransferLen;
2689 
2690     *pulTransferLen = 0;
2691 
2692     switch (ulProperty)
2693     {
2694         case CM_CRP_SECURITY:
2695             lpValueName = L"Security";
2696             break;
2697 
2698         case CM_CRP_DEVTYPE:
2699             lpValueName = L"DeviceType";
2700             break;
2701 
2702         case CM_CRP_EXCLUSIVE:
2703             lpValueName = L"Exclusive";
2704             break;
2705 
2706         case CM_CRP_CHARACTERISTICS:
2707             lpValueName = L"DeviceCharacteristics";
2708             break;
2709 
2710         default:
2711             ret = CR_INVALID_PROPERTY;
2712             goto done;
2713     }
2714 
2715     DPRINT("Value name: %S\n", lpValueName);
2716 
2717     lError = RegOpenKeyExW(hClassKey,
2718                            pszClassGuid,
2719                            0,
2720                            KEY_READ,
2721                            &hInstKey);
2722     if (lError != ERROR_SUCCESS)
2723     {
2724         *pulLength = 0;
2725         ret = CR_NO_SUCH_REGISTRY_KEY;
2726         goto done;
2727     }
2728 
2729     lError = RegOpenKeyExW(hInstKey,
2730                            L"Properties",
2731                            0,
2732                            KEY_READ,
2733                            &hPropKey);
2734     if (lError != ERROR_SUCCESS)
2735     {
2736         *pulLength = 0;
2737         ret = CR_NO_SUCH_REGISTRY_KEY;
2738         goto done;
2739     }
2740 
2741     lError = RegQueryValueExW(hPropKey,
2742                               lpValueName,
2743                               NULL,
2744                               pulRegDataType,
2745                               Buffer,
2746                               pulLength);
2747     if (lError != ERROR_SUCCESS)
2748     {
2749         if (lError == ERROR_MORE_DATA)
2750         {
2751             ret = CR_BUFFER_SMALL;
2752         }
2753         else
2754         {
2755             *pulLength = 0;
2756             ret = CR_NO_SUCH_VALUE;
2757         }
2758     }
2759 
2760 done:
2761     if (ret == CR_SUCCESS)
2762         *pulTransferLen = *pulLength;
2763 
2764     if (hPropKey != NULL)
2765         RegCloseKey(hPropKey);
2766 
2767     if (hInstKey != NULL)
2768         RegCloseKey(hInstKey);
2769 
2770     DPRINT("PNP_GetClassRegProp() done (returns %lx)\n", ret);
2771 
2772     return ret;
2773 }
2774 
2775 
2776 /* Function 27 */
2777 DWORD
2778 WINAPI
2779 PNP_SetClassRegProp(
2780     handle_t hBinding,
2781     LPWSTR pszClassGuid,
2782     DWORD ulProperty,
2783     DWORD ulDataType,
2784     BYTE *Buffer,
2785     PNP_PROP_SIZE ulLength,
2786     DWORD ulFlags)
2787 {
2788     CONFIGRET ret = CR_SUCCESS;
2789     LPWSTR lpValueName = NULL;
2790     HKEY hInstKey = 0;
2791     HKEY hPropKey = 0;
2792     LONG lError;
2793 
2794     UNREFERENCED_PARAMETER(hBinding);
2795 
2796     DPRINT("PNP_SetClassRegProp(%p %S %lu %lu %p %lu 0x%08lx)\n",
2797            hBinding, pszClassGuid, ulProperty, ulDataType,
2798            Buffer, ulLength, ulFlags);
2799 
2800     if (ulFlags != 0)
2801         return CR_INVALID_FLAG;
2802 
2803     switch (ulProperty)
2804     {
2805         case CM_CRP_SECURITY:
2806             lpValueName = L"Security";
2807             break;
2808 
2809         case CM_CRP_DEVTYPE:
2810             lpValueName = L"DeviceType";
2811             break;
2812 
2813         case CM_CRP_EXCLUSIVE:
2814             lpValueName = L"Exclusive";
2815             break;
2816 
2817         case CM_CRP_CHARACTERISTICS:
2818             lpValueName = L"DeviceCharacteristics";
2819             break;
2820 
2821         default:
2822             return CR_INVALID_PROPERTY;
2823     }
2824 
2825     lError = RegOpenKeyExW(hClassKey,
2826                            pszClassGuid,
2827                            0,
2828                            KEY_WRITE,
2829                            &hInstKey);
2830     if (lError != ERROR_SUCCESS)
2831     {
2832         ret = CR_NO_SUCH_REGISTRY_KEY;
2833         goto done;
2834     }
2835 
2836     /* FIXME: Set security descriptor */
2837     lError = RegCreateKeyExW(hInstKey,
2838                              L"Properties",
2839                              0,
2840                              NULL,
2841                              REG_OPTION_NON_VOLATILE,
2842                              KEY_ALL_ACCESS,
2843                              NULL,
2844                              &hPropKey,
2845                              NULL);
2846     if (lError != ERROR_SUCCESS)
2847     {
2848         ret = CR_REGISTRY_ERROR;
2849         goto done;
2850     }
2851 
2852     if (ulLength == 0)
2853     {
2854         if (RegDeleteValueW(hPropKey,
2855                             lpValueName))
2856             ret = CR_REGISTRY_ERROR;
2857     }
2858     else
2859     {
2860         if (RegSetValueExW(hPropKey,
2861                            lpValueName,
2862                            0,
2863                            ulDataType,
2864                            Buffer,
2865                            ulLength))
2866             ret = CR_REGISTRY_ERROR;
2867     }
2868 
2869 done:
2870     if (hPropKey != NULL)
2871         RegCloseKey(hPropKey);
2872 
2873     if (hInstKey != NULL)
2874         RegCloseKey(hInstKey);
2875 
2876     return ret;
2877 }
2878 
2879 
2880 static
2881 CONFIGRET
2882 CreateDeviceInstance(
2883     _In_ LPWSTR pszDeviceID,
2884     _In_ BOOL bPhantomDevice)
2885 {
2886     WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
2887     WCHAR szDevice[MAX_DEVICE_ID_LEN];
2888     WCHAR szInstance[MAX_DEVICE_ID_LEN];
2889     HKEY hKeyEnumerator;
2890     HKEY hKeyDevice;
2891     HKEY hKeyInstance;
2892     HKEY hKeyControl;
2893     LONG lError;
2894 
2895     /* Split the instance ID */
2896     SplitDeviceInstanceID(pszDeviceID,
2897                           szEnumerator,
2898                           szDevice,
2899                           szInstance);
2900 
2901     /* Open or create the enumerator key */
2902     lError = RegCreateKeyExW(hEnumKey,
2903                              szEnumerator,
2904                              0,
2905                              NULL,
2906                              REG_OPTION_NON_VOLATILE,
2907                              KEY_ALL_ACCESS,
2908                              NULL,
2909                              &hKeyEnumerator,
2910                              NULL);
2911     if (lError != ERROR_SUCCESS)
2912     {
2913         return CR_REGISTRY_ERROR;
2914     }
2915 
2916     /* Open or create the device key */
2917     lError = RegCreateKeyExW(hKeyEnumerator,
2918                              szDevice,
2919                              0,
2920                              NULL,
2921                              REG_OPTION_NON_VOLATILE,
2922                              KEY_ALL_ACCESS,
2923                              NULL,
2924                              &hKeyDevice,
2925                              NULL);
2926 
2927     /* Close the enumerator key */
2928     RegCloseKey(hKeyEnumerator);
2929 
2930     if (lError != ERROR_SUCCESS)
2931     {
2932         return CR_REGISTRY_ERROR;
2933     }
2934 
2935     /* Try to open the instance key and fail if it exists */
2936     lError = RegOpenKeyExW(hKeyDevice,
2937                            szInstance,
2938                            0,
2939                            KEY_SET_VALUE,
2940                            &hKeyInstance);
2941     if (lError == ERROR_SUCCESS)
2942     {
2943         DPRINT1("Instance %S already exists!\n", szInstance);
2944         RegCloseKey(hKeyInstance);
2945         RegCloseKey(hKeyDevice);
2946         return CR_ALREADY_SUCH_DEVINST;
2947     }
2948 
2949     /* Create a new instance key */
2950     lError = RegCreateKeyExW(hKeyDevice,
2951                              szInstance,
2952                              0,
2953                              NULL,
2954                              REG_OPTION_NON_VOLATILE,
2955                              KEY_ALL_ACCESS,
2956                              NULL,
2957                              &hKeyInstance,
2958                              NULL);
2959 
2960     /* Close the device key */
2961     RegCloseKey(hKeyDevice);
2962 
2963     if (lError != ERROR_SUCCESS)
2964     {
2965         return CR_REGISTRY_ERROR;
2966     }
2967 
2968     if (bPhantomDevice)
2969     {
2970         DWORD dwPhantomValue = 1;
2971         RegSetValueExW(hKeyInstance,
2972                        L"Phantom",
2973                        0,
2974                        REG_DWORD,
2975                        (PBYTE)&dwPhantomValue,
2976                        sizeof(dwPhantomValue));
2977     }
2978 
2979     /* Create the 'Control' sub key */
2980     lError = RegCreateKeyExW(hKeyInstance,
2981                              L"Control",
2982                              0,
2983                              NULL,
2984                              REG_OPTION_NON_VOLATILE,
2985                              KEY_ALL_ACCESS,
2986                              NULL,
2987                              &hKeyControl,
2988                              NULL);
2989     if (lError == ERROR_SUCCESS)
2990     {
2991         RegCloseKey(hKeyControl);
2992     }
2993 
2994     RegCloseKey(hKeyInstance);
2995 
2996     return (lError == ERROR_SUCCESS) ? CR_SUCCESS : CR_REGISTRY_ERROR;
2997 }
2998 
2999 
3000 static
3001 CONFIGRET
3002 GenerateDeviceID(
3003     _Inout_ LPWSTR pszDeviceID,
3004     _In_ PNP_RPC_STRING_LEN ulLength)
3005 {
3006     WCHAR szGeneratedInstance[MAX_DEVICE_ID_LEN];
3007     HKEY hKey;
3008     DWORD dwInstanceNumber;
3009     DWORD dwError = ERROR_SUCCESS;
3010     CONFIGRET ret = CR_SUCCESS;
3011 
3012     /* Fail, if the device name contains backslashes */
3013     if (wcschr(pszDeviceID, L'\\') != NULL)
3014         return CR_INVALID_DEVICE_ID;
3015 
3016     /* Generated ID is: Root\<Device ID>\<Instance number> */
3017     dwInstanceNumber = 0;
3018     while (dwError == ERROR_SUCCESS)
3019     {
3020         if (dwInstanceNumber >= 10000)
3021             return CR_FAILURE;
3022 
3023         swprintf(szGeneratedInstance, L"Root\\%ls\\%04lu",
3024                  pszDeviceID, dwInstanceNumber);
3025 
3026         /* Try to open the enum key of the device instance */
3027         dwError = RegOpenKeyEx(hEnumKey, szGeneratedInstance, 0, KEY_QUERY_VALUE, &hKey);
3028         if (dwError == ERROR_SUCCESS)
3029         {
3030             RegCloseKey(hKey);
3031             dwInstanceNumber++;
3032         }
3033     }
3034 
3035     /* pszDeviceID is an out parameter too for generated IDs */
3036     if (wcslen(szGeneratedInstance) > ulLength)
3037     {
3038         ret = CR_BUFFER_SMALL;
3039     }
3040     else
3041     {
3042         wcscpy(pszDeviceID, szGeneratedInstance);
3043     }
3044 
3045     return ret;
3046 }
3047 
3048 
3049 /* Function 28 */
3050 DWORD
3051 WINAPI
3052 PNP_CreateDevInst(
3053     handle_t hBinding,
3054     LPWSTR pszDeviceID,
3055     LPWSTR pszParentDeviceID,
3056     PNP_RPC_STRING_LEN ulLength,
3057     DWORD ulFlags)
3058 {
3059     PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
3060     HKEY hKey = NULL;
3061     DWORD dwSize, dwPhantom;
3062     NTSTATUS Status;
3063     CONFIGRET ret = CR_SUCCESS;
3064 
3065     DPRINT("PNP_CreateDevInst(%p %S %S %lu 0x%08lx)\n",
3066            hBinding, pszParentDeviceID, pszDeviceID, ulLength, ulFlags);
3067 
3068     if (ulFlags & ~CM_CREATE_DEVNODE_BITS)
3069         return CR_INVALID_FLAG;
3070 
3071     if (pszDeviceID == NULL || pszParentDeviceID == NULL)
3072         return CR_INVALID_POINTER;
3073 
3074     /* Fail, if the parent device is not the root device */
3075     if (!IsRootDeviceInstanceID(pszParentDeviceID))
3076         return CR_INVALID_DEVINST;
3077 
3078     if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID)
3079     {
3080         ret = GenerateDeviceID(pszDeviceID,
3081                                ulLength);
3082         if (ret != CR_SUCCESS)
3083             return ret;
3084     }
3085 
3086     /* Try to open the device instance key */
3087     RegOpenKeyEx(hEnumKey, pszDeviceID, 0, KEY_READ | KEY_WRITE, &hKey);
3088 
3089     if (ulFlags & CM_CREATE_DEVNODE_PHANTOM)
3090     {
3091         /* Fail, if the device already exists */
3092         if (hKey != NULL)
3093         {
3094             ret = CR_ALREADY_SUCH_DEVINST;
3095             goto done;
3096         }
3097 
3098         /* Create the phantom device instance */
3099         ret = CreateDeviceInstance(pszDeviceID, TRUE);
3100     }
3101     else
3102     {
3103         /* Fail, if the device exists and is present */
3104         if ((hKey != NULL) && (IsPresentDeviceInstanceID(pszDeviceID)))
3105         {
3106             ret = CR_ALREADY_SUCH_DEVINST;
3107             goto done;
3108         }
3109 
3110         /* If it does not already exist ... */
3111         if (hKey == NULL)
3112         {
3113             /* Create the device instance */
3114             ret = CreateDeviceInstance(pszDeviceID, FALSE);
3115 
3116             /* Open the device instance key */
3117             RegOpenKeyEx(hEnumKey, pszDeviceID, 0, KEY_READ | KEY_WRITE, &hKey);
3118         }
3119 
3120         /* Create a device node for the device */
3121         RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceID);
3122         Status = NtPlugPlayControl(PlugPlayControlInitializeDevice,
3123                                    &ControlData,
3124                                    sizeof(ControlData));
3125         if (!NT_SUCCESS(Status))
3126         {
3127             ret = CR_FAILURE;
3128             goto done;
3129         }
3130 
3131         /* If the device is a phantom device, turn it into a normal device */
3132         if (hKey != NULL)
3133         {
3134             dwPhantom = 0;
3135             dwSize = sizeof(DWORD);
3136             RegQueryValueEx(hKey, L"Phantom", NULL, NULL, (PBYTE)&dwPhantom, &dwSize);
3137 
3138             if (dwPhantom != 0)
3139                 RegDeleteValue(hKey, L"Phantom");
3140         }
3141     }
3142 
3143 done:
3144     if (hKey)
3145         RegCloseKey(hKey);
3146 
3147     DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
3148 
3149     return ret;
3150 }
3151 
3152 
3153 static CONFIGRET
3154 SetupDeviceInstance(
3155     _In_ LPWSTR pszDeviceInstance,
3156     _In_ DWORD ulMinorAction)
3157 {
3158     PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
3159     HKEY hDeviceKey = NULL;
3160     DWORD dwDisableCount, dwSize;
3161     DWORD ulStatus, ulProblem;
3162     DWORD dwError;
3163     CONFIGRET ret = CR_SUCCESS;
3164     NTSTATUS Status;
3165 
3166     DPRINT1("SetupDeviceInstance(%S 0x%08lx)\n",
3167             pszDeviceInstance, ulMinorAction);
3168 
3169     if (IsRootDeviceInstanceID(pszDeviceInstance))
3170         return CR_INVALID_DEVINST;
3171 
3172     if (ulMinorAction & ~CM_SETUP_BITS)
3173         return CR_INVALID_FLAG;
3174 
3175     if ((ulMinorAction == CM_SETUP_DOWNLOAD) ||
3176         (ulMinorAction == CM_SETUP_WRITE_LOG_CONFS))
3177         return CR_SUCCESS;
3178 
3179     dwError = RegOpenKeyExW(hEnumKey,
3180                             pszDeviceInstance,
3181                             0,
3182                             KEY_READ,
3183                             &hDeviceKey);
3184     if (dwError != ERROR_SUCCESS)
3185         return CR_INVALID_DEVNODE;
3186 
3187     dwSize = sizeof(dwDisableCount);
3188     dwError = RegQueryValueExW(hDeviceKey,
3189                                L"DisableCount",
3190                                NULL,
3191                                NULL,
3192                                (LPBYTE)&dwDisableCount,
3193                                &dwSize);
3194     if ((dwError == ERROR_SUCCESS) &&
3195         (dwDisableCount > 0))
3196     {
3197         goto done;
3198     }
3199 
3200     GetDeviceStatus(pszDeviceInstance,
3201                     &ulStatus,
3202                     &ulProblem);
3203 
3204     if (ulStatus & DN_STARTED)
3205     {
3206         goto done;
3207     }
3208 
3209     if (ulStatus & DN_HAS_PROBLEM)
3210     {
3211         ret = ClearDeviceStatus(pszDeviceInstance,
3212                                 DN_HAS_PROBLEM,
3213                                 ulProblem);
3214     }
3215 
3216     if (ret != CR_SUCCESS)
3217         goto done;
3218 
3219     /* Start the device */
3220     RtlInitUnicodeString(&ControlData.DeviceInstance,
3221                          pszDeviceInstance);
3222     Status = NtPlugPlayControl(PlugPlayControlStartDevice,
3223                                &ControlData,
3224                                sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA));
3225     if (!NT_SUCCESS(Status))
3226         ret = NtStatusToCrError(Status);
3227 
3228 done:
3229     if (hDeviceKey != NULL)
3230         RegCloseKey(hDeviceKey);
3231 
3232     return ret;
3233 }
3234 
3235 
3236 static CONFIGRET
3237 EnableDeviceInstance(
3238     _In_ LPWSTR pszDeviceInstance)
3239 {
3240     PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
3241     CONFIGRET ret = CR_SUCCESS;
3242     NTSTATUS Status;
3243 
3244     DPRINT("Enable device instance %S\n", pszDeviceInstance);
3245 
3246     RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceInstance);
3247     Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData));
3248     if (!NT_SUCCESS(Status))
3249         ret = NtStatusToCrError(Status);
3250 
3251     return ret;
3252 }
3253 
3254 
3255 static CONFIGRET
3256 ReenumerateDeviceInstance(
3257     _In_ LPWSTR pszDeviceInstance,
3258     _In_ ULONG ulMinorAction)
3259 {
3260     PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA EnumerateDeviceData;
3261     CONFIGRET ret = CR_SUCCESS;
3262     NTSTATUS Status;
3263 
3264     DPRINT1("ReenumerateDeviceInstance(%S 0x%08lx)\n",
3265            pszDeviceInstance, ulMinorAction);
3266 
3267     if (ulMinorAction & ~CM_REENUMERATE_BITS)
3268         return CR_INVALID_FLAG;
3269 
3270     if (ulMinorAction & CM_REENUMERATE_RETRY_INSTALLATION)
3271     {
3272         DPRINT1("CM_REENUMERATE_RETRY_INSTALLATION not implemented!\n");
3273     }
3274 
3275     RtlInitUnicodeString(&EnumerateDeviceData.DeviceInstance,
3276                          pszDeviceInstance);
3277     EnumerateDeviceData.Flags = 0;
3278 
3279     Status = NtPlugPlayControl(PlugPlayControlEnumerateDevice,
3280                                &EnumerateDeviceData,
3281                                sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA));
3282     if (!NT_SUCCESS(Status))
3283         ret = NtStatusToCrError(Status);
3284 
3285     return ret;
3286 }
3287 
3288 
3289 /* Function 29 */
3290 DWORD
3291 WINAPI
3292 PNP_DeviceInstanceAction(
3293     handle_t hBinding,
3294     DWORD ulMajorAction,
3295     DWORD ulMinorAction,
3296     LPWSTR pszDeviceInstance1,
3297     LPWSTR pszDeviceInstance2)
3298 {
3299     CONFIGRET ret = CR_SUCCESS;
3300 
3301     UNREFERENCED_PARAMETER(hBinding);
3302 
3303     DPRINT("PNP_DeviceInstanceAction(%p %lu 0x%08lx %S %S)\n",
3304            hBinding, ulMajorAction, ulMinorAction,
3305            pszDeviceInstance1, pszDeviceInstance2);
3306 
3307     switch (ulMajorAction)
3308     {
3309         case PNP_DEVINST_SETUP:
3310             ret = SetupDeviceInstance(pszDeviceInstance1,
3311                                       ulMinorAction);
3312             break;
3313 
3314         case PNP_DEVINST_ENABLE:
3315             ret = EnableDeviceInstance(pszDeviceInstance1);
3316             break;
3317 
3318         case PNP_DEVINST_REENUMERATE:
3319             ret = ReenumerateDeviceInstance(pszDeviceInstance1,
3320                                             ulMinorAction);
3321             break;
3322 
3323         default:
3324             DPRINT1("Unknown device action %lu: not implemented\n", ulMajorAction);
3325             ret = CR_CALL_NOT_IMPLEMENTED;
3326     }
3327 
3328     DPRINT("PNP_DeviceInstanceAction() done (returns %lx)\n", ret);
3329 
3330     return ret;
3331 }
3332 
3333 
3334 /* Function 30 */
3335 DWORD
3336 WINAPI
3337 PNP_GetDeviceStatus(
3338     handle_t hBinding,
3339     LPWSTR pDeviceID,
3340     DWORD *pulStatus,
3341     DWORD *pulProblem,
3342     DWORD ulFlags)
3343 {
3344     DWORD ulDataType, ulTransferLength, ulLength;
3345     DWORD ulCapabilities, ulConfigFlags;
3346     CONFIGRET ret;
3347 
3348     UNREFERENCED_PARAMETER(hBinding);
3349     UNREFERENCED_PARAMETER(ulFlags);
3350 
3351     DPRINT("PNP_GetDeviceStatus(%p %S %p %p 0x%08lx)\n",
3352            hBinding, pDeviceID, pulStatus, pulProblem, ulFlags);
3353 
3354     if (ulFlags != 0)
3355         return CR_INVALID_FLAG;
3356 
3357     if ((pulStatus == NULL) || (pulProblem == NULL))
3358         return CR_INVALID_POINTER;
3359 
3360     if (!IsValidDeviceInstanceID(pDeviceID))
3361         return CR_INVALID_DEVINST;
3362 
3363     ret = GetDeviceStatus(pDeviceID, pulStatus, pulProblem);
3364     if (ret != CR_SUCCESS)
3365         return ret;
3366 
3367     /* Check for DN_REMOVABLE */
3368     ulTransferLength = sizeof(ulCapabilities);
3369     ulLength = sizeof(ulCapabilities);
3370     ret = PNP_GetDeviceRegProp(NULL,
3371                                pDeviceID,
3372                                CM_DRP_CAPABILITIES,
3373                                &ulDataType,
3374                                (PBYTE)&ulCapabilities,
3375                                &ulTransferLength,
3376                                &ulLength,
3377                                0);
3378     if (ret != CR_SUCCESS)
3379         ulCapabilities = 0;
3380 
3381     if (ulCapabilities & CM_DEVCAP_REMOVABLE)
3382         *pulStatus |= DN_REMOVABLE;
3383 
3384     /* Check for DN_MANUAL */
3385     ulTransferLength = sizeof(ulConfigFlags);
3386     ulLength = sizeof(ulConfigFlags);
3387     ret = PNP_GetDeviceRegProp(NULL,
3388                                pDeviceID,
3389                                CM_DRP_CONFIGFLAGS,
3390                                &ulDataType,
3391                                (PBYTE)&ulConfigFlags,
3392                                &ulTransferLength,
3393                                &ulLength,
3394                                0);
3395     if (ret != CR_SUCCESS)
3396         ulConfigFlags = 0;
3397 
3398     if (ulConfigFlags & CONFIGFLAG_MANUAL_INSTALL)
3399         *pulStatus |= DN_MANUAL;
3400 
3401     /* Check for failed install */
3402     if (((*pulStatus & DN_HAS_PROBLEM) == 0) && (ulConfigFlags & CONFIGFLAG_FAILEDINSTALL))
3403     {
3404         *pulStatus |= DN_HAS_PROBLEM;
3405         *pulProblem = CM_PROB_FAILED_INSTALL;
3406     }
3407 
3408     return CR_SUCCESS;
3409 }
3410 
3411 
3412 /* Function 31 */
3413 DWORD
3414 WINAPI
3415 PNP_SetDeviceProblem(
3416     handle_t hBinding,
3417     LPWSTR pDeviceID,
3418     DWORD ulProblem,
3419     DWORD ulFlags)
3420 {
3421     ULONG ulOldStatus, ulOldProblem;
3422     CONFIGRET ret = CR_SUCCESS;
3423 
3424     UNREFERENCED_PARAMETER(hBinding);
3425 
3426     DPRINT1("PNP_SetDeviceProblem(%p %S %lu 0x%08lx)\n",
3427            hBinding, pDeviceID, ulProblem, ulFlags);
3428 
3429     if (ulFlags & ~CM_SET_DEVNODE_PROBLEM_BITS)
3430         return CR_INVALID_FLAG;
3431 
3432     if (!IsValidDeviceInstanceID(pDeviceID))
3433         return CR_INVALID_DEVINST;
3434 
3435     ret = GetDeviceStatus(pDeviceID,
3436                           &ulOldStatus,
3437                           &ulOldProblem);
3438     if (ret != CR_SUCCESS)
3439         return ret;
3440 
3441     if (((ulFlags & CM_SET_DEVNODE_PROBLEM_OVERRIDE) == 0) &&
3442         (ulOldProblem != 0) &&
3443         (ulOldProblem != ulProblem))
3444     {
3445         return CR_FAILURE;
3446     }
3447 
3448     if (ulProblem == 0)
3449     {
3450         ret = ClearDeviceStatus(pDeviceID,
3451                                 DN_HAS_PROBLEM,
3452                                 ulOldProblem);
3453     }
3454     else
3455     {
3456         ret = SetDeviceStatus(pDeviceID,
3457                               DN_HAS_PROBLEM,
3458                               ulProblem);
3459     }
3460 
3461     return ret;
3462 }
3463 
3464 
3465 /* Function 32 */
3466 DWORD
3467 WINAPI
3468 PNP_DisableDevInst(
3469     handle_t hBinding,
3470     LPWSTR pDeviceID,
3471     PPNP_VETO_TYPE pVetoType,
3472     LPWSTR pszVetoName,
3473     DWORD ulNameLength,
3474     DWORD ulFlags)
3475 {
3476     UNREFERENCED_PARAMETER(hBinding);
3477 
3478     DPRINT1("PNP_DisableDevInst(%p %S %p %p %lu 0x%08lx)\n",
3479             hBinding, pDeviceID, pVetoType, pszVetoName, ulNameLength, ulFlags);
3480 
3481     if (ulFlags & ~CM_DISABLE_BITS)
3482         return CR_INVALID_FLAG;
3483 
3484     if (!IsValidDeviceInstanceID(pDeviceID) ||
3485         IsRootDeviceInstanceID(pDeviceID))
3486         return CR_INVALID_DEVINST;
3487 
3488     return DisableDeviceInstance(pDeviceID,
3489                                  pVetoType,
3490                                  pszVetoName,
3491                                  ulNameLength);
3492 }
3493 
3494 
3495 /* Function 33 */
3496 DWORD
3497 WINAPI
3498 PNP_UninstallDevInst(
3499     handle_t hBinding,
3500     LPWSTR pDeviceID,
3501     DWORD ulFlags)
3502 {
3503     UNIMPLEMENTED;
3504     return CR_CALL_NOT_IMPLEMENTED;
3505 }
3506 
3507 
3508 static BOOL
3509 CheckForDeviceId(LPWSTR lpDeviceIdList,
3510                  LPWSTR lpDeviceId)
3511 {
3512     LPWSTR lpPtr;
3513     DWORD dwLength;
3514 
3515     lpPtr = lpDeviceIdList;
3516     while (*lpPtr != 0)
3517     {
3518         dwLength = wcslen(lpPtr);
3519         if (0 == _wcsicmp(lpPtr, lpDeviceId))
3520             return TRUE;
3521 
3522         lpPtr += (dwLength + 1);
3523     }
3524 
3525     return FALSE;
3526 }
3527 
3528 
3529 static VOID
3530 AppendDeviceId(LPWSTR lpDeviceIdList,
3531                LPDWORD lpDeviceIdListSize,
3532                LPWSTR lpDeviceId)
3533 {
3534     DWORD dwLen;
3535     DWORD dwPos;
3536 
3537     dwLen = wcslen(lpDeviceId);
3538     dwPos = (*lpDeviceIdListSize / sizeof(WCHAR)) - 1;
3539 
3540     wcscpy(&lpDeviceIdList[dwPos], lpDeviceId);
3541 
3542     dwPos += (dwLen + 1);
3543 
3544     lpDeviceIdList[dwPos] = 0;
3545 
3546     *lpDeviceIdListSize = dwPos * sizeof(WCHAR);
3547 }
3548 
3549 
3550 /* Function 34 */
3551 DWORD
3552 WINAPI
3553 PNP_AddID(
3554     handle_t hBinding,
3555     LPWSTR pszDeviceID,
3556     LPWSTR pszID,
3557     DWORD ulFlags)
3558 {
3559     CONFIGRET ret = CR_SUCCESS;
3560     HKEY hDeviceKey;
3561     LPWSTR pszSubKey;
3562     DWORD dwDeviceIdListSize;
3563     DWORD dwNewDeviceIdSize;
3564     WCHAR * pszDeviceIdList = NULL;
3565 
3566     UNREFERENCED_PARAMETER(hBinding);
3567 
3568     DPRINT("PNP_AddID(%p %S %S 0x%08lx)\n",
3569            hBinding, pszDeviceID, pszID, ulFlags);
3570 
3571     if (RegOpenKeyExW(hEnumKey,
3572                       pszDeviceID,
3573                       0,
3574                       KEY_QUERY_VALUE | KEY_SET_VALUE,
3575                       &hDeviceKey) != ERROR_SUCCESS)
3576     {
3577         DPRINT("Failed to open the device key!\n");
3578         return CR_INVALID_DEVNODE;
3579     }
3580 
3581     pszSubKey = (ulFlags & CM_ADD_ID_COMPATIBLE) ? L"CompatibleIDs" : L"HardwareID";
3582 
3583     if (RegQueryValueExW(hDeviceKey,
3584                          pszSubKey,
3585                          NULL,
3586                          NULL,
3587                          NULL,
3588                          &dwDeviceIdListSize) != ERROR_SUCCESS)
3589     {
3590         DPRINT("Failed to query the desired ID string!\n");
3591         ret = CR_REGISTRY_ERROR;
3592         goto Done;
3593     }
3594 
3595     dwNewDeviceIdSize = lstrlenW(pszDeviceID);
3596     if (!dwNewDeviceIdSize)
3597     {
3598         ret = CR_INVALID_POINTER;
3599         goto Done;
3600     }
3601 
3602     dwDeviceIdListSize += (dwNewDeviceIdSize + 2) * sizeof(WCHAR);
3603 
3604     pszDeviceIdList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDeviceIdListSize);
3605     if (!pszDeviceIdList)
3606     {
3607         DPRINT("Failed to allocate memory for the desired ID string!\n");
3608         ret = CR_OUT_OF_MEMORY;
3609         goto Done;
3610     }
3611 
3612     if (RegQueryValueExW(hDeviceKey,
3613                          pszSubKey,
3614                          NULL,
3615                          NULL,
3616                          (LPBYTE)pszDeviceIdList,
3617                          &dwDeviceIdListSize) != ERROR_SUCCESS)
3618     {
3619         DPRINT("Failed to query the desired ID string!\n");
3620         ret = CR_REGISTRY_ERROR;
3621         goto Done;
3622     }
3623 
3624     /* Check whether the device ID is already in use */
3625     if (CheckForDeviceId(pszDeviceIdList, pszDeviceID))
3626     {
3627         DPRINT("Device ID was found in the ID string!\n");
3628         ret = CR_SUCCESS;
3629         goto Done;
3630     }
3631 
3632     /* Append the Device ID */
3633     AppendDeviceId(pszDeviceIdList, &dwDeviceIdListSize, pszID);
3634 
3635     if (RegSetValueExW(hDeviceKey,
3636                        pszSubKey,
3637                        0,
3638                        REG_MULTI_SZ,
3639                        (LPBYTE)pszDeviceIdList,
3640                        dwDeviceIdListSize) != ERROR_SUCCESS)
3641     {
3642         DPRINT("Failed to set the desired ID string!\n");
3643         ret = CR_REGISTRY_ERROR;
3644     }
3645 
3646 Done:
3647     RegCloseKey(hDeviceKey);
3648     if (pszDeviceIdList)
3649         HeapFree(GetProcessHeap(), 0, pszDeviceIdList);
3650 
3651     DPRINT("PNP_AddID() done (returns %lx)\n", ret);
3652 
3653     return ret;
3654 }
3655 
3656 
3657 /* Function 35 */
3658 DWORD
3659 WINAPI
3660 PNP_RegisterDriver(
3661     handle_t hBinding,
3662     LPWSTR pszDeviceID,
3663     DWORD ulFlags)
3664 {
3665     DPRINT("PNP_RegisterDriver(%p %S 0x%lx)\n",
3666            hBinding, pszDeviceID, ulFlags);
3667 
3668     if (ulFlags & ~CM_REGISTER_DEVICE_DRIVER_BITS)
3669         return CR_INVALID_FLAG;
3670 
3671     if (!IsValidDeviceInstanceID(pszDeviceID))
3672         return CR_INVALID_DEVINST;
3673 
3674     SetDeviceStatus(pszDeviceID, 0, 0);
3675 
3676     return CR_SUCCESS;
3677 }
3678 
3679 
3680 /* Function 36 */
3681 DWORD
3682 WINAPI
3683 PNP_QueryRemove(
3684     handle_t hBinding,
3685     LPWSTR pszDeviceID,
3686     PPNP_VETO_TYPE pVetoType,
3687     LPWSTR pszVetoName,
3688     DWORD ulNameLength,
3689     DWORD ulFlags)
3690 {
3691     PLUGPLAY_CONTROL_QUERY_REMOVE_DATA PlugPlayData;
3692     NTSTATUS Status;
3693     DWORD ret = CR_SUCCESS;
3694 
3695     DPRINT1("PNP_QueryRemove(%p %S %p %p %lu 0x%lx)\n",
3696             hBinding, pszDeviceID, pVetoType, pszVetoName,
3697             ulNameLength, ulFlags);
3698 
3699     if (ulFlags & ~CM_REMOVE_BITS)
3700         return CR_INVALID_FLAG;
3701 
3702     if (!IsValidDeviceInstanceID(pszDeviceID) ||
3703         IsRootDeviceInstanceID(pszDeviceID))
3704         return CR_INVALID_DEVINST;
3705 
3706     if (pVetoType != NULL)
3707         *pVetoType = PNP_VetoTypeUnknown;
3708 
3709     if (pszVetoName != NULL && ulNameLength > 0)
3710         *pszVetoName = UNICODE_NULL;
3711 
3712     RtlZeroMemory(&PlugPlayData, sizeof(PlugPlayData));
3713     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
3714                          pszDeviceID);
3715     PlugPlayData.VetoName = pszVetoName;
3716     PlugPlayData.NameLength = ulNameLength;
3717 //    PlugPlayData.Flags =
3718 
3719     Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
3720                                &PlugPlayData,
3721                                sizeof(PlugPlayData));
3722     if (!NT_SUCCESS(Status))
3723         ret = NtStatusToCrError(Status);
3724 
3725     return ret;
3726 }
3727 
3728 
3729 /* Function 37 */
3730 DWORD
3731 WINAPI
3732 PNP_RequestDeviceEject(
3733     handle_t hBinding,
3734     LPWSTR pszDeviceID,
3735     PPNP_VETO_TYPE pVetoType,
3736     LPWSTR pszVetoName,
3737     DWORD ulNameLength,
3738     DWORD ulFlags)
3739 {
3740     PLUGPLAY_CONTROL_QUERY_REMOVE_DATA PlugPlayData;
3741     NTSTATUS Status;
3742     DWORD ret = CR_SUCCESS;
3743 
3744     DPRINT1("PNP_RequestDeviceEject(%p %S %p %p %lu 0x%lx)\n",
3745             hBinding, pszDeviceID, pVetoType, pszVetoName,
3746             ulNameLength, ulFlags);
3747 
3748     if (ulFlags != 0)
3749         return CR_INVALID_FLAG;
3750 
3751     if (!IsValidDeviceInstanceID(pszDeviceID))
3752         return CR_INVALID_DEVINST;
3753 
3754     if (pVetoType != NULL)
3755         *pVetoType = PNP_VetoTypeUnknown;
3756 
3757     if (pszVetoName != NULL && ulNameLength > 0)
3758         *pszVetoName = UNICODE_NULL;
3759 
3760     RtlZeroMemory(&PlugPlayData, sizeof(PlugPlayData));
3761     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
3762                          pszDeviceID);
3763     PlugPlayData.VetoName = pszVetoName;
3764     PlugPlayData.NameLength = ulNameLength;
3765 //    PlugPlayData.Flags =
3766 
3767     Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
3768                                &PlugPlayData,
3769                                sizeof(PlugPlayData));
3770     if (!NT_SUCCESS(Status))
3771         ret = NtStatusToCrError(Status);
3772 
3773     return ret;
3774 }
3775 
3776 
3777 /* Function 38 */
3778 CONFIGRET
3779 WINAPI
3780 PNP_IsDockStationPresent(
3781     handle_t hBinding,
3782     BOOL *Present)
3783 {
3784     HKEY hKey;
3785     DWORD dwType;
3786     DWORD dwValue;
3787     DWORD dwSize;
3788     CONFIGRET ret = CR_SUCCESS;
3789 
3790     UNREFERENCED_PARAMETER(hBinding);
3791 
3792     DPRINT1("PNP_IsDockStationPresent(%p %p)\n",
3793             hBinding, Present);
3794 
3795     *Present = FALSE;
3796 
3797     if (RegOpenKeyExW(HKEY_CURRENT_CONFIG,
3798                       L"CurrentDockInfo",
3799                       0,
3800                       KEY_READ,
3801                       &hKey) != ERROR_SUCCESS)
3802         return CR_REGISTRY_ERROR;
3803 
3804     dwSize = sizeof(DWORD);
3805     if (RegQueryValueExW(hKey,
3806                          L"DockingState",
3807                          NULL,
3808                          &dwType,
3809                          (LPBYTE)&dwValue,
3810                          &dwSize) != ERROR_SUCCESS)
3811         ret = CR_REGISTRY_ERROR;
3812 
3813     RegCloseKey(hKey);
3814 
3815     if (ret == CR_SUCCESS)
3816     {
3817         if (dwType != REG_DWORD || dwSize != sizeof(DWORD))
3818         {
3819             ret = CR_REGISTRY_ERROR;
3820         }
3821         else if (dwValue != 0)
3822         {
3823             *Present = TRUE;
3824         }
3825     }
3826 
3827     DPRINT1("PNP_IsDockStationPresent() done (returns %lx)\n", ret);
3828 
3829     return ret;
3830 }
3831 
3832 
3833 /* Function 39 */
3834 DWORD
3835 WINAPI
3836 PNP_RequestEjectPC(
3837     handle_t hBinding)
3838 {
3839     WCHAR szDockDeviceInstance[MAX_DEVICE_ID_LEN];
3840     PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA DockData;
3841     NTSTATUS Status;
3842 
3843     DPRINT("PNP_RequestEjectPC(%p)\n", hBinding);
3844 
3845     /* Retrieve the dock device */
3846     DockData.DeviceInstanceLength = ARRAYSIZE(szDockDeviceInstance);
3847     DockData.DeviceInstance = szDockDeviceInstance;
3848 
3849     Status = NtPlugPlayControl(PlugPlayControlRetrieveDock,
3850                                &DockData,
3851                                sizeof(DockData));
3852     if (!NT_SUCCESS(Status))
3853         return NtStatusToCrError(Status);
3854 
3855     /* Eject the dock device */
3856     return PNP_RequestDeviceEject(hBinding,
3857                                   szDockDeviceInstance,
3858                                   NULL,
3859                                   NULL,
3860                                   0,
3861                                   0);
3862 }
3863 
3864 
3865 /* Function 40 */
3866 DWORD
3867 WINAPI
3868 PNP_HwProfFlags(
3869     handle_t hBinding,
3870     DWORD ulAction,
3871     LPWSTR pDeviceID,
3872     DWORD ulConfig,
3873     DWORD *pulValue,
3874     PPNP_VETO_TYPE pVetoType,
3875     LPWSTR pszVetoName,
3876     DWORD ulNameLength,
3877     DWORD ulFlags)
3878 {
3879     CONFIGRET ret = CR_SUCCESS;
3880     WCHAR szKeyName[MAX_PATH];
3881     HKEY hKey;
3882     HKEY hDeviceKey;
3883     DWORD dwSize;
3884 
3885     UNREFERENCED_PARAMETER(hBinding);
3886 
3887     DPRINT("PNP_HwProfFlags() called\n");
3888 
3889     if (!IsValidDeviceInstanceID(pDeviceID))
3890         return CR_INVALID_DEVINST;
3891 
3892     if (ulConfig == 0)
3893     {
3894         wcscpy(szKeyName,
3895                L"System\\CurrentControlSet\\HardwareProfiles\\Current\\System\\CurrentControlSet\\Enum");
3896     }
3897     else
3898     {
3899         swprintf(szKeyName,
3900                  L"System\\CurrentControlSet\\HardwareProfiles\\%04lu\\System\\CurrentControlSet\\Enum",
3901                  ulConfig);
3902     }
3903 
3904     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3905                       szKeyName,
3906                       0,
3907                       KEY_QUERY_VALUE,
3908                       &hKey) != ERROR_SUCCESS)
3909         return CR_REGISTRY_ERROR;
3910 
3911     if (ulAction == PNP_GET_HWPROFFLAGS)
3912     {
3913          if (RegOpenKeyExW(hKey,
3914                            pDeviceID,
3915                            0,
3916                            KEY_QUERY_VALUE,
3917                            &hDeviceKey) != ERROR_SUCCESS)
3918          {
3919             *pulValue = 0;
3920          }
3921          else
3922          {
3923              dwSize = sizeof(DWORD);
3924              if (RegQueryValueExW(hDeviceKey,
3925                                   L"CSConfigFlags",
3926                                   NULL,
3927                                   NULL,
3928                                   (LPBYTE)pulValue,
3929                                   &dwSize) != ERROR_SUCCESS)
3930              {
3931                  *pulValue = 0;
3932              }
3933 
3934              RegCloseKey(hDeviceKey);
3935          }
3936     }
3937     else if (ulAction == PNP_SET_HWPROFFLAGS)
3938     {
3939         /* FIXME: not implemented yet */
3940         ret = CR_CALL_NOT_IMPLEMENTED;
3941     }
3942 
3943     RegCloseKey(hKey);
3944 
3945     return ret;
3946 }
3947 
3948 
3949 /* Function 41 */
3950 DWORD
3951 WINAPI
3952 PNP_GetHwProfInfo(
3953     handle_t hBinding,
3954     DWORD ulIndex,
3955     HWPROFILEINFO *pHWProfileInfo,
3956     DWORD ulProfileInfoSize,
3957     DWORD ulFlags)
3958 {
3959     WCHAR szProfileName[5];
3960     HKEY hKeyConfig = NULL;
3961     HKEY hKeyProfiles = NULL;
3962     HKEY hKeyProfile = NULL;
3963     DWORD dwDisposition;
3964     DWORD dwSize;
3965     LONG lError;
3966     CONFIGRET ret = CR_SUCCESS;
3967 
3968     UNREFERENCED_PARAMETER(hBinding);
3969 
3970     DPRINT("PNP_GetHwProfInfo() called\n");
3971 
3972     if (ulProfileInfoSize == 0)
3973     {
3974         ret = CR_INVALID_DATA;
3975         goto done;
3976     }
3977 
3978     if (ulFlags != 0)
3979     {
3980         ret = CR_INVALID_FLAG;
3981         goto done;
3982     }
3983 
3984     /* Initialize the profile information */
3985     pHWProfileInfo->HWPI_ulHWProfile = 0;
3986     pHWProfileInfo->HWPI_szFriendlyName[0] = 0;
3987     pHWProfileInfo->HWPI_dwFlags = 0;
3988 
3989     /* Open the 'IDConfigDB' key */
3990     lError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3991                              L"System\\CurrentControlSet\\Control\\IDConfigDB",
3992                              0,
3993                              NULL,
3994                              REG_OPTION_NON_VOLATILE,
3995                              KEY_QUERY_VALUE,
3996                              NULL,
3997                              &hKeyConfig,
3998                              &dwDisposition);
3999     if (lError != ERROR_SUCCESS)
4000     {
4001         ret = CR_REGISTRY_ERROR;
4002         goto done;
4003     }
4004 
4005     /* Open the 'Hardware Profiles' subkey */
4006     lError = RegCreateKeyExW(hKeyConfig,
4007                              L"Hardware Profiles",
4008                              0,
4009                              NULL,
4010                              REG_OPTION_NON_VOLATILE,
4011                              KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
4012                              NULL,
4013                              &hKeyProfiles,
4014                              &dwDisposition);
4015     if (lError != ERROR_SUCCESS)
4016     {
4017         ret = CR_REGISTRY_ERROR;
4018         goto done;
4019     }
4020 
4021     if (ulIndex == (ULONG)-1)
4022     {
4023         dwSize = sizeof(ULONG);
4024         lError = RegQueryValueExW(hKeyConfig,
4025                                   L"CurrentConfig",
4026                                   NULL,
4027                                   NULL,
4028                                   (LPBYTE)&pHWProfileInfo->HWPI_ulHWProfile,
4029                                   &dwSize);
4030         if (lError != ERROR_SUCCESS)
4031         {
4032             pHWProfileInfo->HWPI_ulHWProfile = 0;
4033             ret = CR_REGISTRY_ERROR;
4034             goto done;
4035         }
4036     }
4037     else
4038     {
4039         /* FIXME: not implemented yet */
4040         ret = CR_CALL_NOT_IMPLEMENTED;
4041         goto done;
4042     }
4043 
4044     swprintf(szProfileName, L"%04lu", pHWProfileInfo->HWPI_ulHWProfile);
4045 
4046     lError = RegOpenKeyExW(hKeyProfiles,
4047                            szProfileName,
4048                            0,
4049                            KEY_QUERY_VALUE,
4050                            &hKeyProfile);
4051     if (lError != ERROR_SUCCESS)
4052     {
4053         ret = CR_REGISTRY_ERROR;
4054         goto done;
4055     }
4056 
4057     dwSize = sizeof(pHWProfileInfo->HWPI_szFriendlyName);
4058     lError = RegQueryValueExW(hKeyProfile,
4059                               L"FriendlyName",
4060                               NULL,
4061                               NULL,
4062                               (LPBYTE)&pHWProfileInfo->HWPI_szFriendlyName,
4063                               &dwSize);
4064     if (lError != ERROR_SUCCESS)
4065     {
4066         ret = CR_REGISTRY_ERROR;
4067         goto done;
4068     }
4069 
4070 done:
4071     if (hKeyProfile != NULL)
4072         RegCloseKey(hKeyProfile);
4073 
4074     if (hKeyProfiles != NULL)
4075         RegCloseKey(hKeyProfiles);
4076 
4077     if (hKeyConfig != NULL)
4078         RegCloseKey(hKeyConfig);
4079 
4080     return ret;
4081 }
4082 
4083 
4084 /* Function 42 */
4085 DWORD
4086 WINAPI
4087 PNP_AddEmptyLogConf(
4088     handle_t hBinding,
4089     LPWSTR pDeviceID,
4090     DWORD ulPriority,
4091     DWORD *pulLogConfTag,
4092     DWORD ulFlags)
4093 {
4094     UNIMPLEMENTED;
4095     return CR_CALL_NOT_IMPLEMENTED;
4096 }
4097 
4098 
4099 /* Function 43 */
4100 DWORD
4101 WINAPI
4102 PNP_FreeLogConf(
4103     handle_t hBinding,
4104     LPWSTR pDeviceID,
4105     DWORD ulLogConfType,
4106     DWORD ulLogConfTag,
4107     DWORD ulFlags)
4108 {
4109     UNIMPLEMENTED;
4110     return CR_CALL_NOT_IMPLEMENTED;
4111 }
4112 
4113 
4114 /* Function 44 */
4115 DWORD
4116 WINAPI
4117 PNP_GetFirstLogConf(
4118     handle_t hBinding,
4119     LPWSTR pDeviceID,
4120     DWORD ulLogConfType,
4121     DWORD *pulLogConfTag,
4122     DWORD ulFlags)
4123 {
4124     HKEY hConfigKey = NULL;
4125     DWORD RegDataType = 0;
4126     ULONG ulDataSize = 0;
4127     LPBYTE lpData = NULL;
4128     CONFIGRET ret = CR_SUCCESS;
4129 
4130     DPRINT("PNP_GetFirstLogConf(%p %S %lu %p 0x%08lx)\n",
4131            hBinding, pDeviceID, ulLogConfType, pulLogConfTag, ulFlags);
4132 
4133     if (pulLogConfTag == NULL)
4134         return CR_INVALID_POINTER;
4135 
4136     *pulLogConfTag = (DWORD)0;
4137 
4138     if (ulFlags & ~LOG_CONF_BITS)
4139         return CR_INVALID_FLAG;
4140 
4141     if (!IsValidDeviceInstanceID(pDeviceID))
4142         return CR_INVALID_DEVINST;
4143 
4144     ret = OpenConfigurationKey(pDeviceID,
4145                                &hConfigKey);
4146     if (ret != CR_SUCCESS)
4147     {
4148         DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
4149         ret = CR_NO_MORE_LOG_CONF;
4150         goto done;
4151     }
4152 
4153     ret = GetConfigurationData(hConfigKey,
4154                                ulLogConfType,
4155                                &RegDataType,
4156                                &ulDataSize,
4157                                &lpData);
4158     if (ret != CR_SUCCESS)
4159     {
4160         DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
4161         ret = CR_NO_MORE_LOG_CONF;
4162         goto done;
4163     }
4164 
4165     DPRINT("Data size %lu\n", ulDataSize);
4166     if (ulDataSize == 0 || lpData == NULL)
4167     {
4168         DPRINT1("No config data available!\n");
4169         ret = CR_NO_MORE_LOG_CONF;
4170         goto done;
4171     }
4172 
4173     /* Get the first tag */
4174     if (RegDataType == REG_RESOURCE_LIST)
4175     {
4176         DPRINT("REG_RESOURCE_LIST\n");
4177 
4178         DPRINT("ResourceList->Count %lu\n", ((PCM_RESOURCE_LIST)lpData)->Count);
4179         if (((PCM_RESOURCE_LIST)lpData)->Count == 0)
4180         {
4181             DPRINT1("No resource descriptors!\n");
4182             ret = CR_NO_MORE_LOG_CONF;
4183             goto done;
4184         }
4185 
4186         DPRINT("lpData %p\n", lpData);
4187         DPRINT("&List[0] %p\n", &(((PCM_RESOURCE_LIST)lpData)->List[0]));
4188 
4189         *pulLogConfTag = (DWORD)((DWORD_PTR)&(((PCM_RESOURCE_LIST)lpData)->List[0]) - (DWORD_PTR)lpData);
4190         DPRINT("Offset (Tag): 0x%08lx\n", *pulLogConfTag);
4191     }
4192     else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
4193     {
4194         DPRINT1("FIXME: REG_RESOURCE_REQUIREMENTS_LIST\n");
4195         /* FIXME */
4196         ret = CR_NO_MORE_LOG_CONF;
4197         goto done;
4198     }
4199 
4200 done:
4201     if (lpData != NULL)
4202         HeapFree(GetProcessHeap(), 0, lpData);
4203 
4204     if (hConfigKey != NULL)
4205         RegCloseKey(hConfigKey);
4206 
4207     DPRINT("PNP_GetFirstLogConf() returns %lu\n", ret);
4208 
4209     return ret;
4210 }
4211 
4212 
4213 /* Function 45 */
4214 DWORD
4215 WINAPI
4216 PNP_GetNextLogConf(
4217     handle_t hBinding,
4218     LPWSTR pDeviceID,
4219     DWORD ulLogConfType,
4220     DWORD ulCurrentTag,
4221     DWORD *pulNextTag,
4222     DWORD ulFlags)
4223 {
4224     HKEY hConfigKey = NULL;
4225     DWORD RegDataType = 0;
4226     ULONG ulDataSize = 0;
4227     LPBYTE lpData = NULL;
4228     CONFIGRET ret = CR_SUCCESS;
4229 
4230     DPRINT("PNP_GetNextLogConf(%p %S %lu %ul %p 0x%08lx)\n",
4231            hBinding, pDeviceID, ulLogConfType, ulCurrentTag, pulNextTag, ulFlags);
4232 
4233     if (pulNextTag == NULL)
4234         return CR_INVALID_POINTER;
4235 
4236     *pulNextTag = (DWORD)0;
4237 
4238     if (ulFlags != 0)
4239         return CR_INVALID_FLAG;
4240 
4241     if (!IsValidDeviceInstanceID(pDeviceID))
4242         return CR_INVALID_DEVINST;
4243 
4244     ret = OpenConfigurationKey(pDeviceID,
4245                                &hConfigKey);
4246     if (ret != CR_SUCCESS)
4247     {
4248         DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
4249         ret = CR_NO_MORE_LOG_CONF;
4250         goto done;
4251     }
4252 
4253     ret = GetConfigurationData(hConfigKey,
4254                                ulLogConfType,
4255                                &RegDataType,
4256                                &ulDataSize,
4257                                &lpData);
4258     if (ret != CR_SUCCESS)
4259     {
4260         DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
4261         ret = CR_NO_MORE_LOG_CONF;
4262         goto done;
4263     }
4264 
4265     DPRINT("Data size %lu\n", ulDataSize);
4266 
4267     if (ulDataSize == 0 || lpData == NULL)
4268     {
4269         DPRINT1("No config data available!\n");
4270         ret = CR_NO_MORE_LOG_CONF;
4271         goto done;
4272     }
4273 
4274     /* FIXME: Get the next tag */
4275     if (RegDataType == REG_RESOURCE_LIST)
4276     {
4277         DPRINT1("FIXME: REG_RESOURCE_LIST\n");
4278         /* FIXME */
4279         ret = CR_NO_MORE_LOG_CONF;
4280         goto done;
4281     }
4282     else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
4283     {
4284         DPRINT1("FIXME: REG_RESOURCE_REQUIREMENTS_LIST\n");
4285         /* FIXME */
4286         ret = CR_NO_MORE_LOG_CONF;
4287         goto done;
4288     }
4289 
4290 done:
4291     if (lpData != NULL)
4292         HeapFree(GetProcessHeap(), 0, lpData);
4293 
4294     if (hConfigKey != NULL)
4295         RegCloseKey(hConfigKey);
4296 
4297     DPRINT("PNP_GetNextLogConf() returns %lu\n", ret);
4298 
4299     return ret;
4300 }
4301 
4302 
4303 /* Function 46 */
4304 DWORD
4305 WINAPI
4306 PNP_GetLogConfPriority(
4307     handle_t hBinding,
4308     LPWSTR pDeviceID,
4309     DWORD ulType,
4310     DWORD ulTag,
4311     DWORD *pPriority,
4312     DWORD ulFlags)
4313 {
4314     UNIMPLEMENTED;
4315     return CR_CALL_NOT_IMPLEMENTED;
4316 }
4317 
4318 
4319 /* Function 47 */
4320 DWORD
4321 WINAPI
4322 PNP_AddResDes(
4323     handle_t hBinding,
4324     LPWSTR pDeviceID,
4325     DWORD ulLogConfTag,
4326     DWORD ulLogConfType,
4327     RESOURCEID ResourceID,
4328     DWORD *pulResourceTag,
4329     BYTE *ResourceData,
4330     PNP_RPC_BUFFER_SIZE ResourceLen,
4331     DWORD ulFlags)
4332 {
4333     UNIMPLEMENTED;
4334     return CR_CALL_NOT_IMPLEMENTED;
4335 }
4336 
4337 
4338 /* Function 48 */
4339 DWORD
4340 WINAPI
4341 PNP_FreeResDes(
4342     handle_t hBinding,
4343     LPWSTR pDeviceID,
4344     DWORD ulLogConfTag,
4345     DWORD ulLogConfType,
4346     RESOURCEID ResourceID,
4347     DWORD ulResourceTag,
4348     DWORD *pulPreviousResType,
4349     DWORD *pulPreviousResTag,
4350     DWORD ulFlags)
4351 {
4352     UNIMPLEMENTED;
4353     return CR_CALL_NOT_IMPLEMENTED;
4354 }
4355 
4356 
4357 /* Function 49 */
4358 DWORD
4359 WINAPI
4360 PNP_GetNextResDes(
4361     handle_t hBinding,
4362     LPWSTR pDeviceID,
4363     DWORD ulLogConfTag,
4364     DWORD ulLogConfType,
4365     RESOURCEID ResourceID,
4366     DWORD ulResourceTag,
4367     DWORD *pulNextResType,
4368     DWORD *pulNextResTag,
4369     DWORD ulFlags)
4370 {
4371     HKEY hConfigKey = NULL;
4372     DWORD RegDataType = 0;
4373     ULONG ulDataSize = 0;
4374     LPBYTE lpData = NULL;
4375     CONFIGRET ret = CR_SUCCESS;
4376 
4377     DPRINT1("PNP_GetNextResDes(%p %S 0x%lx %lu %lu %ul %p %p 0x%08lx)\n",
4378            hBinding, pDeviceID, ulLogConfTag, ulLogConfType, ResourceID,
4379            ulResourceTag, pulNextResType, pulNextResTag, ulFlags);
4380 
4381     if (pulNextResType == NULL)
4382         return CR_INVALID_POINTER;
4383 
4384     *pulNextResType = 0;
4385 
4386     if (ulFlags != 0)
4387         return CR_INVALID_FLAG;
4388 
4389     if (!IsValidDeviceInstanceID(pDeviceID))
4390         return CR_INVALID_DEVINST;
4391 
4392     ret = OpenConfigurationKey(pDeviceID,
4393                                &hConfigKey);
4394     if (ret != CR_SUCCESS)
4395     {
4396         DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
4397         ret = CR_NO_MORE_LOG_CONF;
4398         goto done;
4399     }
4400 
4401     ret = GetConfigurationData(hConfigKey,
4402                                ulLogConfType,
4403                                &RegDataType,
4404                                &ulDataSize,
4405                                &lpData);
4406     if (ret != CR_SUCCESS)
4407     {
4408         DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
4409         ret = CR_NO_MORE_LOG_CONF;
4410         goto done;
4411     }
4412 
4413     DPRINT1("Data size %lu\n", ulDataSize);
4414 
4415     if (ulDataSize == 0 || lpData == NULL)
4416     {
4417         DPRINT1("No config data available!\n");
4418         ret = CR_NO_MORE_LOG_CONF;
4419         goto done;
4420     }
4421 
4422     /* Get the next resource descriptor */
4423     if (RegDataType == REG_RESOURCE_LIST)
4424     {
4425         DPRINT1("FIXME: REG_RESOURCE_LIST\n");
4426         /* FIXME */
4427         ret = CR_NO_MORE_LOG_CONF;
4428         goto done;
4429     }
4430     else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
4431     {
4432         DPRINT1("FIXME: REG_RESOURCE_REQUIREMENTS_LIST\n");
4433         /* FIXME */
4434         ret = CR_NO_MORE_LOG_CONF;
4435         goto done;
4436     }
4437 
4438 done:
4439     if (lpData != NULL)
4440         HeapFree(GetProcessHeap(), 0, lpData);
4441 
4442     if (hConfigKey != NULL)
4443         RegCloseKey(hConfigKey);
4444 
4445     DPRINT1("PNP_GetNextResDes() returns %lu\n", ret);
4446 
4447     return ret;
4448 }
4449 
4450 
4451 /* Function 50 */
4452 DWORD
4453 WINAPI
4454 PNP_GetResDesData(
4455     handle_t hBinding,
4456     LPWSTR pDeviceID,
4457     DWORD ulLogConfTag,
4458     DWORD ulLogConfType,
4459     RESOURCEID ResourceID,
4460     DWORD ulResourceTag,
4461     BYTE *Buffer,
4462     PNP_RPC_BUFFER_SIZE BufferLen,
4463     DWORD ulFlags)
4464 {
4465     UNIMPLEMENTED;
4466     return CR_CALL_NOT_IMPLEMENTED;
4467 }
4468 
4469 
4470 /* Function 51 */
4471 DWORD
4472 WINAPI
4473 PNP_GetResDesDataSize(
4474     handle_t hBinding,
4475     LPWSTR pDeviceID,
4476     DWORD ulLogConfTag,
4477     DWORD ulLogConfType,
4478     RESOURCEID ResourceID,
4479     DWORD ulResourceTag,
4480     DWORD *pulSize,
4481     DWORD ulFlags)
4482 {
4483     UNIMPLEMENTED;
4484     return CR_CALL_NOT_IMPLEMENTED;
4485 }
4486 
4487 
4488 /* Function 52 */
4489 DWORD
4490 WINAPI
4491 PNP_ModifyResDes(
4492     handle_t hBinding,
4493     LPWSTR pDeviceID,
4494     DWORD ulLogConfTag,
4495     DWORD ulLogConfType,
4496     RESOURCEID CurrentResourceID,
4497     RESOURCEID NewResourceID,
4498     DWORD ulResourceTag,
4499     BYTE *ResourceData,
4500     PNP_RPC_BUFFER_SIZE ResourceLen,
4501     DWORD ulFlags)
4502 {
4503     UNIMPLEMENTED;
4504     return CR_CALL_NOT_IMPLEMENTED;
4505 }
4506 
4507 
4508 /* Function 53 */
4509 DWORD
4510 WINAPI
4511 PNP_DetectResourceConflict(
4512     handle_t hBinding,
4513     LPWSTR pDeviceID,
4514     RESOURCEID ResourceID,
4515     BYTE *ResourceData,
4516     PNP_RPC_BUFFER_SIZE ResourceLen,
4517     BOOL *pbConflictDetected,
4518     DWORD ulFlags)
4519 {
4520     DPRINT("PNP_DetectResourceConflict()\n");
4521 
4522     if (pbConflictDetected != NULL)
4523         *pbConflictDetected = FALSE;
4524 
4525     return CR_CALL_NOT_IMPLEMENTED;
4526 }
4527 
4528 
4529 /* Function 54 */
4530 DWORD
4531 WINAPI
4532 PNP_QueryResConfList(
4533     handle_t hBinding,
4534     LPWSTR pDeviceID,
4535     RESOURCEID ResourceID,
4536     BYTE *ResourceData,
4537     PNP_RPC_BUFFER_SIZE ResourceLen,
4538     BYTE *Buffer,
4539     PNP_RPC_BUFFER_SIZE BufferLen,
4540     DWORD ulFlags)
4541 {
4542     UNIMPLEMENTED;
4543     return CR_CALL_NOT_IMPLEMENTED;
4544 }
4545 
4546 
4547 /* Function 55 */
4548 DWORD
4549 WINAPI
4550 PNP_SetHwProf(
4551     handle_t hBinding,
4552     DWORD ulHardwareProfile,
4553     DWORD ulFlags)
4554 {
4555     return CR_CALL_NOT_IMPLEMENTED;
4556 }
4557 
4558 
4559 /* Function 56 */
4560 DWORD
4561 WINAPI
4562 PNP_QueryArbitratorFreeData(
4563     handle_t hBinding,
4564     BYTE *pData,
4565     DWORD DataLen,
4566     LPWSTR pDeviceID,
4567     RESOURCEID ResourceID,
4568     DWORD ulFlags)
4569 {
4570     return CR_CALL_NOT_IMPLEMENTED;
4571 }
4572 
4573 
4574 /* Function 57 */
4575 DWORD
4576 WINAPI
4577 PNP_QueryArbitratorFreeSize(
4578     handle_t hBinding,
4579     DWORD *pulSize,
4580     LPWSTR pDeviceID,
4581     RESOURCEID ResourceID,
4582     DWORD ulFlags)
4583 {
4584     if (pulSize != NULL)
4585         *pulSize = 0;
4586 
4587     return CR_CALL_NOT_IMPLEMENTED;
4588 }
4589 
4590 
4591 /* Function 58 */
4592 CONFIGRET
4593 WINAPI
4594 PNP_RunDetection(
4595     handle_t hBinding,
4596     DWORD ulFlags)
4597 {
4598     return CR_CALL_NOT_IMPLEMENTED;
4599 }
4600 
4601 
4602 /* Function 59 */
4603 DWORD
4604 WINAPI
4605 PNP_RegisterNotification(
4606     handle_t hBinding,
4607     DWORD ulUnknown2,
4608     LPWSTR pszName,
4609     BYTE *pNotificationFilter,
4610     DWORD ulNotificationFilterSize,
4611     DWORD ulFlags,
4612     PNP_NOTIFY_HANDLE *pNotifyHandle,
4613     DWORD ulUnknown8,
4614     DWORD *pulUnknown9)
4615 {
4616     PDEV_BROADCAST_DEVICEINTERFACE_W pBroadcastDeviceInterface;
4617     PDEV_BROADCAST_HANDLE pBroadcastDeviceHandle;
4618     PNOTIFY_ENTRY pNotifyData = NULL;
4619 
4620     DPRINT1("PNP_RegisterNotification(%p %lx '%S' %p %lu 0x%lx %p %lx %p)\n",
4621            hBinding, ulUnknown2, pszName, pNotificationFilter,
4622            ulNotificationFilterSize, ulFlags, pNotifyHandle, ulUnknown8, pulUnknown9);
4623 
4624     if (pNotifyHandle == NULL)
4625         return CR_INVALID_POINTER;
4626 
4627     *pNotifyHandle = NULL;
4628 
4629     if (pNotificationFilter == NULL ||
4630         pulUnknown9 == NULL)
4631         return CR_INVALID_POINTER;
4632 
4633     if (ulFlags & ~0x7)
4634         return CR_INVALID_FLAG;
4635 
4636     if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_HDR)) ||
4637         (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_size < sizeof(DEV_BROADCAST_HDR)))
4638         return CR_INVALID_DATA;
4639 
4640     if (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
4641     {
4642         DPRINT1("DBT_DEVTYP_DEVICEINTERFACE\n");
4643         pBroadcastDeviceInterface = (PDEV_BROADCAST_DEVICEINTERFACE_W)pNotificationFilter;
4644 
4645         if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_DEVICEINTERFACE_W)) ||
4646             (pBroadcastDeviceInterface->dbcc_size < sizeof(DEV_BROADCAST_DEVICEINTERFACE_W)))
4647             return CR_INVALID_DATA;
4648 
4649         pNotifyData = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFY_ENTRY));
4650         if (pNotifyData == NULL)
4651             return CR_OUT_OF_MEMORY;
4652 
4653         if (pszName != NULL)
4654         {
4655             pNotifyData->pszName = RtlAllocateHeap(GetProcessHeap(),
4656                                                    HEAP_ZERO_MEMORY,
4657                                                    (wcslen(pszName) + 1) * sizeof(WCHAR));
4658             if (pNotifyData->pszName == NULL)
4659             {
4660                 RtlFreeHeap(GetProcessHeap(), 0, pNotifyData);
4661                 return CR_OUT_OF_MEMORY;
4662             }
4663         }
4664 
4665         /* Add the entry to the notification list */
4666         InsertTailList(&NotificationListHead, &pNotifyData->ListEntry);
4667 
4668         DPRINT("pNotifyData: %p\n", pNotifyData);
4669         *pNotifyHandle = (PNP_NOTIFY_HANDLE)pNotifyData;
4670     }
4671     else if (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype == DBT_DEVTYP_HANDLE)
4672     {
4673         DPRINT1("DBT_DEVTYP_HANDLE\n");
4674         pBroadcastDeviceHandle = (PDEV_BROADCAST_HANDLE)pNotificationFilter;
4675 
4676         if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_HANDLE)) ||
4677             (pBroadcastDeviceHandle->dbch_size < sizeof(DEV_BROADCAST_HANDLE)))
4678             return CR_INVALID_DATA;
4679 
4680         if (ulFlags & DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)
4681             return CR_INVALID_FLAG;
4682     }
4683     else
4684     {
4685         DPRINT1("Invalid device type %lu\n", ((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype);
4686         return CR_INVALID_DATA;
4687     }
4688 
4689     return CR_SUCCESS;
4690 }
4691 
4692 
4693 /* Function 60 */
4694 DWORD
4695 WINAPI
4696 PNP_UnregisterNotification(
4697     handle_t hBinding,
4698     PNP_NOTIFY_HANDLE *pNotifyHandle)
4699 {
4700     PNOTIFY_ENTRY pEntry;
4701 
4702     DPRINT1("PNP_UnregisterNotification(%p %p)\n",
4703            hBinding, pNotifyHandle);
4704 
4705     pEntry = (PNOTIFY_ENTRY)*pNotifyHandle;
4706     if (pEntry == NULL)
4707         return CR_INVALID_DATA;
4708 
4709     RemoveEntryList(&pEntry->ListEntry);
4710     if (pEntry->pszName)
4711         RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry->pszName);
4712     RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
4713     *pNotifyHandle = NULL;
4714 
4715     return CR_SUCCESS;
4716 }
4717 
4718 
4719 /* Function 61 */
4720 DWORD
4721 WINAPI
4722 PNP_GetCustomDevProp(
4723     handle_t hBinding,
4724     LPWSTR pDeviceID,
4725     LPWSTR CustomPropName,
4726     DWORD *pulRegDataType,
4727     BYTE *Buffer,
4728     PNP_RPC_STRING_LEN *pulTransferLen,
4729     PNP_RPC_STRING_LEN *pulLength,
4730     DWORD ulFlags)
4731 {
4732     HKEY hDeviceKey = NULL;
4733     HKEY hParamKey = NULL;
4734     LONG lError;
4735     CONFIGRET ret = CR_SUCCESS;
4736 
4737     UNREFERENCED_PARAMETER(hBinding);
4738 
4739     DPRINT("PNP_GetCustomDevProp() called\n");
4740 
4741     if (pulTransferLen == NULL || pulLength == NULL)
4742     {
4743         ret = CR_INVALID_POINTER;
4744         goto done;
4745     }
4746 
4747     if (ulFlags & ~CM_CUSTOMDEVPROP_BITS)
4748     {
4749         ret = CR_INVALID_FLAG;
4750         goto done;
4751     }
4752 
4753     if (!IsValidDeviceInstanceID(pDeviceID))
4754         return CR_INVALID_DEVINST;
4755 
4756     if (*pulLength < *pulTransferLen)
4757         *pulLength = *pulTransferLen;
4758 
4759     *pulTransferLen = 0;
4760 
4761     lError = RegOpenKeyExW(hEnumKey,
4762                            pDeviceID,
4763                            0,
4764                            KEY_READ,
4765                            &hDeviceKey);
4766     if (lError != ERROR_SUCCESS)
4767     {
4768         ret = CR_REGISTRY_ERROR;
4769         goto done;
4770     }
4771 
4772     lError = RegOpenKeyExW(hDeviceKey,
4773                            L"Device Parameters",
4774                            0,
4775                            KEY_READ,
4776                            &hParamKey);
4777     if (lError != ERROR_SUCCESS)
4778     {
4779         ret = CR_REGISTRY_ERROR;
4780         goto done;
4781     }
4782 
4783     lError = RegQueryValueExW(hParamKey,
4784                               CustomPropName,
4785                               NULL,
4786                               pulRegDataType,
4787                               Buffer,
4788                               pulLength);
4789     if (lError != ERROR_SUCCESS)
4790     {
4791         if (lError == ERROR_MORE_DATA)
4792         {
4793             ret = CR_BUFFER_SMALL;
4794         }
4795         else
4796         {
4797             *pulLength = 0;
4798             ret = CR_NO_SUCH_VALUE;
4799         }
4800     }
4801 
4802 done:
4803     if (ret == CR_SUCCESS)
4804         *pulTransferLen = *pulLength;
4805 
4806     if (hParamKey != NULL)
4807         RegCloseKey(hParamKey);
4808 
4809     if (hDeviceKey != NULL)
4810         RegCloseKey(hDeviceKey);
4811 
4812     DPRINT("PNP_GetCustomDevProp() done (returns %lx)\n", ret);
4813 
4814     return ret;
4815 }
4816 
4817 
4818 /* Function 62 */
4819 DWORD
4820 WINAPI
4821 PNP_GetVersionInternal(
4822     handle_t hBinding,
4823     WORD *pwVersion)
4824 {
4825     UNREFERENCED_PARAMETER(hBinding);
4826 
4827     *pwVersion = 0x501;
4828     return CR_SUCCESS;
4829 }
4830 
4831 
4832 /* Function 63 */
4833 DWORD
4834 WINAPI
4835 PNP_GetBlockedDriverInfo(
4836     handle_t hBinding,
4837     BYTE *Buffer,
4838     PNP_RPC_BUFFER_SIZE *pulTransferLen,
4839     PNP_RPC_BUFFER_SIZE *pulLength,
4840     DWORD ulFlags)
4841 {
4842     UNIMPLEMENTED;
4843     return CR_CALL_NOT_IMPLEMENTED;
4844 }
4845 
4846 
4847 /* Function 64 */
4848 DWORD
4849 WINAPI
4850 PNP_GetServerSideDeviceInstallFlags(
4851     handle_t hBinding,
4852     DWORD *pulSSDIFlags,
4853     DWORD ulFlags)
4854 {
4855     UNREFERENCED_PARAMETER(hBinding);
4856 
4857     DPRINT1("PNP_GetServerSideDeviceInstallFlags(%p %p %lu)\n",
4858             hBinding, pulSSDIFlags, ulFlags);
4859 
4860     if (pulSSDIFlags == NULL)
4861         return CR_INVALID_POINTER;
4862 
4863     if (ulFlags != 0)
4864         return CR_INVALID_FLAG;
4865 
4866     /* FIXME */
4867     *pulSSDIFlags = 0;
4868 
4869     return CR_SUCCESS;
4870 }
4871 
4872 
4873 /* Function 65 */
4874 DWORD
4875 WINAPI
4876 PNP_GetObjectPropKeys(
4877     handle_t hBinding,
4878     LPWSTR ObjectName,
4879     DWORD ObjectType,
4880     LPWSTR PropertyCultureName,
4881     PNP_PROP_COUNT *PropertyCount,
4882     PNP_PROP_COUNT *TransferLen,
4883     DEVPROPKEY *PropertyKeys,
4884     DWORD Flags)
4885 {
4886     UNIMPLEMENTED;
4887     return CR_CALL_NOT_IMPLEMENTED;
4888 }
4889 
4890 
4891 /* Function 66 */
4892 DWORD
4893 WINAPI
4894 PNP_GetObjectProp(
4895     handle_t hBinding,
4896     LPWSTR ObjectName,
4897     DWORD ObjectType,
4898     LPWSTR PropertyCultureName,
4899     const DEVPROPKEY *PropertyKey,
4900     DEVPROPTYPE *PropertyType,
4901     PNP_PROP_SIZE *PropertySize,
4902     PNP_PROP_SIZE *TransferLen,
4903     BYTE *PropertyBuffer,
4904     DWORD Flags)
4905 {
4906     UNIMPLEMENTED;
4907     return CR_CALL_NOT_IMPLEMENTED;
4908 }
4909 
4910 
4911 /* Function 67 */
4912 DWORD
4913 WINAPI
4914 PNP_SetObjectProp(
4915     handle_t hBinding,
4916     LPWSTR ObjectName,
4917     DWORD ObjectType,
4918     LPWSTR PropertyCultureName,
4919     const DEVPROPKEY *PropertyKey,
4920     DEVPROPTYPE PropertyType,
4921     PNP_PROP_SIZE PropertySize,
4922     BYTE *PropertyBuffer,
4923     DWORD Flags)
4924 {
4925     UNIMPLEMENTED;
4926     return CR_CALL_NOT_IMPLEMENTED;
4927 }
4928 
4929 
4930 /* Function 68 */
4931 DWORD
4932 WINAPI
4933 PNP_InstallDevInst(
4934     handle_t hBinding)
4935 {
4936     UNIMPLEMENTED;
4937     return CR_CALL_NOT_IMPLEMENTED;
4938 }
4939 
4940 
4941 /* Function 69 */
4942 DWORD
4943 WINAPI
4944 PNP_ApplyPowerSettings(
4945     handle_t hBinding)
4946 {
4947     UNIMPLEMENTED;
4948     return CR_CALL_NOT_IMPLEMENTED;
4949 }
4950 
4951 
4952 /* Function 70 */
4953 DWORD
4954 WINAPI
4955 PNP_DriverStoreAddDriverPackage(
4956     handle_t hBinding)
4957 {
4958     UNIMPLEMENTED;
4959     return CR_CALL_NOT_IMPLEMENTED;
4960 }
4961 
4962 
4963 /* Function 71 */
4964 DWORD
4965 WINAPI
4966 PNP_DriverStoreDeleteDriverPackage(
4967     handle_t hBinding)
4968 {
4969     UNIMPLEMENTED;
4970     return CR_CALL_NOT_IMPLEMENTED;
4971 }
4972 
4973 
4974 /* Function 72 */
4975 DWORD
4976 WINAPI
4977 PNP_RegisterServiceNotification(
4978     handle_t hBinding)
4979 {
4980     UNIMPLEMENTED;
4981     return CR_CALL_NOT_IMPLEMENTED;
4982 }
4983 
4984 
4985 /* Function 73 */
4986 DWORD
4987 WINAPI
4988 PNP_SetActiveService(
4989     handle_t hBinding,
4990     LPWSTR pszFilter,
4991     DWORD ulFlags)
4992 {
4993     UNIMPLEMENTED;
4994     return CR_CALL_NOT_IMPLEMENTED;
4995 }
4996 
4997 
4998 /* Function 74 */
4999 DWORD
5000 WINAPI
5001 PNP_DeleteServiceDevices(
5002     handle_t hBinding)
5003 {
5004     UNIMPLEMENTED;
5005     return CR_CALL_NOT_IMPLEMENTED;
5006 }
5007