3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/deviface.c
6 * PURPOSE: Device interface functions
8 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
9 * Matthew Brace (ismarc@austin.rr.com)
10 * Hervé Poussineau (hpoussin@reactos.com)
13 /* INCLUDES ******************************************************************/
18 #include <internal/debug.h>
20 /* FUNCTIONS *****************************************************************/
22 static PWCHAR BaseKeyString
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
29 IoOpenDeviceInterfaceRegistryKey(
30 IN PUNICODE_STRING SymbolicLinkName
,
31 IN ACCESS_MASK DesiredAccess
,
32 OUT PHANDLE DeviceInterfaceKey
)
34 return STATUS_NOT_IMPLEMENTED
;
42 IoGetDeviceInterfaceAlias(
43 IN PUNICODE_STRING SymbolicLinkName
,
44 IN CONST GUID
*AliasInterfaceClassGuid
,
45 OUT PUNICODE_STRING AliasSymbolicLinkName
)
47 return STATUS_NOT_IMPLEMENTED
;
51 * IoGetDeviceInterfaces
53 * Returns a list of device interfaces of a particular device interface class.
57 * Points to a class GUID specifying the device interface class.
59 * PhysicalDeviceObject
60 * Points to an optional PDO that narrows the search to only the
61 * device interfaces of the device represented by the PDO.
64 * Specifies flags that modify the search for device interfaces. The
65 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
66 * returned symbolic links should contain also disabled device
67 * interfaces in addition to the enabled ones.
70 * Points to a character pointer that is filled in on successful return
71 * with a list of unicode strings identifying the device interfaces
72 * that match the search criteria. The newly allocated buffer contains
73 * a list of symbolic link names. Each unicode string in the list is
74 * null-terminated; the end of the whole list is marked by an additional
75 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
76 * when it is no longer needed.
77 * If no device interfaces match the search criteria, this routine
78 * returns STATUS_SUCCESS and the string contains a single NULL
84 * The parameters PhysicalDeviceObject and Flags aren't correctly
85 * processed. Rest of the cases was tested under Windows(R) XP and
86 * the function worked correctly.
90 IoGetDeviceInterfaces(
91 IN CONST GUID
*InterfaceClassGuid
,
92 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
94 OUT PWSTR
*SymbolicLinkList
)
96 PWCHAR BaseInterfaceString
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
97 UNICODE_STRING GuidString
;
98 UNICODE_STRING BaseKeyName
;
99 UNICODE_STRING AliasKeyName
;
100 UNICODE_STRING SymbolicLink
;
101 UNICODE_STRING Control
;
102 UNICODE_STRING SubKeyName
;
103 UNICODE_STRING SymbolicLinkKeyName
;
104 UNICODE_STRING ControlKeyName
;
105 UNICODE_STRING TempString
;
108 HANDLE SymbolicLinkKey
;
109 PKEY_FULL_INFORMATION fip
;
110 PKEY_FULL_INFORMATION bfip
= NULL
;
111 PKEY_BASIC_INFORMATION bip
;
112 PKEY_VALUE_PARTIAL_INFORMATION vpip
= NULL
;
113 PWCHAR SymLinkList
= NULL
;
114 ULONG SymLinkListSize
= 0;
119 OBJECT_ATTRIBUTES ObjectAttributes
;
121 ASSERT_IRQL(PASSIVE_LEVEL
);
123 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
124 if (!NT_SUCCESS(Status
))
126 DPRINT("RtlStringFromGUID() Failed.\n");
127 return STATUS_INVALID_HANDLE
;
130 RtlInitUnicodeString(&AliasKeyName
, BaseInterfaceString
);
131 RtlInitUnicodeString(&SymbolicLink
, L
"SymbolicLink");
132 RtlInitUnicodeString(&Control
, L
"\\Control");
133 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
134 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
+ (38 * sizeof(WCHAR
));
135 BaseKeyName
.Buffer
= ExAllocatePool(
137 BaseKeyName
.MaximumLength
);
138 ASSERT(BaseKeyName
.Buffer
!= NULL
);
139 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
140 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
142 if (PhysicalDeviceObject
)
144 WCHAR GuidBuffer
[40];
145 UNICODE_STRING PdoGuidString
;
147 RtlFreeUnicodeString(&BaseKeyName
);
150 PhysicalDeviceObject
,
151 DevicePropertyClassGuid
,
156 RtlInitUnicodeString(&PdoGuidString
, GuidBuffer
);
157 if (RtlCompareUnicodeString(&GuidString
, &PdoGuidString
, TRUE
))
159 DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
160 return STATUS_INVALID_HANDLE
;
163 DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
164 return STATUS_NOT_IMPLEMENTED
;
168 InitializeObjectAttributes(
171 OBJ_CASE_INSENSITIVE
,
180 if (!NT_SUCCESS(Status
))
182 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status
);
183 RtlFreeUnicodeString(&BaseKeyName
);
194 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
196 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
197 RtlFreeUnicodeString(&BaseKeyName
);
198 ZwClose(InterfaceKey
);
202 fip
= (PKEY_FULL_INFORMATION
)ExAllocatePool(PagedPool
, Size
);
212 if (!NT_SUCCESS(Status
))
214 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
216 RtlFreeUnicodeString(&BaseKeyName
);
217 ZwClose(InterfaceKey
);
221 for (; i
< fip
->SubKeys
; i
++)
223 Status
= ZwEnumerateKey(
231 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
233 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
235 if (SymLinkList
!= NULL
)
236 ExFreePool(SymLinkList
);
237 RtlFreeUnicodeString(&BaseKeyName
);
238 ZwClose(InterfaceKey
);
242 bip
= (PKEY_BASIC_INFORMATION
)ExAllocatePool(PagedPool
, Size
);
245 Status
= ZwEnumerateKey(
253 if (!NT_SUCCESS(Status
))
255 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
258 if (SymLinkList
!= NULL
)
259 ExFreePool(SymLinkList
);
260 RtlFreeUnicodeString(&BaseKeyName
);
261 ZwClose(InterfaceKey
);
265 SubKeyName
.Length
= 0;
266 SubKeyName
.MaximumLength
= BaseKeyName
.Length
+ bip
->NameLength
+ sizeof(WCHAR
);
267 SubKeyName
.Buffer
= ExAllocatePool(PagedPool
, SubKeyName
.MaximumLength
);
268 ASSERT(SubKeyName
.Buffer
!= NULL
);
269 TempString
.Length
= TempString
.MaximumLength
= bip
->NameLength
;
270 TempString
.Buffer
= bip
->Name
;
271 RtlCopyUnicodeString(&SubKeyName
, &BaseKeyName
);
272 RtlAppendUnicodeToString(&SubKeyName
, L
"\\");
273 RtlAppendUnicodeStringToString(&SubKeyName
, &TempString
);
277 InitializeObjectAttributes(
280 OBJ_CASE_INSENSITIVE
,
289 if (!NT_SUCCESS(Status
))
291 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status
);
293 if (SymLinkList
!= NULL
)
294 ExFreePool(SymLinkList
);
295 RtlFreeUnicodeString(&SubKeyName
);
296 RtlFreeUnicodeString(&BaseKeyName
);
297 ZwClose(InterfaceKey
);
308 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
310 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
312 RtlFreeUnicodeString(&BaseKeyName
);
313 RtlFreeUnicodeString(&SubKeyName
);
315 ZwClose(InterfaceKey
);
319 bfip
= (PKEY_FULL_INFORMATION
)ExAllocatePool(PagedPool
, Size
);
320 ASSERT(bfip
!= NULL
);
329 if (!NT_SUCCESS(Status
))
331 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
333 RtlFreeUnicodeString(&SubKeyName
);
334 RtlFreeUnicodeString(&BaseKeyName
);
336 ZwClose(InterfaceKey
);
340 for(j
= 0; j
< bfip
->SubKeys
; j
++)
342 Status
= ZwEnumerateKey(
350 if (Status
== STATUS_NO_MORE_ENTRIES
)
353 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
355 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
358 if (SymLinkList
!= NULL
)
359 ExFreePool(SymLinkList
);
360 RtlFreeUnicodeString(&SubKeyName
);
361 RtlFreeUnicodeString(&BaseKeyName
);
363 ZwClose(InterfaceKey
);
367 bip
= (PKEY_BASIC_INFORMATION
)ExAllocatePool(PagedPool
, Size
);
370 Status
= ZwEnumerateKey(
378 if (!NT_SUCCESS(Status
))
380 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
384 if (SymLinkList
!= NULL
)
385 ExFreePool(SymLinkList
);
386 RtlFreeUnicodeString(&SubKeyName
);
387 RtlFreeUnicodeString(&BaseKeyName
);
389 ZwClose(InterfaceKey
);
393 if (!wcsncmp(bip
->Name
, L
"Control", bip
->NameLength
))
398 SymbolicLinkKeyName
.Length
= 0;
399 SymbolicLinkKeyName
.MaximumLength
= SubKeyName
.Length
+ bip
->NameLength
+ sizeof(WCHAR
);
400 SymbolicLinkKeyName
.Buffer
= ExAllocatePool(PagedPool
, SymbolicLinkKeyName
.MaximumLength
);
401 ASSERT(SymbolicLinkKeyName
.Buffer
!= NULL
);
402 TempString
.Length
= TempString
.MaximumLength
= bip
->NameLength
;
403 TempString
.Buffer
= bip
->Name
;
404 RtlCopyUnicodeString(&SymbolicLinkKeyName
, &SubKeyName
);
405 RtlAppendUnicodeToString(&SymbolicLinkKeyName
, L
"\\");
406 RtlAppendUnicodeStringToString(&SymbolicLinkKeyName
, &TempString
);
408 ControlKeyName
.Length
= 0;
409 ControlKeyName
.MaximumLength
= SymbolicLinkKeyName
.Length
+ Control
.Length
+ sizeof(WCHAR
);
410 ControlKeyName
.Buffer
= ExAllocatePool(PagedPool
, ControlKeyName
.MaximumLength
);
411 ASSERT(ControlKeyName
.Buffer
!= NULL
);
412 RtlCopyUnicodeString(&ControlKeyName
, &SymbolicLinkKeyName
);
413 RtlAppendUnicodeStringToString(&ControlKeyName
, &Control
);
417 InitializeObjectAttributes(
419 &SymbolicLinkKeyName
,
420 OBJ_CASE_INSENSITIVE
,
429 if (!NT_SUCCESS(Status
))
431 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status
);
434 if (SymLinkList
!= NULL
)
435 ExFreePool(SymLinkList
);
436 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
437 RtlFreeUnicodeString(&SubKeyName
);
438 RtlFreeUnicodeString(&BaseKeyName
);
440 ZwClose(InterfaceKey
);
444 Status
= ZwQueryValueKey(
447 KeyValuePartialInformation
,
452 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
455 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
457 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status
);
460 if (SymLinkList
!= NULL
)
461 ExFreePool(SymLinkList
);
462 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
463 RtlFreeUnicodeString(&SubKeyName
);
464 RtlFreeUnicodeString(&BaseKeyName
);
465 ZwClose(SymbolicLinkKey
);
467 ZwClose(InterfaceKey
);
471 vpip
= (PKEY_VALUE_PARTIAL_INFORMATION
)ExAllocatePool(PagedPool
, Size
);
472 ASSERT(vpip
!= NULL
);
474 Status
= ZwQueryValueKey(
477 KeyValuePartialInformation
,
482 if (!NT_SUCCESS(Status
))
484 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status
);
488 if (SymLinkList
!= NULL
)
489 ExFreePool(SymLinkList
);
490 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
491 RtlFreeUnicodeString(&SubKeyName
);
492 RtlFreeUnicodeString(&BaseKeyName
);
493 ZwClose(SymbolicLinkKey
);
495 ZwClose(InterfaceKey
);
499 Status
= RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE
, ControlKeyName
.Buffer
);
501 if (NT_SUCCESS(Status
))
503 /* Put the name in the string here */
504 if (SymLinkList
== NULL
)
506 SymLinkListSize
= vpip
->DataLength
;
507 SymLinkList
= ExAllocatePool(PagedPool
, SymLinkListSize
+ sizeof(WCHAR
));
508 ASSERT(SymLinkList
!= NULL
);
509 RtlCopyMemory(SymLinkList
, vpip
->Data
, vpip
->DataLength
);
510 SymLinkList
[vpip
->DataLength
/ sizeof(WCHAR
)] = 0;
511 SymLinkList
[1] = '?';
515 PWCHAR OldSymLinkList
;
516 ULONG OldSymLinkListSize
;
517 PWCHAR SymLinkListPtr
;
519 OldSymLinkList
= SymLinkList
;
520 OldSymLinkListSize
= SymLinkListSize
;
521 SymLinkListSize
+= vpip
->DataLength
;
522 SymLinkList
= ExAllocatePool(PagedPool
, SymLinkListSize
+ sizeof(WCHAR
));
523 ASSERT(SymLinkList
!= NULL
);
524 RtlCopyMemory(SymLinkList
, OldSymLinkList
, OldSymLinkListSize
);
525 ExFreePool(OldSymLinkList
);
526 SymLinkListPtr
= SymLinkList
+ (OldSymLinkListSize
/ sizeof(WCHAR
));
527 RtlCopyMemory(SymLinkListPtr
, vpip
->Data
, vpip
->DataLength
);
528 SymLinkListPtr
[vpip
->DataLength
/ sizeof(WCHAR
)] = 0;
529 SymLinkListPtr
[1] = '?';
533 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
534 RtlFreeUnicodeString(&ControlKeyName
);
535 ZwClose(SymbolicLinkKey
);
539 RtlFreeUnicodeString(&SubKeyName
);
543 if (SymLinkList
!= NULL
)
545 SymLinkList
[SymLinkListSize
/ sizeof(WCHAR
)] = 0;
549 SymLinkList
= ExAllocatePool(PagedPool
, 2 * sizeof(WCHAR
));
553 *SymbolicLinkList
= SymLinkList
;
555 RtlFreeUnicodeString(&BaseKeyName
);
556 ZwClose(InterfaceKey
);
561 return STATUS_SUCCESS
;
569 IoRegisterDeviceInterface(
570 IN PDEVICE_OBJECT PhysicalDeviceObject
,
571 IN CONST GUID
*InterfaceClassGuid
,
572 IN PUNICODE_STRING ReferenceString OPTIONAL
,
573 OUT PUNICODE_STRING SymbolicLinkName
)
575 PUNICODE_STRING InstancePath
;
576 UNICODE_STRING GuidString
;
577 UNICODE_STRING SubKeyName
;
578 UNICODE_STRING InterfaceKeyName
;
579 UNICODE_STRING BaseKeyName
;
580 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
581 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
582 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
583 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
588 OBJECT_ATTRIBUTES ObjectAttributes
;
592 ASSERT_IRQL(PASSIVE_LEVEL
);
594 if (!(PhysicalDeviceObject
->Flags
& DO_BUS_ENUMERATED_DEVICE
))
596 DPRINT("PhysicalDeviceObject 0x%p is not a valid Pdo\n", PhysicalDeviceObject
);
597 return STATUS_INVALID_PARAMETER_1
;
600 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
601 if (!NT_SUCCESS(Status
))
603 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
607 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
608 Status
= ObQueryNameString(
609 PhysicalDeviceObject
,
611 sizeof(PdoNameInfoBuffer
),
613 if (!NT_SUCCESS(Status
))
615 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
618 ASSERT(PdoNameInfo
->Name
.Length
);
620 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
621 ASSERT(PhysicalDeviceObject
->DeviceObjectExtension
->DeviceNode
);
622 InstancePath
= &PhysicalDeviceObject
->DeviceObjectExtension
->DeviceNode
->InstancePath
;
623 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
624 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
626 BaseKeyName
.Buffer
= ExAllocatePool(
628 BaseKeyName
.MaximumLength
);
629 if (!BaseKeyName
.Buffer
)
631 DPRINT("ExAllocatePool() failed\n");
632 return STATUS_INSUFFICIENT_RESOURCES
;
634 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
635 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
637 /* Create BaseKeyName key in registry */
638 InitializeObjectAttributes(
641 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
642 NULL
, /* RootDirectory */
643 NULL
); /* SecurityDescriptor */
645 Status
= ZwCreateKey(
652 NULL
); /* Disposition */
654 if (!NT_SUCCESS(Status
))
656 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
657 ExFreePool(BaseKeyName
.Buffer
);
661 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
662 InterfaceKeyName
.Length
= 0;
663 InterfaceKeyName
.MaximumLength
=
664 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
665 InstancePath
->Length
+
666 sizeof(WCHAR
) + /* 1 = size of # */
668 InterfaceKeyName
.Buffer
= ExAllocatePool(
670 InterfaceKeyName
.MaximumLength
);
671 if (!InterfaceKeyName
.Buffer
)
673 DPRINT("ExAllocatePool() failed\n");
674 return STATUS_INSUFFICIENT_RESOURCES
;
677 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
678 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
679 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
680 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
682 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
683 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
685 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
686 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
688 /* Create the interface key in registry */
689 InitializeObjectAttributes(
692 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
694 NULL
); /* SecurityDescriptor */
696 Status
= ZwCreateKey(
703 NULL
); /* Disposition */
705 if (!NT_SUCCESS(Status
))
707 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
709 ExFreePool(BaseKeyName
.Buffer
);
713 /* Write DeviceInstance entry. Value is InstancePath */
714 Status
= ZwSetValueKey(
719 InstancePath
->Buffer
,
720 InstancePath
->Length
);
721 if (!NT_SUCCESS(Status
))
723 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
724 ZwClose(InterfaceKey
);
726 ExFreePool(InterfaceKeyName
.Buffer
);
727 ExFreePool(BaseKeyName
.Buffer
);
731 /* Create subkey. Name is #ReferenceString */
732 SubKeyName
.Length
= 0;
733 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
734 if (ReferenceString
&& ReferenceString
->Length
)
735 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
736 SubKeyName
.Buffer
= ExAllocatePool(
738 SubKeyName
.MaximumLength
);
739 if (!SubKeyName
.Buffer
)
741 DPRINT("ExAllocatePool() failed\n");
742 ZwClose(InterfaceKey
);
744 ExFreePool(InterfaceKeyName
.Buffer
);
745 ExFreePool(BaseKeyName
.Buffer
);
746 return STATUS_INSUFFICIENT_RESOURCES
;
748 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
749 if (ReferenceString
&& ReferenceString
->Length
)
750 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
752 /* Create SubKeyName key in registry */
753 InitializeObjectAttributes(
756 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
757 InterfaceKey
, /* RootDirectory */
758 NULL
); /* SecurityDescriptor */
760 Status
= ZwCreateKey(
767 NULL
); /* Disposition */
769 if (!NT_SUCCESS(Status
))
771 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
772 ZwClose(InterfaceKey
);
774 ExFreePool(InterfaceKeyName
.Buffer
);
775 ExFreePool(BaseKeyName
.Buffer
);
779 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
780 SymbolicLinkName
->Length
= 0;
781 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
782 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
783 + InstancePath
->Length
784 + sizeof(WCHAR
) /* 1 = size of # */
786 + sizeof(WCHAR
); /* final NULL */
787 if (ReferenceString
&& ReferenceString
->Length
)
788 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
789 SymbolicLinkName
->Buffer
= ExAllocatePool(
791 SymbolicLinkName
->MaximumLength
);
792 if (!SymbolicLinkName
->Buffer
)
794 DPRINT("ExAllocatePool() failed\n");
796 ZwClose(InterfaceKey
);
798 ExFreePool(InterfaceKeyName
.Buffer
);
799 ExFreePool(SubKeyName
.Buffer
);
800 ExFreePool(BaseKeyName
.Buffer
);
801 return STATUS_INSUFFICIENT_RESOURCES
;
803 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
804 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
805 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
806 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
808 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
809 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
811 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
812 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
813 if (ReferenceString
&& ReferenceString
->Length
)
815 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
816 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
818 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
] = '\0';
820 /* Create symbolic link */
821 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
822 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
823 if (!NT_SUCCESS(Status
))
825 DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
827 ZwClose(InterfaceKey
);
829 ExFreePool(SubKeyName
.Buffer
);
830 ExFreePool(InterfaceKeyName
.Buffer
);
831 ExFreePool(BaseKeyName
.Buffer
);
832 ExFreePool(SymbolicLinkName
->Buffer
);
836 /* Write symbolic link name in registry */
837 SymbolicLinkName
->Buffer
[1] = '\\';
838 Status
= ZwSetValueKey(
843 SymbolicLinkName
->Buffer
,
844 SymbolicLinkName
->Length
);
845 if (!NT_SUCCESS(Status
))
847 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
848 ExFreePool(SymbolicLinkName
->Buffer
);
851 /* Remove \\?\ at the start of symbolic link name */
852 SymbolicLinkName
->Length
-= 4 * sizeof(WCHAR
);
853 SymbolicLinkName
->MaximumLength
-= 4 * sizeof(WCHAR
);
855 SymbolicLinkName
->Buffer
,
856 &SymbolicLinkName
->Buffer
[4],
857 SymbolicLinkName
->Length
);
860 ZwClose(InterfaceKey
);
862 ExFreePool(SubKeyName
.Buffer
);
863 ExFreePool(InterfaceKeyName
.Buffer
);
864 ExFreePool(BaseKeyName
.Buffer
);
874 IoSetDeviceInterfaceState(
875 IN PUNICODE_STRING SymbolicLinkName
,
878 PDEVICE_OBJECT PhysicalDeviceObject
;
879 PFILE_OBJECT FileObject
;
880 UNICODE_STRING ObjectName
;
881 UNICODE_STRING GuidString
;
882 PWCHAR StartPosition
;
886 if (SymbolicLinkName
== NULL
)
887 return STATUS_INVALID_PARAMETER_1
;
889 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
891 /* Symbolic link name is ACPI#PNP0501#1#{GUID}\ReferenceString */
892 /* Get GUID from SymbolicLinkName */
893 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
894 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
895 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
896 return STATUS_INVALID_PARAMETER_1
;
897 GuidString
.Buffer
= StartPosition
;
898 GuidString
.MaximumLength
= GuidString
.Length
= (ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
;
900 /* Create \??\SymbolicLinkName string */
901 ObjectName
.Length
= 0;
902 ObjectName
.MaximumLength
= SymbolicLinkName
->Length
+ 4 * sizeof(WCHAR
);
903 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
904 if (!ObjectName
.Buffer
)
905 return STATUS_INSUFFICIENT_RESOURCES
;
906 RtlAppendUnicodeToString(&ObjectName
, L
"\\??\\");
907 RtlAppendUnicodeStringToString(&ObjectName
, SymbolicLinkName
);
909 /* Get pointer to the PDO */
910 Status
= IoGetDeviceObjectPointer(&ObjectName
,
911 0, /* DesiredAccess */
913 &PhysicalDeviceObject
);
914 if (!NT_SUCCESS(Status
))
916 ExFreePool(ObjectName
.Buffer
);
920 IopNotifyPlugPlayNotification(
921 PhysicalDeviceObject
,
922 EventCategoryDeviceInterfaceChange
,
923 Enable
? (LPGUID
)&GUID_DEVICE_INTERFACE_ARRIVAL
: (LPGUID
)&GUID_DEVICE_INTERFACE_REMOVAL
,
925 (PVOID
)SymbolicLinkName
);
927 ObDereferenceObject(FileObject
);
928 ExFreePool(ObjectName
.Buffer
);
930 return STATUS_SUCCESS
;