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