xref: /reactos/base/services/umpnpmgr/rpcserver.c (revision 682f85ad)
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     HKEY hDeviceKey = NULL;
3011     DWORD dwDisableCount, dwSize;
3012     DWORD ulStatus, ulProblem;
3013     DWORD dwError;
3014     CONFIGRET ret = CR_SUCCESS;
3015 
3016     DPRINT1("SetupDeviceInstance(%S 0x%08lx)\n",
3017             pszDeviceInstance, ulMinorAction);
3018 
3019     if (IsRootDeviceInstanceID(pszDeviceInstance))
3020         return CR_INVALID_DEVINST;
3021 
3022     if (ulMinorAction & ~CM_SETUP_BITS)
3023         return CR_INVALID_FLAG;
3024 
3025     if ((ulMinorAction == CM_SETUP_DOWNLOAD) ||
3026         (ulMinorAction == CM_SETUP_WRITE_LOG_CONFS))
3027         return CR_SUCCESS;
3028 
3029     dwError = RegOpenKeyExW(hEnumKey,
3030                             pszDeviceInstance,
3031                             0,
3032                             KEY_READ,
3033                             &hDeviceKey);
3034     if (dwError != ERROR_SUCCESS)
3035         return CR_INVALID_DEVNODE;
3036 
3037     dwSize = sizeof(dwDisableCount);
3038     dwError = RegQueryValueExW(hDeviceKey,
3039                                L"DisableCount",
3040                                NULL,
3041                                NULL,
3042                                (LPBYTE)&dwDisableCount,
3043                                &dwSize);
3044     if ((dwError == ERROR_SUCCESS) &&
3045         (dwDisableCount > 0))
3046     {
3047         goto done;
3048     }
3049 
3050     GetDeviceStatus(pszDeviceInstance,
3051                     &ulStatus,
3052                     &ulProblem);
3053 
3054     if (ulStatus & DN_STARTED)
3055     {
3056         goto done;
3057     }
3058 
3059     if (ulStatus & DN_HAS_PROBLEM)
3060     {
3061         ret = ClearDeviceStatus(pszDeviceInstance,
3062                                 DN_HAS_PROBLEM,
3063                                 ulProblem);
3064     }
3065 
3066     if (ret != CR_SUCCESS)
3067         goto done;
3068 
3069 
3070     /* FIXME: Start the device */
3071 
3072 done:
3073     if (hDeviceKey != NULL)
3074         RegCloseKey(hDeviceKey);
3075 
3076     return ret;
3077 }
3078 
3079 
3080 static CONFIGRET
3081 EnableDeviceInstance(
3082     _In_ LPWSTR pszDeviceInstance)
3083 {
3084     PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
3085     CONFIGRET ret = CR_SUCCESS;
3086     NTSTATUS Status;
3087 
3088     DPRINT("Enable device instance %S\n", pszDeviceInstance);
3089 
3090     RtlInitUnicodeString(&ResetDeviceData.DeviceInstance,
3091                          pszDeviceInstance);
3092     Status = NtPlugPlayControl(PlugPlayControlResetDevice,
3093                                &ResetDeviceData,
3094                                sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
3095     if (!NT_SUCCESS(Status))
3096         ret = NtStatusToCrError(Status);
3097 
3098     return ret;
3099 }
3100 
3101 
3102 static CONFIGRET
3103 ReenumerateDeviceInstance(
3104     _In_ LPWSTR pszDeviceInstance,
3105     _In_ ULONG ulMinorAction)
3106 {
3107     PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA EnumerateDeviceData;
3108     CONFIGRET ret = CR_SUCCESS;
3109     NTSTATUS Status;
3110 
3111     DPRINT1("ReenumerateDeviceInstance(%S 0x%08lx)\n",
3112            pszDeviceInstance, ulMinorAction);
3113 
3114     if (ulMinorAction & ~CM_REENUMERATE_BITS)
3115         return CR_INVALID_FLAG;
3116 
3117     if (ulMinorAction & CM_REENUMERATE_RETRY_INSTALLATION)
3118     {
3119         DPRINT1("CM_REENUMERATE_RETRY_INSTALLATION not implemented!\n");
3120     }
3121 
3122     RtlInitUnicodeString(&EnumerateDeviceData.DeviceInstance,
3123                          pszDeviceInstance);
3124     EnumerateDeviceData.Flags = 0;
3125 
3126     Status = NtPlugPlayControl(PlugPlayControlEnumerateDevice,
3127                                &EnumerateDeviceData,
3128                                sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA));
3129     if (!NT_SUCCESS(Status))
3130         ret = NtStatusToCrError(Status);
3131 
3132     return ret;
3133 }
3134 
3135 
3136 /* Function 29 */
3137 DWORD
3138 WINAPI
3139 PNP_DeviceInstanceAction(
3140     handle_t hBinding,
3141     DWORD ulMajorAction,
3142     DWORD ulMinorAction,
3143     LPWSTR pszDeviceInstance1,
3144     LPWSTR pszDeviceInstance2)
3145 {
3146     CONFIGRET ret = CR_SUCCESS;
3147 
3148     UNREFERENCED_PARAMETER(hBinding);
3149 
3150     DPRINT("PNP_DeviceInstanceAction(%p %lu 0x%08lx %S %S)\n",
3151            hBinding, ulMajorAction, ulMinorAction,
3152            pszDeviceInstance1, pszDeviceInstance2);
3153 
3154     switch (ulMajorAction)
3155     {
3156         case PNP_DEVINST_SETUP:
3157             ret = SetupDeviceInstance(pszDeviceInstance1,
3158                                       ulMinorAction);
3159             break;
3160 
3161         case PNP_DEVINST_ENABLE:
3162             ret = EnableDeviceInstance(pszDeviceInstance1);
3163             break;
3164 
3165         case PNP_DEVINST_REENUMERATE:
3166             ret = ReenumerateDeviceInstance(pszDeviceInstance1,
3167                                             ulMinorAction);
3168             break;
3169 
3170         default:
3171             DPRINT1("Unknown device action %lu: not implemented\n", ulMajorAction);
3172             ret = CR_CALL_NOT_IMPLEMENTED;
3173     }
3174 
3175     DPRINT("PNP_DeviceInstanceAction() done (returns %lx)\n", ret);
3176 
3177     return ret;
3178 }
3179 
3180 
3181 /* Function 30 */
3182 DWORD
3183 WINAPI
3184 PNP_GetDeviceStatus(
3185     handle_t hBinding,
3186     LPWSTR pDeviceID,
3187     DWORD *pulStatus,
3188     DWORD *pulProblem,
3189     DWORD ulFlags)
3190 {
3191     UNREFERENCED_PARAMETER(hBinding);
3192     UNREFERENCED_PARAMETER(ulFlags);
3193 
3194     DPRINT("PNP_GetDeviceStatus(%p %S %p %p)\n",
3195            hBinding, pDeviceID, pulStatus, pulProblem, ulFlags);
3196 
3197     if (!IsValidDeviceInstanceID(pDeviceID))
3198         return CR_INVALID_DEVINST;
3199 
3200     return GetDeviceStatus(pDeviceID, pulStatus, pulProblem);
3201 }
3202 
3203 
3204 /* Function 31 */
3205 DWORD
3206 WINAPI
3207 PNP_SetDeviceProblem(
3208     handle_t hBinding,
3209     LPWSTR pDeviceID,
3210     DWORD ulProblem,
3211     DWORD ulFlags)
3212 {
3213     UNIMPLEMENTED;
3214     return CR_CALL_NOT_IMPLEMENTED;
3215 }
3216 
3217 
3218 /* Function 32 */
3219 DWORD
3220 WINAPI
3221 PNP_DisableDevInst(
3222     handle_t hBinding,
3223     LPWSTR pDeviceID,
3224     PPNP_VETO_TYPE pVetoType,
3225     LPWSTR pszVetoName,
3226     DWORD ulNameLength,
3227     DWORD ulFlags)
3228 {
3229     UNREFERENCED_PARAMETER(hBinding);
3230 
3231     DPRINT1("PNP_DisableDevInst(%p %S %p %p %lu 0x%08lx)\n",
3232             hBinding, pDeviceID, pVetoType, pszVetoName, ulNameLength, ulFlags);
3233 
3234     if (ulFlags & ~CM_DISABLE_BITS)
3235         return CR_INVALID_FLAG;
3236 
3237     if (!IsValidDeviceInstanceID(pDeviceID) ||
3238         IsRootDeviceInstanceID(pDeviceID))
3239         return CR_INVALID_DEVINST;
3240 
3241     return DisableDeviceInstance(pDeviceID,
3242                                  pVetoType,
3243                                  pszVetoName,
3244                                  ulNameLength);
3245 }
3246 
3247 
3248 /* Function 33 */
3249 DWORD
3250 WINAPI
3251 PNP_UninstallDevInst(
3252     handle_t hBinding,
3253     LPWSTR pDeviceID,
3254     DWORD ulFlags)
3255 {
3256     UNIMPLEMENTED;
3257     return CR_CALL_NOT_IMPLEMENTED;
3258 }
3259 
3260 
3261 static BOOL
3262 CheckForDeviceId(LPWSTR lpDeviceIdList,
3263                  LPWSTR lpDeviceId)
3264 {
3265     LPWSTR lpPtr;
3266     DWORD dwLength;
3267 
3268     lpPtr = lpDeviceIdList;
3269     while (*lpPtr != 0)
3270     {
3271         dwLength = wcslen(lpPtr);
3272         if (0 == _wcsicmp(lpPtr, lpDeviceId))
3273             return TRUE;
3274 
3275         lpPtr += (dwLength + 1);
3276     }
3277 
3278     return FALSE;
3279 }
3280 
3281 
3282 static VOID
3283 AppendDeviceId(LPWSTR lpDeviceIdList,
3284                LPDWORD lpDeviceIdListSize,
3285                LPWSTR lpDeviceId)
3286 {
3287     DWORD dwLen;
3288     DWORD dwPos;
3289 
3290     dwLen = wcslen(lpDeviceId);
3291     dwPos = (*lpDeviceIdListSize / sizeof(WCHAR)) - 1;
3292 
3293     wcscpy(&lpDeviceIdList[dwPos], lpDeviceId);
3294 
3295     dwPos += (dwLen + 1);
3296 
3297     lpDeviceIdList[dwPos] = 0;
3298 
3299     *lpDeviceIdListSize = dwPos * sizeof(WCHAR);
3300 }
3301 
3302 
3303 /* Function 34 */
3304 DWORD
3305 WINAPI
3306 PNP_AddID(
3307     handle_t hBinding,
3308     LPWSTR pszDeviceID,
3309     LPWSTR pszID,
3310     DWORD ulFlags)
3311 {
3312     CONFIGRET ret = CR_SUCCESS;
3313     HKEY hDeviceKey;
3314     LPWSTR pszSubKey;
3315     DWORD dwDeviceIdListSize;
3316     DWORD dwNewDeviceIdSize;
3317     WCHAR * pszDeviceIdList = NULL;
3318 
3319     UNREFERENCED_PARAMETER(hBinding);
3320 
3321     DPRINT("PNP_AddID(%p %S %S 0x%08lx)\n",
3322            hBinding, pszDeviceID, pszID, ulFlags);
3323 
3324     if (RegOpenKeyExW(hEnumKey,
3325                       pszDeviceID,
3326                       0,
3327                       KEY_QUERY_VALUE | KEY_SET_VALUE,
3328                       &hDeviceKey) != ERROR_SUCCESS)
3329     {
3330         DPRINT("Failed to open the device key!\n");
3331         return CR_INVALID_DEVNODE;
3332     }
3333 
3334     pszSubKey = (ulFlags & CM_ADD_ID_COMPATIBLE) ? L"CompatibleIDs" : L"HardwareID";
3335 
3336     if (RegQueryValueExW(hDeviceKey,
3337                          pszSubKey,
3338                          NULL,
3339                          NULL,
3340                          NULL,
3341                          &dwDeviceIdListSize) != ERROR_SUCCESS)
3342     {
3343         DPRINT("Failed to query the desired ID string!\n");
3344         ret = CR_REGISTRY_ERROR;
3345         goto Done;
3346     }
3347 
3348     dwNewDeviceIdSize = lstrlenW(pszDeviceID);
3349     if (!dwNewDeviceIdSize)
3350     {
3351         ret = CR_INVALID_POINTER;
3352         goto Done;
3353     }
3354 
3355     dwDeviceIdListSize += (dwNewDeviceIdSize + 2) * sizeof(WCHAR);
3356 
3357     pszDeviceIdList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDeviceIdListSize);
3358     if (!pszDeviceIdList)
3359     {
3360         DPRINT("Failed to allocate memory for the desired ID string!\n");
3361         ret = CR_OUT_OF_MEMORY;
3362         goto Done;
3363     }
3364 
3365     if (RegQueryValueExW(hDeviceKey,
3366                          pszSubKey,
3367                          NULL,
3368                          NULL,
3369                          (LPBYTE)pszDeviceIdList,
3370                          &dwDeviceIdListSize) != ERROR_SUCCESS)
3371     {
3372         DPRINT("Failed to query the desired ID string!\n");
3373         ret = CR_REGISTRY_ERROR;
3374         goto Done;
3375     }
3376 
3377     /* Check whether the device ID is already in use */
3378     if (CheckForDeviceId(pszDeviceIdList, pszDeviceID))
3379     {
3380         DPRINT("Device ID was found in the ID string!\n");
3381         ret = CR_SUCCESS;
3382         goto Done;
3383     }
3384 
3385     /* Append the Device ID */
3386     AppendDeviceId(pszDeviceIdList, &dwDeviceIdListSize, pszID);
3387 
3388     if (RegSetValueExW(hDeviceKey,
3389                        pszSubKey,
3390                        0,
3391                        REG_MULTI_SZ,
3392                        (LPBYTE)pszDeviceIdList,
3393                        dwDeviceIdListSize) != ERROR_SUCCESS)
3394     {
3395         DPRINT("Failed to set the desired ID string!\n");
3396         ret = CR_REGISTRY_ERROR;
3397     }
3398 
3399 Done:
3400     RegCloseKey(hDeviceKey);
3401     if (pszDeviceIdList)
3402         HeapFree(GetProcessHeap(), 0, pszDeviceIdList);
3403 
3404     DPRINT("PNP_AddID() done (returns %lx)\n", ret);
3405 
3406     return ret;
3407 }
3408 
3409 
3410 /* Function 35 */
3411 DWORD
3412 WINAPI
3413 PNP_RegisterDriver(
3414     handle_t hBinding,
3415     LPWSTR pszDeviceID,
3416     DWORD ulFlags)
3417 {
3418     DPRINT("PNP_RegisterDriver(%p %S 0x%lx)\n",
3419            hBinding, pszDeviceID, ulFlags);
3420 
3421     if (ulFlags & ~CM_REGISTER_DEVICE_DRIVER_BITS)
3422         return CR_INVALID_FLAG;
3423 
3424     if (!IsValidDeviceInstanceID(pszDeviceID))
3425         return CR_INVALID_DEVINST;
3426 
3427     SetDeviceStatus(pszDeviceID, 0, 0);
3428 
3429     return CR_SUCCESS;
3430 }
3431 
3432 
3433 /* Function 36 */
3434 DWORD
3435 WINAPI
3436 PNP_QueryRemove(
3437     handle_t hBinding,
3438     LPWSTR pszDeviceID,
3439     PPNP_VETO_TYPE pVetoType,
3440     LPWSTR pszVetoName,
3441     DWORD ulNameLength,
3442     DWORD ulFlags)
3443 {
3444     PLUGPLAY_CONTROL_QUERY_REMOVE_DATA PlugPlayData;
3445     NTSTATUS Status;
3446     DWORD ret = CR_SUCCESS;
3447 
3448     DPRINT1("PNP_QueryRemove(%p %S %p %p %lu 0x%lx)\n",
3449             hBinding, pszDeviceID, pVetoType, pszVetoName,
3450             ulNameLength, ulFlags);
3451 
3452     if (ulFlags & ~CM_REMOVE_BITS)
3453         return CR_INVALID_FLAG;
3454 
3455     if (!IsValidDeviceInstanceID(pszDeviceID) ||
3456         IsRootDeviceInstanceID(pszDeviceID))
3457         return CR_INVALID_DEVINST;
3458 
3459     if (pVetoType != NULL)
3460         *pVetoType = PNP_VetoTypeUnknown;
3461 
3462     if (pszVetoName != NULL && ulNameLength > 0)
3463         *pszVetoName = UNICODE_NULL;
3464 
3465     RtlZeroMemory(&PlugPlayData, sizeof(PlugPlayData));
3466     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
3467                          pszDeviceID);
3468     PlugPlayData.VetoName = pszVetoName;
3469     PlugPlayData.NameLength = ulNameLength;
3470 //    PlugPlayData.Flags =
3471 
3472     Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
3473                                &PlugPlayData,
3474                                sizeof(PlugPlayData));
3475     if (!NT_SUCCESS(Status))
3476         ret = NtStatusToCrError(Status);
3477 
3478     return ret;
3479 }
3480 
3481 
3482 /* Function 37 */
3483 DWORD
3484 WINAPI
3485 PNP_RequestDeviceEject(
3486     handle_t hBinding,
3487     LPWSTR pszDeviceID,
3488     PPNP_VETO_TYPE pVetoType,
3489     LPWSTR pszVetoName,
3490     DWORD ulNameLength,
3491     DWORD ulFlags)
3492 {
3493     PLUGPLAY_CONTROL_QUERY_REMOVE_DATA PlugPlayData;
3494     NTSTATUS Status;
3495     DWORD ret = CR_SUCCESS;
3496 
3497     DPRINT1("PNP_RequestDeviceEject(%p %S %p %p %lu 0x%lx)\n",
3498             hBinding, pszDeviceID, pVetoType, pszVetoName,
3499             ulNameLength, ulFlags);
3500 
3501     if (ulFlags != 0)
3502         return CR_INVALID_FLAG;
3503 
3504     if (!IsValidDeviceInstanceID(pszDeviceID))
3505         return CR_INVALID_DEVINST;
3506 
3507     if (pVetoType != NULL)
3508         *pVetoType = PNP_VetoTypeUnknown;
3509 
3510     if (pszVetoName != NULL && ulNameLength > 0)
3511         *pszVetoName = UNICODE_NULL;
3512 
3513     RtlZeroMemory(&PlugPlayData, sizeof(PlugPlayData));
3514     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
3515                          pszDeviceID);
3516     PlugPlayData.VetoName = pszVetoName;
3517     PlugPlayData.NameLength = ulNameLength;
3518 //    PlugPlayData.Flags =
3519 
3520     Status = NtPlugPlayControl(PlugPlayControlQueryAndRemoveDevice,
3521                                &PlugPlayData,
3522                                sizeof(PlugPlayData));
3523     if (!NT_SUCCESS(Status))
3524         ret = NtStatusToCrError(Status);
3525 
3526     return ret;
3527 }
3528 
3529 
3530 /* Function 38 */
3531 CONFIGRET
3532 WINAPI
3533 PNP_IsDockStationPresent(
3534     handle_t hBinding,
3535     BOOL *Present)
3536 {
3537     HKEY hKey;
3538     DWORD dwType;
3539     DWORD dwValue;
3540     DWORD dwSize;
3541     CONFIGRET ret = CR_SUCCESS;
3542 
3543     UNREFERENCED_PARAMETER(hBinding);
3544 
3545     DPRINT1("PNP_IsDockStationPresent(%p %p)\n",
3546             hBinding, Present);
3547 
3548     *Present = FALSE;
3549 
3550     if (RegOpenKeyExW(HKEY_CURRENT_CONFIG,
3551                       L"CurrentDockInfo",
3552                       0,
3553                       KEY_READ,
3554                       &hKey) != ERROR_SUCCESS)
3555         return CR_REGISTRY_ERROR;
3556 
3557     dwSize = sizeof(DWORD);
3558     if (RegQueryValueExW(hKey,
3559                          L"DockingState",
3560                          NULL,
3561                          &dwType,
3562                          (LPBYTE)&dwValue,
3563                          &dwSize) != ERROR_SUCCESS)
3564         ret = CR_REGISTRY_ERROR;
3565 
3566     RegCloseKey(hKey);
3567 
3568     if (ret == CR_SUCCESS)
3569     {
3570         if (dwType != REG_DWORD || dwSize != sizeof(DWORD))
3571         {
3572             ret = CR_REGISTRY_ERROR;
3573         }
3574         else if (dwValue != 0)
3575         {
3576             *Present = TRUE;
3577         }
3578     }
3579 
3580     DPRINT1("PNP_IsDockStationPresent() done (returns %lx)\n", ret);
3581 
3582     return ret;
3583 }
3584 
3585 
3586 /* Function 39 */
3587 DWORD
3588 WINAPI
3589 PNP_RequestEjectPC(
3590     handle_t hBinding)
3591 {
3592     WCHAR szDockDeviceInstance[MAX_DEVICE_ID_LEN];
3593     PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA DockData;
3594     NTSTATUS Status;
3595 
3596     DPRINT("PNP_RequestEjectPC(%p)\n", hBinding);
3597 
3598     /* Retrieve the dock device */
3599     DockData.DeviceInstanceLength = ARRAYSIZE(szDockDeviceInstance);
3600     DockData.DeviceInstance = szDockDeviceInstance;
3601 
3602     Status = NtPlugPlayControl(PlugPlayControlRetrieveDock,
3603                                &DockData,
3604                                sizeof(DockData));
3605     if (!NT_SUCCESS(Status))
3606         return NtStatusToCrError(Status);
3607 
3608     /* Eject the dock device */
3609     return PNP_RequestDeviceEject(hBinding,
3610                                   szDockDeviceInstance,
3611                                   NULL,
3612                                   NULL,
3613                                   0,
3614                                   0);
3615 }
3616 
3617 
3618 /* Function 40 */
3619 DWORD
3620 WINAPI
3621 PNP_HwProfFlags(
3622     handle_t hBinding,
3623     DWORD ulAction,
3624     LPWSTR pDeviceID,
3625     DWORD ulConfig,
3626     DWORD *pulValue,
3627     PPNP_VETO_TYPE pVetoType,
3628     LPWSTR pszVetoName,
3629     DWORD ulNameLength,
3630     DWORD ulFlags)
3631 {
3632     CONFIGRET ret = CR_SUCCESS;
3633     WCHAR szKeyName[MAX_PATH];
3634     HKEY hKey;
3635     HKEY hDeviceKey;
3636     DWORD dwSize;
3637 
3638     UNREFERENCED_PARAMETER(hBinding);
3639 
3640     DPRINT("PNP_HwProfFlags() called\n");
3641 
3642     if (!IsValidDeviceInstanceID(pDeviceID))
3643         return CR_INVALID_DEVINST;
3644 
3645     if (ulConfig == 0)
3646     {
3647         wcscpy(szKeyName,
3648                L"System\\CurrentControlSet\\HardwareProfiles\\Current\\System\\CurrentControlSet\\Enum");
3649     }
3650     else
3651     {
3652         swprintf(szKeyName,
3653                  L"System\\CurrentControlSet\\HardwareProfiles\\%04lu\\System\\CurrentControlSet\\Enum",
3654                  ulConfig);
3655     }
3656 
3657     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3658                       szKeyName,
3659                       0,
3660                       KEY_QUERY_VALUE,
3661                       &hKey) != ERROR_SUCCESS)
3662         return CR_REGISTRY_ERROR;
3663 
3664     if (ulAction == PNP_GET_HWPROFFLAGS)
3665     {
3666          if (RegOpenKeyExW(hKey,
3667                            pDeviceID,
3668                            0,
3669                            KEY_QUERY_VALUE,
3670                            &hDeviceKey) != ERROR_SUCCESS)
3671          {
3672             *pulValue = 0;
3673          }
3674          else
3675          {
3676              dwSize = sizeof(DWORD);
3677              if (RegQueryValueExW(hDeviceKey,
3678                                   L"CSConfigFlags",
3679                                   NULL,
3680                                   NULL,
3681                                   (LPBYTE)pulValue,
3682                                   &dwSize) != ERROR_SUCCESS)
3683              {
3684                  *pulValue = 0;
3685              }
3686 
3687              RegCloseKey(hDeviceKey);
3688          }
3689     }
3690     else if (ulAction == PNP_SET_HWPROFFLAGS)
3691     {
3692         /* FIXME: not implemented yet */
3693         ret = CR_CALL_NOT_IMPLEMENTED;
3694     }
3695 
3696     RegCloseKey(hKey);
3697 
3698     return ret;
3699 }
3700 
3701 
3702 /* Function 41 */
3703 DWORD
3704 WINAPI
3705 PNP_GetHwProfInfo(
3706     handle_t hBinding,
3707     DWORD ulIndex,
3708     HWPROFILEINFO *pHWProfileInfo,
3709     DWORD ulProfileInfoSize,
3710     DWORD ulFlags)
3711 {
3712     WCHAR szProfileName[5];
3713     HKEY hKeyConfig = NULL;
3714     HKEY hKeyProfiles = NULL;
3715     HKEY hKeyProfile = NULL;
3716     DWORD dwDisposition;
3717     DWORD dwSize;
3718     LONG lError;
3719     CONFIGRET ret = CR_SUCCESS;
3720 
3721     UNREFERENCED_PARAMETER(hBinding);
3722 
3723     DPRINT("PNP_GetHwProfInfo() called\n");
3724 
3725     if (ulProfileInfoSize == 0)
3726     {
3727         ret = CR_INVALID_DATA;
3728         goto done;
3729     }
3730 
3731     if (ulFlags != 0)
3732     {
3733         ret = CR_INVALID_FLAG;
3734         goto done;
3735     }
3736 
3737     /* Initialize the profile information */
3738     pHWProfileInfo->HWPI_ulHWProfile = 0;
3739     pHWProfileInfo->HWPI_szFriendlyName[0] = 0;
3740     pHWProfileInfo->HWPI_dwFlags = 0;
3741 
3742     /* Open the 'IDConfigDB' key */
3743     lError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3744                              L"System\\CurrentControlSet\\Control\\IDConfigDB",
3745                              0,
3746                              NULL,
3747                              REG_OPTION_NON_VOLATILE,
3748                              KEY_QUERY_VALUE,
3749                              NULL,
3750                              &hKeyConfig,
3751                              &dwDisposition);
3752     if (lError != ERROR_SUCCESS)
3753     {
3754         ret = CR_REGISTRY_ERROR;
3755         goto done;
3756     }
3757 
3758     /* Open the 'Hardware Profiles' subkey */
3759     lError = RegCreateKeyExW(hKeyConfig,
3760                              L"Hardware Profiles",
3761                              0,
3762                              NULL,
3763                              REG_OPTION_NON_VOLATILE,
3764                              KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
3765                              NULL,
3766                              &hKeyProfiles,
3767                              &dwDisposition);
3768     if (lError != ERROR_SUCCESS)
3769     {
3770         ret = CR_REGISTRY_ERROR;
3771         goto done;
3772     }
3773 
3774     if (ulIndex == (ULONG)-1)
3775     {
3776         dwSize = sizeof(ULONG);
3777         lError = RegQueryValueExW(hKeyConfig,
3778                                   L"CurrentConfig",
3779                                   NULL,
3780                                   NULL,
3781                                   (LPBYTE)&pHWProfileInfo->HWPI_ulHWProfile,
3782                                   &dwSize);
3783         if (lError != ERROR_SUCCESS)
3784         {
3785             pHWProfileInfo->HWPI_ulHWProfile = 0;
3786             ret = CR_REGISTRY_ERROR;
3787             goto done;
3788         }
3789     }
3790     else
3791     {
3792         /* FIXME: not implemented yet */
3793         ret = CR_CALL_NOT_IMPLEMENTED;
3794         goto done;
3795     }
3796 
3797     swprintf(szProfileName, L"%04lu", pHWProfileInfo->HWPI_ulHWProfile);
3798 
3799     lError = RegOpenKeyExW(hKeyProfiles,
3800                            szProfileName,
3801                            0,
3802                            KEY_QUERY_VALUE,
3803                            &hKeyProfile);
3804     if (lError != ERROR_SUCCESS)
3805     {
3806         ret = CR_REGISTRY_ERROR;
3807         goto done;
3808     }
3809 
3810     dwSize = sizeof(pHWProfileInfo->HWPI_szFriendlyName);
3811     lError = RegQueryValueExW(hKeyProfile,
3812                               L"FriendlyName",
3813                               NULL,
3814                               NULL,
3815                               (LPBYTE)&pHWProfileInfo->HWPI_szFriendlyName,
3816                               &dwSize);
3817     if (lError != ERROR_SUCCESS)
3818     {
3819         ret = CR_REGISTRY_ERROR;
3820         goto done;
3821     }
3822 
3823 done:
3824     if (hKeyProfile != NULL)
3825         RegCloseKey(hKeyProfile);
3826 
3827     if (hKeyProfiles != NULL)
3828         RegCloseKey(hKeyProfiles);
3829 
3830     if (hKeyConfig != NULL)
3831         RegCloseKey(hKeyConfig);
3832 
3833     return ret;
3834 }
3835 
3836 
3837 /* Function 42 */
3838 DWORD
3839 WINAPI
3840 PNP_AddEmptyLogConf(
3841     handle_t hBinding,
3842     LPWSTR pDeviceID,
3843     DWORD ulPriority,
3844     DWORD *pulLogConfTag,
3845     DWORD ulFlags)
3846 {
3847     UNIMPLEMENTED;
3848     return CR_CALL_NOT_IMPLEMENTED;
3849 }
3850 
3851 
3852 /* Function 43 */
3853 DWORD
3854 WINAPI
3855 PNP_FreeLogConf(
3856     handle_t hBinding,
3857     LPWSTR pDeviceID,
3858     DWORD ulLogConfType,
3859     DWORD ulLogConfTag,
3860     DWORD ulFlags)
3861 {
3862     UNIMPLEMENTED;
3863     return CR_CALL_NOT_IMPLEMENTED;
3864 }
3865 
3866 
3867 /* Function 44 */
3868 DWORD
3869 WINAPI
3870 PNP_GetFirstLogConf(
3871     handle_t hBinding,
3872     LPWSTR pDeviceID,
3873     DWORD ulLogConfType,
3874     DWORD *pulLogConfTag,
3875     DWORD ulFlags)
3876 {
3877     HKEY hConfigKey = NULL;
3878     DWORD RegDataType = 0;
3879     ULONG ulDataSize = 0;
3880     LPBYTE lpData = NULL;
3881     CONFIGRET ret = CR_SUCCESS;
3882 
3883     DPRINT("PNP_GetFirstLogConf(%p %S %lu %p 0x%08lx)\n",
3884            hBinding, pDeviceID, ulLogConfType, pulLogConfTag, ulFlags);
3885 
3886     if (pulLogConfTag == NULL)
3887         return CR_INVALID_POINTER;
3888 
3889     *pulLogConfTag = (DWORD)0;
3890 
3891     if (ulFlags & ~LOG_CONF_BITS)
3892         return CR_INVALID_FLAG;
3893 
3894     if (!IsValidDeviceInstanceID(pDeviceID))
3895         return CR_INVALID_DEVINST;
3896 
3897     ret = OpenConfigurationKey(pDeviceID,
3898                                &hConfigKey);
3899     if (ret != CR_SUCCESS)
3900     {
3901         DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
3902         ret = CR_NO_MORE_LOG_CONF;
3903         goto done;
3904     }
3905 
3906     ret = GetConfigurationData(hConfigKey,
3907                                ulLogConfType,
3908                                &RegDataType,
3909                                &ulDataSize,
3910                                &lpData);
3911     if (ret != CR_SUCCESS)
3912     {
3913         DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
3914         ret = CR_NO_MORE_LOG_CONF;
3915         goto done;
3916     }
3917 
3918     DPRINT("Data size %lu\n", ulDataSize);
3919     if (ulDataSize == 0 || lpData == NULL)
3920     {
3921         DPRINT1("No config data available!\n");
3922         ret = CR_NO_MORE_LOG_CONF;
3923         goto done;
3924     }
3925 
3926     /* Get the first tag */
3927     if (RegDataType == REG_RESOURCE_LIST)
3928     {
3929         DPRINT("REG_RESOURCE_LIST\n");
3930 
3931         DPRINT("ResourceList->Count %lu\n", ((PCM_RESOURCE_LIST)lpData)->Count);
3932         if (((PCM_RESOURCE_LIST)lpData)->Count == 0)
3933         {
3934             DPRINT1("No resource descriptors!\n");
3935             ret = CR_NO_MORE_LOG_CONF;
3936             goto done;
3937         }
3938 
3939         DPRINT("lpData %p\n", lpData);
3940         DPRINT("&List[0] %p\n", &(((PCM_RESOURCE_LIST)lpData)->List[0]));
3941 
3942         *pulLogConfTag = (DWORD)((DWORD_PTR)&(((PCM_RESOURCE_LIST)lpData)->List[0]) - (DWORD_PTR)lpData);
3943         DPRINT("Offset (Tag): 0x%08lx\n", *pulLogConfTag);
3944     }
3945     else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
3946     {
3947         DPRINT1("FIXME: REG_RESOURCE_REQUIREMENTS_LIST\n");
3948         /* FIXME */
3949         ret = CR_NO_MORE_LOG_CONF;
3950         goto done;
3951     }
3952 
3953 done:
3954     if (lpData != NULL)
3955         HeapFree(GetProcessHeap(), 0, lpData);
3956 
3957     if (hConfigKey != NULL)
3958         RegCloseKey(hConfigKey);
3959 
3960     DPRINT("PNP_GetFirstLogConf() returns %lu\n", ret);
3961 
3962     return ret;
3963 }
3964 
3965 
3966 /* Function 45 */
3967 DWORD
3968 WINAPI
3969 PNP_GetNextLogConf(
3970     handle_t hBinding,
3971     LPWSTR pDeviceID,
3972     DWORD ulLogConfType,
3973     DWORD ulCurrentTag,
3974     DWORD *pulNextTag,
3975     DWORD ulFlags)
3976 {
3977     HKEY hConfigKey = NULL;
3978     DWORD RegDataType = 0;
3979     ULONG ulDataSize = 0;
3980     LPBYTE lpData = NULL;
3981     CONFIGRET ret = CR_SUCCESS;
3982 
3983     DPRINT("PNP_GetNextLogConf(%p %S %lu %ul %p 0x%08lx)\n",
3984            hBinding, pDeviceID, ulLogConfType, ulCurrentTag, pulNextTag, ulFlags);
3985 
3986     if (pulNextTag == NULL)
3987         return CR_INVALID_POINTER;
3988 
3989     *pulNextTag = (DWORD)0;
3990 
3991     if (ulFlags != 0)
3992         return CR_INVALID_FLAG;
3993 
3994     if (!IsValidDeviceInstanceID(pDeviceID))
3995         return CR_INVALID_DEVINST;
3996 
3997     ret = OpenConfigurationKey(pDeviceID,
3998                                &hConfigKey);
3999     if (ret != CR_SUCCESS)
4000     {
4001         DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
4002         ret = CR_NO_MORE_LOG_CONF;
4003         goto done;
4004     }
4005 
4006     ret = GetConfigurationData(hConfigKey,
4007                                ulLogConfType,
4008                                &RegDataType,
4009                                &ulDataSize,
4010                                &lpData);
4011     if (ret != CR_SUCCESS)
4012     {
4013         DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
4014         ret = CR_NO_MORE_LOG_CONF;
4015         goto done;
4016     }
4017 
4018     DPRINT("Data size %lu\n", ulDataSize);
4019 
4020     if (ulDataSize == 0 || lpData == NULL)
4021     {
4022         DPRINT1("No config data available!\n");
4023         ret = CR_NO_MORE_LOG_CONF;
4024         goto done;
4025     }
4026 
4027     /* FIXME: Get the next tag */
4028     if (RegDataType == REG_RESOURCE_LIST)
4029     {
4030         DPRINT1("FIXME: REG_RESOURCE_LIST\n");
4031         /* FIXME */
4032         ret = CR_NO_MORE_LOG_CONF;
4033         goto done;
4034     }
4035     else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
4036     {
4037         DPRINT1("FIXME: REG_RESOURCE_REQUIREMENTS_LIST\n");
4038         /* FIXME */
4039         ret = CR_NO_MORE_LOG_CONF;
4040         goto done;
4041     }
4042 
4043 done:
4044     if (lpData != NULL)
4045         HeapFree(GetProcessHeap(), 0, lpData);
4046 
4047     if (hConfigKey != NULL)
4048         RegCloseKey(hConfigKey);
4049 
4050     DPRINT("PNP_GetNextLogConf() returns %lu\n", ret);
4051 
4052     return ret;
4053 }
4054 
4055 
4056 /* Function 46 */
4057 DWORD
4058 WINAPI
4059 PNP_GetLogConfPriority(
4060     handle_t hBinding,
4061     LPWSTR pDeviceID,
4062     DWORD ulType,
4063     DWORD ulTag,
4064     DWORD *pPriority,
4065     DWORD ulFlags)
4066 {
4067     UNIMPLEMENTED;
4068     return CR_CALL_NOT_IMPLEMENTED;
4069 }
4070 
4071 
4072 /* Function 47 */
4073 DWORD
4074 WINAPI
4075 PNP_AddResDes(
4076     handle_t hBinding,
4077     LPWSTR pDeviceID,
4078     DWORD ulLogConfTag,
4079     DWORD ulLogConfType,
4080     RESOURCEID ResourceID,
4081     DWORD *pulResourceTag,
4082     BYTE *ResourceData,
4083     PNP_RPC_BUFFER_SIZE ResourceLen,
4084     DWORD ulFlags)
4085 {
4086     UNIMPLEMENTED;
4087     return CR_CALL_NOT_IMPLEMENTED;
4088 }
4089 
4090 
4091 /* Function 48 */
4092 DWORD
4093 WINAPI
4094 PNP_FreeResDes(
4095     handle_t hBinding,
4096     LPWSTR pDeviceID,
4097     DWORD ulLogConfTag,
4098     DWORD ulLogConfType,
4099     RESOURCEID ResourceID,
4100     DWORD ulResourceTag,
4101     DWORD *pulPreviousResType,
4102     DWORD *pulPreviousResTag,
4103     DWORD ulFlags)
4104 {
4105     UNIMPLEMENTED;
4106     return CR_CALL_NOT_IMPLEMENTED;
4107 }
4108 
4109 
4110 /* Function 49 */
4111 DWORD
4112 WINAPI
4113 PNP_GetNextResDes(
4114     handle_t hBinding,
4115     LPWSTR pDeviceID,
4116     DWORD ulLogConfTag,
4117     DWORD ulLogConfType,
4118     RESOURCEID ResourceID,
4119     DWORD ulResourceTag,
4120     DWORD *pulNextResType,
4121     DWORD *pulNextResTag,
4122     DWORD ulFlags)
4123 {
4124     HKEY hConfigKey = NULL;
4125     DWORD RegDataType = 0;
4126     ULONG ulDataSize = 0;
4127     LPBYTE lpData = NULL;
4128     CONFIGRET ret = CR_SUCCESS;
4129 
4130     DPRINT1("PNP_GetNextResDes(%p %S 0x%lx %lu %lu %ul %p %p 0x%08lx)\n",
4131            hBinding, pDeviceID, ulLogConfTag, ulLogConfType, ResourceID,
4132            ulResourceTag, pulNextResType, pulNextResTag, ulFlags);
4133 
4134     if (pulNextResType == NULL)
4135         return CR_INVALID_POINTER;
4136 
4137     *pulNextResType = 0;
4138 
4139     if (ulFlags != 0)
4140         return CR_INVALID_FLAG;
4141 
4142     if (!IsValidDeviceInstanceID(pDeviceID))
4143         return CR_INVALID_DEVINST;
4144 
4145     ret = OpenConfigurationKey(pDeviceID,
4146                                &hConfigKey);
4147     if (ret != CR_SUCCESS)
4148     {
4149         DPRINT1("OpenConfigurationKey() failed (Error %lu)\n", ret);
4150         ret = CR_NO_MORE_LOG_CONF;
4151         goto done;
4152     }
4153 
4154     ret = GetConfigurationData(hConfigKey,
4155                                ulLogConfType,
4156                                &RegDataType,
4157                                &ulDataSize,
4158                                &lpData);
4159     if (ret != CR_SUCCESS)
4160     {
4161         DPRINT1("GetConfigurationData() failed (Error %lu)\n", ret);
4162         ret = CR_NO_MORE_LOG_CONF;
4163         goto done;
4164     }
4165 
4166     DPRINT1("Data size %lu\n", ulDataSize);
4167 
4168     if (ulDataSize == 0 || lpData == NULL)
4169     {
4170         DPRINT1("No config data available!\n");
4171         ret = CR_NO_MORE_LOG_CONF;
4172         goto done;
4173     }
4174 
4175     /* Get the next resource descriptor */
4176     if (RegDataType == REG_RESOURCE_LIST)
4177     {
4178         DPRINT1("FIXME: REG_RESOURCE_LIST\n");
4179         /* FIXME */
4180         ret = CR_NO_MORE_LOG_CONF;
4181         goto done;
4182     }
4183     else if (RegDataType == REG_RESOURCE_REQUIREMENTS_LIST)
4184     {
4185         DPRINT1("FIXME: REG_RESOURCE_REQUIREMENTS_LIST\n");
4186         /* FIXME */
4187         ret = CR_NO_MORE_LOG_CONF;
4188         goto done;
4189     }
4190 
4191 done:
4192     if (lpData != NULL)
4193         HeapFree(GetProcessHeap(), 0, lpData);
4194 
4195     if (hConfigKey != NULL)
4196         RegCloseKey(hConfigKey);
4197 
4198     DPRINT1("PNP_GetNextResDes() returns %lu\n", ret);
4199 
4200     return ret;
4201 }
4202 
4203 
4204 /* Function 50 */
4205 DWORD
4206 WINAPI
4207 PNP_GetResDesData(
4208     handle_t hBinding,
4209     LPWSTR pDeviceID,
4210     DWORD ulLogConfTag,
4211     DWORD ulLogConfType,
4212     RESOURCEID ResourceID,
4213     DWORD ulResourceTag,
4214     BYTE *Buffer,
4215     PNP_RPC_BUFFER_SIZE BufferLen,
4216     DWORD ulFlags)
4217 {
4218     UNIMPLEMENTED;
4219     return CR_CALL_NOT_IMPLEMENTED;
4220 }
4221 
4222 
4223 /* Function 51 */
4224 DWORD
4225 WINAPI
4226 PNP_GetResDesDataSize(
4227     handle_t hBinding,
4228     LPWSTR pDeviceID,
4229     DWORD ulLogConfTag,
4230     DWORD ulLogConfType,
4231     RESOURCEID ResourceID,
4232     DWORD ulResourceTag,
4233     DWORD *pulSize,
4234     DWORD ulFlags)
4235 {
4236     UNIMPLEMENTED;
4237     return CR_CALL_NOT_IMPLEMENTED;
4238 }
4239 
4240 
4241 /* Function 52 */
4242 DWORD
4243 WINAPI
4244 PNP_ModifyResDes(
4245     handle_t hBinding,
4246     LPWSTR pDeviceID,
4247     DWORD ulLogConfTag,
4248     DWORD ulLogConfType,
4249     RESOURCEID CurrentResourceID,
4250     RESOURCEID NewResourceID,
4251     DWORD ulResourceTag,
4252     BYTE *ResourceData,
4253     PNP_RPC_BUFFER_SIZE ResourceLen,
4254     DWORD ulFlags)
4255 {
4256     UNIMPLEMENTED;
4257     return CR_CALL_NOT_IMPLEMENTED;
4258 }
4259 
4260 
4261 /* Function 53 */
4262 DWORD
4263 WINAPI
4264 PNP_DetectResourceConflict(
4265     handle_t hBinding,
4266     LPWSTR pDeviceID,
4267     RESOURCEID ResourceID,
4268     BYTE *ResourceData,
4269     PNP_RPC_BUFFER_SIZE ResourceLen,
4270     BOOL *pbConflictDetected,
4271     DWORD ulFlags)
4272 {
4273     DPRINT("PNP_DetectResourceConflict()\n");
4274 
4275     if (pbConflictDetected != NULL)
4276         *pbConflictDetected = FALSE;
4277 
4278     return CR_CALL_NOT_IMPLEMENTED;
4279 }
4280 
4281 
4282 /* Function 54 */
4283 DWORD
4284 WINAPI
4285 PNP_QueryResConfList(
4286     handle_t hBinding,
4287     LPWSTR pDeviceID,
4288     RESOURCEID ResourceID,
4289     BYTE *ResourceData,
4290     PNP_RPC_BUFFER_SIZE ResourceLen,
4291     BYTE *Buffer,
4292     PNP_RPC_BUFFER_SIZE BufferLen,
4293     DWORD ulFlags)
4294 {
4295     UNIMPLEMENTED;
4296     return CR_CALL_NOT_IMPLEMENTED;
4297 }
4298 
4299 
4300 /* Function 55 */
4301 DWORD
4302 WINAPI
4303 PNP_SetHwProf(
4304     handle_t hBinding,
4305     DWORD ulHardwareProfile,
4306     DWORD ulFlags)
4307 {
4308     return CR_CALL_NOT_IMPLEMENTED;
4309 }
4310 
4311 
4312 /* Function 56 */
4313 DWORD
4314 WINAPI
4315 PNP_QueryArbitratorFreeData(
4316     handle_t hBinding,
4317     BYTE *pData,
4318     DWORD DataLen,
4319     LPWSTR pDeviceID,
4320     RESOURCEID ResourceID,
4321     DWORD ulFlags)
4322 {
4323     return CR_CALL_NOT_IMPLEMENTED;
4324 }
4325 
4326 
4327 /* Function 57 */
4328 DWORD
4329 WINAPI
4330 PNP_QueryArbitratorFreeSize(
4331     handle_t hBinding,
4332     DWORD *pulSize,
4333     LPWSTR pDeviceID,
4334     RESOURCEID ResourceID,
4335     DWORD ulFlags)
4336 {
4337     if (pulSize != NULL)
4338         *pulSize = 0;
4339 
4340     return CR_CALL_NOT_IMPLEMENTED;
4341 }
4342 
4343 
4344 /* Function 58 */
4345 CONFIGRET
4346 WINAPI
4347 PNP_RunDetection(
4348     handle_t hBinding,
4349     DWORD ulFlags)
4350 {
4351     return CR_CALL_NOT_IMPLEMENTED;
4352 }
4353 
4354 
4355 /* Function 59 */
4356 DWORD
4357 WINAPI
4358 PNP_RegisterNotification(
4359     handle_t hBinding,
4360     DWORD ulUnknown2,
4361     LPWSTR pszName,
4362     BYTE *pNotificationFilter,
4363     DWORD ulNotificationFilterSize,
4364     DWORD ulFlags,
4365     DWORD *pulNotify,
4366     DWORD ulUnknown8,
4367     DWORD *pulUnknown9)
4368 {
4369     PDEV_BROADCAST_DEVICEINTERFACE_W pBroadcastDeviceInterface;
4370     PDEV_BROADCAST_HANDLE pBroadcastDeviceHandle;
4371 #if 0
4372     PNOTIFY_DATA pNotifyData;
4373 #endif
4374 
4375     DPRINT1("PNP_RegisterNotification(%p %lx '%S' %p %lu 0x%lx %p %lx %p)\n",
4376            hBinding, ulUnknown2, pszName, pNotificationFilter,
4377            ulNotificationFilterSize, ulFlags, pulNotify, ulUnknown8, pulUnknown9);
4378 
4379     if (pNotificationFilter == NULL ||
4380         pulNotify == NULL ||
4381         pulUnknown9 == NULL)
4382         return CR_INVALID_POINTER;
4383 
4384     if (ulFlags & ~0x7)
4385         return CR_INVALID_FLAG;
4386 
4387     if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_HDR)) ||
4388         (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_size < sizeof(DEV_BROADCAST_HDR)))
4389         return CR_INVALID_DATA;
4390 
4391     if (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
4392     {
4393         DPRINT1("DBT_DEVTYP_DEVICEINTERFACE\n");
4394         pBroadcastDeviceInterface = (PDEV_BROADCAST_DEVICEINTERFACE_W)pNotificationFilter;
4395 
4396         if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_DEVICEINTERFACE_W)) ||
4397             (pBroadcastDeviceInterface->dbcc_size < sizeof(DEV_BROADCAST_DEVICEINTERFACE_W)))
4398             return CR_INVALID_DATA;
4399     }
4400     else if (((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype == DBT_DEVTYP_HANDLE)
4401     {
4402         DPRINT1("DBT_DEVTYP_HANDLE\n");
4403         pBroadcastDeviceHandle = (PDEV_BROADCAST_HANDLE)pNotificationFilter;
4404 
4405         if ((ulNotificationFilterSize < sizeof(DEV_BROADCAST_HANDLE)) ||
4406             (pBroadcastDeviceHandle->dbch_size < sizeof(DEV_BROADCAST_HANDLE)))
4407             return CR_INVALID_DATA;
4408 
4409         if (ulFlags & DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)
4410             return CR_INVALID_FLAG;
4411     }
4412     else
4413     {
4414         DPRINT1("Invalid device type %lu\n", ((PDEV_BROADCAST_HDR)pNotificationFilter)->dbch_devicetype);
4415         return CR_INVALID_DATA;
4416     }
4417 
4418 
4419 #if 0
4420     pNotifyData = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFY_DATA));
4421     if (pNotifyData == NULL)
4422         return CR_OUT_OF_MEMORY;
4423 
4424     *pulNotify = (DWORD)pNotifyData;
4425 #endif
4426 
4427     *pulNotify = 1;
4428 
4429     return CR_SUCCESS;
4430 }
4431 
4432 
4433 /* Function 60 */
4434 DWORD
4435 WINAPI
4436 PNP_UnregisterNotification(
4437     handle_t hBinding,
4438     DWORD ulNotify)
4439 {
4440     DPRINT1("PNP_UnregisterNotification(%p 0x%lx)\n",
4441            hBinding, ulNotify);
4442 
4443 #if 0
4444     UNIMPLEMENTED;
4445     return CR_CALL_NOT_IMPLEMENTED;
4446 #endif
4447 
4448     return CR_SUCCESS;
4449 }
4450 
4451 
4452 /* Function 61 */
4453 DWORD
4454 WINAPI
4455 PNP_GetCustomDevProp(
4456     handle_t hBinding,
4457     LPWSTR pDeviceID,
4458     LPWSTR CustomPropName,
4459     DWORD *pulRegDataType,
4460     BYTE *Buffer,
4461     PNP_RPC_STRING_LEN *pulTransferLen,
4462     PNP_RPC_STRING_LEN *pulLength,
4463     DWORD ulFlags)
4464 {
4465     HKEY hDeviceKey = NULL;
4466     HKEY hParamKey = NULL;
4467     LONG lError;
4468     CONFIGRET ret = CR_SUCCESS;
4469 
4470     UNREFERENCED_PARAMETER(hBinding);
4471 
4472     DPRINT("PNP_GetCustomDevProp() called\n");
4473 
4474     if (pulTransferLen == NULL || pulLength == NULL)
4475     {
4476         ret = CR_INVALID_POINTER;
4477         goto done;
4478     }
4479 
4480     if (ulFlags & ~CM_CUSTOMDEVPROP_BITS)
4481     {
4482         ret = CR_INVALID_FLAG;
4483         goto done;
4484     }
4485 
4486     if (!IsValidDeviceInstanceID(pDeviceID))
4487         return CR_INVALID_DEVINST;
4488 
4489     if (*pulLength < *pulTransferLen)
4490         *pulLength = *pulTransferLen;
4491 
4492     *pulTransferLen = 0;
4493 
4494     lError = RegOpenKeyExW(hEnumKey,
4495                            pDeviceID,
4496                            0,
4497                            KEY_READ,
4498                            &hDeviceKey);
4499     if (lError != ERROR_SUCCESS)
4500     {
4501         ret = CR_REGISTRY_ERROR;
4502         goto done;
4503     }
4504 
4505     lError = RegOpenKeyExW(hDeviceKey,
4506                            L"Device Parameters",
4507                            0,
4508                            KEY_READ,
4509                            &hParamKey);
4510     if (lError != ERROR_SUCCESS)
4511     {
4512         ret = CR_REGISTRY_ERROR;
4513         goto done;
4514     }
4515 
4516     lError = RegQueryValueExW(hParamKey,
4517                               CustomPropName,
4518                               NULL,
4519                               pulRegDataType,
4520                               Buffer,
4521                               pulLength);
4522     if (lError != ERROR_SUCCESS)
4523     {
4524         if (lError == ERROR_MORE_DATA)
4525         {
4526             ret = CR_BUFFER_SMALL;
4527         }
4528         else
4529         {
4530             *pulLength = 0;
4531             ret = CR_NO_SUCH_VALUE;
4532         }
4533     }
4534 
4535 done:
4536     if (ret == CR_SUCCESS)
4537         *pulTransferLen = *pulLength;
4538 
4539     if (hParamKey != NULL)
4540         RegCloseKey(hParamKey);
4541 
4542     if (hDeviceKey != NULL)
4543         RegCloseKey(hDeviceKey);
4544 
4545     DPRINT("PNP_GetCustomDevProp() done (returns %lx)\n", ret);
4546 
4547     return ret;
4548 }
4549 
4550 
4551 /* Function 62 */
4552 DWORD
4553 WINAPI
4554 PNP_GetVersionInternal(
4555     handle_t hBinding,
4556     WORD *pwVersion)
4557 {
4558     UNREFERENCED_PARAMETER(hBinding);
4559 
4560     *pwVersion = 0x501;
4561     return CR_SUCCESS;
4562 }
4563 
4564 
4565 /* Function 63 */
4566 DWORD
4567 WINAPI
4568 PNP_GetBlockedDriverInfo(
4569     handle_t hBinding,
4570     BYTE *Buffer,
4571     PNP_RPC_BUFFER_SIZE *pulTransferLen,
4572     PNP_RPC_BUFFER_SIZE *pulLength,
4573     DWORD ulFlags)
4574 {
4575     UNIMPLEMENTED;
4576     return CR_CALL_NOT_IMPLEMENTED;
4577 }
4578 
4579 
4580 /* Function 64 */
4581 DWORD
4582 WINAPI
4583 PNP_GetServerSideDeviceInstallFlags(
4584     handle_t hBinding,
4585     DWORD *pulSSDIFlags,
4586     DWORD ulFlags)
4587 {
4588     UNREFERENCED_PARAMETER(hBinding);
4589 
4590     DPRINT1("PNP_GetServerSideDeviceInstallFlags(%p %p %lu)\n",
4591             hBinding, pulSSDIFlags, ulFlags);
4592 
4593     if (pulSSDIFlags == NULL)
4594         return CR_INVALID_POINTER;
4595 
4596     if (ulFlags != 0)
4597         return CR_INVALID_FLAG;
4598 
4599     /* FIXME */
4600     *pulSSDIFlags = 0;
4601 
4602     return CR_SUCCESS;
4603 }
4604 
4605 
4606 /* Function 65 */
4607 DWORD
4608 WINAPI
4609 PNP_GetObjectPropKeys(
4610     handle_t hBinding,
4611     LPWSTR ObjectName,
4612     DWORD ObjectType,
4613     LPWSTR PropertyCultureName,
4614     PNP_PROP_COUNT *PropertyCount,
4615     PNP_PROP_COUNT *TransferLen,
4616     DEVPROPKEY *PropertyKeys,
4617     DWORD Flags)
4618 {
4619     UNIMPLEMENTED;
4620     return CR_CALL_NOT_IMPLEMENTED;
4621 }
4622 
4623 
4624 /* Function 66 */
4625 DWORD
4626 WINAPI
4627 PNP_GetObjectProp(
4628     handle_t hBinding,
4629     LPWSTR ObjectName,
4630     DWORD ObjectType,
4631     LPWSTR PropertyCultureName,
4632     const DEVPROPKEY *PropertyKey,
4633     DEVPROPTYPE *PropertyType,
4634     PNP_PROP_SIZE *PropertySize,
4635     PNP_PROP_SIZE *TransferLen,
4636     BYTE *PropertyBuffer,
4637     DWORD Flags)
4638 {
4639     UNIMPLEMENTED;
4640     return CR_CALL_NOT_IMPLEMENTED;
4641 }
4642 
4643 
4644 /* Function 67 */
4645 DWORD
4646 WINAPI
4647 PNP_SetObjectProp(
4648     handle_t hBinding,
4649     LPWSTR ObjectName,
4650     DWORD ObjectType,
4651     LPWSTR PropertyCultureName,
4652     const DEVPROPKEY *PropertyKey,
4653     DEVPROPTYPE PropertyType,
4654     PNP_PROP_SIZE PropertySize,
4655     BYTE *PropertyBuffer,
4656     DWORD Flags)
4657 {
4658     UNIMPLEMENTED;
4659     return CR_CALL_NOT_IMPLEMENTED;
4660 }
4661 
4662 
4663 /* Function 68 */
4664 DWORD
4665 WINAPI
4666 PNP_InstallDevInst(
4667     handle_t hBinding)
4668 {
4669     UNIMPLEMENTED;
4670     return CR_CALL_NOT_IMPLEMENTED;
4671 }
4672 
4673 
4674 /* Function 69 */
4675 DWORD
4676 WINAPI
4677 PNP_ApplyPowerSettings(
4678     handle_t hBinding)
4679 {
4680     UNIMPLEMENTED;
4681     return CR_CALL_NOT_IMPLEMENTED;
4682 }
4683 
4684 
4685 /* Function 70 */
4686 DWORD
4687 WINAPI
4688 PNP_DriverStoreAddDriverPackage(
4689     handle_t hBinding)
4690 {
4691     UNIMPLEMENTED;
4692     return CR_CALL_NOT_IMPLEMENTED;
4693 }
4694 
4695 
4696 /* Function 71 */
4697 DWORD
4698 WINAPI
4699 PNP_DriverStoreDeleteDriverPackage(
4700     handle_t hBinding)
4701 {
4702     UNIMPLEMENTED;
4703     return CR_CALL_NOT_IMPLEMENTED;
4704 }
4705 
4706 
4707 /* Function 72 */
4708 DWORD
4709 WINAPI
4710 PNP_RegisterServiceNotification(
4711     handle_t hBinding)
4712 {
4713     UNIMPLEMENTED;
4714     return CR_CALL_NOT_IMPLEMENTED;
4715 }
4716 
4717 
4718 /* Function 73 */
4719 DWORD
4720 WINAPI
4721 PNP_SetActiveService(
4722     handle_t hBinding,
4723     LPWSTR pszFilter,
4724     DWORD ulFlags)
4725 {
4726     UNIMPLEMENTED;
4727     return CR_CALL_NOT_IMPLEMENTED;
4728 }
4729 
4730 
4731 /* Function 74 */
4732 DWORD
4733 WINAPI
4734 PNP_DeleteServiceDevices(
4735     handle_t hBinding)
4736 {
4737     UNIMPLEMENTED;
4738     return CR_CALL_NOT_IMPLEMENTED;
4739 }
4740