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
= (USHORT
)((ULONG_PTR
)(ReferenceString
.Buffer
) - (ULONG_PTR
)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 HANDLE InstanceKey
, DeviceParametersKey
;
229 OBJECT_ATTRIBUTES ObjectAttributes
;
230 UNICODE_STRING DeviceParametersU
= RTL_CONSTANT_STRING(L
"Device Parameters");
232 Status
= OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName
,
237 if (!NT_SUCCESS(Status
))
240 InitializeObjectAttributes(&ObjectAttributes
,
242 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
245 Status
= ZwCreateKey(&DeviceParametersKey
,
250 REG_OPTION_NON_VOLATILE
,
252 ZwClose(InstanceKey
);
254 if (NT_SUCCESS(Status
))
255 *DeviceInterfaceKey
= DeviceParametersKey
;
261 * @name IoGetDeviceInterfaceAlias
264 * Returns the alias device interface of the specified device interface
265 * instance, if the alias exists.
268 * @param SymbolicLinkName
269 * Pointer to a string which identifies the device interface instance
271 * @param AliasInterfaceClassGuid
274 * @param AliasSymbolicLinkName
277 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
278 * otherwise (see WDK for details)
280 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
285 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName
,
286 IN CONST GUID
*AliasInterfaceClassGuid
,
287 OUT PUNICODE_STRING AliasSymbolicLinkName
)
289 return STATUS_NOT_IMPLEMENTED
;
293 * @name IopOpenInterfaceKey
295 * Returns the alias device interface of the specified device interface
297 * @param InterfaceClassGuid
300 * @param DesiredAccess
303 * @param pInterfaceKey
306 * @return Usual NTSTATUS
312 IopOpenInterfaceKey(IN CONST GUID
*InterfaceClassGuid
,
313 IN ACCESS_MASK DesiredAccess
,
314 OUT HANDLE
*pInterfaceKey
)
316 UNICODE_STRING LocalMachine
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\");
317 UNICODE_STRING GuidString
;
318 UNICODE_STRING KeyName
;
319 OBJECT_ATTRIBUTES ObjectAttributes
;
320 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
323 GuidString
.Buffer
= KeyName
.Buffer
= NULL
;
325 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
326 if (!NT_SUCCESS(Status
))
328 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
333 KeyName
.MaximumLength
= LocalMachine
.Length
+ (wcslen(REGSTR_PATH_DEVICE_CLASSES
) + 1) * sizeof(WCHAR
) + GuidString
.Length
;
334 KeyName
.Buffer
= ExAllocatePool(PagedPool
, KeyName
.MaximumLength
);
337 DPRINT("ExAllocatePool() failed\n");
338 Status
= STATUS_INSUFFICIENT_RESOURCES
;
342 Status
= RtlAppendUnicodeStringToString(&KeyName
, &LocalMachine
);
343 if (!NT_SUCCESS(Status
))
345 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
348 Status
= RtlAppendUnicodeToString(&KeyName
, REGSTR_PATH_DEVICE_CLASSES
);
349 if (!NT_SUCCESS(Status
))
351 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
354 Status
= RtlAppendUnicodeToString(&KeyName
, L
"\\");
355 if (!NT_SUCCESS(Status
))
357 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
360 Status
= RtlAppendUnicodeStringToString(&KeyName
, &GuidString
);
361 if (!NT_SUCCESS(Status
))
363 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
367 InitializeObjectAttributes(
370 OBJ_CASE_INSENSITIVE
,
377 if (!NT_SUCCESS(Status
))
379 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
383 *pInterfaceKey
= InterfaceKey
;
384 Status
= STATUS_SUCCESS
;
387 if (!NT_SUCCESS(Status
))
389 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
390 ZwClose(InterfaceKey
);
392 RtlFreeUnicodeString(&GuidString
);
393 RtlFreeUnicodeString(&KeyName
);
398 * @name IoGetDeviceInterfaces
401 * Returns a list of device interfaces of a particular device interface class.
404 * @param InterfaceClassGuid
405 * Points to a class GUID specifying the device interface class
407 * @param PhysicalDeviceObject
408 * Points to an optional PDO that narrows the search to only the
409 * device interfaces of the device represented by the PDO
412 * Specifies flags that modify the search for device interfaces. The
413 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
414 * returned symbolic links should contain also disabled device
415 * interfaces in addition to the enabled ones.
417 * @param SymbolicLinkList
418 * Points to a character pointer that is filled in on successful return
419 * with a list of unicode strings identifying the device interfaces
420 * that match the search criteria. The newly allocated buffer contains
421 * a list of symbolic link names. Each unicode string in the list is
422 * null-terminated; the end of the whole list is marked by an additional
423 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
424 * when it is no longer needed.
425 * If no device interfaces match the search criteria, this routine
426 * returns STATUS_SUCCESS and the string contains a single NULL
429 * @return Usual NTSTATUS
436 IoGetDeviceInterfaces(IN CONST GUID
*InterfaceClassGuid
,
437 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
439 OUT PWSTR
*SymbolicLinkList
)
441 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
442 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
443 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
444 HANDLE DeviceKey
= INVALID_HANDLE_VALUE
;
445 HANDLE ReferenceKey
= INVALID_HANDLE_VALUE
;
446 HANDLE ControlKey
= INVALID_HANDLE_VALUE
;
447 PKEY_BASIC_INFORMATION DeviceBi
= NULL
;
448 PKEY_BASIC_INFORMATION ReferenceBi
= NULL
;
449 PKEY_VALUE_PARTIAL_INFORMATION bip
= NULL
;
450 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
451 UNICODE_STRING KeyName
;
452 OBJECT_ATTRIBUTES ObjectAttributes
;
453 BOOLEAN FoundRightPDO
= FALSE
;
454 ULONG i
= 0, j
, Size
, NeededLength
, ActualLength
, LinkedValue
;
455 UNICODE_STRING ReturnBuffer
= { 0, 0, NULL
};
460 Status
= IopOpenInterfaceKey(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, &InterfaceKey
);
461 if (!NT_SUCCESS(Status
))
463 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status
);
467 /* Enumerate subkeys (ie the different device objets) */
470 Status
= ZwEnumerateKey(
477 if (Status
== STATUS_NO_MORE_ENTRIES
)
481 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
483 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
487 DeviceBi
= ExAllocatePool(PagedPool
, Size
);
490 DPRINT("ExAllocatePool() failed\n");
491 Status
= STATUS_INSUFFICIENT_RESOURCES
;
494 Status
= ZwEnumerateKey(
501 if (!NT_SUCCESS(Status
))
503 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
507 /* Open device key */
508 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)DeviceBi
->NameLength
;
509 KeyName
.Buffer
= DeviceBi
->Name
;
510 InitializeObjectAttributes(
513 OBJ_CASE_INSENSITIVE
,
518 KEY_ENUMERATE_SUB_KEYS
,
520 if (!NT_SUCCESS(Status
))
522 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
526 if (PhysicalDeviceObject
)
528 /* Check if we are on the right physical device object,
529 * by reading the DeviceInstance string
531 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
532 //FoundRightPDO = TRUE;
533 Status
= STATUS_NOT_IMPLEMENTED
;
537 /* Enumerate subkeys (ie the different reference strings) */
541 Status
= ZwEnumerateKey(
548 if (Status
== STATUS_NO_MORE_ENTRIES
)
552 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
554 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
558 ReferenceBi
= ExAllocatePool(PagedPool
, Size
);
561 DPRINT("ExAllocatePool() failed\n");
562 Status
= STATUS_INSUFFICIENT_RESOURCES
;
565 Status
= ZwEnumerateKey(
572 if (!NT_SUCCESS(Status
))
574 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
578 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)ReferenceBi
->NameLength
;
579 KeyName
.Buffer
= ReferenceBi
->Name
;
580 if (RtlEqualUnicodeString(&KeyName
, &Control
, TRUE
))
582 /* Skip Control subkey */
583 goto NextReferenceString
;
586 /* Open reference key */
587 InitializeObjectAttributes(
590 OBJ_CASE_INSENSITIVE
,
597 if (!NT_SUCCESS(Status
))
599 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
603 if (!(Flags
& DEVICE_INTERFACE_INCLUDE_NONACTIVE
))
605 /* We have to check if the interface is enabled, by
606 * reading the Linked value in the Control subkey
608 InitializeObjectAttributes(
611 OBJ_CASE_INSENSITIVE
,
618 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
620 /* That's OK. The key doesn't exist (yet) because
621 * the interface is not activated.
623 goto NextReferenceString
;
625 else if (!NT_SUCCESS(Status
))
627 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
631 RtlInitUnicodeString(&KeyName
, L
"Linked");
632 Status
= ZwQueryValueKey(ControlKey
,
634 KeyValuePartialInformation
,
638 if (Status
== STATUS_BUFFER_TOO_SMALL
)
640 ActualLength
= NeededLength
;
641 PartialInfo
= ExAllocatePool(NonPagedPool
, ActualLength
);
644 Status
= STATUS_INSUFFICIENT_RESOURCES
;
648 Status
= ZwQueryValueKey(ControlKey
,
650 KeyValuePartialInformation
,
654 if (!NT_SUCCESS(Status
))
656 DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status
);
657 ExFreePool(PartialInfo
);
661 if (PartialInfo
->Type
!= REG_DWORD
|| PartialInfo
->DataLength
!= sizeof(ULONG
))
663 DPRINT1("Bad registry read\n");
664 ExFreePool(PartialInfo
);
668 RtlCopyMemory(&LinkedValue
,
670 PartialInfo
->DataLength
);
672 ExFreePool(PartialInfo
);
673 if (LinkedValue
== 0)
675 /* This interface isn't active */
676 goto NextReferenceString
;
681 DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status
);
686 /* Read the SymbolicLink string and add it into SymbolicLinkList */
687 Status
= ZwQueryValueKey(
690 KeyValuePartialInformation
,
694 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
696 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
699 bip
= ExAllocatePool(PagedPool
, Size
);
702 DPRINT("ExAllocatePool() failed\n");
703 Status
= STATUS_INSUFFICIENT_RESOURCES
;
706 Status
= ZwQueryValueKey(
709 KeyValuePartialInformation
,
713 if (!NT_SUCCESS(Status
))
715 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
718 else if (bip
->Type
!= REG_SZ
)
720 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
721 Status
= STATUS_UNSUCCESSFUL
;
724 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
726 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
727 Status
= STATUS_UNSUCCESSFUL
;
730 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)bip
->DataLength
- 4 * sizeof(WCHAR
);
731 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
732 if (KeyName
.Length
&& KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
)
734 /* Remove trailing NULL */
735 KeyName
.Length
-= sizeof(WCHAR
);
738 /* Add new symbolic link to symbolic link list */
739 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
742 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
743 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
746 DPRINT("ExAllocatePool() failed\n");
747 Status
= STATUS_INSUFFICIENT_RESOURCES
;
750 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
751 if (ReturnBuffer
.Buffer
)
752 ExFreePool(ReturnBuffer
.Buffer
);
753 ReturnBuffer
.Buffer
= NewBuffer
;
755 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
756 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
757 if (!NT_SUCCESS(Status
))
759 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
762 /* RtlAppendUnicodeStringToString added a NULL at the end of the
763 * destination string, but didn't increase the Length field.
766 ReturnBuffer
.Length
+= sizeof(WCHAR
);
769 ExFreePool(ReferenceBi
);
774 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
776 ZwClose(ReferenceKey
);
777 ReferenceKey
= INVALID_HANDLE_VALUE
;
779 if (ControlKey
!= INVALID_HANDLE_VALUE
)
782 ControlKey
= INVALID_HANDLE_VALUE
;
787 /* No need to go further, as we already have found what we searched */
791 ExFreePool(DeviceBi
);
794 DeviceKey
= INVALID_HANDLE_VALUE
;
797 /* Add final NULL to ReturnBuffer */
798 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
801 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
802 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
805 DPRINT("ExAllocatePool() failed\n");
806 Status
= STATUS_INSUFFICIENT_RESOURCES
;
809 if (ReturnBuffer
.Buffer
)
811 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
812 ExFreePool(ReturnBuffer
.Buffer
);
814 ReturnBuffer
.Buffer
= NewBuffer
;
816 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
817 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
818 Status
= STATUS_SUCCESS
;
821 if (!NT_SUCCESS(Status
) && ReturnBuffer
.Buffer
)
822 ExFreePool(ReturnBuffer
.Buffer
);
823 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
824 ZwClose(InterfaceKey
);
825 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
827 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
828 ZwClose(ReferenceKey
);
829 if (ControlKey
!= INVALID_HANDLE_VALUE
)
832 ExFreePool(DeviceBi
);
834 ExFreePool(ReferenceBi
);
841 * @name IoRegisterDeviceInterface
844 * Registers a device interface class, if it has not been previously registered,
845 * and creates a new instance of the interface class, which a driver can
846 * subsequently enable for use by applications or other system components.
849 * @param PhysicalDeviceObject
850 * Points to an optional PDO that narrows the search to only the
851 * device interfaces of the device represented by the PDO
853 * @param InterfaceClassGuid
854 * Points to a class GUID specifying the device interface class
856 * @param ReferenceString
857 * Optional parameter, pointing to a unicode string. For a full
858 * description of this rather rarely used param (usually drivers
859 * pass NULL here) see WDK
861 * @param SymbolicLinkName
862 * Pointer to the resulting unicode string
864 * @return Usual NTSTATUS
866 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
872 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject
,
873 IN CONST GUID
*InterfaceClassGuid
,
874 IN PUNICODE_STRING ReferenceString OPTIONAL
,
875 OUT PUNICODE_STRING SymbolicLinkName
)
877 PUNICODE_STRING InstancePath
;
878 UNICODE_STRING GuidString
;
879 UNICODE_STRING SubKeyName
;
880 UNICODE_STRING InterfaceKeyName
;
881 UNICODE_STRING BaseKeyName
;
882 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
883 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
884 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
885 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
890 OBJECT_ATTRIBUTES ObjectAttributes
;
893 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension
;
895 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
897 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
898 PhysicalDeviceObject
, ReferenceString
);
900 /* Parameters must pass three border of checks */
901 DeviceObjectExtension
= (PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
;
903 /* 1st level: Presence of a Device Node */
904 if (DeviceObjectExtension
->DeviceNode
== NULL
)
906 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject
);
907 return STATUS_INVALID_DEVICE_REQUEST
;
910 /* 2nd level: Presence of an non-zero length InstancePath */
911 if (DeviceObjectExtension
->DeviceNode
->InstancePath
.Length
== 0)
913 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject
);
914 return STATUS_INVALID_DEVICE_REQUEST
;
917 /* 3rd level: Optional, based on WDK documentation */
918 if (ReferenceString
!= NULL
)
920 /* Reference string must not contain path-separator symbols */
921 for (i
= 0; i
< ReferenceString
->Length
/ sizeof(WCHAR
); i
++)
923 if ((ReferenceString
->Buffer
[i
] == '\\') ||
924 (ReferenceString
->Buffer
[i
] == '/'))
925 return STATUS_INVALID_DEVICE_REQUEST
;
929 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
930 if (!NT_SUCCESS(Status
))
932 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
936 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
937 Status
= ObQueryNameString(
938 PhysicalDeviceObject
,
940 sizeof(PdoNameInfoBuffer
),
942 if (!NT_SUCCESS(Status
))
944 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
947 ASSERT(PdoNameInfo
->Name
.Length
);
949 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
950 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
951 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
952 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
953 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
955 BaseKeyName
.Buffer
= ExAllocatePool(
957 BaseKeyName
.MaximumLength
);
958 if (!BaseKeyName
.Buffer
)
960 DPRINT("ExAllocatePool() failed\n");
961 return STATUS_INSUFFICIENT_RESOURCES
;
963 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
964 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
966 /* Create BaseKeyName key in registry */
967 InitializeObjectAttributes(
970 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
971 NULL
, /* RootDirectory */
972 NULL
); /* SecurityDescriptor */
974 Status
= ZwCreateKey(
981 NULL
); /* Disposition */
983 if (!NT_SUCCESS(Status
))
985 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
986 ExFreePool(BaseKeyName
.Buffer
);
990 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
991 InterfaceKeyName
.Length
= 0;
992 InterfaceKeyName
.MaximumLength
=
993 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
994 InstancePath
->Length
+
995 sizeof(WCHAR
) + /* 1 = size of # */
997 InterfaceKeyName
.Buffer
= ExAllocatePool(
999 InterfaceKeyName
.MaximumLength
);
1000 if (!InterfaceKeyName
.Buffer
)
1002 DPRINT("ExAllocatePool() failed\n");
1003 return STATUS_INSUFFICIENT_RESOURCES
;
1006 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
1007 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
1008 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
1009 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1011 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
1012 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
1014 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
1015 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
1017 /* Create the interface key in registry */
1018 InitializeObjectAttributes(
1021 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
1023 NULL
); /* SecurityDescriptor */
1025 Status
= ZwCreateKey(
1031 REG_OPTION_VOLATILE
,
1032 NULL
); /* Disposition */
1034 if (!NT_SUCCESS(Status
))
1036 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1038 ExFreePool(BaseKeyName
.Buffer
);
1042 /* Write DeviceInstance entry. Value is InstancePath */
1043 Status
= ZwSetValueKey(
1048 InstancePath
->Buffer
,
1049 InstancePath
->Length
);
1050 if (!NT_SUCCESS(Status
))
1052 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1053 ZwClose(InterfaceKey
);
1055 ExFreePool(InterfaceKeyName
.Buffer
);
1056 ExFreePool(BaseKeyName
.Buffer
);
1060 /* Create subkey. Name is #ReferenceString */
1061 SubKeyName
.Length
= 0;
1062 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
1063 if (ReferenceString
&& ReferenceString
->Length
)
1064 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
1065 SubKeyName
.Buffer
= ExAllocatePool(
1067 SubKeyName
.MaximumLength
);
1068 if (!SubKeyName
.Buffer
)
1070 DPRINT("ExAllocatePool() failed\n");
1071 ZwClose(InterfaceKey
);
1073 ExFreePool(InterfaceKeyName
.Buffer
);
1074 ExFreePool(BaseKeyName
.Buffer
);
1075 return STATUS_INSUFFICIENT_RESOURCES
;
1077 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
1078 if (ReferenceString
&& ReferenceString
->Length
)
1079 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
1081 /* Create SubKeyName key in registry */
1082 InitializeObjectAttributes(
1085 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1086 InterfaceKey
, /* RootDirectory */
1087 NULL
); /* SecurityDescriptor */
1089 Status
= ZwCreateKey(
1095 REG_OPTION_VOLATILE
,
1096 NULL
); /* Disposition */
1098 if (!NT_SUCCESS(Status
))
1100 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1101 ZwClose(InterfaceKey
);
1103 ExFreePool(InterfaceKeyName
.Buffer
);
1104 ExFreePool(BaseKeyName
.Buffer
);
1108 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1109 SymbolicLinkName
->Length
= 0;
1110 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
1111 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
1112 + InstancePath
->Length
1113 + sizeof(WCHAR
) /* 1 = size of # */
1115 + sizeof(WCHAR
); /* final NULL */
1116 if (ReferenceString
&& ReferenceString
->Length
)
1117 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
1118 SymbolicLinkName
->Buffer
= ExAllocatePool(
1120 SymbolicLinkName
->MaximumLength
);
1121 if (!SymbolicLinkName
->Buffer
)
1123 DPRINT("ExAllocatePool() failed\n");
1125 ZwClose(InterfaceKey
);
1127 ExFreePool(InterfaceKeyName
.Buffer
);
1128 ExFreePool(SubKeyName
.Buffer
);
1129 ExFreePool(BaseKeyName
.Buffer
);
1130 return STATUS_INSUFFICIENT_RESOURCES
;
1132 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
1133 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
1134 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
1135 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1137 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
1138 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
1140 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
1141 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
1142 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1144 /* Create symbolic link */
1145 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
1146 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
1147 if (!NT_SUCCESS(Status
) && ReferenceString
== NULL
)
1149 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
1151 ZwClose(InterfaceKey
);
1153 ExFreePool(SubKeyName
.Buffer
);
1154 ExFreePool(InterfaceKeyName
.Buffer
);
1155 ExFreePool(BaseKeyName
.Buffer
);
1156 ExFreePool(SymbolicLinkName
->Buffer
);
1160 if (ReferenceString
&& ReferenceString
->Length
)
1162 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
1163 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
1165 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1167 /* Write symbolic link name in registry */
1168 SymbolicLinkName
->Buffer
[1] = '\\';
1169 Status
= ZwSetValueKey(
1174 SymbolicLinkName
->Buffer
,
1175 SymbolicLinkName
->Length
);
1176 if (!NT_SUCCESS(Status
))
1178 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1179 ExFreePool(SymbolicLinkName
->Buffer
);
1183 SymbolicLinkName
->Buffer
[1] = '?';
1187 ZwClose(InterfaceKey
);
1189 ExFreePool(SubKeyName
.Buffer
);
1190 ExFreePool(InterfaceKeyName
.Buffer
);
1191 ExFreePool(BaseKeyName
.Buffer
);
1197 * @name IoSetDeviceInterfaceState
1200 * Enables or disables an instance of a previously registered device
1202 * Documented in WDK.
1204 * @param SymbolicLinkName
1205 * Pointer to the string identifying instance to enable or disable
1208 * TRUE = enable, FALSE = disable
1210 * @return Usual NTSTATUS
1212 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1218 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName
,
1221 PDEVICE_OBJECT PhysicalDeviceObject
;
1222 PFILE_OBJECT FileObject
;
1223 UNICODE_STRING GuidString
;
1224 UNICODE_STRING SymLink
;
1225 PWCHAR StartPosition
;
1229 HANDLE InstanceHandle
, ControlHandle
;
1230 UNICODE_STRING KeyName
;
1231 OBJECT_ATTRIBUTES ObjectAttributes
;
1234 if (SymbolicLinkName
== NULL
)
1235 return STATUS_INVALID_PARAMETER_1
;
1237 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1239 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1240 /* Get GUID from SymbolicLinkName */
1241 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
1242 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
1243 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
1245 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1246 return STATUS_INVALID_PARAMETER_1
;
1248 GuidString
.Buffer
= StartPosition
;
1249 GuidString
.MaximumLength
= GuidString
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
);
1251 SymLink
.Buffer
= SymbolicLinkName
->Buffer
;
1252 SymLink
.MaximumLength
= SymLink
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)SymLink
.Buffer
);
1253 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1255 Status
= OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName
,
1260 if (!NT_SUCCESS(Status
))
1263 RtlInitUnicodeString(&KeyName
, L
"Control");
1264 InitializeObjectAttributes(&ObjectAttributes
,
1266 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1269 Status
= ZwCreateKey(&ControlHandle
,
1274 REG_OPTION_VOLATILE
,
1276 ZwClose(InstanceHandle
);
1277 if (!NT_SUCCESS(Status
))
1279 DPRINT1("Failed to create the Control subkey\n");
1283 LinkedValue
= (Enable
? 1 : 0);
1285 RtlInitUnicodeString(&KeyName
, L
"Linked");
1286 Status
= ZwSetValueKey(ControlHandle
,
1292 ZwClose(ControlHandle
);
1293 if (!NT_SUCCESS(Status
))
1295 DPRINT1("Failed to write the Linked value\n");
1299 /* Get pointer to the PDO */
1300 Status
= IoGetDeviceObjectPointer(
1302 0, /* DesiredAccess */
1304 &PhysicalDeviceObject
);
1305 if (!NT_SUCCESS(Status
))
1307 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status
);
1311 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
1312 IopNotifyPlugPlayNotification(
1313 PhysicalDeviceObject
,
1314 EventCategoryDeviceInterfaceChange
,
1317 (PVOID
)SymbolicLinkName
);
1319 ObDereferenceObject(FileObject
);
1320 DPRINT("Status %x\n", Status
);
1321 return STATUS_SUCCESS
;