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