2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/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 ******************************************************************/
17 #include <internal/debug.h>
19 /* FUNCTIONS *****************************************************************/
21 static PWCHAR BaseKeyString
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
28 IoOpenDeviceInterfaceRegistryKey(
29 IN PUNICODE_STRING SymbolicLinkName
,
30 IN ACCESS_MASK DesiredAccess
,
31 OUT PHANDLE DeviceInterfaceKey
)
33 return STATUS_NOT_IMPLEMENTED
;
41 IoGetDeviceInterfaceAlias(
42 IN PUNICODE_STRING SymbolicLinkName
,
43 IN CONST GUID
*AliasInterfaceClassGuid
,
44 OUT PUNICODE_STRING AliasSymbolicLinkName
)
46 return STATUS_NOT_IMPLEMENTED
;
51 IN CONST GUID
*InterfaceClassGuid
,
52 IN ACCESS_MASK DesiredAccess
,
53 OUT HANDLE
*pInterfaceKey
)
55 UNICODE_STRING LocalMachine
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\");
56 UNICODE_STRING GuidString
;
57 UNICODE_STRING KeyName
;
58 OBJECT_ATTRIBUTES ObjectAttributes
;
59 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
62 GuidString
.Buffer
= KeyName
.Buffer
= NULL
;
64 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
65 if (!NT_SUCCESS(Status
))
67 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
72 KeyName
.MaximumLength
= LocalMachine
.Length
+ (wcslen(REGSTR_PATH_DEVICE_CLASSES
) + 1) * sizeof(WCHAR
) + GuidString
.Length
;
73 KeyName
.Buffer
= ExAllocatePool(PagedPool
, KeyName
.MaximumLength
);
76 DPRINT("ExAllocatePool() failed\n");
77 Status
= STATUS_INSUFFICIENT_RESOURCES
;
81 Status
= RtlAppendUnicodeStringToString(&KeyName
, &LocalMachine
);
82 if (!NT_SUCCESS(Status
))
84 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
87 Status
= RtlAppendUnicodeToString(&KeyName
, REGSTR_PATH_DEVICE_CLASSES
);
88 if (!NT_SUCCESS(Status
))
90 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
93 Status
= RtlAppendUnicodeToString(&KeyName
, L
"\\");
94 if (!NT_SUCCESS(Status
))
96 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
99 Status
= RtlAppendUnicodeStringToString(&KeyName
, &GuidString
);
100 if (!NT_SUCCESS(Status
))
102 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
106 InitializeObjectAttributes(
109 OBJ_CASE_INSENSITIVE
,
116 if (!NT_SUCCESS(Status
))
118 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
122 *pInterfaceKey
= InterfaceKey
;
123 Status
= STATUS_SUCCESS
;
126 if (!NT_SUCCESS(Status
))
128 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
129 ZwClose(InterfaceKey
);
131 RtlFreeUnicodeString(&GuidString
);
132 RtlFreeUnicodeString(&KeyName
);
137 * IoGetDeviceInterfaces
139 * Returns a list of device interfaces of a particular device interface class.
143 * Points to a class GUID specifying the device interface class.
145 * PhysicalDeviceObject
146 * Points to an optional PDO that narrows the search to only the
147 * device interfaces of the device represented by the PDO.
150 * Specifies flags that modify the search for device interfaces. The
151 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
152 * returned symbolic links should contain also disabled device
153 * interfaces in addition to the enabled ones.
156 * Points to a character pointer that is filled in on successful return
157 * with a list of unicode strings identifying the device interfaces
158 * that match the search criteria. The newly allocated buffer contains
159 * a list of symbolic link names. Each unicode string in the list is
160 * null-terminated; the end of the whole list is marked by an additional
161 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
162 * when it is no longer needed.
163 * If no device interfaces match the search criteria, this routine
164 * returns STATUS_SUCCESS and the string contains a single NULL
173 IoGetDeviceInterfaces(
174 IN CONST GUID
*InterfaceClassGuid
,
175 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
177 OUT PWSTR
*SymbolicLinkList
)
179 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
180 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
181 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
182 HANDLE DeviceKey
= INVALID_HANDLE_VALUE
;
183 HANDLE ReferenceKey
= INVALID_HANDLE_VALUE
;
184 HANDLE ControlKey
= INVALID_HANDLE_VALUE
;
185 PKEY_BASIC_INFORMATION DeviceBi
= NULL
;
186 PKEY_BASIC_INFORMATION ReferenceBi
= NULL
;
187 PKEY_VALUE_PARTIAL_INFORMATION bip
= NULL
;
188 UNICODE_STRING KeyName
;
189 OBJECT_ATTRIBUTES ObjectAttributes
;
190 BOOLEAN FoundRightPDO
= FALSE
;
191 ULONG i
= 0, j
, Size
;
192 UNICODE_STRING ReturnBuffer
= {0,};
197 Status
= IopOpenInterfaceKey(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, &InterfaceKey
);
198 if (!NT_SUCCESS(Status
))
200 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status
);
204 /* Enumerate subkeys (ie the different device objets) */
207 Status
= ZwEnumerateKey(
214 if (Status
== STATUS_NO_MORE_ENTRIES
)
216 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
218 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
222 DeviceBi
= ExAllocatePool(PagedPool
, Size
);
225 DPRINT("ExAllocatePool() failed\n");
226 Status
= STATUS_INSUFFICIENT_RESOURCES
;
229 Status
= ZwEnumerateKey(
236 if (!NT_SUCCESS(Status
))
238 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
242 /* Open device key */
243 KeyName
.Length
= KeyName
.MaximumLength
= DeviceBi
->NameLength
;
244 KeyName
.Buffer
= DeviceBi
->Name
;
245 InitializeObjectAttributes(
248 OBJ_CASE_INSENSITIVE
,
253 KEY_ENUMERATE_SUB_KEYS
,
255 if (!NT_SUCCESS(Status
))
257 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
261 if (PhysicalDeviceObject
)
263 /* Check if we are on the right physical device object,
264 * by reading the DeviceInstance string
266 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
267 //FoundRightPDO = TRUE;
268 Status
= STATUS_NOT_IMPLEMENTED
;
272 /* Enumerate subkeys (ie the different reference strings) */
276 Status
= ZwEnumerateKey(
283 if (Status
== STATUS_NO_MORE_ENTRIES
)
285 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
287 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
291 ReferenceBi
= ExAllocatePool(PagedPool
, Size
);
294 DPRINT("ExAllocatePool() failed\n");
295 Status
= STATUS_INSUFFICIENT_RESOURCES
;
298 Status
= ZwEnumerateKey(
305 if (!NT_SUCCESS(Status
))
307 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
311 KeyName
.Length
= KeyName
.MaximumLength
= ReferenceBi
->NameLength
;
312 KeyName
.Buffer
= ReferenceBi
->Name
;
313 if (RtlEqualUnicodeString(&KeyName
, &Control
, TRUE
))
315 /* Skip Control subkey */
316 goto NextReferenceString
;
319 /* Open reference key */
320 InitializeObjectAttributes(
323 OBJ_CASE_INSENSITIVE
,
330 if (!NT_SUCCESS(Status
))
332 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
336 if (!(Flags
& DEVICE_INTERFACE_INCLUDE_NONACTIVE
))
338 /* We have to check if the interface is enabled, by
339 * reading the Linked value in the Control subkey
341 InitializeObjectAttributes(
344 OBJ_CASE_INSENSITIVE
,
351 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
353 /* That's OK. The key doesn't exist (yet) because
354 * the interface is not activated.
356 goto NextReferenceString
;
358 else if (!NT_SUCCESS(Status
))
360 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
363 /* FIXME: Read the Linked value
364 * If it doesn't exist => ERROR
365 * If it is not a REG_DWORD or Size != sizeof(ULONG) => ERROR
366 * If its value is 0, go to NextReferenceString
367 * At the moment, do as if it is active...
369 DPRINT1("Checking if device is enabled is not implemented yet!\n");
372 /* Read the SymbolicLink string and add it into SymbolicLinkList */
373 Status
= ZwQueryValueKey(
376 KeyValuePartialInformation
,
380 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
382 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
385 bip
= ExAllocatePool(PagedPool
, Size
);
388 DPRINT("ExAllocatePool() failed\n");
389 Status
= STATUS_INSUFFICIENT_RESOURCES
;
392 Status
= ZwQueryValueKey(
395 KeyValuePartialInformation
,
399 if (!NT_SUCCESS(Status
))
401 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
404 else if (bip
->Type
!= REG_SZ
)
406 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
407 Status
= STATUS_UNSUCCESSFUL
;
410 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
412 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
413 Status
= STATUS_UNSUCCESSFUL
;
416 KeyName
.Length
= KeyName
.MaximumLength
= bip
->DataLength
- 4 * sizeof(WCHAR
);
417 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
418 if (KeyName
.Length
&& KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
)
419 /* Remove trailing NULL */
420 KeyName
.Length
-= sizeof(WCHAR
);
422 /* Add new symbolic link to symbolic link list */
423 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
426 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
427 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
430 DPRINT("ExAllocatePool() failed\n");
431 Status
= STATUS_INSUFFICIENT_RESOURCES
;
434 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
435 ExFreePool(ReturnBuffer
.Buffer
);
436 ReturnBuffer
.Buffer
= NewBuffer
;
438 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
439 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
440 if (!NT_SUCCESS(Status
))
442 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
445 /* RtlAppendUnicodeStringToString added a NULL at the end of the
446 * destination string, but didn't increase the Length field.
449 ReturnBuffer
.Length
+= sizeof(WCHAR
);
452 ExFreePool(ReferenceBi
);
456 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
458 ZwClose(ReferenceKey
);
459 ReferenceKey
= INVALID_HANDLE_VALUE
;
461 if (ControlKey
!= INVALID_HANDLE_VALUE
)
464 ControlKey
= INVALID_HANDLE_VALUE
;
469 /* No need to go further, as we already have found what we searched */
473 ExFreePool(DeviceBi
);
476 DeviceKey
= INVALID_HANDLE_VALUE
;
479 /* Add final NULL to ReturnBuffer */
480 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
483 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
484 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
487 DPRINT("ExAllocatePool() failed\n");
488 Status
= STATUS_INSUFFICIENT_RESOURCES
;
491 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
492 ExFreePool(ReturnBuffer
.Buffer
);
493 ReturnBuffer
.Buffer
= NewBuffer
;
495 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
496 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
497 Status
= STATUS_SUCCESS
;
500 if (!NT_SUCCESS(Status
))
501 ExFreePool(ReturnBuffer
.Buffer
);
502 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
503 ZwClose(InterfaceKey
);
504 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
506 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
507 ZwClose(ReferenceKey
);
508 if (ControlKey
!= INVALID_HANDLE_VALUE
)
510 ExFreePool(DeviceBi
);
511 ExFreePool(ReferenceBi
);
521 IoRegisterDeviceInterface(
522 IN PDEVICE_OBJECT PhysicalDeviceObject
,
523 IN CONST GUID
*InterfaceClassGuid
,
524 IN PUNICODE_STRING ReferenceString OPTIONAL
,
525 OUT PUNICODE_STRING SymbolicLinkName
)
527 PUNICODE_STRING InstancePath
;
528 UNICODE_STRING GuidString
;
529 UNICODE_STRING SubKeyName
;
530 UNICODE_STRING InterfaceKeyName
;
531 UNICODE_STRING BaseKeyName
;
532 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
533 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
534 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
535 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
540 OBJECT_ATTRIBUTES ObjectAttributes
;
544 ASSERT_IRQL(PASSIVE_LEVEL
);
546 if (!(PhysicalDeviceObject
->Flags
& DO_BUS_ENUMERATED_DEVICE
))
548 DPRINT("PhysicalDeviceObject 0x%p is not a valid Pdo\n", PhysicalDeviceObject
);
549 return STATUS_INVALID_PARAMETER_1
;
552 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
553 if (!NT_SUCCESS(Status
))
555 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
559 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
560 Status
= ObQueryNameString(
561 PhysicalDeviceObject
,
563 sizeof(PdoNameInfoBuffer
),
565 if (!NT_SUCCESS(Status
))
567 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
570 ASSERT(PdoNameInfo
->Name
.Length
);
572 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
573 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
574 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
575 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
576 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
578 BaseKeyName
.Buffer
= ExAllocatePool(
580 BaseKeyName
.MaximumLength
);
581 if (!BaseKeyName
.Buffer
)
583 DPRINT("ExAllocatePool() failed\n");
584 return STATUS_INSUFFICIENT_RESOURCES
;
586 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
587 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
589 /* Create BaseKeyName key in registry */
590 InitializeObjectAttributes(
593 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
594 NULL
, /* RootDirectory */
595 NULL
); /* SecurityDescriptor */
597 Status
= ZwCreateKey(
604 NULL
); /* Disposition */
606 if (!NT_SUCCESS(Status
))
608 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
609 ExFreePool(BaseKeyName
.Buffer
);
613 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
614 InterfaceKeyName
.Length
= 0;
615 InterfaceKeyName
.MaximumLength
=
616 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
617 InstancePath
->Length
+
618 sizeof(WCHAR
) + /* 1 = size of # */
620 InterfaceKeyName
.Buffer
= ExAllocatePool(
622 InterfaceKeyName
.MaximumLength
);
623 if (!InterfaceKeyName
.Buffer
)
625 DPRINT("ExAllocatePool() failed\n");
626 return STATUS_INSUFFICIENT_RESOURCES
;
629 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
630 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
631 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
632 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
634 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
635 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
637 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
638 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
640 /* Create the interface key in registry */
641 InitializeObjectAttributes(
644 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
646 NULL
); /* SecurityDescriptor */
648 Status
= ZwCreateKey(
655 NULL
); /* Disposition */
657 if (!NT_SUCCESS(Status
))
659 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
661 ExFreePool(BaseKeyName
.Buffer
);
665 /* Write DeviceInstance entry. Value is InstancePath */
666 Status
= ZwSetValueKey(
671 InstancePath
->Buffer
,
672 InstancePath
->Length
);
673 if (!NT_SUCCESS(Status
))
675 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
676 ZwClose(InterfaceKey
);
678 ExFreePool(InterfaceKeyName
.Buffer
);
679 ExFreePool(BaseKeyName
.Buffer
);
683 /* Create subkey. Name is #ReferenceString */
684 SubKeyName
.Length
= 0;
685 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
686 if (ReferenceString
&& ReferenceString
->Length
)
687 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
688 SubKeyName
.Buffer
= ExAllocatePool(
690 SubKeyName
.MaximumLength
);
691 if (!SubKeyName
.Buffer
)
693 DPRINT("ExAllocatePool() failed\n");
694 ZwClose(InterfaceKey
);
696 ExFreePool(InterfaceKeyName
.Buffer
);
697 ExFreePool(BaseKeyName
.Buffer
);
698 return STATUS_INSUFFICIENT_RESOURCES
;
700 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
701 if (ReferenceString
&& ReferenceString
->Length
)
702 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
704 /* Create SubKeyName key in registry */
705 InitializeObjectAttributes(
708 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
709 InterfaceKey
, /* RootDirectory */
710 NULL
); /* SecurityDescriptor */
712 Status
= ZwCreateKey(
719 NULL
); /* Disposition */
721 if (!NT_SUCCESS(Status
))
723 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
724 ZwClose(InterfaceKey
);
726 ExFreePool(InterfaceKeyName
.Buffer
);
727 ExFreePool(BaseKeyName
.Buffer
);
731 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
732 SymbolicLinkName
->Length
= 0;
733 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
734 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
735 + InstancePath
->Length
736 + sizeof(WCHAR
) /* 1 = size of # */
738 + sizeof(WCHAR
); /* final NULL */
739 if (ReferenceString
&& ReferenceString
->Length
)
740 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
741 SymbolicLinkName
->Buffer
= ExAllocatePool(
743 SymbolicLinkName
->MaximumLength
);
744 if (!SymbolicLinkName
->Buffer
)
746 DPRINT("ExAllocatePool() failed\n");
748 ZwClose(InterfaceKey
);
750 ExFreePool(InterfaceKeyName
.Buffer
);
751 ExFreePool(SubKeyName
.Buffer
);
752 ExFreePool(BaseKeyName
.Buffer
);
753 return STATUS_INSUFFICIENT_RESOURCES
;
755 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
756 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
757 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
758 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
760 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
761 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
763 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
764 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
765 if (ReferenceString
&& ReferenceString
->Length
)
767 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
768 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
770 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
772 /* Create symbolic link */
773 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
774 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
775 if (!NT_SUCCESS(Status
))
777 DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
779 ZwClose(InterfaceKey
);
781 ExFreePool(SubKeyName
.Buffer
);
782 ExFreePool(InterfaceKeyName
.Buffer
);
783 ExFreePool(BaseKeyName
.Buffer
);
784 ExFreePool(SymbolicLinkName
->Buffer
);
788 /* Write symbolic link name in registry */
789 SymbolicLinkName
->Buffer
[1] = '\\';
790 Status
= ZwSetValueKey(
795 SymbolicLinkName
->Buffer
,
796 SymbolicLinkName
->Length
);
797 if (!NT_SUCCESS(Status
))
799 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
800 ExFreePool(SymbolicLinkName
->Buffer
);
803 /* Remove \\?\ at the start of symbolic link name */
804 SymbolicLinkName
->Length
-= 4 * sizeof(WCHAR
);
805 SymbolicLinkName
->MaximumLength
-= 4 * sizeof(WCHAR
);
807 SymbolicLinkName
->Buffer
,
808 &SymbolicLinkName
->Buffer
[4],
809 SymbolicLinkName
->Length
);
812 ZwClose(InterfaceKey
);
814 ExFreePool(SubKeyName
.Buffer
);
815 ExFreePool(InterfaceKeyName
.Buffer
);
816 ExFreePool(BaseKeyName
.Buffer
);
826 IoSetDeviceInterfaceState(
827 IN PUNICODE_STRING SymbolicLinkName
,
830 PDEVICE_OBJECT PhysicalDeviceObject
;
831 PFILE_OBJECT FileObject
;
832 UNICODE_STRING ObjectName
;
833 UNICODE_STRING GuidString
;
834 PWCHAR StartPosition
;
839 if (SymbolicLinkName
== NULL
)
840 return STATUS_INVALID_PARAMETER_1
;
842 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
844 /* Symbolic link name is ACPI#PNP0501#1#{GUID}\ReferenceString */
845 /* Get GUID from SymbolicLinkName */
846 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
847 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
848 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
849 return STATUS_INVALID_PARAMETER_1
;
850 GuidString
.Buffer
= StartPosition
;
851 GuidString
.MaximumLength
= GuidString
.Length
= (ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
;
853 /* Create \??\SymbolicLinkName string */
854 ObjectName
.Length
= 0;
855 ObjectName
.MaximumLength
= SymbolicLinkName
->Length
+ 4 * sizeof(WCHAR
);
856 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
857 if (!ObjectName
.Buffer
)
858 return STATUS_INSUFFICIENT_RESOURCES
;
859 RtlAppendUnicodeToString(&ObjectName
, L
"\\??\\");
860 RtlAppendUnicodeStringToString(&ObjectName
, SymbolicLinkName
);
862 /* Get pointer to the PDO */
863 Status
= IoGetDeviceObjectPointer(&ObjectName
,
864 0, /* DesiredAccess */
866 &PhysicalDeviceObject
);
867 if (!NT_SUCCESS(Status
))
869 ExFreePool(ObjectName
.Buffer
);
873 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
874 IopNotifyPlugPlayNotification(
875 PhysicalDeviceObject
,
876 EventCategoryDeviceInterfaceChange
,
879 (PVOID
)SymbolicLinkName
);
881 ObDereferenceObject(FileObject
);
882 ExFreePool(ObjectName
.Buffer
);
884 return STATUS_SUCCESS
;