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