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