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