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