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
.MaximumLength
= SymbolicLinkName
->Length
+ sizeof(WCHAR
);
109 SubKeyName
.Length
= 0;
110 SubKeyName
.Buffer
= ExAllocatePool(PagedPool
, SubKeyName
.MaximumLength
);
111 if (!SubKeyName
.Buffer
)
113 Status
= STATUS_INSUFFICIENT_RESOURCES
;
117 RtlAppendUnicodeStringToString(&SubKeyName
,
120 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
122 SubKeyName
.Buffer
[0] = L
'#';
123 SubKeyName
.Buffer
[1] = L
'#';
124 SubKeyName
.Buffer
[2] = L
'?';
125 SubKeyName
.Buffer
[3] = L
'#';
127 ReferenceString
.Buffer
= wcsrchr(SubKeyName
.Buffer
, '\\');
128 if (ReferenceString
.Buffer
!= NULL
)
130 ReferenceString
.Buffer
[0] = L
'#';
132 SubKeyName
.Length
= (USHORT
)((ULONG_PTR
)(ReferenceString
.Buffer
) - (ULONG_PTR
)SubKeyName
.Buffer
);
133 ReferenceString
.Length
= SymbolicLinkName
->Length
- SubKeyName
.Length
;
137 RtlInitUnicodeString(&ReferenceString
, L
"#");
140 InitializeObjectAttributes(&ObjectAttributes
,
142 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
145 Status
= ZwOpenKey(DeviceKeyRealP
,
146 DesiredAccess
| KEY_ENUMERATE_SUB_KEYS
,
148 if (!NT_SUCCESS(Status
))
150 DPRINT1("Failed to open %wZ%wZ\\%wZ\n", &BaseKeyU
, &GuidString
, &SubKeyName
);
154 InitializeObjectAttributes(&ObjectAttributes
,
156 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
159 Status
= ZwOpenKey(InstanceKeyRealP
,
162 if (!NT_SUCCESS(Status
))
164 DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU
, &GuidString
, &SubKeyName
, &ReferenceString
, Status
);
168 Status
= STATUS_SUCCESS
;
171 if (SubKeyName
.Buffer
!= NULL
)
172 ExFreePool(SubKeyName
.Buffer
);
174 if (NT_SUCCESS(Status
))
177 ZwClose(*GuidKeyRealP
);
180 ZwClose(*DeviceKeyRealP
);
183 ZwClose(*InstanceKeyRealP
);
187 if (*GuidKeyRealP
!= INVALID_HANDLE_VALUE
)
188 ZwClose(*GuidKeyRealP
);
190 if (*DeviceKeyRealP
!= INVALID_HANDLE_VALUE
)
191 ZwClose(*DeviceKeyRealP
);
193 if (*InstanceKeyRealP
!= INVALID_HANDLE_VALUE
)
194 ZwClose(*InstanceKeyRealP
);
200 * @name IoOpenDeviceInterfaceRegistryKey
203 * Provides a handle to the device's interface instance registry key.
206 * @param SymbolicLinkName
207 * Pointer to a string which identifies the device interface instance
209 * @param DesiredAccess
210 * Desired ACCESS_MASK used to access the key (like KEY_READ,
213 * @param DeviceInterfaceKey
214 * If a call has been succesfull, a handle to the registry key
215 * will be stored there
217 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
218 * otherwise (see WDK for details)
220 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
225 IoOpenDeviceInterfaceRegistryKey(IN PUNICODE_STRING SymbolicLinkName
,
226 IN ACCESS_MASK DesiredAccess
,
227 OUT PHANDLE DeviceInterfaceKey
)
229 HANDLE InstanceKey
, DeviceParametersKey
;
231 OBJECT_ATTRIBUTES ObjectAttributes
;
232 UNICODE_STRING DeviceParametersU
= RTL_CONSTANT_STRING(L
"Device Parameters");
234 Status
= OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName
,
239 if (!NT_SUCCESS(Status
))
242 InitializeObjectAttributes(&ObjectAttributes
,
244 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
247 Status
= ZwCreateKey(&DeviceParametersKey
,
252 REG_OPTION_NON_VOLATILE
,
254 ZwClose(InstanceKey
);
256 if (NT_SUCCESS(Status
))
257 *DeviceInterfaceKey
= DeviceParametersKey
;
263 * @name IoGetDeviceInterfaceAlias
266 * Returns the alias device interface of the specified device interface
267 * instance, if the alias exists.
270 * @param SymbolicLinkName
271 * Pointer to a string which identifies the device interface instance
273 * @param AliasInterfaceClassGuid
276 * @param AliasSymbolicLinkName
279 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
280 * otherwise (see WDK for details)
282 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
287 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName
,
288 IN CONST GUID
*AliasInterfaceClassGuid
,
289 OUT PUNICODE_STRING AliasSymbolicLinkName
)
291 return STATUS_NOT_IMPLEMENTED
;
295 * @name IopOpenInterfaceKey
297 * Returns the alias device interface of the specified device interface
299 * @param InterfaceClassGuid
302 * @param DesiredAccess
305 * @param pInterfaceKey
308 * @return Usual NTSTATUS
314 IopOpenInterfaceKey(IN CONST GUID
*InterfaceClassGuid
,
315 IN ACCESS_MASK DesiredAccess
,
316 OUT HANDLE
*pInterfaceKey
)
318 UNICODE_STRING LocalMachine
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\");
319 UNICODE_STRING GuidString
;
320 UNICODE_STRING KeyName
;
321 OBJECT_ATTRIBUTES ObjectAttributes
;
322 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
325 GuidString
.Buffer
= KeyName
.Buffer
= NULL
;
327 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
328 if (!NT_SUCCESS(Status
))
330 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
335 KeyName
.MaximumLength
= LocalMachine
.Length
+ (wcslen(REGSTR_PATH_DEVICE_CLASSES
) + 1) * sizeof(WCHAR
) + GuidString
.Length
;
336 KeyName
.Buffer
= ExAllocatePool(PagedPool
, KeyName
.MaximumLength
);
339 DPRINT("ExAllocatePool() failed\n");
340 Status
= STATUS_INSUFFICIENT_RESOURCES
;
344 Status
= RtlAppendUnicodeStringToString(&KeyName
, &LocalMachine
);
345 if (!NT_SUCCESS(Status
))
347 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
350 Status
= RtlAppendUnicodeToString(&KeyName
, REGSTR_PATH_DEVICE_CLASSES
);
351 if (!NT_SUCCESS(Status
))
353 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
356 Status
= RtlAppendUnicodeToString(&KeyName
, L
"\\");
357 if (!NT_SUCCESS(Status
))
359 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
362 Status
= RtlAppendUnicodeStringToString(&KeyName
, &GuidString
);
363 if (!NT_SUCCESS(Status
))
365 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
369 InitializeObjectAttributes(
372 OBJ_CASE_INSENSITIVE
,
379 if (!NT_SUCCESS(Status
))
381 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
385 *pInterfaceKey
= InterfaceKey
;
386 Status
= STATUS_SUCCESS
;
389 if (!NT_SUCCESS(Status
))
391 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
392 ZwClose(InterfaceKey
);
394 RtlFreeUnicodeString(&GuidString
);
395 RtlFreeUnicodeString(&KeyName
);
400 * @name IoGetDeviceInterfaces
403 * Returns a list of device interfaces of a particular device interface class.
406 * @param InterfaceClassGuid
407 * Points to a class GUID specifying the device interface class
409 * @param PhysicalDeviceObject
410 * Points to an optional PDO that narrows the search to only the
411 * device interfaces of the device represented by the PDO
414 * Specifies flags that modify the search for device interfaces. The
415 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
416 * returned symbolic links should contain also disabled device
417 * interfaces in addition to the enabled ones.
419 * @param SymbolicLinkList
420 * Points to a character pointer that is filled in on successful return
421 * with a list of unicode strings identifying the device interfaces
422 * that match the search criteria. The newly allocated buffer contains
423 * a list of symbolic link names. Each unicode string in the list is
424 * null-terminated; the end of the whole list is marked by an additional
425 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
426 * when it is no longer needed.
427 * If no device interfaces match the search criteria, this routine
428 * returns STATUS_SUCCESS and the string contains a single NULL
431 * @return Usual NTSTATUS
438 IoGetDeviceInterfaces(IN CONST GUID
*InterfaceClassGuid
,
439 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
441 OUT PWSTR
*SymbolicLinkList
)
443 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
444 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
445 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
446 HANDLE DeviceKey
= INVALID_HANDLE_VALUE
;
447 HANDLE ReferenceKey
= INVALID_HANDLE_VALUE
;
448 HANDLE ControlKey
= INVALID_HANDLE_VALUE
;
449 PKEY_BASIC_INFORMATION DeviceBi
= NULL
;
450 PKEY_BASIC_INFORMATION ReferenceBi
= NULL
;
451 PKEY_VALUE_PARTIAL_INFORMATION bip
= NULL
;
452 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
453 UNICODE_STRING KeyName
;
454 OBJECT_ATTRIBUTES ObjectAttributes
;
455 BOOLEAN FoundRightPDO
= FALSE
;
456 ULONG i
= 0, j
, Size
, NeededLength
, ActualLength
, LinkedValue
;
457 UNICODE_STRING ReturnBuffer
= { 0, 0, NULL
};
462 Status
= IopOpenInterfaceKey(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, &InterfaceKey
);
463 if (!NT_SUCCESS(Status
))
465 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status
);
469 /* Enumerate subkeys (ie the different device objets) */
472 Status
= ZwEnumerateKey(
479 if (Status
== STATUS_NO_MORE_ENTRIES
)
483 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
485 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
489 DeviceBi
= ExAllocatePool(PagedPool
, Size
);
492 DPRINT("ExAllocatePool() failed\n");
493 Status
= STATUS_INSUFFICIENT_RESOURCES
;
496 Status
= ZwEnumerateKey(
503 if (!NT_SUCCESS(Status
))
505 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
509 /* Open device key */
510 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)DeviceBi
->NameLength
;
511 KeyName
.Buffer
= DeviceBi
->Name
;
512 InitializeObjectAttributes(
515 OBJ_CASE_INSENSITIVE
,
520 KEY_ENUMERATE_SUB_KEYS
,
522 if (!NT_SUCCESS(Status
))
524 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
528 if (PhysicalDeviceObject
)
530 /* Check if we are on the right physical device object,
531 * by reading the DeviceInstance string
533 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
534 //FoundRightPDO = TRUE;
535 Status
= STATUS_NOT_IMPLEMENTED
;
539 /* Enumerate subkeys (ie the different reference strings) */
543 Status
= ZwEnumerateKey(
550 if (Status
== STATUS_NO_MORE_ENTRIES
)
554 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
556 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
560 ReferenceBi
= ExAllocatePool(PagedPool
, Size
);
563 DPRINT("ExAllocatePool() failed\n");
564 Status
= STATUS_INSUFFICIENT_RESOURCES
;
567 Status
= ZwEnumerateKey(
574 if (!NT_SUCCESS(Status
))
576 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
580 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)ReferenceBi
->NameLength
;
581 KeyName
.Buffer
= ReferenceBi
->Name
;
582 if (RtlEqualUnicodeString(&KeyName
, &Control
, TRUE
))
584 /* Skip Control subkey */
585 goto NextReferenceString
;
588 /* Open reference key */
589 InitializeObjectAttributes(
592 OBJ_CASE_INSENSITIVE
,
599 if (!NT_SUCCESS(Status
))
601 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
605 if (!(Flags
& DEVICE_INTERFACE_INCLUDE_NONACTIVE
))
607 /* We have to check if the interface is enabled, by
608 * reading the Linked value in the Control subkey
610 InitializeObjectAttributes(
613 OBJ_CASE_INSENSITIVE
,
620 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
622 /* That's OK. The key doesn't exist (yet) because
623 * the interface is not activated.
625 goto NextReferenceString
;
627 else if (!NT_SUCCESS(Status
))
629 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
633 RtlInitUnicodeString(&KeyName
, L
"Linked");
634 Status
= ZwQueryValueKey(ControlKey
,
636 KeyValuePartialInformation
,
640 if (Status
== STATUS_BUFFER_TOO_SMALL
)
642 ActualLength
= NeededLength
;
643 PartialInfo
= ExAllocatePool(NonPagedPool
, ActualLength
);
646 Status
= STATUS_INSUFFICIENT_RESOURCES
;
650 Status
= ZwQueryValueKey(ControlKey
,
652 KeyValuePartialInformation
,
656 if (!NT_SUCCESS(Status
))
658 DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status
);
659 ExFreePool(PartialInfo
);
663 if (PartialInfo
->Type
!= REG_DWORD
|| PartialInfo
->DataLength
!= sizeof(ULONG
))
665 DPRINT1("Bad registry read\n");
666 ExFreePool(PartialInfo
);
670 RtlCopyMemory(&LinkedValue
,
672 PartialInfo
->DataLength
);
674 ExFreePool(PartialInfo
);
675 if (LinkedValue
== 0)
677 /* This interface isn't active */
678 goto NextReferenceString
;
683 DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status
);
688 /* Read the SymbolicLink string and add it into SymbolicLinkList */
689 Status
= ZwQueryValueKey(
692 KeyValuePartialInformation
,
696 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
698 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
701 bip
= ExAllocatePool(PagedPool
, Size
);
704 DPRINT("ExAllocatePool() failed\n");
705 Status
= STATUS_INSUFFICIENT_RESOURCES
;
708 Status
= ZwQueryValueKey(
711 KeyValuePartialInformation
,
715 if (!NT_SUCCESS(Status
))
717 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
720 else if (bip
->Type
!= REG_SZ
)
722 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
723 Status
= STATUS_UNSUCCESSFUL
;
726 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
728 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
729 Status
= STATUS_UNSUCCESSFUL
;
732 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)bip
->DataLength
- 4 * sizeof(WCHAR
);
733 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
735 /* Add new symbolic link to symbolic link list */
736 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
739 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
740 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
743 DPRINT("ExAllocatePool() failed\n");
744 Status
= STATUS_INSUFFICIENT_RESOURCES
;
747 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
748 if (ReturnBuffer
.Buffer
)
749 ExFreePool(ReturnBuffer
.Buffer
);
750 ReturnBuffer
.Buffer
= NewBuffer
;
752 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
753 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
754 if (!NT_SUCCESS(Status
))
756 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
759 /* RtlAppendUnicodeStringToString added a NULL at the end of the
760 * destination string, but didn't increase the Length field.
763 ReturnBuffer
.Length
+= sizeof(WCHAR
);
766 ExFreePool(ReferenceBi
);
771 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
773 ZwClose(ReferenceKey
);
774 ReferenceKey
= INVALID_HANDLE_VALUE
;
776 if (ControlKey
!= INVALID_HANDLE_VALUE
)
779 ControlKey
= INVALID_HANDLE_VALUE
;
784 /* No need to go further, as we already have found what we searched */
788 ExFreePool(DeviceBi
);
791 DeviceKey
= INVALID_HANDLE_VALUE
;
794 /* Add final NULL to ReturnBuffer */
795 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
798 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
799 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
802 DPRINT("ExAllocatePool() failed\n");
803 Status
= STATUS_INSUFFICIENT_RESOURCES
;
806 if (ReturnBuffer
.Buffer
)
808 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
809 ExFreePool(ReturnBuffer
.Buffer
);
811 ReturnBuffer
.Buffer
= NewBuffer
;
813 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
814 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
815 Status
= STATUS_SUCCESS
;
818 if (!NT_SUCCESS(Status
) && ReturnBuffer
.Buffer
)
819 ExFreePool(ReturnBuffer
.Buffer
);
820 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
821 ZwClose(InterfaceKey
);
822 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
824 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
825 ZwClose(ReferenceKey
);
826 if (ControlKey
!= INVALID_HANDLE_VALUE
)
829 ExFreePool(DeviceBi
);
831 ExFreePool(ReferenceBi
);
838 * @name IoRegisterDeviceInterface
841 * Registers a device interface class, if it has not been previously registered,
842 * and creates a new instance of the interface class, which a driver can
843 * subsequently enable for use by applications or other system components.
846 * @param PhysicalDeviceObject
847 * Points to an optional PDO that narrows the search to only the
848 * device interfaces of the device represented by the PDO
850 * @param InterfaceClassGuid
851 * Points to a class GUID specifying the device interface class
853 * @param ReferenceString
854 * Optional parameter, pointing to a unicode string. For a full
855 * description of this rather rarely used param (usually drivers
856 * pass NULL here) see WDK
858 * @param SymbolicLinkName
859 * Pointer to the resulting unicode string
861 * @return Usual NTSTATUS
863 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
869 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject
,
870 IN CONST GUID
*InterfaceClassGuid
,
871 IN PUNICODE_STRING ReferenceString OPTIONAL
,
872 OUT PUNICODE_STRING SymbolicLinkName
)
874 PUNICODE_STRING InstancePath
;
875 UNICODE_STRING GuidString
;
876 UNICODE_STRING SubKeyName
;
877 UNICODE_STRING InterfaceKeyName
;
878 UNICODE_STRING BaseKeyName
;
879 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
880 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
881 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
882 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
887 OBJECT_ATTRIBUTES ObjectAttributes
;
890 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension
;
892 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
894 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
895 PhysicalDeviceObject
, ReferenceString
);
897 /* Parameters must pass three border of checks */
898 DeviceObjectExtension
= (PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
;
900 /* 1st level: Presence of a Device Node */
901 if (DeviceObjectExtension
->DeviceNode
== NULL
)
903 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject
);
904 return STATUS_INVALID_DEVICE_REQUEST
;
907 /* 2nd level: Presence of an non-zero length InstancePath */
908 if (DeviceObjectExtension
->DeviceNode
->InstancePath
.Length
== 0)
910 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject
);
911 return STATUS_INVALID_DEVICE_REQUEST
;
914 /* 3rd level: Optional, based on WDK documentation */
915 if (ReferenceString
!= NULL
)
917 /* Reference string must not contain path-separator symbols */
918 for (i
= 0; i
< ReferenceString
->Length
/ sizeof(WCHAR
); i
++)
920 if ((ReferenceString
->Buffer
[i
] == '\\') ||
921 (ReferenceString
->Buffer
[i
] == '/'))
922 return STATUS_INVALID_DEVICE_REQUEST
;
926 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
927 if (!NT_SUCCESS(Status
))
929 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
933 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
934 Status
= ObQueryNameString(
935 PhysicalDeviceObject
,
937 sizeof(PdoNameInfoBuffer
),
939 if (!NT_SUCCESS(Status
))
941 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
944 ASSERT(PdoNameInfo
->Name
.Length
);
946 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
947 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
948 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
949 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
950 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
952 BaseKeyName
.Buffer
= ExAllocatePool(
954 BaseKeyName
.MaximumLength
);
955 if (!BaseKeyName
.Buffer
)
957 DPRINT("ExAllocatePool() failed\n");
958 return STATUS_INSUFFICIENT_RESOURCES
;
960 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
961 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
963 /* Create BaseKeyName key in registry */
964 InitializeObjectAttributes(
967 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
968 NULL
, /* RootDirectory */
969 NULL
); /* SecurityDescriptor */
971 Status
= ZwCreateKey(
978 NULL
); /* Disposition */
980 if (!NT_SUCCESS(Status
))
982 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
983 ExFreePool(BaseKeyName
.Buffer
);
987 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
988 InterfaceKeyName
.Length
= 0;
989 InterfaceKeyName
.MaximumLength
=
990 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
991 InstancePath
->Length
+
992 sizeof(WCHAR
) + /* 1 = size of # */
994 InterfaceKeyName
.Buffer
= ExAllocatePool(
996 InterfaceKeyName
.MaximumLength
);
997 if (!InterfaceKeyName
.Buffer
)
999 DPRINT("ExAllocatePool() failed\n");
1000 return STATUS_INSUFFICIENT_RESOURCES
;
1003 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
1004 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
1005 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
1006 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1008 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
1009 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
1011 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
1012 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
1014 /* Create the interface key in registry */
1015 InitializeObjectAttributes(
1018 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
1020 NULL
); /* SecurityDescriptor */
1022 Status
= ZwCreateKey(
1028 REG_OPTION_VOLATILE
,
1029 NULL
); /* Disposition */
1031 if (!NT_SUCCESS(Status
))
1033 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1035 ExFreePool(BaseKeyName
.Buffer
);
1039 /* Write DeviceInstance entry. Value is InstancePath */
1040 Status
= ZwSetValueKey(
1045 InstancePath
->Buffer
,
1046 InstancePath
->Length
);
1047 if (!NT_SUCCESS(Status
))
1049 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1050 ZwClose(InterfaceKey
);
1052 ExFreePool(InterfaceKeyName
.Buffer
);
1053 ExFreePool(BaseKeyName
.Buffer
);
1057 /* Create subkey. Name is #ReferenceString */
1058 SubKeyName
.Length
= 0;
1059 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
1060 if (ReferenceString
&& ReferenceString
->Length
)
1061 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
1062 SubKeyName
.Buffer
= ExAllocatePool(
1064 SubKeyName
.MaximumLength
);
1065 if (!SubKeyName
.Buffer
)
1067 DPRINT("ExAllocatePool() failed\n");
1068 ZwClose(InterfaceKey
);
1070 ExFreePool(InterfaceKeyName
.Buffer
);
1071 ExFreePool(BaseKeyName
.Buffer
);
1072 return STATUS_INSUFFICIENT_RESOURCES
;
1074 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
1075 if (ReferenceString
&& ReferenceString
->Length
)
1076 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
1078 /* Create SubKeyName key in registry */
1079 InitializeObjectAttributes(
1082 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1083 InterfaceKey
, /* RootDirectory */
1084 NULL
); /* SecurityDescriptor */
1086 Status
= ZwCreateKey(
1092 REG_OPTION_VOLATILE
,
1093 NULL
); /* Disposition */
1095 if (!NT_SUCCESS(Status
))
1097 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1098 ZwClose(InterfaceKey
);
1100 ExFreePool(InterfaceKeyName
.Buffer
);
1101 ExFreePool(BaseKeyName
.Buffer
);
1105 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1106 SymbolicLinkName
->Length
= 0;
1107 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
1108 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
1109 + InstancePath
->Length
1110 + sizeof(WCHAR
) /* 1 = size of # */
1112 + sizeof(WCHAR
); /* final NULL */
1113 if (ReferenceString
&& ReferenceString
->Length
)
1114 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
1115 SymbolicLinkName
->Buffer
= ExAllocatePool(
1117 SymbolicLinkName
->MaximumLength
);
1118 if (!SymbolicLinkName
->Buffer
)
1120 DPRINT("ExAllocatePool() failed\n");
1122 ZwClose(InterfaceKey
);
1124 ExFreePool(InterfaceKeyName
.Buffer
);
1125 ExFreePool(SubKeyName
.Buffer
);
1126 ExFreePool(BaseKeyName
.Buffer
);
1127 return STATUS_INSUFFICIENT_RESOURCES
;
1129 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
1130 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
1131 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
1132 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1134 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
1135 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
1137 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
1138 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
1139 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1141 /* Create symbolic link */
1142 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
1143 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
1144 if (!NT_SUCCESS(Status
) && ReferenceString
== NULL
)
1146 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
1148 ZwClose(InterfaceKey
);
1150 ExFreePool(SubKeyName
.Buffer
);
1151 ExFreePool(InterfaceKeyName
.Buffer
);
1152 ExFreePool(BaseKeyName
.Buffer
);
1153 ExFreePool(SymbolicLinkName
->Buffer
);
1157 if (ReferenceString
&& ReferenceString
->Length
)
1159 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
1160 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
1162 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1164 /* Write symbolic link name in registry */
1165 SymbolicLinkName
->Buffer
[1] = '\\';
1166 Status
= ZwSetValueKey(
1171 SymbolicLinkName
->Buffer
,
1172 SymbolicLinkName
->Length
);
1173 if (!NT_SUCCESS(Status
))
1175 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1176 ExFreePool(SymbolicLinkName
->Buffer
);
1180 SymbolicLinkName
->Buffer
[1] = '?';
1184 ZwClose(InterfaceKey
);
1186 ExFreePool(SubKeyName
.Buffer
);
1187 ExFreePool(InterfaceKeyName
.Buffer
);
1188 ExFreePool(BaseKeyName
.Buffer
);
1194 * @name IoSetDeviceInterfaceState
1197 * Enables or disables an instance of a previously registered device
1199 * Documented in WDK.
1201 * @param SymbolicLinkName
1202 * Pointer to the string identifying instance to enable or disable
1205 * TRUE = enable, FALSE = disable
1207 * @return Usual NTSTATUS
1209 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1215 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName
,
1218 PDEVICE_OBJECT PhysicalDeviceObject
;
1219 PFILE_OBJECT FileObject
;
1220 UNICODE_STRING GuidString
;
1221 UNICODE_STRING SymLink
;
1222 PWCHAR StartPosition
;
1226 HANDLE InstanceHandle
, ControlHandle
;
1227 UNICODE_STRING KeyName
;
1228 OBJECT_ATTRIBUTES ObjectAttributes
;
1232 if (SymbolicLinkName
== NULL
)
1233 return STATUS_INVALID_PARAMETER_1
;
1235 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1237 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1238 /* Get GUID from SymbolicLinkName */
1239 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
1240 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
1241 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
1243 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1244 return STATUS_INVALID_PARAMETER_1
;
1246 GuidString
.Buffer
= StartPosition
;
1247 GuidString
.MaximumLength
= GuidString
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
);
1249 SymLink
.Buffer
= SymbolicLinkName
->Buffer
;
1250 SymLink
.MaximumLength
= SymLink
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)SymLink
.Buffer
);
1251 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1253 Status
= OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName
,
1258 if (!NT_SUCCESS(Status
))
1261 RtlInitUnicodeString(&KeyName
, L
"Control");
1262 InitializeObjectAttributes(&ObjectAttributes
,
1264 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1267 Status
= ZwCreateKey(&ControlHandle
,
1272 REG_OPTION_VOLATILE
,
1274 ZwClose(InstanceHandle
);
1275 if (!NT_SUCCESS(Status
))
1277 DPRINT1("Failed to create the Control subkey\n");
1281 LinkedValue
= (Enable
? 1 : 0);
1283 RtlInitUnicodeString(&KeyName
, L
"Linked");
1284 Status
= ZwSetValueKey(ControlHandle
,
1290 ZwClose(ControlHandle
);
1291 if (!NT_SUCCESS(Status
))
1293 DPRINT1("Failed to write the Linked value\n");
1297 /* Get pointer to the PDO */
1298 Status
= IoGetDeviceObjectPointer(
1300 0, /* DesiredAccess */
1302 &PhysicalDeviceObject
);
1303 if (!NT_SUCCESS(Status
))
1305 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status
);
1309 Status
= RtlGUIDFromString(&GuidString
, &DeviceGuid
);
1310 if (!NT_SUCCESS(Status
))
1312 DPRINT1("RtlGUIDFromString() failed with status 0x%08lx\n", Status
);
1316 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
1317 IopNotifyPlugPlayNotification(
1318 PhysicalDeviceObject
,
1319 EventCategoryDeviceInterfaceChange
,
1322 (PVOID
)SymbolicLinkName
);
1324 ObDereferenceObject(FileObject
);
1325 DPRINT("Status %x\n", Status
);
1326 return STATUS_SUCCESS
;