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