2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/deviface.c
5 * PURPOSE: Device interface functions
7 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
8 * Matthew Brace (ismarc@austin.rr.com)
9 * Hervé Poussineau (hpoussin@reactos.org)
12 /* INCLUDES ******************************************************************/
19 /* FUNCTIONS *****************************************************************/
21 static PWCHAR BaseKeyString
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
25 OpenRegistryHandlesFromSymbolicLink(IN PUNICODE_STRING SymbolicLinkName
,
26 IN ACCESS_MASK DesiredAccess
,
27 IN OPTIONAL PHANDLE GuidKey
,
28 IN OPTIONAL PHANDLE DeviceKey
,
29 IN OPTIONAL PHANDLE InstanceKey
)
31 OBJECT_ATTRIBUTES ObjectAttributes
;
32 WCHAR PathBuffer
[MAX_PATH
];
33 UNICODE_STRING BaseKeyU
;
34 UNICODE_STRING GuidString
, SubKeyName
, ReferenceString
;
35 PWCHAR StartPosition
, EndPosition
;
37 PHANDLE GuidKeyRealP
, DeviceKeyRealP
, InstanceKeyRealP
;
38 HANDLE GuidKeyReal
, DeviceKeyReal
, InstanceKeyReal
;
41 SubKeyName
.Buffer
= NULL
;
44 GuidKeyRealP
= GuidKey
;
46 GuidKeyRealP
= &GuidKeyReal
;
48 if (DeviceKey
!= NULL
)
49 DeviceKeyRealP
= DeviceKey
;
51 DeviceKeyRealP
= &DeviceKeyReal
;
53 if (InstanceKey
!= NULL
)
54 InstanceKeyRealP
= InstanceKey
;
56 InstanceKeyRealP
= &InstanceKeyReal
;
58 *GuidKeyRealP
= INVALID_HANDLE_VALUE
;
59 *DeviceKeyRealP
= INVALID_HANDLE_VALUE
;
60 *InstanceKeyRealP
= INVALID_HANDLE_VALUE
;
62 BaseKeyU
.Buffer
= PathBuffer
;
64 BaseKeyU
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
66 RtlAppendUnicodeToString(&BaseKeyU
, BaseKeyString
);
68 /* Open the DeviceClasses key */
69 InitializeObjectAttributes(&ObjectAttributes
,
71 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
74 Status
= ZwOpenKey(&ClassesKey
,
75 DesiredAccess
| KEY_ENUMERATE_SUB_KEYS
,
77 if (!NT_SUCCESS(Status
))
79 DPRINT1("Failed to open %wZ\n", &BaseKeyU
);
83 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
84 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
85 if (!StartPosition
|| !EndPosition
|| StartPosition
> EndPosition
)
87 DPRINT1("Bad symbolic link: %wZ\n", SymbolicLinkName
);
88 return STATUS_INVALID_PARAMETER_1
;
90 GuidString
.Buffer
= StartPosition
;
91 GuidString
.MaximumLength
= GuidString
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
);
93 InitializeObjectAttributes(&ObjectAttributes
,
95 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
98 Status
= ZwOpenKey(GuidKeyRealP
,
99 DesiredAccess
| KEY_ENUMERATE_SUB_KEYS
,
102 if (!NT_SUCCESS(Status
))
104 DPRINT1("Failed to open %wZ%wZ (%x)\n", &BaseKeyU
, &GuidString
, Status
);
108 SubKeyName
.Buffer
= ExAllocatePool(PagedPool
, SymbolicLinkName
->Length
);
109 if (!SubKeyName
.Buffer
)
111 Status
= STATUS_INSUFFICIENT_RESOURCES
;
114 SubKeyName
.MaximumLength
= SymbolicLinkName
->Length
;
115 SubKeyName
.Length
= 0;
117 RtlAppendUnicodeStringToString(&SubKeyName
,
120 SubKeyName
.Buffer
[0] = L
'#';
121 SubKeyName
.Buffer
[1] = L
'#';
122 SubKeyName
.Buffer
[2] = L
'?';
123 SubKeyName
.Buffer
[3] = L
'#';
125 ReferenceString
.Buffer
= wcsrchr(SubKeyName
.Buffer
, '\\');
126 if (ReferenceString
.Buffer
!= NULL
)
128 ReferenceString
.Buffer
[0] = L
'#';
130 SubKeyName
.Length
= ReferenceString
.Buffer
- SubKeyName
.Buffer
;
131 ReferenceString
.Length
= SymbolicLinkName
->Length
- SubKeyName
.Length
;
135 RtlInitUnicodeString(&ReferenceString
, L
"#");
138 InitializeObjectAttributes(&ObjectAttributes
,
140 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
143 Status
= ZwOpenKey(DeviceKeyRealP
,
144 DesiredAccess
| KEY_ENUMERATE_SUB_KEYS
,
146 if (!NT_SUCCESS(Status
))
148 DPRINT1("Failed to open %wZ%wZ\\%wZ\n", &BaseKeyU
, &GuidString
, &SubKeyName
);
152 InitializeObjectAttributes(&ObjectAttributes
,
154 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
157 Status
= ZwOpenKey(InstanceKeyRealP
,
160 if (!NT_SUCCESS(Status
))
162 DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU
, &GuidString
, &SubKeyName
, &ReferenceString
, Status
);
166 Status
= STATUS_SUCCESS
;
169 if (SubKeyName
.Buffer
!= NULL
)
170 ExFreePool(SubKeyName
.Buffer
);
172 if (NT_SUCCESS(Status
))
175 ZwClose(*GuidKeyRealP
);
178 ZwClose(*DeviceKeyRealP
);
181 ZwClose(*InstanceKeyRealP
);
185 if (*GuidKeyRealP
!= INVALID_HANDLE_VALUE
)
186 ZwClose(*GuidKeyRealP
);
188 if (*DeviceKeyRealP
!= INVALID_HANDLE_VALUE
)
189 ZwClose(*DeviceKeyRealP
);
191 if (*InstanceKeyRealP
!= INVALID_HANDLE_VALUE
)
192 ZwClose(*InstanceKeyRealP
);
198 * @name IoOpenDeviceInterfaceRegistryKey
201 * Provides a handle to the device's interface instance registry key.
204 * @param SymbolicLinkName
205 * Pointer to a string which identifies the device interface instance
207 * @param DesiredAccess
208 * Desired ACCESS_MASK used to access the key (like KEY_READ,
211 * @param DeviceInterfaceKey
212 * If a call has been succesfull, a handle to the registry key
213 * will be stored there
215 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
216 * otherwise (see WDK for details)
218 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
223 IoOpenDeviceInterfaceRegistryKey(IN PUNICODE_STRING SymbolicLinkName
,
224 IN ACCESS_MASK DesiredAccess
,
225 OUT PHANDLE DeviceInterfaceKey
)
227 WCHAR StrBuff
[MAX_PATH
], PathBuff
[MAX_PATH
];
228 PWCHAR Guid
, RefString
;
229 UNICODE_STRING DevParamU
= RTL_CONSTANT_STRING(L
"\\Device Parameters");
230 UNICODE_STRING PrefixU
= RTL_CONSTANT_STRING(L
"\\??\\");
231 UNICODE_STRING KeyPath
, KeyName
;
232 UNICODE_STRING MatchableGuid
;
233 UNICODE_STRING GuidString
;
234 HANDLE GuidKey
, hInterfaceKey
;
236 PKEY_BASIC_INFORMATION KeyInformation
;
237 ULONG KeyInformationLength
;
238 OBJECT_ATTRIBUTES ObjectAttributes
;
240 ULONG RequiredLength
;
242 swprintf(StrBuff
, L
"##?#%s", &SymbolicLinkName
->Buffer
[PrefixU
.Length
/ sizeof(WCHAR
)]);
244 RefString
= wcsstr(StrBuff
, L
"\\");
250 RtlInitUnicodeString(&MatchableGuid
, StrBuff
);
252 Guid
= wcsstr(StrBuff
, L
"{");
254 return STATUS_OBJECT_NAME_NOT_FOUND
;
256 KeyPath
.Buffer
= PathBuff
;
258 KeyPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
260 GuidString
.Buffer
= Guid
;
261 GuidString
.Length
= GuidString
.MaximumLength
= 38 * sizeof(WCHAR
);
263 RtlAppendUnicodeToString(&KeyPath
, BaseKeyString
);
264 RtlAppendUnicodeStringToString(&KeyPath
, &GuidString
);
266 InitializeObjectAttributes(&ObjectAttributes
,
268 OBJ_CASE_INSENSITIVE
,
272 Status
= ZwOpenKey(&GuidKey
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
);
273 if (!NT_SUCCESS(Status
))
278 Status
= ZwEnumerateKey(GuidKey
,
284 if (Status
== STATUS_NO_MORE_ENTRIES
)
286 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
288 KeyInformationLength
= RequiredLength
;
289 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
293 return STATUS_INSUFFICIENT_RESOURCES
;
296 Status
= ZwEnumerateKey(GuidKey
,
300 KeyInformationLength
,
306 return STATUS_OBJECT_PATH_NOT_FOUND
;
310 if (!NT_SUCCESS(Status
))
316 KeyName
.Length
= KeyName
.MaximumLength
= KeyInformation
->NameLength
;
317 KeyName
.Buffer
= KeyInformation
->Name
;
319 if (!RtlEqualUnicodeString(&KeyName
, &MatchableGuid
, TRUE
))
321 ExFreePool(KeyInformation
);
326 RtlAppendUnicodeStringToString(&KeyPath
, &KeyName
);
327 RtlAppendUnicodeToString(&KeyPath
, L
"\\");
329 /* check for presence of a reference string */
332 /* append reference string */
334 RtlInitUnicodeString(&KeyName
, RefString
);
338 /* no reference string */
339 RtlInitUnicodeString(&KeyName
, L
"#");
341 RtlAppendUnicodeStringToString(&KeyPath
, &KeyName
);
343 /* initialize reference string attributes */
344 InitializeObjectAttributes(&ObjectAttributes
,
346 OBJ_CASE_INSENSITIVE
,
350 /* now open device interface key */
351 Status
= ZwOpenKey(&hInterfaceKey
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
);
353 if (NT_SUCCESS(Status
))
355 /* check if it provides a DeviceParameters key */
356 InitializeObjectAttributes(&ObjectAttributes
, &DevParamU
, OBJ_CASE_INSENSITIVE
, hInterfaceKey
, NULL
);
358 Status
= ZwCreateKey(DeviceInterfaceKey
, DesiredAccess
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
360 if (NT_SUCCESS(Status
))
362 /* DeviceParameters key present */
363 ZwClose(hInterfaceKey
);
367 /* fall back to device interface */
368 *DeviceInterfaceKey
= hInterfaceKey
;
369 Status
= STATUS_SUCCESS
;
373 /* close class key */
375 ExFreePool(KeyInformation
);
379 return STATUS_OBJECT_PATH_NOT_FOUND
;
383 * @name IoGetDeviceInterfaceAlias
386 * Returns the alias device interface of the specified device interface
387 * instance, if the alias exists.
390 * @param SymbolicLinkName
391 * Pointer to a string which identifies the device interface instance
393 * @param AliasInterfaceClassGuid
396 * @param AliasSymbolicLinkName
399 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
400 * otherwise (see WDK for details)
402 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
407 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName
,
408 IN CONST GUID
*AliasInterfaceClassGuid
,
409 OUT PUNICODE_STRING AliasSymbolicLinkName
)
411 return STATUS_NOT_IMPLEMENTED
;
415 * @name IopOpenInterfaceKey
417 * Returns the alias device interface of the specified device interface
419 * @param InterfaceClassGuid
422 * @param DesiredAccess
425 * @param pInterfaceKey
428 * @return Usual NTSTATUS
434 IopOpenInterfaceKey(IN CONST GUID
*InterfaceClassGuid
,
435 IN ACCESS_MASK DesiredAccess
,
436 OUT HANDLE
*pInterfaceKey
)
438 UNICODE_STRING LocalMachine
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\");
439 UNICODE_STRING GuidString
;
440 UNICODE_STRING KeyName
;
441 OBJECT_ATTRIBUTES ObjectAttributes
;
442 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
445 GuidString
.Buffer
= KeyName
.Buffer
= NULL
;
447 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
448 if (!NT_SUCCESS(Status
))
450 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
455 KeyName
.MaximumLength
= LocalMachine
.Length
+ (wcslen(REGSTR_PATH_DEVICE_CLASSES
) + 1) * sizeof(WCHAR
) + GuidString
.Length
;
456 KeyName
.Buffer
= ExAllocatePool(PagedPool
, KeyName
.MaximumLength
);
459 DPRINT("ExAllocatePool() failed\n");
460 Status
= STATUS_INSUFFICIENT_RESOURCES
;
464 Status
= RtlAppendUnicodeStringToString(&KeyName
, &LocalMachine
);
465 if (!NT_SUCCESS(Status
))
467 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
470 Status
= RtlAppendUnicodeToString(&KeyName
, REGSTR_PATH_DEVICE_CLASSES
);
471 if (!NT_SUCCESS(Status
))
473 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
476 Status
= RtlAppendUnicodeToString(&KeyName
, L
"\\");
477 if (!NT_SUCCESS(Status
))
479 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
482 Status
= RtlAppendUnicodeStringToString(&KeyName
, &GuidString
);
483 if (!NT_SUCCESS(Status
))
485 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
489 InitializeObjectAttributes(
492 OBJ_CASE_INSENSITIVE
,
499 if (!NT_SUCCESS(Status
))
501 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
505 *pInterfaceKey
= InterfaceKey
;
506 Status
= STATUS_SUCCESS
;
509 if (!NT_SUCCESS(Status
))
511 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
512 ZwClose(InterfaceKey
);
514 RtlFreeUnicodeString(&GuidString
);
515 RtlFreeUnicodeString(&KeyName
);
520 * @name IoGetDeviceInterfaces
523 * Returns a list of device interfaces of a particular device interface class.
526 * @param InterfaceClassGuid
527 * Points to a class GUID specifying the device interface class
529 * @param PhysicalDeviceObject
530 * Points to an optional PDO that narrows the search to only the
531 * device interfaces of the device represented by the PDO
534 * Specifies flags that modify the search for device interfaces. The
535 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
536 * returned symbolic links should contain also disabled device
537 * interfaces in addition to the enabled ones.
539 * @param SymbolicLinkList
540 * Points to a character pointer that is filled in on successful return
541 * with a list of unicode strings identifying the device interfaces
542 * that match the search criteria. The newly allocated buffer contains
543 * a list of symbolic link names. Each unicode string in the list is
544 * null-terminated; the end of the whole list is marked by an additional
545 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
546 * when it is no longer needed.
547 * If no device interfaces match the search criteria, this routine
548 * returns STATUS_SUCCESS and the string contains a single NULL
551 * @return Usual NTSTATUS
558 IoGetDeviceInterfaces(IN CONST GUID
*InterfaceClassGuid
,
559 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
561 OUT PWSTR
*SymbolicLinkList
)
563 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
564 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
565 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
566 HANDLE DeviceKey
= INVALID_HANDLE_VALUE
;
567 HANDLE ReferenceKey
= INVALID_HANDLE_VALUE
;
568 HANDLE ControlKey
= INVALID_HANDLE_VALUE
;
569 PKEY_BASIC_INFORMATION DeviceBi
= NULL
;
570 PKEY_BASIC_INFORMATION ReferenceBi
= NULL
;
571 PKEY_VALUE_PARTIAL_INFORMATION bip
= NULL
;
572 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
573 UNICODE_STRING KeyName
;
574 OBJECT_ATTRIBUTES ObjectAttributes
;
575 BOOLEAN FoundRightPDO
= FALSE
;
576 ULONG i
= 0, j
, Size
, NeededLength
, ActualLength
, LinkedValue
;
577 UNICODE_STRING ReturnBuffer
= { 0, 0, NULL
};
582 Status
= IopOpenInterfaceKey(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, &InterfaceKey
);
583 if (!NT_SUCCESS(Status
))
585 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status
);
589 /* Enumerate subkeys (ie the different device objets) */
592 Status
= ZwEnumerateKey(
599 if (Status
== STATUS_NO_MORE_ENTRIES
)
603 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
605 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
609 DeviceBi
= ExAllocatePool(PagedPool
, Size
);
612 DPRINT("ExAllocatePool() failed\n");
613 Status
= STATUS_INSUFFICIENT_RESOURCES
;
616 Status
= ZwEnumerateKey(
623 if (!NT_SUCCESS(Status
))
625 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
629 /* Open device key */
630 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)DeviceBi
->NameLength
;
631 KeyName
.Buffer
= DeviceBi
->Name
;
632 InitializeObjectAttributes(
635 OBJ_CASE_INSENSITIVE
,
640 KEY_ENUMERATE_SUB_KEYS
,
642 if (!NT_SUCCESS(Status
))
644 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
648 if (PhysicalDeviceObject
)
650 /* Check if we are on the right physical device object,
651 * by reading the DeviceInstance string
653 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
654 //FoundRightPDO = TRUE;
655 Status
= STATUS_NOT_IMPLEMENTED
;
659 /* Enumerate subkeys (ie the different reference strings) */
663 Status
= ZwEnumerateKey(
670 if (Status
== STATUS_NO_MORE_ENTRIES
)
674 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
676 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
680 ReferenceBi
= ExAllocatePool(PagedPool
, Size
);
683 DPRINT("ExAllocatePool() failed\n");
684 Status
= STATUS_INSUFFICIENT_RESOURCES
;
687 Status
= ZwEnumerateKey(
694 if (!NT_SUCCESS(Status
))
696 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
700 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)ReferenceBi
->NameLength
;
701 KeyName
.Buffer
= ReferenceBi
->Name
;
702 if (RtlEqualUnicodeString(&KeyName
, &Control
, TRUE
))
704 /* Skip Control subkey */
705 goto NextReferenceString
;
708 /* Open reference key */
709 InitializeObjectAttributes(
712 OBJ_CASE_INSENSITIVE
,
719 if (!NT_SUCCESS(Status
))
721 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
725 if (!(Flags
& DEVICE_INTERFACE_INCLUDE_NONACTIVE
))
727 /* We have to check if the interface is enabled, by
728 * reading the Linked value in the Control subkey
730 InitializeObjectAttributes(
733 OBJ_CASE_INSENSITIVE
,
740 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
742 /* That's OK. The key doesn't exist (yet) because
743 * the interface is not activated.
745 goto NextReferenceString
;
747 else if (!NT_SUCCESS(Status
))
749 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
753 RtlInitUnicodeString(&KeyName
, L
"Linked");
754 Status
= ZwQueryValueKey(ControlKey
,
756 KeyValuePartialInformation
,
760 if (Status
== STATUS_BUFFER_TOO_SMALL
)
762 ActualLength
= NeededLength
;
763 PartialInfo
= ExAllocatePool(NonPagedPool
, ActualLength
);
766 Status
= STATUS_INSUFFICIENT_RESOURCES
;
770 Status
= ZwQueryValueKey(ControlKey
,
772 KeyValuePartialInformation
,
776 if (!NT_SUCCESS(Status
))
778 DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status
);
779 ExFreePool(PartialInfo
);
783 if (PartialInfo
->Type
!= REG_DWORD
|| PartialInfo
->DataLength
!= sizeof(ULONG
))
785 DPRINT1("Bad registry read\n");
786 ExFreePool(PartialInfo
);
790 RtlCopyMemory(&LinkedValue
,
792 PartialInfo
->DataLength
);
794 ExFreePool(PartialInfo
);
795 if (LinkedValue
== 0)
797 /* This interface isn't active */
798 goto NextReferenceString
;
803 DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status
);
808 /* Read the SymbolicLink string and add it into SymbolicLinkList */
809 Status
= ZwQueryValueKey(
812 KeyValuePartialInformation
,
816 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
818 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
821 bip
= ExAllocatePool(PagedPool
, Size
);
824 DPRINT("ExAllocatePool() failed\n");
825 Status
= STATUS_INSUFFICIENT_RESOURCES
;
828 Status
= ZwQueryValueKey(
831 KeyValuePartialInformation
,
835 if (!NT_SUCCESS(Status
))
837 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
840 else if (bip
->Type
!= REG_SZ
)
842 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
843 Status
= STATUS_UNSUCCESSFUL
;
846 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
848 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
849 Status
= STATUS_UNSUCCESSFUL
;
852 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)bip
->DataLength
- 4 * sizeof(WCHAR
);
853 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
854 if (KeyName
.Length
&& KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
)
856 /* Remove trailing NULL */
857 KeyName
.Length
-= sizeof(WCHAR
);
860 /* Add new symbolic link to symbolic link list */
861 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
864 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
865 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
868 DPRINT("ExAllocatePool() failed\n");
869 Status
= STATUS_INSUFFICIENT_RESOURCES
;
872 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
873 if (ReturnBuffer
.Buffer
)
874 ExFreePool(ReturnBuffer
.Buffer
);
875 ReturnBuffer
.Buffer
= NewBuffer
;
877 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
878 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
879 if (!NT_SUCCESS(Status
))
881 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
885 ExFreePool(ReferenceBi
);
890 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
892 ZwClose(ReferenceKey
);
893 ReferenceKey
= INVALID_HANDLE_VALUE
;
895 if (ControlKey
!= INVALID_HANDLE_VALUE
)
898 ControlKey
= INVALID_HANDLE_VALUE
;
903 /* No need to go further, as we already have found what we searched */
907 ExFreePool(DeviceBi
);
910 DeviceKey
= INVALID_HANDLE_VALUE
;
913 /* Add final NULL to ReturnBuffer */
914 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
917 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
918 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
921 DPRINT("ExAllocatePool() failed\n");
922 Status
= STATUS_INSUFFICIENT_RESOURCES
;
925 if (ReturnBuffer
.Buffer
)
927 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
928 ExFreePool(ReturnBuffer
.Buffer
);
930 ReturnBuffer
.Buffer
= NewBuffer
;
932 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
933 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
934 Status
= STATUS_SUCCESS
;
937 if (!NT_SUCCESS(Status
) && ReturnBuffer
.Buffer
)
938 ExFreePool(ReturnBuffer
.Buffer
);
939 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
940 ZwClose(InterfaceKey
);
941 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
943 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
944 ZwClose(ReferenceKey
);
945 if (ControlKey
!= INVALID_HANDLE_VALUE
)
948 ExFreePool(DeviceBi
);
950 ExFreePool(ReferenceBi
);
957 * @name IoRegisterDeviceInterface
960 * Registers a device interface class, if it has not been previously registered,
961 * and creates a new instance of the interface class, which a driver can
962 * subsequently enable for use by applications or other system components.
965 * @param PhysicalDeviceObject
966 * Points to an optional PDO that narrows the search to only the
967 * device interfaces of the device represented by the PDO
969 * @param InterfaceClassGuid
970 * Points to a class GUID specifying the device interface class
972 * @param ReferenceString
973 * Optional parameter, pointing to a unicode string. For a full
974 * description of this rather rarely used param (usually drivers
975 * pass NULL here) see WDK
977 * @param SymbolicLinkName
978 * Pointer to the resulting unicode string
980 * @return Usual NTSTATUS
982 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
988 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject
,
989 IN CONST GUID
*InterfaceClassGuid
,
990 IN PUNICODE_STRING ReferenceString OPTIONAL
,
991 OUT PUNICODE_STRING SymbolicLinkName
)
993 PUNICODE_STRING InstancePath
;
994 UNICODE_STRING GuidString
;
995 UNICODE_STRING SubKeyName
;
996 UNICODE_STRING InterfaceKeyName
;
997 UNICODE_STRING BaseKeyName
;
998 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
999 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
1000 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
1001 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
1003 HANDLE InterfaceKey
;
1006 OBJECT_ATTRIBUTES ObjectAttributes
;
1009 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension
;
1011 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
1013 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
1014 PhysicalDeviceObject
, ReferenceString
);
1016 /* Parameters must pass three border of checks */
1017 DeviceObjectExtension
= (PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
;
1019 /* 1st level: Presence of a Device Node */
1020 if (DeviceObjectExtension
->DeviceNode
== NULL
)
1022 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject
);
1023 return STATUS_INVALID_DEVICE_REQUEST
;
1026 /* 2nd level: Presence of an non-zero length InstancePath */
1027 if (DeviceObjectExtension
->DeviceNode
->InstancePath
.Length
== 0)
1029 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject
);
1030 return STATUS_INVALID_DEVICE_REQUEST
;
1033 /* 3rd level: Optional, based on WDK documentation */
1034 if (ReferenceString
!= NULL
)
1036 /* Reference string must not contain path-separator symbols */
1037 for (i
= 0; i
< ReferenceString
->Length
/ sizeof(WCHAR
); i
++)
1039 if ((ReferenceString
->Buffer
[i
] == '\\') ||
1040 (ReferenceString
->Buffer
[i
] == '/'))
1041 return STATUS_INVALID_DEVICE_REQUEST
;
1045 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
1046 if (!NT_SUCCESS(Status
))
1048 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
1052 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
1053 Status
= ObQueryNameString(
1054 PhysicalDeviceObject
,
1056 sizeof(PdoNameInfoBuffer
),
1058 if (!NT_SUCCESS(Status
))
1060 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
1063 ASSERT(PdoNameInfo
->Name
.Length
);
1065 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1066 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
1067 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
1068 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
1069 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
1070 + GuidString
.Length
;
1071 BaseKeyName
.Buffer
= ExAllocatePool(
1073 BaseKeyName
.MaximumLength
);
1074 if (!BaseKeyName
.Buffer
)
1076 DPRINT("ExAllocatePool() failed\n");
1077 return STATUS_INSUFFICIENT_RESOURCES
;
1079 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
1080 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
1082 /* Create BaseKeyName key in registry */
1083 InitializeObjectAttributes(
1086 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
1087 NULL
, /* RootDirectory */
1088 NULL
); /* SecurityDescriptor */
1090 Status
= ZwCreateKey(
1096 REG_OPTION_VOLATILE
,
1097 NULL
); /* Disposition */
1099 if (!NT_SUCCESS(Status
))
1101 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1102 ExFreePool(BaseKeyName
.Buffer
);
1106 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
1107 InterfaceKeyName
.Length
= 0;
1108 InterfaceKeyName
.MaximumLength
=
1109 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
1110 InstancePath
->Length
+
1111 sizeof(WCHAR
) + /* 1 = size of # */
1113 InterfaceKeyName
.Buffer
= ExAllocatePool(
1115 InterfaceKeyName
.MaximumLength
);
1116 if (!InterfaceKeyName
.Buffer
)
1118 DPRINT("ExAllocatePool() failed\n");
1119 return STATUS_INSUFFICIENT_RESOURCES
;
1122 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
1123 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
1124 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
1125 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1127 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
1128 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
1130 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
1131 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
1133 /* Create the interface key in registry */
1134 InitializeObjectAttributes(
1137 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
1139 NULL
); /* SecurityDescriptor */
1141 Status
= ZwCreateKey(
1147 REG_OPTION_VOLATILE
,
1148 NULL
); /* Disposition */
1150 if (!NT_SUCCESS(Status
))
1152 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1154 ExFreePool(BaseKeyName
.Buffer
);
1158 /* Write DeviceInstance entry. Value is InstancePath */
1159 Status
= ZwSetValueKey(
1164 InstancePath
->Buffer
,
1165 InstancePath
->Length
);
1166 if (!NT_SUCCESS(Status
))
1168 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1169 ZwClose(InterfaceKey
);
1171 ExFreePool(InterfaceKeyName
.Buffer
);
1172 ExFreePool(BaseKeyName
.Buffer
);
1176 /* Create subkey. Name is #ReferenceString */
1177 SubKeyName
.Length
= 0;
1178 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
1179 if (ReferenceString
&& ReferenceString
->Length
)
1180 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
1181 SubKeyName
.Buffer
= ExAllocatePool(
1183 SubKeyName
.MaximumLength
);
1184 if (!SubKeyName
.Buffer
)
1186 DPRINT("ExAllocatePool() failed\n");
1187 ZwClose(InterfaceKey
);
1189 ExFreePool(InterfaceKeyName
.Buffer
);
1190 ExFreePool(BaseKeyName
.Buffer
);
1191 return STATUS_INSUFFICIENT_RESOURCES
;
1193 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
1194 if (ReferenceString
&& ReferenceString
->Length
)
1195 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
1197 /* Create SubKeyName key in registry */
1198 InitializeObjectAttributes(
1201 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1202 InterfaceKey
, /* RootDirectory */
1203 NULL
); /* SecurityDescriptor */
1205 Status
= ZwCreateKey(
1211 REG_OPTION_VOLATILE
,
1212 NULL
); /* Disposition */
1214 if (!NT_SUCCESS(Status
))
1216 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1217 ZwClose(InterfaceKey
);
1219 ExFreePool(InterfaceKeyName
.Buffer
);
1220 ExFreePool(BaseKeyName
.Buffer
);
1224 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1225 SymbolicLinkName
->Length
= 0;
1226 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
1227 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
1228 + InstancePath
->Length
1229 + sizeof(WCHAR
) /* 1 = size of # */
1231 + sizeof(WCHAR
); /* final NULL */
1232 if (ReferenceString
&& ReferenceString
->Length
)
1233 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
1234 SymbolicLinkName
->Buffer
= ExAllocatePool(
1236 SymbolicLinkName
->MaximumLength
);
1237 if (!SymbolicLinkName
->Buffer
)
1239 DPRINT("ExAllocatePool() failed\n");
1241 ZwClose(InterfaceKey
);
1243 ExFreePool(InterfaceKeyName
.Buffer
);
1244 ExFreePool(SubKeyName
.Buffer
);
1245 ExFreePool(BaseKeyName
.Buffer
);
1246 return STATUS_INSUFFICIENT_RESOURCES
;
1248 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
1249 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
1250 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
1251 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1253 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
1254 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
1256 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
1257 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
1258 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1260 /* Create symbolic link */
1261 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
1262 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
1263 if (!NT_SUCCESS(Status
) && ReferenceString
== NULL
)
1265 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
1267 ZwClose(InterfaceKey
);
1269 ExFreePool(SubKeyName
.Buffer
);
1270 ExFreePool(InterfaceKeyName
.Buffer
);
1271 ExFreePool(BaseKeyName
.Buffer
);
1272 ExFreePool(SymbolicLinkName
->Buffer
);
1276 if (ReferenceString
&& ReferenceString
->Length
)
1278 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
1279 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
1281 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1283 /* Write symbolic link name in registry */
1284 SymbolicLinkName
->Buffer
[1] = '\\';
1285 Status
= ZwSetValueKey(
1290 SymbolicLinkName
->Buffer
,
1291 SymbolicLinkName
->Length
);
1292 if (!NT_SUCCESS(Status
))
1294 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1295 ExFreePool(SymbolicLinkName
->Buffer
);
1299 SymbolicLinkName
->Buffer
[1] = '?';
1303 ZwClose(InterfaceKey
);
1305 ExFreePool(SubKeyName
.Buffer
);
1306 ExFreePool(InterfaceKeyName
.Buffer
);
1307 ExFreePool(BaseKeyName
.Buffer
);
1313 * @name IoSetDeviceInterfaceState
1316 * Enables or disables an instance of a previously registered device
1318 * Documented in WDK.
1320 * @param SymbolicLinkName
1321 * Pointer to the string identifying instance to enable or disable
1324 * TRUE = enable, FALSE = disable
1326 * @return Usual NTSTATUS
1328 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1334 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName
,
1337 PDEVICE_OBJECT PhysicalDeviceObject
;
1338 PFILE_OBJECT FileObject
;
1339 UNICODE_STRING GuidString
;
1340 UNICODE_STRING SymLink
;
1341 PWCHAR StartPosition
;
1345 HANDLE InstanceHandle
, ControlHandle
;
1346 UNICODE_STRING KeyName
;
1347 OBJECT_ATTRIBUTES ObjectAttributes
;
1350 if (SymbolicLinkName
== NULL
)
1351 return STATUS_INVALID_PARAMETER_1
;
1353 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1355 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1356 /* Get GUID from SymbolicLinkName */
1357 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
1358 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
1359 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
1361 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1362 return STATUS_INVALID_PARAMETER_1
;
1364 GuidString
.Buffer
= StartPosition
;
1365 GuidString
.MaximumLength
= GuidString
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
);
1367 SymLink
.Buffer
= SymbolicLinkName
->Buffer
;
1368 SymLink
.MaximumLength
= SymLink
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)SymLink
.Buffer
);
1369 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1371 Status
= OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName
,
1376 if (!NT_SUCCESS(Status
))
1379 RtlInitUnicodeString(&KeyName
, L
"Control");
1380 InitializeObjectAttributes(&ObjectAttributes
,
1382 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1385 Status
= ZwCreateKey(&ControlHandle
,
1390 REG_OPTION_VOLATILE
,
1392 ZwClose(InstanceHandle
);
1393 if (!NT_SUCCESS(Status
))
1395 DPRINT1("Failed to create the Control subkey\n");
1399 LinkedValue
= (Enable
? 1 : 0);
1401 RtlInitUnicodeString(&KeyName
, L
"Linked");
1402 Status
= ZwSetValueKey(ControlHandle
,
1408 ZwClose(ControlHandle
);
1409 if (!NT_SUCCESS(Status
))
1411 DPRINT1("Failed to write the Linked value\n");
1415 /* Get pointer to the PDO */
1416 Status
= IoGetDeviceObjectPointer(
1418 0, /* DesiredAccess */
1420 &PhysicalDeviceObject
);
1421 if (!NT_SUCCESS(Status
))
1423 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status
);
1427 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
1428 IopNotifyPlugPlayNotification(
1429 PhysicalDeviceObject
,
1430 EventCategoryDeviceInterfaceChange
,
1433 (PVOID
)SymbolicLinkName
);
1435 ObDereferenceObject(FileObject
);
1436 DPRINT("Status %x\n", Status
);
1437 return STATUS_SUCCESS
;