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