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