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