3 * Copyright (C) 2005 ReactOS Team
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.
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.
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.
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)
29 /* INCLUDES *****************************************************************/
31 #define WIN32_NO_STATUS
33 #define COM_NO_WINDOWS_H
45 #include <umpnpmgr/sysguid.h>
55 /* GLOBALS ******************************************************************/
57 static WCHAR ServiceName
[] = L
"PlugPlay";
59 static SERVICE_STATUS_HANDLE ServiceStatusHandle
;
60 static SERVICE_STATUS ServiceStatus
;
62 static WCHAR szRootDeviceId
[] = L
"HTREE\\ROOT\\0";
64 static HKEY hEnumKey
= NULL
;
65 static HKEY hClassKey
= NULL
;
67 static HANDLE hUserToken
= NULL
;
68 static HANDLE hInstallEvent
= NULL
;
69 static HANDLE hNoPendingInstalls
= NULL
;
71 static SLIST_HEADER DeviceInstallListHead
;
72 static HANDLE hDeviceInstallListNotEmpty
;
76 SLIST_ENTRY ListEntry
;
78 } DeviceInstallParams
;
80 /* FUNCTIONS *****************************************************************/
83 RpcServerThread(LPVOID lpParameter
)
86 BOOLEAN RegisteredProtSeq
= FALSE
;
88 UNREFERENCED_PARAMETER(lpParameter
);
90 DPRINT("RpcServerThread() called\n");
93 /* 2k/XP/2k3-compatible protocol sequence/endpoint */
94 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
97 NULL
); // Security descriptor
98 if (Status
== RPC_S_OK
)
99 RegisteredProtSeq
= TRUE
;
101 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
104 /* Vista/7-compatible protocol sequence/endpoint */
105 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
108 NULL
); // Security descriptor
109 if (Status
== RPC_S_OK
)
110 RegisteredProtSeq
= TRUE
;
112 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
114 /* Make sure there's a usable endpoint */
115 if (RegisteredProtSeq
== FALSE
)
118 Status
= RpcServerRegisterIf(pnp_v1_0_s_ifspec
,
121 if (Status
!= RPC_S_OK
)
123 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status
);
127 Status
= RpcServerListen(1,
130 if (Status
!= RPC_S_OK
)
132 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status
);
136 /* ROS HACK (this should never happen...) */
137 DPRINT1("*** Other devices won't be installed correctly. If something\n");
138 DPRINT1("*** doesn't work, try to reboot to get a new chance.\n");
140 DPRINT("RpcServerThread() done\n");
146 void __RPC_FAR
* __RPC_USER
midl_user_allocate(SIZE_T len
)
148 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
152 void __RPC_USER
midl_user_free(void __RPC_FAR
* ptr
)
154 HeapFree(GetProcessHeap(), 0, ptr
);
158 static CONFIGRET WINAPI
159 NtStatusToCrError(NTSTATUS Status
)
163 case STATUS_NOT_IMPLEMENTED
:
164 return CR_CALL_NOT_IMPLEMENTED
;
166 case STATUS_INVALID_PARAMETER
:
167 return CR_INVALID_DATA
;
169 case STATUS_NO_SUCH_DEVICE
:
170 return CR_NO_SUCH_DEVINST
;
172 case STATUS_ACCESS_DENIED
:
173 return CR_ACCESS_DENIED
;
175 case STATUS_BUFFER_TOO_SMALL
:
176 return CR_BUFFER_SMALL
;
178 case STATUS_OBJECT_NAME_NOT_FOUND
:
179 return CR_NO_SUCH_VALUE
;
188 SplitDeviceInstanceID(IN LPWSTR pszDeviceInstanceID
,
189 OUT LPWSTR pszEnumerator
,
190 OUT LPWSTR pszDevice
,
191 OUT LPWSTR pszInstance
)
193 WCHAR szLocalDeviceInstanceID
[MAX_DEVICE_ID_LEN
];
194 LPWSTR lpEnumerator
= NULL
;
195 LPWSTR lpDevice
= NULL
;
196 LPWSTR lpInstance
= NULL
;
199 wcscpy(szLocalDeviceInstanceID
, pszDeviceInstanceID
);
205 lpEnumerator
= szLocalDeviceInstanceID
;
207 ptr
= wcschr(lpEnumerator
, L
'\\');
213 ptr
= wcschr(lpDevice
, L
'\\');
221 if (lpEnumerator
!= NULL
)
222 wcscpy(pszEnumerator
, lpEnumerator
);
224 if (lpDevice
!= NULL
)
225 wcscpy(pszDevice
, lpDevice
);
227 if (lpInstance
!= NULL
)
228 wcscpy(pszInstance
, lpInstance
);
232 /* PUBLIC FUNCTIONS **********************************************************/
240 UNREFERENCED_PARAMETER(hBinding
);
251 UNREFERENCED_PARAMETER(hBinding
);
263 UNREFERENCED_PARAMETER(hBinding
);
278 UNREFERENCED_PARAMETER(hBinding
);
279 UNREFERENCED_PARAMETER(ulFlags
);
281 *pulState
= CM_GLOBAL_STATE_CAN_DO_UI
| CM_GLOBAL_STATE_SERVICES_AVAILABLE
;
292 UNREFERENCED_PARAMETER(hBinding
);
294 DPRINT("PNP_InitDetection() called\n");
307 DWORD ReturnValue
= CR_FAILURE
;
310 UNREFERENCED_PARAMETER(hBinding
);
311 UNREFERENCED_PARAMETER(Admin
);
313 DPRINT("PNP_ReportLogOn(%u, %u) called\n", Admin
, ProcessId
);
315 /* Get the users token */
316 hProcess
= OpenProcess(PROCESS_ALL_ACCESS
, TRUE
, ProcessId
);
320 DPRINT1("OpenProcess failed with error %u\n", GetLastError());
326 CloseHandle(hUserToken
);
330 if (!OpenProcessToken(hProcess
, TOKEN_ASSIGN_PRIMARY
| TOKEN_DUPLICATE
| TOKEN_QUERY
, &hUserToken
))
332 DPRINT1("OpenProcessToken failed with error %u\n", GetLastError());
336 /* Trigger the installer thread */
338 SetEvent(hInstallEvent
);
340 ReturnValue
= CR_SUCCESS
;
344 CloseHandle(hProcess
);
353 PNP_ValidateDeviceInstance(
358 CONFIGRET ret
= CR_SUCCESS
;
359 HKEY hDeviceKey
= NULL
;
361 UNREFERENCED_PARAMETER(hBinding
);
362 UNREFERENCED_PARAMETER(ulFlags
);
364 DPRINT("PNP_ValidateDeviceInstance(%S %lx) called\n",
367 if (RegOpenKeyExW(hEnumKey
,
373 DPRINT("Could not open the Device Key!\n");
374 ret
= CR_NO_SUCH_DEVNODE
;
378 /* FIXME: add more tests */
381 if (hDeviceKey
!= NULL
)
382 RegCloseKey(hDeviceKey
);
384 DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret
);
393 PNP_GetRootDeviceInstance(
396 PNP_RPC_STRING_LEN ulLength
)
398 CONFIGRET ret
= CR_SUCCESS
;
400 UNREFERENCED_PARAMETER(hBinding
);
402 DPRINT("PNP_GetRootDeviceInstance() called\n");
406 ret
= CR_INVALID_POINTER
;
409 if (ulLength
< lstrlenW(szRootDeviceId
) + 1)
411 ret
= CR_BUFFER_SMALL
;
419 DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret
);
428 PNP_GetRelatedDeviceInstance(
430 DWORD ulRelationship
,
432 LPWSTR pRelatedDeviceId
,
433 PNP_RPC_STRING_LEN
*pulLength
,
436 PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData
;
437 CONFIGRET ret
= CR_SUCCESS
;
440 UNREFERENCED_PARAMETER(hBinding
);
441 UNREFERENCED_PARAMETER(ulFlags
);
443 DPRINT("PNP_GetRelatedDeviceInstance() called\n");
444 DPRINT(" Relationship %ld\n", ulRelationship
);
445 DPRINT(" DeviceId %S\n", pDeviceID
);
447 RtlInitUnicodeString(&PlugPlayData
.TargetDeviceInstance
,
450 PlugPlayData
.Relation
= ulRelationship
;
452 PlugPlayData
.RelatedDeviceInstanceLength
= *pulLength
;
453 PlugPlayData
.RelatedDeviceInstance
= pRelatedDeviceId
;
455 Status
= NtPlugPlayControl(PlugPlayControlGetRelatedDevice
,
456 (PVOID
)&PlugPlayData
,
457 sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
));
458 if (!NT_SUCCESS(Status
))
460 ret
= NtStatusToCrError(Status
);
463 DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret
);
464 if (ret
== CR_SUCCESS
)
466 DPRINT("RelatedDevice: %wZ\n", &PlugPlayData
.RelatedDeviceInstance
);
476 PNP_EnumerateSubKeys(
481 PNP_RPC_STRING_LEN ulLength
,
482 PNP_RPC_STRING_LEN
*pulRequiredLen
,
485 CONFIGRET ret
= CR_SUCCESS
;
489 UNREFERENCED_PARAMETER(hBinding
);
490 UNREFERENCED_PARAMETER(ulFlags
);
492 DPRINT("PNP_EnumerateSubKeys() called\n");
496 case PNP_ENUMERATOR_SUBKEYS
:
500 case PNP_CLASS_SUBKEYS
:
508 *pulRequiredLen
= ulLength
;
509 dwError
= RegEnumKeyExW(hKey
,
517 if (dwError
!= ERROR_SUCCESS
)
519 ret
= (dwError
== ERROR_NO_MORE_ITEMS
) ? CR_NO_SUCH_VALUE
: CR_FAILURE
;
526 DPRINT("PNP_EnumerateSubKeys() done (returns %lx)\n", ret
);
534 GetDeviceInstanceList(
535 _In_ PWSTR pszDevice
,
536 _Inout_ PWSTR pszBuffer
,
537 _Inout_ PDWORD pulLength
)
539 WCHAR szInstanceBuffer
[MAX_DEVICE_ID_LEN
];
540 WCHAR szPathBuffer
[512];
542 DWORD dwInstanceLength
, dwPathLength
, dwUsedLength
;
543 DWORD dwIndex
, dwError
;
545 CONFIGRET ret
= CR_SUCCESS
;
547 /* Open the device key */
548 dwError
= RegOpenKeyExW(hEnumKey
,
551 KEY_ENUMERATE_SUB_KEYS
,
553 if (dwError
!= ERROR_SUCCESS
)
555 DPRINT("Failed to open the device key (Error %lu)\n", dwError
);
556 return CR_REGISTRY_ERROR
;
562 for (dwIndex
= 0; ; dwIndex
++)
564 dwInstanceLength
= MAX_DEVICE_ID_LEN
;
565 dwError
= RegEnumKeyExW(hDeviceKey
,
573 if (dwError
!= ERROR_SUCCESS
)
576 wsprintf(szPathBuffer
, L
"%s\\%s", pszDevice
, szInstanceBuffer
);
577 DPRINT("Path: %S\n", szPathBuffer
);
579 dwPathLength
= wcslen(szPathBuffer
) + 1;
580 if (dwUsedLength
+ dwPathLength
+ 1 > *pulLength
)
582 ret
= CR_BUFFER_SMALL
;
586 wcscpy(pPtr
, szPathBuffer
);
587 dwUsedLength
+= dwPathLength
;
588 pPtr
+= dwPathLength
;
590 *pPtr
= UNICODE_NULL
;
593 RegCloseKey(hDeviceKey
);
595 if (ret
== CR_SUCCESS
)
596 *pulLength
= dwUsedLength
+ 1;
605 GetEnumeratorInstanceList(
606 _In_ PWSTR pszEnumerator
,
607 _Inout_ PWSTR pszBuffer
,
608 _Inout_ PDWORD pulLength
)
610 WCHAR szDeviceBuffer
[MAX_DEVICE_ID_LEN
];
611 WCHAR szPathBuffer
[512];
614 DWORD dwIndex
, dwDeviceLength
, dwUsedLength
, dwRemainingLength
, dwPathLength
;
616 CONFIGRET ret
= CR_SUCCESS
;
618 /* Open the enumerator key */
619 dwError
= RegOpenKeyExW(hEnumKey
,
622 KEY_ENUMERATE_SUB_KEYS
,
624 if (dwError
!= ERROR_SUCCESS
)
626 DPRINT("Failed to open the enumerator key (Error %lu)\n", dwError
);
627 return CR_REGISTRY_ERROR
;
631 dwRemainingLength
= *pulLength
;
634 for (dwIndex
= 0; ; dwIndex
++)
636 dwDeviceLength
= MAX_DEVICE_ID_LEN
;
637 dwError
= RegEnumKeyExW(hEnumeratorKey
,
645 if (dwError
!= ERROR_SUCCESS
)
648 wsprintf(szPathBuffer
, L
"%s\\%s", pszEnumerator
, szDeviceBuffer
);
649 DPRINT("Path: %S\n", szPathBuffer
);
651 dwPathLength
= dwRemainingLength
;
652 ret
= GetDeviceInstanceList(szPathBuffer
,
655 if (ret
!= CR_SUCCESS
)
658 dwUsedLength
+= dwPathLength
- 1;
659 dwRemainingLength
+= dwPathLength
- 1;
660 pPtr
+= dwPathLength
- 1;
663 RegCloseKey(hEnumeratorKey
);
665 if (ret
== CR_SUCCESS
)
666 *pulLength
= dwUsedLength
+ 1;
681 PNP_RPC_STRING_LEN
*pulLength
,
684 PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData
;
685 WCHAR szEnumerator
[MAX_DEVICE_ID_LEN
];
686 WCHAR szDevice
[MAX_DEVICE_ID_LEN
];
687 WCHAR szInstance
[MAX_DEVICE_ID_LEN
];
688 CONFIGRET ret
= CR_SUCCESS
;
691 DPRINT("PNP_GetDeviceList() called\n");
693 if (ulFlags
& ~CM_GETIDLIST_FILTER_BITS
)
694 return CR_INVALID_FLAG
;
696 if (pulLength
== NULL
)
697 return CR_INVALID_POINTER
;
699 if ((ulFlags
!= CM_GETIDLIST_FILTER_NONE
) &&
701 return CR_INVALID_POINTER
;
704 (CM_GETIDLIST_FILTER_BUSRELATIONS
|
705 CM_GETIDLIST_FILTER_POWERRELATIONS
|
706 CM_GETIDLIST_FILTER_REMOVALRELATIONS
|
707 CM_GETIDLIST_FILTER_EJECTRELATIONS
))
709 RtlInitUnicodeString(&PlugPlayData
.DeviceInstance
,
711 if (ulFlags
& CM_GETIDLIST_FILTER_BUSRELATIONS
)
713 PlugPlayData
.Relations
= 3;
715 else if (ulFlags
& CM_GETIDLIST_FILTER_POWERRELATIONS
)
717 PlugPlayData
.Relations
= 2;
719 else if (ulFlags
& CM_GETIDLIST_FILTER_REMOVALRELATIONS
)
721 PlugPlayData
.Relations
= 1;
723 else if (ulFlags
& CM_GETIDLIST_FILTER_EJECTRELATIONS
)
725 PlugPlayData
.Relations
= 0;
728 PlugPlayData
.BufferSize
= *pulLength
* sizeof(WCHAR
);
729 PlugPlayData
.Buffer
= Buffer
;
731 Status
= NtPlugPlayControl(PlugPlayControlQueryDeviceRelations
,
732 (PVOID
)&PlugPlayData
,
733 sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
));
734 if (NT_SUCCESS(Status
))
736 *pulLength
= PlugPlayData
.BufferSize
/ sizeof(WCHAR
);
740 ret
= NtStatusToCrError(Status
);
743 else if (ulFlags
& CM_GETIDLIST_FILTER_SERVICE
)
745 ret
= CR_CALL_NOT_IMPLEMENTED
;
747 else if (ulFlags
& CM_GETIDLIST_FILTER_ENUMERATOR
)
749 SplitDeviceInstanceID(pszFilter
,
754 if (*szEnumerator
!= UNICODE_NULL
&& *szDevice
!= UNICODE_NULL
)
756 ret
= GetDeviceInstanceList(pszFilter
,
762 ret
= GetEnumeratorInstanceList(pszFilter
,
767 else /* CM_GETIDLIST_FILTER_NONE */
769 ret
= CR_CALL_NOT_IMPLEMENTED
;
778 GetDeviceInstanceListSize(
779 _In_ LPCWSTR pszDevice
,
780 _Out_ PULONG pulLength
)
783 DWORD dwSubKeys
, dwMaxSubKeyLength
;
786 /* Open the device key */
787 dwError
= RegOpenKeyExW(hEnumKey
,
792 if (dwError
!= ERROR_SUCCESS
)
794 DPRINT("Failed to open the device key (Error %lu)\n", dwError
);
795 return CR_REGISTRY_ERROR
;
798 /* Retrieve the number of device instances and the maximum name length */
799 dwError
= RegQueryInfoKeyW(hDeviceKey
,
811 if (dwError
!= ERROR_SUCCESS
)
813 DPRINT("RegQueryInfoKeyW failed (Error %lu)\n", dwError
);
815 dwMaxSubKeyLength
= 0;
818 /* Close the device key */
819 RegCloseKey(hDeviceKey
);
821 /* Return the largest possible buffer size */
822 *pulLength
= dwSubKeys
* (wcslen(pszDevice
) + 1 + dwMaxSubKeyLength
+ 1);
830 GetEnumeratorInstanceListSize(
831 _In_ LPCWSTR pszEnumerator
,
832 _Out_ PULONG pulLength
)
834 WCHAR szDeviceBuffer
[MAX_DEVICE_ID_LEN
];
835 WCHAR szPathBuffer
[512];
837 DWORD dwIndex
, dwDeviceLength
, dwBufferLength
;
839 CONFIGRET ret
= CR_SUCCESS
;
843 /* Open the enumerator key */
844 dwError
= RegOpenKeyExW(hEnumKey
,
847 KEY_ENUMERATE_SUB_KEYS
,
849 if (dwError
!= ERROR_SUCCESS
)
851 DPRINT("Failed to open the enumerator key (Error %lu)\n", dwError
);
852 return CR_REGISTRY_ERROR
;
855 for (dwIndex
= 0; ; dwIndex
++)
857 dwDeviceLength
= MAX_DEVICE_ID_LEN
;
858 dwError
= RegEnumKeyExW(hEnumeratorKey
,
866 if (dwError
!= ERROR_SUCCESS
)
869 wsprintf(szPathBuffer
, L
"%s\\%s", pszEnumerator
, szDeviceBuffer
);
870 DPRINT("Path: %S\n", szPathBuffer
);
872 ret
= GetDeviceInstanceListSize(szPathBuffer
, &dwBufferLength
);
873 if (ret
!= CR_SUCCESS
)
879 *pulLength
+= dwBufferLength
;
882 /* Close the enumerator key */
883 RegCloseKey(hEnumeratorKey
);
891 GetAllInstanceListSize(
892 _In_ LPCWSTR pszEnumerator
,
893 _Out_ PULONG pulLength
)
895 WCHAR szEnumeratorBuffer
[MAX_DEVICE_ID_LEN
];
896 DWORD dwIndex
, dwEnumeratorLength
, dwBufferLength
;
898 CONFIGRET ret
= CR_SUCCESS
;
900 for (dwIndex
= 0; ; dwIndex
++)
902 dwEnumeratorLength
= MAX_DEVICE_ID_LEN
;
903 dwError
= RegEnumKeyExW(hEnumKey
,
907 NULL
, NULL
, NULL
, NULL
);
908 if (dwError
!= ERROR_SUCCESS
)
911 /* Get the size of all device instances for the enumerator */
912 ret
= GetEnumeratorInstanceListSize(szEnumeratorBuffer
,
914 if (ret
!= CR_SUCCESS
)
917 *pulLength
+= dwBufferLength
;
927 PNP_GetDeviceListSize(
930 PNP_RPC_BUFFER_SIZE
*pulLength
,
933 PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA PlugPlayData
;
934 WCHAR szEnumerator
[MAX_DEVICE_ID_LEN
];
935 WCHAR szDevice
[MAX_DEVICE_ID_LEN
];
936 WCHAR szInstance
[MAX_DEVICE_ID_LEN
];
937 CONFIGRET ret
= CR_SUCCESS
;
940 DPRINT("PNP_GetDeviceListSize(%p %S %p 0x%lx)\n",
941 hBinding
, pszFilter
, pulLength
, ulFlags
);
943 if (ulFlags
& ~CM_GETIDLIST_FILTER_BITS
)
944 return CR_INVALID_FLAG
;
946 if (pulLength
== NULL
)
947 return CR_INVALID_POINTER
;
949 if ((ulFlags
!= CM_GETIDLIST_FILTER_NONE
) &&
951 return CR_INVALID_POINTER
;
956 (CM_GETIDLIST_FILTER_BUSRELATIONS
|
957 CM_GETIDLIST_FILTER_POWERRELATIONS
|
958 CM_GETIDLIST_FILTER_REMOVALRELATIONS
|
959 CM_GETIDLIST_FILTER_EJECTRELATIONS
))
961 RtlInitUnicodeString(&PlugPlayData
.DeviceInstance
,
963 if (ulFlags
& CM_GETIDLIST_FILTER_BUSRELATIONS
)
965 PlugPlayData
.Relations
= 3;
967 else if (ulFlags
& CM_GETIDLIST_FILTER_POWERRELATIONS
)
969 PlugPlayData
.Relations
= 2;
971 else if (ulFlags
& CM_GETIDLIST_FILTER_REMOVALRELATIONS
)
973 PlugPlayData
.Relations
= 1;
975 else if (ulFlags
& CM_GETIDLIST_FILTER_EJECTRELATIONS
)
977 PlugPlayData
.Relations
= 0;
980 PlugPlayData
.BufferSize
= 0;
981 PlugPlayData
.Buffer
= NULL
;
983 Status
= NtPlugPlayControl(PlugPlayControlQueryDeviceRelations
,
984 (PVOID
)&PlugPlayData
,
985 sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
));
986 if (NT_SUCCESS(Status
))
988 *pulLength
= PlugPlayData
.BufferSize
/ sizeof(WCHAR
);
992 ret
= NtStatusToCrError(Status
);
995 else if (ulFlags
& CM_GETIDLIST_FILTER_SERVICE
)
997 ret
= CR_CALL_NOT_IMPLEMENTED
;
999 else if (ulFlags
& CM_GETIDLIST_FILTER_ENUMERATOR
)
1001 SplitDeviceInstanceID(pszFilter
,
1006 if (*szEnumerator
!= UNICODE_NULL
&& *szDevice
!= UNICODE_NULL
)
1008 ret
= GetDeviceInstanceListSize(pszFilter
,
1013 ret
= GetEnumeratorInstanceListSize(pszFilter
,
1017 else /* CM_GETIDLIST_FILTER_NONE */
1019 ret
= GetAllInstanceListSize(pszFilter
,
1023 /* Add one character for the terminating double UNICODE_NULL */
1024 if (ret
== CR_SUCCESS
)
1040 PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData
;
1041 CONFIGRET ret
= CR_SUCCESS
;
1044 UNREFERENCED_PARAMETER(hBinding
);
1045 UNREFERENCED_PARAMETER(ulFlags
);
1047 DPRINT("PNP_GetDepth() called\n");
1049 RtlInitUnicodeString(&PlugPlayData
.DeviceInstance
,
1052 Status
= NtPlugPlayControl(PlugPlayControlGetDeviceDepth
,
1053 (PVOID
)&PlugPlayData
,
1054 sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
));
1055 if (NT_SUCCESS(Status
))
1057 *pulDepth
= PlugPlayData
.Depth
;
1061 ret
= NtStatusToCrError(Status
);
1064 DPRINT("PNP_GetDepth() done (returns %lx)\n", ret
);
1073 PNP_GetDeviceRegProp(
1077 DWORD
*pulRegDataType
,
1079 PNP_PROP_SIZE
*pulTransferLen
,
1080 PNP_PROP_SIZE
*pulLength
,
1083 PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData
;
1084 CONFIGRET ret
= CR_SUCCESS
;
1085 LPWSTR lpValueName
= NULL
;
1090 UNREFERENCED_PARAMETER(hBinding
);
1092 DPRINT("PNP_GetDeviceRegProp() called\n");
1094 if (pulTransferLen
== NULL
|| pulLength
== NULL
)
1096 ret
= CR_INVALID_POINTER
;
1102 ret
= CR_INVALID_FLAG
;
1106 /* FIXME: Check pDeviceID */
1108 if (*pulLength
< *pulTransferLen
)
1109 *pulLength
= *pulTransferLen
;
1111 *pulTransferLen
= 0;
1115 case CM_DRP_DEVICEDESC
:
1116 lpValueName
= L
"DeviceDesc";
1119 case CM_DRP_HARDWAREID
:
1120 lpValueName
= L
"HardwareID";
1123 case CM_DRP_COMPATIBLEIDS
:
1124 lpValueName
= L
"CompatibleIDs";
1127 case CM_DRP_SERVICE
:
1128 lpValueName
= L
"Service";
1132 lpValueName
= L
"Class";
1135 case CM_DRP_CLASSGUID
:
1136 lpValueName
= L
"ClassGUID";
1140 lpValueName
= L
"Driver";
1143 case CM_DRP_CONFIGFLAGS
:
1144 lpValueName
= L
"ConfigFlags";
1148 lpValueName
= L
"Mfg";
1151 case CM_DRP_FRIENDLYNAME
:
1152 lpValueName
= L
"FriendlyName";
1155 case CM_DRP_LOCATION_INFORMATION
:
1156 lpValueName
= L
"LocationInformation";
1159 case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME
:
1160 PlugPlayData
.Property
= PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME
;
1163 case CM_DRP_CAPABILITIES
:
1164 lpValueName
= L
"Capabilities";
1167 case CM_DRP_UI_NUMBER
:
1168 PlugPlayData
.Property
= PNP_PROPERTY_UI_NUMBER
;
1171 case CM_DRP_UPPERFILTERS
:
1172 lpValueName
= L
"UpperFilters";
1175 case CM_DRP_LOWERFILTERS
:
1176 lpValueName
= L
"LowerFilters";
1179 case CM_DRP_BUSTYPEGUID
:
1180 PlugPlayData
.Property
= PNP_PROPERTY_BUSTYPEGUID
;
1183 case CM_DRP_LEGACYBUSTYPE
:
1184 PlugPlayData
.Property
= PNP_PROPERTY_LEGACYBUSTYPE
;
1187 case CM_DRP_BUSNUMBER
:
1188 PlugPlayData
.Property
= PNP_PROPERTY_BUSNUMBER
;
1191 case CM_DRP_ENUMERATOR_NAME
:
1192 PlugPlayData
.Property
= PNP_PROPERTY_ENUMERATOR_NAME
;
1195 case CM_DRP_SECURITY
:
1196 lpValueName
= L
"Security";
1199 case CM_DRP_DEVTYPE
:
1200 lpValueName
= L
"DeviceType";
1203 case CM_DRP_EXCLUSIVE
:
1204 lpValueName
= L
"Exclusive";
1207 case CM_DRP_CHARACTERISTICS
:
1208 lpValueName
= L
"DeviceCharacteristics";
1211 case CM_DRP_ADDRESS
:
1212 PlugPlayData
.Property
= PNP_PROPERTY_ADDRESS
;
1215 case CM_DRP_UI_NUMBER_DESC_FORMAT
:
1216 lpValueName
= L
"UINumberDescFormat";
1219 case CM_DRP_DEVICE_POWER_DATA
:
1220 PlugPlayData
.Property
= PNP_PROPERTY_POWER_DATA
;
1223 case CM_DRP_REMOVAL_POLICY
:
1224 PlugPlayData
.Property
= PNP_PROPERTY_REMOVAL_POLICY
;
1227 case CM_DRP_REMOVAL_POLICY_HW_DEFAULT
:
1228 PlugPlayData
.Property
= PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT
;
1231 case CM_DRP_REMOVAL_POLICY_OVERRIDE
:
1232 lpValueName
= L
"RemovalPolicy";
1235 case CM_DRP_INSTALL_STATE
:
1236 PlugPlayData
.Property
= PNP_PROPERTY_INSTALL_STATE
;
1239 #if (WINVER >= _WIN32_WINNT_WS03)
1240 case CM_DRP_LOCATION_PATHS
:
1241 PlugPlayData
.Property
= PNP_PROPERTY_LOCATION_PATHS
;
1245 #if (WINVER >= _WIN32_WINNT_WIN7)
1246 case CM_DRP_BASE_CONTAINERID
:
1247 PlugPlayData
.Property
= PNP_PROPERTY_CONTAINERID
;
1252 ret
= CR_INVALID_PROPERTY
;
1256 DPRINT("Value name: %S\n", lpValueName
);
1260 /* Retrieve information from the Registry */
1261 lError
= RegOpenKeyExW(hEnumKey
,
1266 if (lError
!= ERROR_SUCCESS
)
1270 ret
= CR_INVALID_DEVNODE
;
1274 lError
= RegQueryValueExW(hKey
,
1280 if (lError
!= ERROR_SUCCESS
)
1282 if (lError
== ERROR_MORE_DATA
)
1284 ret
= CR_BUFFER_SMALL
;
1289 ret
= CR_NO_SUCH_VALUE
;
1295 /* Retrieve information from the Device Node */
1296 RtlInitUnicodeString(&PlugPlayData
.DeviceInstance
,
1298 PlugPlayData
.Buffer
= Buffer
;
1299 PlugPlayData
.BufferSize
= *pulLength
;
1301 Status
= NtPlugPlayControl(PlugPlayControlProperty
,
1302 (PVOID
)&PlugPlayData
,
1303 sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
));
1304 if (NT_SUCCESS(Status
))
1306 *pulLength
= PlugPlayData
.BufferSize
;
1310 ret
= NtStatusToCrError(Status
);
1316 *pulTransferLen
= (ret
== CR_SUCCESS
) ? *pulLength
: 0;
1321 DPRINT("PNP_GetDeviceRegProp() done (returns %lx)\n", ret
);
1330 PNP_SetDeviceRegProp(
1336 PNP_PROP_SIZE ulLength
,
1339 CONFIGRET ret
= CR_SUCCESS
;
1340 LPWSTR lpValueName
= NULL
;
1343 UNREFERENCED_PARAMETER(hBinding
);
1344 UNREFERENCED_PARAMETER(ulFlags
);
1346 DPRINT("PNP_SetDeviceRegProp() called\n");
1348 DPRINT("DeviceId: %S\n", pDeviceId
);
1349 DPRINT("Property: %lu\n", ulProperty
);
1350 DPRINT("DataType: %lu\n", ulDataType
);
1351 DPRINT("Length: %lu\n", ulLength
);
1355 case CM_DRP_DEVICEDESC
:
1356 lpValueName
= L
"DeviceDesc";
1359 case CM_DRP_HARDWAREID
:
1360 lpValueName
= L
"HardwareID";
1363 case CM_DRP_COMPATIBLEIDS
:
1364 lpValueName
= L
"CompatibleIDs";
1367 case CM_DRP_SERVICE
:
1368 lpValueName
= L
"Service";
1372 lpValueName
= L
"Class";
1375 case CM_DRP_CLASSGUID
:
1376 lpValueName
= L
"ClassGUID";
1380 lpValueName
= L
"Driver";
1383 case CM_DRP_CONFIGFLAGS
:
1384 lpValueName
= L
"ConfigFlags";
1388 lpValueName
= L
"Mfg";
1391 case CM_DRP_FRIENDLYNAME
:
1392 lpValueName
= L
"FriendlyName";
1395 case CM_DRP_LOCATION_INFORMATION
:
1396 lpValueName
= L
"LocationInformation";
1399 case CM_DRP_UPPERFILTERS
:
1400 lpValueName
= L
"UpperFilters";
1403 case CM_DRP_LOWERFILTERS
:
1404 lpValueName
= L
"LowerFilters";
1407 case CM_DRP_SECURITY
:
1408 lpValueName
= L
"Security";
1411 case CM_DRP_DEVTYPE
:
1412 lpValueName
= L
"DeviceType";
1415 case CM_DRP_EXCLUSIVE
:
1416 lpValueName
= L
"Exclusive";
1419 case CM_DRP_CHARACTERISTICS
:
1420 lpValueName
= L
"DeviceCharacteristics";
1423 case CM_DRP_UI_NUMBER_DESC_FORMAT
:
1424 lpValueName
= L
"UINumberDescFormat";
1427 case CM_DRP_REMOVAL_POLICY_OVERRIDE
:
1428 lpValueName
= L
"RemovalPolicy";
1432 return CR_INVALID_PROPERTY
;
1435 DPRINT("Value name: %S\n", lpValueName
);
1437 if (RegOpenKeyExW(hEnumKey
,
1442 return CR_INVALID_DEVNODE
;
1446 if (RegDeleteValueW(hKey
,
1448 ret
= CR_REGISTRY_ERROR
;
1452 if (RegSetValueExW(hKey
,
1458 ret
= CR_REGISTRY_ERROR
;
1463 DPRINT("PNP_SetDeviceRegProp() done (returns %lx)\n", ret
);
1472 PNP_GetClassInstance(
1475 LPWSTR pszClassInstance
,
1476 PNP_RPC_STRING_LEN ulLength
)
1479 return CR_CALL_NOT_IMPLEMENTED
;
1494 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
1503 return CR_REGISTRY_ERROR
;
1505 /* FIXME: Set security key */
1516 PNP_DeleteRegistryKey(
1519 LPWSTR pszParentKey
,
1524 return CR_CALL_NOT_IMPLEMENTED
;
1533 DWORD
*pulClassCount
,
1539 UNREFERENCED_PARAMETER(hBinding
);
1540 UNREFERENCED_PARAMETER(ulFlags
);
1542 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1547 if (dwError
!= ERROR_SUCCESS
)
1548 return CR_INVALID_DATA
;
1550 dwError
= RegQueryInfoKeyW(hKey
,
1563 if (dwError
!= ERROR_SUCCESS
)
1564 return CR_INVALID_DATA
;
1575 LPWSTR pszClassGuid
,
1577 PNP_RPC_STRING_LEN
*pulLength
,
1580 WCHAR szKeyName
[MAX_PATH
];
1581 CONFIGRET ret
= CR_SUCCESS
;
1585 UNREFERENCED_PARAMETER(hBinding
);
1586 UNREFERENCED_PARAMETER(ulFlags
);
1588 DPRINT("PNP_GetClassName() called\n");
1590 lstrcpyW(szKeyName
, L
"System\\CurrentControlSet\\Control\\Class\\");
1591 if (lstrlenW(pszClassGuid
) + 1 < sizeof(szKeyName
)/sizeof(WCHAR
)-(lstrlenW(szKeyName
) * sizeof(WCHAR
)))
1592 lstrcatW(szKeyName
, pszClassGuid
);
1594 return CR_INVALID_DATA
;
1596 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1601 return CR_REGISTRY_ERROR
;
1603 dwSize
= *pulLength
* sizeof(WCHAR
);
1604 if (RegQueryValueExW(hKey
,
1612 ret
= CR_REGISTRY_ERROR
;
1616 *pulLength
= dwSize
/ sizeof(WCHAR
);
1621 DPRINT("PNP_GetClassName() done (returns %lx)\n", ret
);
1632 LPWSTR pszClassGuid
,
1635 CONFIGRET ret
= CR_SUCCESS
;
1637 UNREFERENCED_PARAMETER(hBinding
);
1639 DPRINT("PNP_GetClassName(%S, %lx) called\n", pszClassGuid
, ulFlags
);
1641 if (ulFlags
& CM_DELETE_CLASS_SUBKEYS
)
1643 if (SHDeleteKeyW(hClassKey
, pszClassGuid
) != ERROR_SUCCESS
)
1644 ret
= CR_REGISTRY_ERROR
;
1648 if (RegDeleteKeyW(hClassKey
, pszClassGuid
) != ERROR_SUCCESS
)
1649 ret
= CR_REGISTRY_ERROR
;
1652 DPRINT("PNP_DeleteClassKey() done (returns %lx)\n", ret
);
1661 PNP_GetInterfaceDeviceAlias(
1663 LPWSTR pszInterfaceDevice
,
1664 GUID
*AliasInterfaceGuid
,
1665 LPWSTR pszAliasInterfaceDevice
,
1666 PNP_RPC_STRING_LEN
*pulLength
,
1667 PNP_RPC_STRING_LEN
*pulTransferLen
,
1671 return CR_CALL_NOT_IMPLEMENTED
;
1678 PNP_GetInterfaceDeviceList(
1680 GUID
*InterfaceGuid
,
1683 PNP_RPC_BUFFER_SIZE
*pulLength
,
1687 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData
;
1688 DWORD ret
= CR_SUCCESS
;
1690 UNREFERENCED_PARAMETER(hBinding
);
1692 RtlInitUnicodeString(&PlugPlayData
.DeviceInstance
,
1695 PlugPlayData
.Flags
= ulFlags
;
1696 PlugPlayData
.FilterGuid
= InterfaceGuid
;
1697 PlugPlayData
.Buffer
= Buffer
;
1698 PlugPlayData
.BufferSize
= *pulLength
;
1700 Status
= NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList
,
1701 (PVOID
)&PlugPlayData
,
1702 sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
));
1703 if (NT_SUCCESS(Status
))
1705 *pulLength
= PlugPlayData
.BufferSize
;
1709 ret
= NtStatusToCrError(Status
);
1712 DPRINT("PNP_GetInterfaceDeviceListSize() done (returns %lx)\n", ret
);
1720 PNP_GetInterfaceDeviceListSize(
1722 PNP_RPC_BUFFER_SIZE
*pulLen
,
1723 GUID
*InterfaceGuid
,
1728 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA PlugPlayData
;
1729 DWORD ret
= CR_SUCCESS
;
1731 UNREFERENCED_PARAMETER(hBinding
);
1733 DPRINT("PNP_GetInterfaceDeviceListSize() called\n");
1735 RtlInitUnicodeString(&PlugPlayData
.DeviceInstance
,
1738 PlugPlayData
.FilterGuid
= InterfaceGuid
;
1739 PlugPlayData
.Buffer
= NULL
;
1740 PlugPlayData
.BufferSize
= 0;
1741 PlugPlayData
.Flags
= ulFlags
;
1743 Status
= NtPlugPlayControl(PlugPlayControlGetInterfaceDeviceList
,
1744 (PVOID
)&PlugPlayData
,
1745 sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
));
1746 if (NT_SUCCESS(Status
))
1748 *pulLen
= PlugPlayData
.BufferSize
;
1752 ret
= NtStatusToCrError(Status
);
1755 DPRINT("PNP_GetInterfaceDeviceListSize() done (returns %lx)\n", ret
);
1763 PNP_RegisterDeviceClassAssociation(
1766 GUID
*InterfaceGuid
,
1767 LPWSTR pszReference
,
1769 PNP_RPC_STRING_LEN
*pulLength
,
1770 PNP_RPC_STRING_LEN
*pulTransferLen
,
1774 return CR_CALL_NOT_IMPLEMENTED
;
1781 PNP_UnregisterDeviceClassAssociation(
1783 LPWSTR pszInterfaceDevice
,
1787 return CR_CALL_NOT_IMPLEMENTED
;
1794 PNP_GetClassRegProp(
1796 LPWSTR pszClassGuid
,
1798 DWORD
*pulRegDataType
,
1800 PNP_RPC_STRING_LEN
*pulTransferLen
,
1801 PNP_RPC_STRING_LEN
*pulLength
,
1804 CONFIGRET ret
= CR_SUCCESS
;
1805 LPWSTR lpValueName
= NULL
;
1806 HKEY hInstKey
= NULL
;
1807 HKEY hPropKey
= NULL
;
1810 UNREFERENCED_PARAMETER(hBinding
);
1812 DPRINT("PNP_GetClassRegProp() called\n");
1814 if (pulTransferLen
== NULL
|| pulLength
== NULL
)
1816 ret
= CR_INVALID_POINTER
;
1822 ret
= CR_INVALID_FLAG
;
1826 if (*pulLength
< *pulTransferLen
)
1827 *pulLength
= *pulTransferLen
;
1829 *pulTransferLen
= 0;
1833 case CM_CRP_SECURITY
:
1834 lpValueName
= L
"Security";
1837 case CM_CRP_DEVTYPE
:
1838 lpValueName
= L
"DeviceType";
1841 case CM_CRP_EXCLUSIVE
:
1842 lpValueName
= L
"Exclusive";
1845 case CM_CRP_CHARACTERISTICS
:
1846 lpValueName
= L
"DeviceCharacteristics";
1850 ret
= CR_INVALID_PROPERTY
;
1854 DPRINT("Value name: %S\n", lpValueName
);
1856 lError
= RegOpenKeyExW(hClassKey
,
1861 if (lError
!= ERROR_SUCCESS
)
1864 ret
= CR_NO_SUCH_REGISTRY_KEY
;
1868 lError
= RegOpenKeyExW(hInstKey
,
1873 if (lError
!= ERROR_SUCCESS
)
1876 ret
= CR_NO_SUCH_REGISTRY_KEY
;
1880 lError
= RegQueryValueExW(hPropKey
,
1886 if (lError
!= ERROR_SUCCESS
)
1888 if (lError
== ERROR_MORE_DATA
)
1890 ret
= CR_BUFFER_SMALL
;
1895 ret
= CR_NO_SUCH_VALUE
;
1900 if (ret
== CR_SUCCESS
)
1901 *pulTransferLen
= *pulLength
;
1903 if (hPropKey
!= NULL
)
1904 RegCloseKey(hPropKey
);
1906 if (hInstKey
!= NULL
)
1907 RegCloseKey(hInstKey
);
1909 DPRINT("PNP_GetClassRegProp() done (returns %lx)\n", ret
);
1918 PNP_SetClassRegProp(
1920 LPWSTR pszClassGuid
,
1924 PNP_PROP_SIZE ulLength
,
1927 CONFIGRET ret
= CR_SUCCESS
;
1928 LPWSTR lpValueName
= NULL
;
1933 UNREFERENCED_PARAMETER(hBinding
);
1935 DPRINT("PNP_SetClassRegProp() called\n");
1938 return CR_INVALID_FLAG
;
1942 case CM_CRP_SECURITY
:
1943 lpValueName
= L
"Security";
1946 case CM_CRP_DEVTYPE
:
1947 lpValueName
= L
"DeviceType";
1950 case CM_CRP_EXCLUSIVE
:
1951 lpValueName
= L
"Exclusive";
1954 case CM_CRP_CHARACTERISTICS
:
1955 lpValueName
= L
"DeviceCharacteristics";
1959 return CR_INVALID_PROPERTY
;
1962 lError
= RegOpenKeyExW(hClassKey
,
1967 if (lError
!= ERROR_SUCCESS
)
1969 ret
= CR_NO_SUCH_REGISTRY_KEY
;
1973 /* FIXME: Set security descriptor */
1974 lError
= RegCreateKeyExW(hInstKey
,
1978 REG_OPTION_NON_VOLATILE
,
1983 if (lError
!= ERROR_SUCCESS
)
1985 ret
= CR_REGISTRY_ERROR
;
1991 if (RegDeleteValueW(hPropKey
,
1993 ret
= CR_REGISTRY_ERROR
;
1997 if (RegSetValueExW(hPropKey
,
2003 ret
= CR_REGISTRY_ERROR
;
2007 if (hPropKey
!= NULL
)
2008 RegCloseKey(hPropKey
);
2010 if (hInstKey
!= NULL
)
2011 RegCloseKey(hInstKey
);
2018 CreateDeviceInstance(LPWSTR pszDeviceID
)
2020 WCHAR szEnumerator
[MAX_DEVICE_ID_LEN
];
2021 WCHAR szDevice
[MAX_DEVICE_ID_LEN
];
2022 WCHAR szInstance
[MAX_DEVICE_ID_LEN
];
2023 HKEY hKeyEnumerator
;
2029 /* Split the instance ID */
2030 SplitDeviceInstanceID(pszDeviceID
,
2035 /* Open or create the enumerator key */
2036 lError
= RegCreateKeyExW(hEnumKey
,
2040 REG_OPTION_NON_VOLATILE
,
2045 if (lError
!= ERROR_SUCCESS
)
2047 return CR_REGISTRY_ERROR
;
2050 /* Open or create the device key */
2051 lError
= RegCreateKeyExW(hKeyEnumerator
,
2055 REG_OPTION_NON_VOLATILE
,
2061 /* Close the enumerator key */
2062 RegCloseKey(hKeyEnumerator
);
2064 if (lError
!= ERROR_SUCCESS
)
2066 return CR_REGISTRY_ERROR
;
2069 /* Try to open the instance key and fail if it exists */
2070 lError
= RegOpenKeyExW(hKeyDevice
,
2075 if (lError
== ERROR_SUCCESS
)
2077 DPRINT1("Instance %S already exists!\n", szInstance
);
2078 RegCloseKey(hKeyInstance
);
2079 RegCloseKey(hKeyDevice
);
2080 return CR_ALREADY_SUCH_DEVINST
;
2083 /* Create a new instance key */
2084 lError
= RegCreateKeyExW(hKeyDevice
,
2088 REG_OPTION_NON_VOLATILE
,
2094 /* Close the device key */
2095 RegCloseKey(hKeyDevice
);
2097 if (lError
!= ERROR_SUCCESS
)
2099 return CR_REGISTRY_ERROR
;
2102 /* Create the 'Control' sub key */
2103 lError
= RegCreateKeyExW(hKeyInstance
,
2107 REG_OPTION_NON_VOLATILE
,
2112 if (lError
== ERROR_SUCCESS
)
2114 RegCloseKey(hKeyControl
);
2117 RegCloseKey(hKeyInstance
);
2119 return (lError
== ERROR_SUCCESS
) ? CR_SUCCESS
: CR_REGISTRY_ERROR
;
2129 LPWSTR pszParentDeviceID
,
2130 PNP_RPC_STRING_LEN ulLength
,
2133 CONFIGRET ret
= CR_SUCCESS
;
2135 DPRINT("PNP_CreateDevInst: %S\n", pszDeviceID
);
2137 if (ulFlags
& CM_CREATE_DEVNODE_GENERATE_ID
)
2139 WCHAR szGeneratedInstance
[MAX_DEVICE_ID_LEN
];
2140 DWORD dwInstanceNumber
;
2142 /* Generated ID is: Root\<Device ID>\<Instance number> */
2143 dwInstanceNumber
= 0;
2146 swprintf(szGeneratedInstance
, L
"Root\\%ls\\%04lu",
2147 pszDeviceID
, dwInstanceNumber
);
2149 /* Try to create a device instance with this ID */
2150 ret
= CreateDeviceInstance(szGeneratedInstance
);
2154 while (ret
== CR_ALREADY_SUCH_DEVINST
);
2156 if (ret
== CR_SUCCESS
)
2158 /* pszDeviceID is an out parameter too for generated IDs */
2159 if (wcslen(szGeneratedInstance
) > ulLength
)
2161 ret
= CR_BUFFER_SMALL
;
2165 wcscpy(pszDeviceID
, szGeneratedInstance
);
2171 /* Create the device instance */
2172 ret
= CreateDeviceInstance(pszDeviceID
);
2175 DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret
);
2182 MoveDeviceInstance(LPWSTR pszDeviceInstanceDestination
,
2183 LPWSTR pszDeviceInstanceSource
)
2185 DPRINT("MoveDeviceInstance: not implemented\n");
2187 return CR_CALL_NOT_IMPLEMENTED
;
2192 SetupDeviceInstance(LPWSTR pszDeviceInstance
,
2195 DPRINT("SetupDeviceInstance: not implemented\n");
2197 return CR_CALL_NOT_IMPLEMENTED
;
2202 EnableDeviceInstance(LPWSTR pszDeviceInstance
)
2204 PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
;
2205 CONFIGRET ret
= CR_SUCCESS
;
2208 DPRINT("Enable device instance %S\n", pszDeviceInstance
);
2210 RtlInitUnicodeString(&ResetDeviceData
.DeviceInstance
, pszDeviceInstance
);
2211 Status
= NtPlugPlayControl(PlugPlayControlResetDevice
, &ResetDeviceData
, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
));
2212 if (!NT_SUCCESS(Status
))
2213 ret
= NtStatusToCrError(Status
);
2220 DisableDeviceInstance(LPWSTR pszDeviceInstance
)
2222 DPRINT("DisableDeviceInstance: not implemented\n");
2224 return CR_CALL_NOT_IMPLEMENTED
;
2229 ReenumerateDeviceInstance(
2230 _In_ LPWSTR pszDeviceInstance
,
2233 PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA EnumerateDeviceData
;
2234 CONFIGRET ret
= CR_SUCCESS
;
2237 DPRINT1("ReenumerateDeviceInstance(%S 0x%08lx)\n",
2238 pszDeviceInstance
, ulFlags
);
2240 if (ulFlags
& ~CM_REENUMERATE_BITS
)
2241 return CR_INVALID_FLAG
;
2243 if (ulFlags
& CM_REENUMERATE_RETRY_INSTALLATION
)
2245 DPRINT1("CM_REENUMERATE_RETRY_INSTALLATION not implemented!\n");
2248 RtlInitUnicodeString(&EnumerateDeviceData
.DeviceInstance
,
2250 EnumerateDeviceData
.Flags
= 0;
2252 Status
= NtPlugPlayControl(PlugPlayControlEnumerateDevice
,
2253 &EnumerateDeviceData
,
2254 sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA
));
2255 if (!NT_SUCCESS(Status
))
2256 ret
= NtStatusToCrError(Status
);
2265 PNP_DeviceInstanceAction(
2269 LPWSTR pszDeviceInstance1
,
2270 LPWSTR pszDeviceInstance2
)
2272 CONFIGRET ret
= CR_SUCCESS
;
2274 UNREFERENCED_PARAMETER(hBinding
);
2276 DPRINT("PNP_DeviceInstanceAction() called\n");
2280 case PNP_DEVINST_MOVE
:
2281 ret
= MoveDeviceInstance(pszDeviceInstance1
,
2282 pszDeviceInstance2
);
2285 case PNP_DEVINST_SETUP
:
2286 ret
= SetupDeviceInstance(pszDeviceInstance1
,
2290 case PNP_DEVINST_ENABLE
:
2291 ret
= EnableDeviceInstance(pszDeviceInstance1
);
2294 case PNP_DEVINST_DISABLE
:
2295 ret
= DisableDeviceInstance(pszDeviceInstance1
);
2298 case PNP_DEVINST_REENUMERATE
:
2299 ret
= ReenumerateDeviceInstance(pszDeviceInstance1
,
2304 DPRINT1("Unknown device action %lu: not implemented\n", ulAction
);
2305 ret
= CR_CALL_NOT_IMPLEMENTED
;
2308 DPRINT("PNP_DeviceInstanceAction() done (returns %lx)\n", ret
);
2317 PNP_GetDeviceStatus(
2324 PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData
;
2325 CONFIGRET ret
= CR_SUCCESS
;
2328 UNREFERENCED_PARAMETER(hBinding
);
2329 UNREFERENCED_PARAMETER(ulFlags
);
2331 DPRINT("PNP_GetDeviceStatus() called\n");
2333 RtlInitUnicodeString(&PlugPlayData
.DeviceInstance
,
2335 PlugPlayData
.Operation
= 0; /* Get status */
2337 Status
= NtPlugPlayControl(PlugPlayControlDeviceStatus
,
2338 (PVOID
)&PlugPlayData
,
2339 sizeof(PLUGPLAY_CONTROL_STATUS_DATA
));
2340 if (NT_SUCCESS(Status
))
2342 *pulStatus
= PlugPlayData
.DeviceStatus
;
2343 *pulProblem
= PlugPlayData
.DeviceProblem
;
2347 ret
= NtStatusToCrError(Status
);
2350 DPRINT("PNP_GetDeviceStatus() done (returns %lx)\n", ret
);
2359 PNP_SetDeviceProblem(
2366 return CR_CALL_NOT_IMPLEMENTED
;
2376 PPNP_VETO_TYPE pVetoType
,
2382 return CR_CALL_NOT_IMPLEMENTED
;
2388 PNP_UninstallDevInst(
2394 return CR_CALL_NOT_IMPLEMENTED
;
2399 CheckForDeviceId(LPWSTR lpDeviceIdList
,
2405 lpPtr
= lpDeviceIdList
;
2408 dwLength
= wcslen(lpPtr
);
2409 if (0 == _wcsicmp(lpPtr
, lpDeviceId
))
2412 lpPtr
+= (dwLength
+ 1);
2420 AppendDeviceId(LPWSTR lpDeviceIdList
,
2421 LPDWORD lpDeviceIdListSize
,
2427 dwLen
= wcslen(lpDeviceId
);
2428 dwPos
= (*lpDeviceIdListSize
/ sizeof(WCHAR
)) - 1;
2430 wcscpy(&lpDeviceIdList
[dwPos
], lpDeviceId
);
2432 dwPos
+= (dwLen
+ 1);
2434 lpDeviceIdList
[dwPos
] = 0;
2436 *lpDeviceIdListSize
= dwPos
* sizeof(WCHAR
);
2449 CONFIGRET ret
= CR_SUCCESS
;
2452 DWORD dwDeviceIdListSize
;
2453 DWORD dwNewDeviceIdSize
;
2454 WCHAR
* pszDeviceIdList
= NULL
;
2456 UNREFERENCED_PARAMETER(hBinding
);
2458 DPRINT("PNP_AddID() called\n");
2459 DPRINT(" DeviceInstance: %S\n", pszDeviceID
);
2460 DPRINT(" DeviceId: %S\n", pszID
);
2461 DPRINT(" Flags: %lx\n", ulFlags
);
2463 if (RegOpenKeyExW(hEnumKey
,
2466 KEY_QUERY_VALUE
| KEY_SET_VALUE
,
2467 &hDeviceKey
) != ERROR_SUCCESS
)
2469 DPRINT("Failed to open the device key!\n");
2470 return CR_INVALID_DEVNODE
;
2473 pszSubKey
= (ulFlags
& CM_ADD_ID_COMPATIBLE
) ? L
"CompatibleIDs" : L
"HardwareID";
2475 if (RegQueryValueExW(hDeviceKey
,
2480 &dwDeviceIdListSize
) != ERROR_SUCCESS
)
2482 DPRINT("Failed to query the desired ID string!\n");
2483 ret
= CR_REGISTRY_ERROR
;
2487 dwNewDeviceIdSize
= lstrlenW(pszDeviceID
);
2488 if (!dwNewDeviceIdSize
)
2490 ret
= CR_INVALID_POINTER
;
2494 dwDeviceIdListSize
+= (dwNewDeviceIdSize
+ 2) * sizeof(WCHAR
);
2496 pszDeviceIdList
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDeviceIdListSize
);
2497 if (!pszDeviceIdList
)
2499 DPRINT("Failed to allocate memory for the desired ID string!\n");
2500 ret
= CR_OUT_OF_MEMORY
;
2504 if (RegQueryValueExW(hDeviceKey
,
2508 (LPBYTE
)pszDeviceIdList
,
2509 &dwDeviceIdListSize
) != ERROR_SUCCESS
)
2511 DPRINT("Failed to query the desired ID string!\n");
2512 ret
= CR_REGISTRY_ERROR
;
2516 /* Check whether the device ID is already in use */
2517 if (CheckForDeviceId(pszDeviceIdList
, pszDeviceID
))
2519 DPRINT("Device ID was found in the ID string!\n");
2524 /* Append the Device ID */
2525 AppendDeviceId(pszDeviceIdList
, &dwDeviceIdListSize
, pszID
);
2527 if (RegSetValueExW(hDeviceKey
,
2531 (LPBYTE
)pszDeviceIdList
,
2532 dwDeviceIdListSize
) != ERROR_SUCCESS
)
2534 DPRINT("Failed to set the desired ID string!\n");
2535 ret
= CR_REGISTRY_ERROR
;
2539 RegCloseKey(hDeviceKey
);
2540 if (pszDeviceIdList
)
2541 HeapFree(GetProcessHeap(), 0, pszDeviceIdList
);
2543 DPRINT("PNP_AddID() done (returns %lx)\n", ret
);
2558 return CR_CALL_NOT_IMPLEMENTED
;
2568 PPNP_VETO_TYPE pVetoType
,
2574 return CR_CALL_NOT_IMPLEMENTED
;
2581 PNP_RequestDeviceEject(
2584 PPNP_VETO_TYPE pVetoType
,
2590 return CR_CALL_NOT_IMPLEMENTED
;
2597 PNP_IsDockStationPresent(
2605 CONFIGRET ret
= CR_SUCCESS
;
2607 UNREFERENCED_PARAMETER(hBinding
);
2609 DPRINT1("PNP_IsDockStationPresent() called\n");
2613 if (RegOpenKeyExW(HKEY_CURRENT_CONFIG
,
2617 &hKey
) != ERROR_SUCCESS
)
2618 return CR_REGISTRY_ERROR
;
2620 dwSize
= sizeof(DWORD
);
2621 if (RegQueryValueExW(hKey
,
2626 &dwSize
) != ERROR_SUCCESS
)
2627 ret
= CR_REGISTRY_ERROR
;
2631 if (ret
== CR_SUCCESS
)
2633 if (dwType
!= REG_DWORD
|| dwSize
!= sizeof(DWORD
))
2635 ret
= CR_REGISTRY_ERROR
;
2637 else if (dwValue
!= 0)
2643 DPRINT1("PNP_IsDockStationPresent() done (returns %lx)\n", ret
);
2656 return CR_CALL_NOT_IMPLEMENTED
;
2669 PPNP_VETO_TYPE pVetoType
,
2674 CONFIGRET ret
= CR_SUCCESS
;
2675 WCHAR szKeyName
[MAX_PATH
];
2680 UNREFERENCED_PARAMETER(hBinding
);
2682 DPRINT("PNP_HwProfFlags() called\n");
2687 L
"System\\CurrentControlSet\\HardwareProfiles\\Current\\System\\CurrentControlSet\\Enum");
2692 L
"System\\CurrentControlSet\\HardwareProfiles\\%04lu\\System\\CurrentControlSet\\Enum",
2696 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2700 &hKey
) != ERROR_SUCCESS
)
2701 return CR_REGISTRY_ERROR
;
2703 if (ulAction
== PNP_GET_HWPROFFLAGS
)
2705 if (RegOpenKeyExW(hKey
,
2709 &hDeviceKey
) != ERROR_SUCCESS
)
2715 dwSize
= sizeof(DWORD
);
2716 if (RegQueryValueExW(hDeviceKey
,
2721 &dwSize
) != ERROR_SUCCESS
)
2726 RegCloseKey(hDeviceKey
);
2729 else if (ulAction
== PNP_SET_HWPROFFLAGS
)
2731 /* FIXME: not implemented yet */
2732 ret
= CR_CALL_NOT_IMPLEMENTED
;
2747 HWPROFILEINFO
*pHWProfileInfo
,
2748 DWORD ulProfileInfoSize
,
2751 WCHAR szProfileName
[5];
2752 HKEY hKeyConfig
= NULL
;
2753 HKEY hKeyProfiles
= NULL
;
2754 HKEY hKeyProfile
= NULL
;
2755 DWORD dwDisposition
;
2758 CONFIGRET ret
= CR_SUCCESS
;
2760 UNREFERENCED_PARAMETER(hBinding
);
2762 DPRINT("PNP_GetHwProfInfo() called\n");
2764 if (ulProfileInfoSize
== 0)
2766 ret
= CR_INVALID_DATA
;
2772 ret
= CR_INVALID_FLAG
;
2776 /* Initialize the profile information */
2777 pHWProfileInfo
->HWPI_ulHWProfile
= 0;
2778 pHWProfileInfo
->HWPI_szFriendlyName
[0] = 0;
2779 pHWProfileInfo
->HWPI_dwFlags
= 0;
2781 /* Open the 'IDConfigDB' key */
2782 lError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
2783 L
"System\\CurrentControlSet\\Control\\IDConfigDB",
2786 REG_OPTION_NON_VOLATILE
,
2791 if (lError
!= ERROR_SUCCESS
)
2793 ret
= CR_REGISTRY_ERROR
;
2797 /* Open the 'Hardware Profiles' subkey */
2798 lError
= RegCreateKeyExW(hKeyConfig
,
2799 L
"Hardware Profiles",
2802 REG_OPTION_NON_VOLATILE
,
2803 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
2807 if (lError
!= ERROR_SUCCESS
)
2809 ret
= CR_REGISTRY_ERROR
;
2813 if (ulIndex
== (ULONG
)-1)
2815 dwSize
= sizeof(ULONG
);
2816 lError
= RegQueryValueExW(hKeyConfig
,
2820 (LPBYTE
)&pHWProfileInfo
->HWPI_ulHWProfile
,
2822 if (lError
!= ERROR_SUCCESS
)
2824 pHWProfileInfo
->HWPI_ulHWProfile
= 0;
2825 ret
= CR_REGISTRY_ERROR
;
2831 /* FIXME: not implemented yet */
2832 ret
= CR_CALL_NOT_IMPLEMENTED
;
2836 swprintf(szProfileName
, L
"%04lu", pHWProfileInfo
->HWPI_ulHWProfile
);
2838 lError
= RegOpenKeyExW(hKeyProfiles
,
2843 if (lError
!= ERROR_SUCCESS
)
2845 ret
= CR_REGISTRY_ERROR
;
2849 dwSize
= sizeof(pHWProfileInfo
->HWPI_szFriendlyName
);
2850 lError
= RegQueryValueExW(hKeyProfile
,
2854 (LPBYTE
)&pHWProfileInfo
->HWPI_szFriendlyName
,
2856 if (lError
!= ERROR_SUCCESS
)
2858 ret
= CR_REGISTRY_ERROR
;
2863 if (hKeyProfile
!= NULL
)
2864 RegCloseKey(hKeyProfile
);
2866 if (hKeyProfiles
!= NULL
)
2867 RegCloseKey(hKeyProfiles
);
2869 if (hKeyConfig
!= NULL
)
2870 RegCloseKey(hKeyConfig
);
2879 PNP_AddEmptyLogConf(
2883 DWORD
*pulLogConfTag
,
2887 return CR_CALL_NOT_IMPLEMENTED
;
2897 DWORD ulLogConfType
,
2902 return CR_CALL_NOT_IMPLEMENTED
;
2909 PNP_GetFirstLogConf(
2912 DWORD ulLogConfType
,
2913 DWORD
*pulLogConfTag
,
2917 return CR_CALL_NOT_IMPLEMENTED
;
2927 DWORD ulLogConfType
,
2933 return CR_CALL_NOT_IMPLEMENTED
;
2940 PNP_GetLogConfPriority(
2949 return CR_CALL_NOT_IMPLEMENTED
;
2960 DWORD ulLogConfType
,
2961 RESOURCEID ResourceID
,
2962 DWORD
*pulResourceTag
,
2964 PNP_RPC_BUFFER_SIZE ResourceLen
,
2968 return CR_CALL_NOT_IMPLEMENTED
;
2979 DWORD ulLogConfType
,
2980 RESOURCEID ResourceID
,
2981 DWORD ulResourceTag
,
2982 DWORD
*pulPreviousResType
,
2983 DWORD
*pulPreviousResTag
,
2987 return CR_CALL_NOT_IMPLEMENTED
;
2998 DWORD ulLogConfType
,
2999 RESOURCEID ResourceID
,
3000 DWORD ulResourceTag
,
3001 DWORD
*pulNextResType
,
3002 DWORD
*pulNextResTag
,
3006 return CR_CALL_NOT_IMPLEMENTED
;
3017 DWORD ulLogConfType
,
3018 RESOURCEID ResourceID
,
3019 DWORD ulResourceTag
,
3021 PNP_RPC_BUFFER_SIZE BufferLen
,
3025 return CR_CALL_NOT_IMPLEMENTED
;
3032 PNP_GetResDesDataSize(
3036 DWORD ulLogConfType
,
3037 RESOURCEID ResourceID
,
3038 DWORD ulResourceTag
,
3043 return CR_CALL_NOT_IMPLEMENTED
;
3054 DWORD ulLogConfType
,
3055 RESOURCEID CurrentResourceID
,
3056 RESOURCEID NewResourceID
,
3057 DWORD ulResourceTag
,
3059 PNP_RPC_BUFFER_SIZE ResourceLen
,
3063 return CR_CALL_NOT_IMPLEMENTED
;
3070 PNP_DetectResourceConflict(
3073 RESOURCEID ResourceID
,
3075 PNP_RPC_BUFFER_SIZE ResourceLen
,
3076 BOOL
*pbConflictDetected
,
3079 DPRINT("PNP_DetectResourceConflict()\n");
3081 if (pbConflictDetected
!= NULL
)
3082 *pbConflictDetected
= FALSE
;
3084 return CR_CALL_NOT_IMPLEMENTED
;
3091 PNP_QueryResConfList(
3094 RESOURCEID ResourceID
,
3096 PNP_RPC_BUFFER_SIZE ResourceLen
,
3098 PNP_RPC_BUFFER_SIZE BufferLen
,
3102 return CR_CALL_NOT_IMPLEMENTED
;
3111 DWORD ulHardwareProfile
,
3115 return CR_CALL_NOT_IMPLEMENTED
;
3122 PNP_QueryArbitratorFreeData(
3127 RESOURCEID ResourceID
,
3131 return CR_CALL_NOT_IMPLEMENTED
;
3138 PNP_QueryArbitratorFreeSize(
3142 RESOURCEID ResourceID
,
3146 return CR_CALL_NOT_IMPLEMENTED
;
3157 return CR_CALL_NOT_IMPLEMENTED
;
3164 PNP_RegisterNotification(
3170 PNOTIFY_DATA pNotifyData
;
3173 DPRINT1("PNP_RegisterNotification(%p 0x%lx %p)\n",
3174 hBinding
, ulFlags
, pulNotify
);
3177 pNotifyData
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(NOTIFY_DATA
));
3178 if (pNotifyData
== NULL
)
3179 return CR_OUT_OF_MEMORY
;
3181 *pulNotify
= (DWORD
)pNotifyData
;
3193 PNP_UnregisterNotification(
3197 DPRINT1("PNP_UnregisterNotification(%p 0x%lx)\n",
3198 hBinding
, ulNotify
);
3202 return CR_CALL_NOT_IMPLEMENTED
;
3212 PNP_GetCustomDevProp(
3215 LPWSTR CustomPropName
,
3216 DWORD
*pulRegDataType
,
3218 PNP_RPC_STRING_LEN
*pulTransferLen
,
3219 PNP_RPC_STRING_LEN
*pulLength
,
3222 HKEY hDeviceKey
= NULL
;
3223 HKEY hParamKey
= NULL
;
3225 CONFIGRET ret
= CR_SUCCESS
;
3227 UNREFERENCED_PARAMETER(hBinding
);
3229 DPRINT("PNP_GetCustomDevProp() called\n");
3231 if (pulTransferLen
== NULL
|| pulLength
== NULL
)
3233 ret
= CR_INVALID_POINTER
;
3237 if (ulFlags
& ~CM_CUSTOMDEVPROP_BITS
)
3239 ret
= CR_INVALID_FLAG
;
3243 if (*pulLength
< *pulTransferLen
)
3244 *pulLength
= *pulTransferLen
;
3246 *pulTransferLen
= 0;
3248 lError
= RegOpenKeyExW(hEnumKey
,
3253 if (lError
!= ERROR_SUCCESS
)
3255 ret
= CR_REGISTRY_ERROR
;
3259 lError
= RegOpenKeyExW(hDeviceKey
,
3260 L
"Device Parameters",
3264 if (lError
!= ERROR_SUCCESS
)
3266 ret
= CR_REGISTRY_ERROR
;
3270 lError
= RegQueryValueExW(hParamKey
,
3276 if (lError
!= ERROR_SUCCESS
)
3278 if (lError
== ERROR_MORE_DATA
)
3280 ret
= CR_BUFFER_SMALL
;
3285 ret
= CR_NO_SUCH_VALUE
;
3290 if (ret
== CR_SUCCESS
)
3291 *pulTransferLen
= *pulLength
;
3293 if (hParamKey
!= NULL
)
3294 RegCloseKey(hParamKey
);
3296 if (hDeviceKey
!= NULL
)
3297 RegCloseKey(hDeviceKey
);
3299 DPRINT("PNP_GetCustomDevProp() done (returns %lx)\n", ret
);
3308 PNP_GetVersionInternal(
3312 UNREFERENCED_PARAMETER(hBinding
);
3322 PNP_GetBlockedDriverInfo(
3325 PNP_RPC_BUFFER_SIZE
*pulTransferLen
,
3326 PNP_RPC_BUFFER_SIZE
*pulLength
,
3330 return CR_CALL_NOT_IMPLEMENTED
;
3337 PNP_GetServerSideDeviceInstallFlags(
3339 DWORD
*pulSSDIFlags
,
3342 UNREFERENCED_PARAMETER(hBinding
);
3344 DPRINT1("PNP_GetServerSideDeviceInstallFlags(%p %p %lu)\n",
3345 hBinding
, pulSSDIFlags
, ulFlags
);
3347 if (pulSSDIFlags
== NULL
)
3348 return CR_INVALID_POINTER
;
3351 return CR_INVALID_FLAG
;
3363 PNP_GetObjectPropKeys(
3367 LPWSTR PropertyCultureName
,
3368 PNP_PROP_COUNT
*PropertyCount
,
3369 PNP_PROP_COUNT
*TransferLen
,
3370 DEVPROPKEY
*PropertyKeys
,
3374 return CR_CALL_NOT_IMPLEMENTED
;
3385 LPWSTR PropertyCultureName
,
3386 const DEVPROPKEY
*PropertyKey
,
3387 DEVPROPTYPE
*PropertyType
,
3388 PNP_PROP_SIZE
*PropertySize
,
3389 PNP_PROP_SIZE
*TransferLen
,
3390 BYTE
*PropertyBuffer
,
3394 return CR_CALL_NOT_IMPLEMENTED
;
3405 LPWSTR PropertyCultureName
,
3406 const DEVPROPKEY
*PropertyKey
,
3407 DEVPROPTYPE PropertyType
,
3408 PNP_PROP_SIZE PropertySize
,
3409 BYTE
*PropertyBuffer
,
3413 return CR_CALL_NOT_IMPLEMENTED
;
3424 return CR_CALL_NOT_IMPLEMENTED
;
3431 PNP_ApplyPowerSettings(
3435 return CR_CALL_NOT_IMPLEMENTED
;
3442 PNP_DriverStoreAddDriverPackage(
3446 return CR_CALL_NOT_IMPLEMENTED
;
3453 PNP_DriverStoreDeleteDriverPackage(
3457 return CR_CALL_NOT_IMPLEMENTED
;
3464 PNP_RegisterServiceNotification(
3468 return CR_CALL_NOT_IMPLEMENTED
;
3475 PNP_SetActiveService(
3481 return CR_CALL_NOT_IMPLEMENTED
;
3488 PNP_DeleteServiceDevices(
3492 return CR_CALL_NOT_IMPLEMENTED
;
3497 InstallDevice(PCWSTR DeviceInstance
, BOOL ShowWizard
)
3499 BOOL DeviceInstalled
= FALSE
;
3502 HANDLE hInstallEvent
;
3503 HANDLE hPipe
= INVALID_HANDLE_VALUE
;
3504 LPVOID Environment
= NULL
;
3505 PROCESS_INFORMATION ProcessInfo
;
3506 STARTUPINFOW StartupInfo
;
3510 /* The following lengths are constant (see below), they cannot overflow */
3511 WCHAR CommandLine
[116];
3512 WCHAR InstallEventName
[73];
3514 WCHAR UuidString
[39];
3516 DPRINT("InstallDevice(%S, %d)\n", DeviceInstance
, ShowWizard
);
3518 ZeroMemory(&ProcessInfo
, sizeof(ProcessInfo
));
3520 if (RegOpenKeyExW(hEnumKey
,
3524 &DeviceKey
) == ERROR_SUCCESS
)
3526 if (RegQueryValueExW(DeviceKey
,
3531 NULL
) == ERROR_SUCCESS
)
3533 DPRINT("No need to install: %S\n", DeviceInstance
);
3534 RegCloseKey(DeviceKey
);
3538 BytesWritten
= sizeof(DWORD
);
3539 if (RegQueryValueExW(DeviceKey
,
3544 &BytesWritten
) == ERROR_SUCCESS
)
3546 if (Value
& CONFIGFLAG_FAILEDINSTALL
)
3548 DPRINT("No need to install: %S\n", DeviceInstance
);
3549 RegCloseKey(DeviceKey
);
3554 RegCloseKey(DeviceKey
);
3557 DPRINT1("Installing: %S\n", DeviceInstance
);
3559 /* Create a random UUID for the named pipe & event*/
3560 UuidCreate(&RandomUuid
);
3561 swprintf(UuidString
, L
"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
3562 RandomUuid
.Data1
, RandomUuid
.Data2
, RandomUuid
.Data3
,
3563 RandomUuid
.Data4
[0], RandomUuid
.Data4
[1], RandomUuid
.Data4
[2],
3564 RandomUuid
.Data4
[3], RandomUuid
.Data4
[4], RandomUuid
.Data4
[5],
3565 RandomUuid
.Data4
[6], RandomUuid
.Data4
[7]);
3567 /* Create the event */
3568 wcscpy(InstallEventName
, L
"Global\\PNP_Device_Install_Event_0.");
3569 wcscat(InstallEventName
, UuidString
);
3570 hInstallEvent
= CreateEventW(NULL
, TRUE
, FALSE
, InstallEventName
);
3573 DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName
, GetLastError());
3577 /* Create the named pipe */
3578 wcscpy(PipeName
, L
"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
3579 wcscat(PipeName
, UuidString
);
3580 hPipe
= CreateNamedPipeW(PipeName
, PIPE_ACCESS_OUTBOUND
, PIPE_TYPE_BYTE
, 1, 512, 512, 0, NULL
);
3581 if (hPipe
== INVALID_HANDLE_VALUE
)
3583 DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
3587 /* Launch rundll32 to call ClientSideInstallW */
3588 wcscpy(CommandLine
, L
"rundll32.exe newdev.dll,ClientSideInstall ");
3589 wcscat(CommandLine
, PipeName
);
3591 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
3592 StartupInfo
.cb
= sizeof(StartupInfo
);
3596 /* newdev has to run under the environment of the current user */
3597 if (!CreateEnvironmentBlock(&Environment
, hUserToken
, FALSE
))
3599 DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
3603 if (!CreateProcessAsUserW(hUserToken
, NULL
, CommandLine
, NULL
, NULL
, FALSE
, CREATE_UNICODE_ENVIRONMENT
, Environment
, NULL
, &StartupInfo
, &ProcessInfo
))
3605 DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
3611 /* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
3613 Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
3614 (ShowWizard is only set to FALSE for these two modes) */
3615 ASSERT(!ShowWizard
);
3617 if (!CreateProcessW(NULL
, CommandLine
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &StartupInfo
, &ProcessInfo
))
3619 DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
3624 /* Wait for the function to connect to our pipe */
3625 if (!ConnectNamedPipe(hPipe
, NULL
))
3627 if (GetLastError() != ERROR_PIPE_CONNECTED
)
3629 DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
3634 /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
3635 Value
= sizeof(InstallEventName
);
3636 WriteFile(hPipe
, &Value
, sizeof(Value
), &BytesWritten
, NULL
);
3637 WriteFile(hPipe
, InstallEventName
, Value
, &BytesWritten
, NULL
);
3639 /* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
3640 Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
3641 WriteFile(hPipe
, &ShowWizard
, sizeof(ShowWizard
), &BytesWritten
, NULL
);
3643 Value
= (wcslen(DeviceInstance
) + 1) * sizeof(WCHAR
);
3644 WriteFile(hPipe
, &Value
, sizeof(Value
), &BytesWritten
, NULL
);
3645 WriteFile(hPipe
, DeviceInstance
, Value
, &BytesWritten
, NULL
);
3647 /* Wait for newdev.dll to finish processing */
3648 WaitForSingleObject(ProcessInfo
.hProcess
, INFINITE
);
3650 /* If the event got signalled, this is success */
3651 DeviceInstalled
= WaitForSingleObject(hInstallEvent
, 0) == WAIT_OBJECT_0
;
3655 CloseHandle(hInstallEvent
);
3657 if (hPipe
!= INVALID_HANDLE_VALUE
)
3661 DestroyEnvironmentBlock(Environment
);
3663 if (ProcessInfo
.hProcess
)
3664 CloseHandle(ProcessInfo
.hProcess
);
3666 if (ProcessInfo
.hThread
)
3667 CloseHandle(ProcessInfo
.hThread
);
3669 if (!DeviceInstalled
)
3671 DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance
);
3674 return DeviceInstalled
;
3690 return ERROR_INVALID_PARAMETER
;
3693 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, &dwType
, NULL
, &cbData
);
3694 if (rc
!= ERROR_SUCCESS
)
3696 if (dwType
!= REG_SZ
)
3697 return ERROR_FILE_NOT_FOUND
;
3698 Value
= HeapAlloc(GetProcessHeap(), 0, cbData
+ sizeof(WCHAR
));
3700 return ERROR_NOT_ENOUGH_MEMORY
;
3701 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, NULL
, (LPBYTE
)Value
, &cbData
);
3702 if (rc
!= ERROR_SUCCESS
)
3704 HeapFree(GetProcessHeap(), 0, Value
);
3707 /* NULL-terminate the string */
3708 Value
[cbData
/ sizeof(WCHAR
)] = '\0';
3711 return ERROR_SUCCESS
;
3719 DWORD regType
, active
, size
;
3723 rc
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"SYSTEM\\Setup", 0, KEY_QUERY_VALUE
, &hKey
);
3724 if (rc
!= ERROR_SUCCESS
)
3727 size
= sizeof(DWORD
);
3728 rc
= RegQueryValueExW(hKey
, L
"SystemSetupInProgress", NULL
, ®Type
, (LPBYTE
)&active
, &size
);
3729 if (rc
!= ERROR_SUCCESS
)
3731 if (regType
!= REG_DWORD
|| size
!= sizeof(DWORD
))
3734 ret
= (active
!= 0);
3740 DPRINT("System setup in progress? %S\n", ret
? L
"YES" : L
"NO");
3749 HKEY ControlKey
= NULL
;
3750 LPWSTR SystemStartOptions
= NULL
;
3751 LPWSTR CurrentOption
, NextOption
; /* Pointers into SystemStartOptions */
3752 BOOL ConsoleBoot
= FALSE
;
3757 L
"SYSTEM\\CurrentControlSet\\Control",
3762 rc
= ReadRegSzKey(ControlKey
, L
"SystemStartOptions", &SystemStartOptions
);
3763 if (rc
!= ERROR_SUCCESS
)
3766 /* Check for CONSOLE switch in SystemStartOptions */
3767 CurrentOption
= SystemStartOptions
;
3768 while (CurrentOption
)
3770 NextOption
= wcschr(CurrentOption
, L
' ');
3772 *NextOption
= L
'\0';
3773 if (_wcsicmp(CurrentOption
, L
"CONSOLE") == 0)
3775 DPRINT("Found %S. Switching to console boot\n", CurrentOption
);
3779 CurrentOption
= NextOption
? NextOption
+ 1 : NULL
;
3783 if (ControlKey
!= NULL
)
3784 RegCloseKey(ControlKey
);
3785 HeapFree(GetProcessHeap(), 0, SystemStartOptions
);
3790 /* Loop to install all queued devices installations */
3792 DeviceInstallThread(LPVOID lpParameter
)
3794 PSLIST_ENTRY ListEntry
;
3795 DeviceInstallParams
* Params
;
3798 UNREFERENCED_PARAMETER(lpParameter
);
3800 WaitForSingleObject(hInstallEvent
, INFINITE
);
3802 showWizard
= !SetupIsActive() && !IsConsoleBoot();
3806 ListEntry
= InterlockedPopEntrySList(&DeviceInstallListHead
);
3808 if (ListEntry
== NULL
)
3810 SetEvent(hNoPendingInstalls
);
3811 WaitForSingleObject(hDeviceInstallListNotEmpty
, INFINITE
);
3815 ResetEvent(hNoPendingInstalls
);
3816 Params
= CONTAINING_RECORD(ListEntry
, DeviceInstallParams
, ListEntry
);
3817 InstallDevice(Params
->DeviceIds
, showWizard
);
3818 HeapFree(GetProcessHeap(), 0, Params
);
3827 PnpEventThread(LPVOID lpParameter
)
3829 DWORD dwRet
= ERROR_SUCCESS
;
3831 RPC_STATUS RpcStatus
;
3832 PPLUGPLAY_EVENT_BLOCK PnpEvent
, NewPnpEvent
;
3835 UNREFERENCED_PARAMETER(lpParameter
);
3837 PnpEventSize
= 0x1000;
3838 PnpEvent
= HeapAlloc(GetProcessHeap(), 0, PnpEventSize
);
3839 if (PnpEvent
== NULL
)
3840 return ERROR_OUTOFMEMORY
;
3844 DPRINT("Calling NtGetPlugPlayEvent()\n");
3846 /* Wait for the next PnP event */
3847 Status
= NtGetPlugPlayEvent(0, 0, PnpEvent
, PnpEventSize
);
3849 /* Resize the buffer for the PnP event if it's too small */
3850 if (Status
== STATUS_BUFFER_TOO_SMALL
)
3852 PnpEventSize
+= 0x400;
3853 NewPnpEvent
= HeapReAlloc(GetProcessHeap(), 0, PnpEvent
, PnpEventSize
);
3854 if (NewPnpEvent
== NULL
)
3856 dwRet
= ERROR_OUTOFMEMORY
;
3859 PnpEvent
= NewPnpEvent
;
3863 if (!NT_SUCCESS(Status
))
3865 DPRINT1("NtGetPlugPlayEvent() failed (Status 0x%08lx)\n", Status
);
3869 /* Process the PnP event */
3870 DPRINT("Received PnP Event\n");
3871 if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_ENUMERATED
, &RpcStatus
))
3873 DeviceInstallParams
* Params
;
3875 DWORD DeviceIdLength
;
3877 DPRINT("Device enumerated: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3879 DeviceIdLength
= lstrlenW(PnpEvent
->TargetDevice
.DeviceIds
);
3882 /* Queue device install (will be dequeued by DeviceInstallThread) */
3883 len
= FIELD_OFFSET(DeviceInstallParams
, DeviceIds
) + (DeviceIdLength
+ 1) * sizeof(WCHAR
);
3884 Params
= HeapAlloc(GetProcessHeap(), 0, len
);
3887 wcscpy(Params
->DeviceIds
, PnpEvent
->TargetDevice
.DeviceIds
);
3888 InterlockedPushEntrySList(&DeviceInstallListHead
, &Params
->ListEntry
);
3889 SetEvent(hDeviceInstallListNotEmpty
);
3893 else if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_ARRIVAL
, &RpcStatus
))
3895 // DWORD dwRecipient;
3897 DPRINT("Device arrival: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3899 // dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
3900 // BroadcastSystemMessageW(BSF_POSTMESSAGE,
3903 // DBT_DEVNODES_CHANGED,
3905 SendMessageW(HWND_BROADCAST
, WM_DEVICECHANGE
, DBT_DEVNODES_CHANGED
, 0);
3907 else if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_EJECT_VETOED
, &RpcStatus
))
3909 DPRINT1("Eject vetoed: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3911 else if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_KERNEL_INITIATED_EJECT
, &RpcStatus
))
3913 DPRINT1("Kernel initiated eject: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3915 else if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_SAFE_REMOVAL
, &RpcStatus
))
3917 // DWORD dwRecipient;
3919 DPRINT1("Safe removal: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3921 // dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
3922 // BroadcastSystemMessageW(BSF_POSTMESSAGE,
3925 // DBT_DEVNODES_CHANGED,
3927 SendMessageW(HWND_BROADCAST
, WM_DEVICECHANGE
, DBT_DEVNODES_CHANGED
, 0);
3929 else if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_SURPRISE_REMOVAL
, &RpcStatus
))
3931 // DWORD dwRecipient;
3933 DPRINT1("Surprise removal: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3935 // dwRecipient = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
3936 // BroadcastSystemMessageW(BSF_POSTMESSAGE,
3939 // DBT_DEVNODES_CHANGED,
3941 SendMessageW(HWND_BROADCAST
, WM_DEVICECHANGE
, DBT_DEVNODES_CHANGED
, 0);
3943 else if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_REMOVAL_VETOED
, &RpcStatus
))
3945 DPRINT1("Removal vetoed: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3947 else if (UuidEqual(&PnpEvent
->EventGuid
, (UUID
*)&GUID_DEVICE_REMOVE_PENDING
, &RpcStatus
))
3949 DPRINT1("Removal pending: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
3953 DPRINT1("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
3954 PnpEvent
->EventGuid
.Data1
, PnpEvent
->EventGuid
.Data2
, PnpEvent
->EventGuid
.Data3
,
3955 PnpEvent
->EventGuid
.Data4
[0], PnpEvent
->EventGuid
.Data4
[1], PnpEvent
->EventGuid
.Data4
[2],
3956 PnpEvent
->EventGuid
.Data4
[3], PnpEvent
->EventGuid
.Data4
[4], PnpEvent
->EventGuid
.Data4
[5],
3957 PnpEvent
->EventGuid
.Data4
[6], PnpEvent
->EventGuid
.Data4
[7]);
3960 /* Dequeue the current PnP event and signal the next one */
3961 NtPlugPlayControl(PlugPlayControlUserResponse
, NULL
, 0);
3964 HeapFree(GetProcessHeap(), 0, PnpEvent
);
3971 UpdateServiceStatus(DWORD dwState
)
3973 ServiceStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
3974 ServiceStatus
.dwCurrentState
= dwState
;
3975 ServiceStatus
.dwControlsAccepted
= 0;
3976 ServiceStatus
.dwWin32ExitCode
= 0;
3977 ServiceStatus
.dwServiceSpecificExitCode
= 0;
3978 ServiceStatus
.dwCheckPoint
= 0;
3980 if (dwState
== SERVICE_START_PENDING
||
3981 dwState
== SERVICE_STOP_PENDING
||
3982 dwState
== SERVICE_PAUSE_PENDING
||
3983 dwState
== SERVICE_CONTINUE_PENDING
)
3984 ServiceStatus
.dwWaitHint
= 10000;
3986 ServiceStatus
.dwWaitHint
= 0;
3988 SetServiceStatus(ServiceStatusHandle
,
3994 ServiceControlHandler(DWORD dwControl
,
3999 DPRINT1("ServiceControlHandler() called\n");
4003 case SERVICE_CONTROL_STOP
:
4004 DPRINT1(" SERVICE_CONTROL_STOP received\n");
4005 /* Stop listening to RPC Messages */
4006 RpcMgmtStopServerListening(NULL
);
4007 UpdateServiceStatus(SERVICE_STOPPED
);
4008 return ERROR_SUCCESS
;
4010 case SERVICE_CONTROL_PAUSE
:
4011 DPRINT1(" SERVICE_CONTROL_PAUSE received\n");
4012 UpdateServiceStatus(SERVICE_PAUSED
);
4013 return ERROR_SUCCESS
;
4015 case SERVICE_CONTROL_CONTINUE
:
4016 DPRINT1(" SERVICE_CONTROL_CONTINUE received\n");
4017 UpdateServiceStatus(SERVICE_RUNNING
);
4018 return ERROR_SUCCESS
;
4020 case SERVICE_CONTROL_INTERROGATE
:
4021 DPRINT1(" SERVICE_CONTROL_INTERROGATE received\n");
4022 SetServiceStatus(ServiceStatusHandle
,
4024 return ERROR_SUCCESS
;
4026 case SERVICE_CONTROL_SHUTDOWN
:
4027 DPRINT1(" SERVICE_CONTROL_SHUTDOWN received\n");
4028 /* Stop listening to RPC Messages */
4029 RpcMgmtStopServerListening(NULL
);
4030 UpdateServiceStatus(SERVICE_STOPPED
);
4031 return ERROR_SUCCESS
;
4034 DPRINT1(" Control %lu received\n", dwControl
);
4035 return ERROR_CALL_NOT_IMPLEMENTED
;
4041 ServiceMain(DWORD argc
, LPTSTR
*argv
)
4046 UNREFERENCED_PARAMETER(argc
);
4047 UNREFERENCED_PARAMETER(argv
);
4049 DPRINT("ServiceMain() called\n");
4051 ServiceStatusHandle
= RegisterServiceCtrlHandlerExW(ServiceName
,
4052 ServiceControlHandler
,
4054 if (!ServiceStatusHandle
)
4056 DPRINT1("RegisterServiceCtrlHandlerExW() failed! (Error %lu)\n", GetLastError());
4060 UpdateServiceStatus(SERVICE_START_PENDING
);
4062 hThread
= CreateThread(NULL
,
4068 if (hThread
!= NULL
)
4069 CloseHandle(hThread
);
4071 hThread
= CreateThread(NULL
,
4077 if (hThread
!= NULL
)
4078 CloseHandle(hThread
);
4080 hThread
= CreateThread(NULL
,
4082 DeviceInstallThread
,
4086 if (hThread
!= NULL
)
4087 CloseHandle(hThread
);
4089 UpdateServiceStatus(SERVICE_RUNNING
);
4091 DPRINT("ServiceMain() done\n");
4095 InitializePnPManager(VOID
)
4100 DPRINT("UMPNPMGR: InitializePnPManager() started\n");
4102 /* We need this privilege for using CreateProcessAsUserW */
4103 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &OldValue
);
4105 hInstallEvent
= CreateEventW(NULL
, TRUE
, SetupIsActive()/*FALSE*/, NULL
);
4106 if (hInstallEvent
== NULL
)
4108 dwError
= GetLastError();
4109 DPRINT1("Could not create the Install Event! (Error %lu)\n", dwError
);
4113 hDeviceInstallListNotEmpty
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
4114 if (hDeviceInstallListNotEmpty
== NULL
)
4116 dwError
= GetLastError();
4117 DPRINT1("Could not create the Event! (Error %lu)\n", dwError
);
4121 hNoPendingInstalls
= CreateEventW(NULL
,
4124 L
"Global\\PnP_No_Pending_Install_Events");
4125 if (hNoPendingInstalls
== NULL
)
4127 dwError
= GetLastError();
4128 DPRINT1("Could not create the Event! (Error %lu)\n", dwError
);
4132 InitializeSListHead(&DeviceInstallListHead
);
4134 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
4135 L
"System\\CurrentControlSet\\Enum",
4139 if (dwError
!= ERROR_SUCCESS
)
4141 DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError
);
4145 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
4146 L
"System\\CurrentControlSet\\Control\\Class",
4150 if (dwError
!= ERROR_SUCCESS
)
4152 DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError
);
4156 DPRINT("UMPNPMGR: InitializePnPManager() done\n");
4162 DllMain(HINSTANCE hinstDLL
,
4168 case DLL_PROCESS_ATTACH
:
4169 DisableThreadLibraryCalls(hinstDLL
);
4170 InitializePnPManager();
4173 case DLL_PROCESS_DETACH
: