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