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