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)
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
;
50 * IoGetDeviceInterfaces
52 * Returns a list of device interfaces of a particular device interface class.
56 * Points to a class GUID specifying the device interface class.
58 * PhysicalDeviceObject
59 * Points to an optional PDO that narrows the search to only the
60 * device interfaces of the device represented by the PDO.
63 * Specifies flags that modify the search for device interfaces. The
64 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
65 * returned symbolic links should contain also disabled device
66 * interfaces in addition to the enabled ones.
69 * Points to a character pointer that is filled in on successful return
70 * with a list of unicode strings identifying the device interfaces
71 * that match the search criteria. The newly allocated buffer contains
72 * a list of symbolic link names. Each unicode string in the list is
73 * null-terminated; the end of the whole list is marked by an additional
74 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
75 * when it is no longer needed.
76 * If no device interfaces match the search criteria, this routine
77 * returns STATUS_SUCCESS and the string contains a single NULL
83 * The parameters PhysicalDeviceObject and Flags aren't correctly
84 * processed. Rest of the cases was tested under Windows(R) XP and
85 * the function worked correctly.
89 IoGetDeviceInterfaces(
90 IN CONST GUID
*InterfaceClassGuid
,
91 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
93 OUT PWSTR
*SymbolicLinkList
)
95 PWCHAR BaseInterfaceString
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
96 UNICODE_STRING GuidString
;
97 UNICODE_STRING BaseKeyName
;
98 UNICODE_STRING AliasKeyName
;
99 UNICODE_STRING SymbolicLink
;
100 UNICODE_STRING Control
;
101 UNICODE_STRING SubKeyName
;
102 UNICODE_STRING SymbolicLinkKeyName
;
103 UNICODE_STRING ControlKeyName
;
104 UNICODE_STRING TempString
;
107 HANDLE SymbolicLinkKey
;
108 PKEY_FULL_INFORMATION fip
;
109 PKEY_FULL_INFORMATION bfip
= NULL
;
110 PKEY_BASIC_INFORMATION bip
;
111 PKEY_VALUE_PARTIAL_INFORMATION vpip
= NULL
;
112 PWCHAR SymLinkList
= NULL
;
113 ULONG SymLinkListSize
= 0;
118 OBJECT_ATTRIBUTES ObjectAttributes
;
120 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
121 if (!NT_SUCCESS(Status
))
123 DPRINT("RtlStringFromGUID() Failed.\n");
124 return STATUS_INVALID_HANDLE
;
127 RtlInitUnicodeString(&AliasKeyName
, BaseInterfaceString
);
128 RtlInitUnicodeString(&SymbolicLink
, L
"SymbolicLink");
129 RtlInitUnicodeString(&Control
, L
"\\Control");
130 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
131 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
+ (38 * sizeof(WCHAR
));
132 BaseKeyName
.Buffer
= ExAllocatePool(
134 BaseKeyName
.MaximumLength
);
135 ASSERT(BaseKeyName
.Buffer
!= NULL
);
136 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
137 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
139 if (PhysicalDeviceObject
)
141 WCHAR GuidBuffer
[40];
142 UNICODE_STRING PdoGuidString
;
144 RtlFreeUnicodeString(&BaseKeyName
);
147 PhysicalDeviceObject
,
148 DevicePropertyClassGuid
,
153 RtlInitUnicodeString(&PdoGuidString
, GuidBuffer
);
154 if (RtlCompareUnicodeString(&GuidString
, &PdoGuidString
, TRUE
))
156 DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
157 return STATUS_INVALID_HANDLE
;
160 DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
161 return STATUS_NOT_IMPLEMENTED
;
165 InitializeObjectAttributes(
168 OBJ_CASE_INSENSITIVE
,
177 if (!NT_SUCCESS(Status
))
179 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status
);
180 RtlFreeUnicodeString(&BaseKeyName
);
191 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
193 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
194 RtlFreeUnicodeString(&BaseKeyName
);
195 ZwClose(InterfaceKey
);
199 fip
= (PKEY_FULL_INFORMATION
)ExAllocatePool(NonPagedPool
, Size
);
209 if (!NT_SUCCESS(Status
))
211 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
213 RtlFreeUnicodeString(&BaseKeyName
);
214 ZwClose(InterfaceKey
);
218 for (; i
< fip
->SubKeys
; i
++)
220 Status
= ZwEnumerateKey(
228 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
230 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
232 if (SymLinkList
!= NULL
)
233 ExFreePool(SymLinkList
);
234 RtlFreeUnicodeString(&BaseKeyName
);
235 ZwClose(InterfaceKey
);
239 bip
= (PKEY_BASIC_INFORMATION
)ExAllocatePool(NonPagedPool
, Size
);
242 Status
= ZwEnumerateKey(
250 if (!NT_SUCCESS(Status
))
252 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
255 if (SymLinkList
!= NULL
)
256 ExFreePool(SymLinkList
);
257 RtlFreeUnicodeString(&BaseKeyName
);
258 ZwClose(InterfaceKey
);
262 SubKeyName
.Length
= 0;
263 SubKeyName
.MaximumLength
= BaseKeyName
.Length
+ bip
->NameLength
+ sizeof(WCHAR
);
264 SubKeyName
.Buffer
= ExAllocatePool(NonPagedPool
, SubKeyName
.MaximumLength
);
265 ASSERT(SubKeyName
.Buffer
!= NULL
);
266 TempString
.Length
= TempString
.MaximumLength
= bip
->NameLength
;
267 TempString
.Buffer
= bip
->Name
;
268 RtlCopyUnicodeString(&SubKeyName
, &BaseKeyName
);
269 RtlAppendUnicodeToString(&SubKeyName
, L
"\\");
270 RtlAppendUnicodeStringToString(&SubKeyName
, &TempString
);
274 InitializeObjectAttributes(
277 OBJ_CASE_INSENSITIVE
,
286 if (!NT_SUCCESS(Status
))
288 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status
);
290 if (SymLinkList
!= NULL
)
291 ExFreePool(SymLinkList
);
292 RtlFreeUnicodeString(&SubKeyName
);
293 RtlFreeUnicodeString(&BaseKeyName
);
294 ZwClose(InterfaceKey
);
305 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
307 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
309 RtlFreeUnicodeString(&BaseKeyName
);
310 RtlFreeUnicodeString(&SubKeyName
);
312 ZwClose(InterfaceKey
);
316 bfip
= (PKEY_FULL_INFORMATION
)ExAllocatePool(NonPagedPool
, Size
);
317 ASSERT(bfip
!= NULL
);
326 if (!NT_SUCCESS(Status
))
328 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status
);
330 RtlFreeUnicodeString(&SubKeyName
);
331 RtlFreeUnicodeString(&BaseKeyName
);
333 ZwClose(InterfaceKey
);
337 for(j
= 0; j
< bfip
->SubKeys
; j
++)
339 Status
= ZwEnumerateKey(
347 if (Status
== STATUS_NO_MORE_ENTRIES
)
350 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
352 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
355 if (SymLinkList
!= NULL
)
356 ExFreePool(SymLinkList
);
357 RtlFreeUnicodeString(&SubKeyName
);
358 RtlFreeUnicodeString(&BaseKeyName
);
360 ZwClose(InterfaceKey
);
364 bip
= (PKEY_BASIC_INFORMATION
)ExAllocatePool(NonPagedPool
, Size
);
367 Status
= ZwEnumerateKey(
375 if (!NT_SUCCESS(Status
))
377 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status
);
381 if (SymLinkList
!= NULL
)
382 ExFreePool(SymLinkList
);
383 RtlFreeUnicodeString(&SubKeyName
);
384 RtlFreeUnicodeString(&BaseKeyName
);
386 ZwClose(InterfaceKey
);
390 if (!wcsncmp(bip
->Name
, L
"Control", bip
->NameLength
))
395 SymbolicLinkKeyName
.Length
= 0;
396 SymbolicLinkKeyName
.MaximumLength
= SubKeyName
.Length
+ bip
->NameLength
+ sizeof(WCHAR
);
397 SymbolicLinkKeyName
.Buffer
= ExAllocatePool(NonPagedPool
, SymbolicLinkKeyName
.MaximumLength
);
398 ASSERT(SymbolicLinkKeyName
.Buffer
!= NULL
);
399 TempString
.Length
= TempString
.MaximumLength
= bip
->NameLength
;
400 TempString
.Buffer
= bip
->Name
;
401 RtlCopyUnicodeString(&SymbolicLinkKeyName
, &SubKeyName
);
402 RtlAppendUnicodeToString(&SymbolicLinkKeyName
, L
"\\");
403 RtlAppendUnicodeStringToString(&SymbolicLinkKeyName
, &TempString
);
405 ControlKeyName
.Length
= 0;
406 ControlKeyName
.MaximumLength
= SymbolicLinkKeyName
.Length
+ Control
.Length
+ sizeof(WCHAR
);
407 ControlKeyName
.Buffer
= ExAllocatePool(NonPagedPool
, ControlKeyName
.MaximumLength
);
408 ASSERT(ControlKeyName
.Buffer
!= NULL
);
409 RtlCopyUnicodeString(&ControlKeyName
, &SymbolicLinkKeyName
);
410 RtlAppendUnicodeStringToString(&ControlKeyName
, &Control
);
414 InitializeObjectAttributes(
416 &SymbolicLinkKeyName
,
417 OBJ_CASE_INSENSITIVE
,
426 if (!NT_SUCCESS(Status
))
428 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status
);
431 if (SymLinkList
!= NULL
)
432 ExFreePool(SymLinkList
);
433 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
434 RtlFreeUnicodeString(&SubKeyName
);
435 RtlFreeUnicodeString(&BaseKeyName
);
437 ZwClose(InterfaceKey
);
441 Status
= ZwQueryValueKey(
444 KeyValuePartialInformation
,
449 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
452 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
454 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status
);
457 if (SymLinkList
!= NULL
)
458 ExFreePool(SymLinkList
);
459 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
460 RtlFreeUnicodeString(&SubKeyName
);
461 RtlFreeUnicodeString(&BaseKeyName
);
462 ZwClose(SymbolicLinkKey
);
464 ZwClose(InterfaceKey
);
468 vpip
= (PKEY_VALUE_PARTIAL_INFORMATION
)ExAllocatePool(NonPagedPool
, Size
);
469 ASSERT(vpip
!= NULL
);
471 Status
= ZwQueryValueKey(
474 KeyValuePartialInformation
,
479 if (!NT_SUCCESS(Status
))
481 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status
);
485 if (SymLinkList
!= NULL
)
486 ExFreePool(SymLinkList
);
487 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
488 RtlFreeUnicodeString(&SubKeyName
);
489 RtlFreeUnicodeString(&BaseKeyName
);
490 ZwClose(SymbolicLinkKey
);
492 ZwClose(InterfaceKey
);
496 Status
= RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE
, ControlKeyName
.Buffer
);
498 if (NT_SUCCESS(Status
))
500 /* Put the name in the string here */
501 if (SymLinkList
== NULL
)
503 SymLinkListSize
= vpip
->DataLength
;
504 SymLinkList
= ExAllocatePool(NonPagedPool
, SymLinkListSize
+ sizeof(WCHAR
));
505 ASSERT(SymLinkList
!= NULL
);
506 RtlCopyMemory(SymLinkList
, vpip
->Data
, vpip
->DataLength
);
507 SymLinkList
[vpip
->DataLength
/ sizeof(WCHAR
)] = 0;
508 SymLinkList
[1] = '?';
512 PWCHAR OldSymLinkList
;
513 ULONG OldSymLinkListSize
;
514 PWCHAR SymLinkListPtr
;
516 OldSymLinkList
= SymLinkList
;
517 OldSymLinkListSize
= SymLinkListSize
;
518 SymLinkListSize
+= vpip
->DataLength
;
519 SymLinkList
= ExAllocatePool(NonPagedPool
, SymLinkListSize
+ sizeof(WCHAR
));
520 ASSERT(SymLinkList
!= NULL
);
521 RtlCopyMemory(SymLinkList
, OldSymLinkList
, OldSymLinkListSize
);
522 ExFreePool(OldSymLinkList
);
523 SymLinkListPtr
= SymLinkList
+ (OldSymLinkListSize
/ sizeof(WCHAR
));
524 RtlCopyMemory(SymLinkListPtr
, vpip
->Data
, vpip
->DataLength
);
525 SymLinkListPtr
[vpip
->DataLength
/ sizeof(WCHAR
)] = 0;
526 SymLinkListPtr
[1] = '?';
530 RtlFreeUnicodeString(&SymbolicLinkKeyName
);
531 RtlFreeUnicodeString(&ControlKeyName
);
532 ZwClose(SymbolicLinkKey
);
536 RtlFreeUnicodeString(&SubKeyName
);
540 if (SymLinkList
!= NULL
)
542 SymLinkList
[SymLinkListSize
/ sizeof(WCHAR
)] = 0;
546 SymLinkList
= ExAllocatePool(NonPagedPool
, 2 * sizeof(WCHAR
));
550 *SymbolicLinkList
= SymLinkList
;
552 RtlFreeUnicodeString(&BaseKeyName
);
553 ZwClose(InterfaceKey
);
558 return STATUS_SUCCESS
;
566 IoRegisterDeviceInterface(
567 IN PDEVICE_OBJECT PhysicalDeviceObject
,
568 IN CONST GUID
*InterfaceClassGuid
,
569 IN PUNICODE_STRING ReferenceString OPTIONAL
,
570 OUT PUNICODE_STRING SymbolicLinkName
)
572 PUNICODE_STRING InstancePath
;
573 UNICODE_STRING GuidString
;
574 UNICODE_STRING SubKeyName
;
575 UNICODE_STRING BaseKeyName
;
576 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
577 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
581 OBJECT_ATTRIBUTES ObjectAttributes
;
585 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
586 if (!NT_SUCCESS(Status
))
588 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
592 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\DeviceClasses\{GUID}\##?#ACPI#PNP0501#1#{GUID} */
593 InstancePath
= &PhysicalDeviceObject
->DeviceObjectExtension
->DeviceNode
->InstancePath
;
594 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
595 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
597 + 5 * sizeof(WCHAR
) /* 5 = size of \##?# */
598 + InstancePath
->Length
599 + sizeof(WCHAR
) /* 1 = size of # */
601 BaseKeyName
.Buffer
= ExAllocatePool(
603 BaseKeyName
.MaximumLength
);
604 if (!BaseKeyName
.Buffer
)
606 DPRINT("ExAllocatePool() failed\n");
607 return STATUS_INSUFFICIENT_RESOURCES
;
609 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
610 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
611 RtlAppendUnicodeToString(&BaseKeyName
, L
"\\##?#");
612 StartIndex
= BaseKeyName
.Length
/ sizeof(WCHAR
);
613 RtlAppendUnicodeStringToString(&BaseKeyName
, InstancePath
);
614 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
616 if (BaseKeyName
.Buffer
[StartIndex
+ i
] == '\\')
617 BaseKeyName
.Buffer
[StartIndex
+ i
] = '#';
619 RtlAppendUnicodeToString(&BaseKeyName
, L
"#");
620 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
622 /* Create BaseKeyName key in registry */
623 InitializeObjectAttributes(
626 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
627 NULL
, /* RootDirectory */
628 NULL
); /* SecurityDescriptor */
630 Status
= ZwCreateKey(
637 NULL
); /* Disposition */
639 if (!NT_SUCCESS(Status
))
641 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
642 ExFreePool(BaseKeyName
.Buffer
);
646 /* Write DeviceInstance entry. Value is InstancePath */
647 Status
= ZwSetValueKey(
652 InstancePath
->Buffer
,
653 InstancePath
->Length
);
654 if (!NT_SUCCESS(Status
))
656 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
657 ZwClose(InterfaceKey
);
658 ExFreePool(BaseKeyName
.Buffer
);
662 /* Create subkey. Name is #ReferenceString */
663 SubKeyName
.Length
= 0;
664 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
665 if (ReferenceString
&& ReferenceString
->Length
)
666 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
667 SubKeyName
.Buffer
= ExAllocatePool(
669 SubKeyName
.MaximumLength
);
670 if (!SubKeyName
.Buffer
)
672 DPRINT("ExAllocatePool() failed\n");
673 ZwClose(InterfaceKey
);
674 ExFreePool(BaseKeyName
.Buffer
);
675 return STATUS_INSUFFICIENT_RESOURCES
;
677 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
678 if (ReferenceString
&& ReferenceString
->Length
)
679 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
681 /* Create SubKeyName key in registry */
682 InitializeObjectAttributes(
685 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
686 InterfaceKey
, /* RootDirectory */
687 NULL
); /* SecurityDescriptor */
689 Status
= ZwCreateKey(
696 NULL
); /* Disposition */
698 if (!NT_SUCCESS(Status
))
700 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
701 ZwClose(InterfaceKey
);
702 ExFreePool(BaseKeyName
.Buffer
);
706 /* Create symbolic link name: \\?\ACPI#PNP0501#1#{GUID}\ReferenceString */
707 SymbolicLinkName
->Length
= 0;
708 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
709 + 4 * sizeof(WCHAR
) /* 5 = size of \\??\ */
710 + InstancePath
->Length
711 + sizeof(WCHAR
) /* 1 = size of # */
713 + sizeof(WCHAR
); /* final NULL */
714 if (ReferenceString
&& ReferenceString
->Length
)
715 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
716 SymbolicLinkName
->Buffer
= ExAllocatePool(
718 SymbolicLinkName
->MaximumLength
);
719 if (!SymbolicLinkName
->Buffer
)
721 DPRINT("ExAllocatePool() failed\n");
722 ZwClose(InterfaceKey
);
724 ExFreePool(SubKeyName
.Buffer
);
725 ExFreePool(BaseKeyName
.Buffer
);
726 return STATUS_INSUFFICIENT_RESOURCES
;
728 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\\\??\\");
729 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
730 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
731 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
733 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
734 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
736 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
737 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
738 if (ReferenceString
&& ReferenceString
->Length
)
740 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
741 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
743 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
] = '\0';
745 /* Create symbolic link */
746 Status
= IoCreateSymbolicLink(SymbolicLinkName
, InstancePath
);
747 if (!NT_SUCCESS(Status
))
749 DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
750 ZwClose(InterfaceKey
);
752 ExFreePool(SubKeyName
.Buffer
);
753 ExFreePool(BaseKeyName
.Buffer
);
754 ExFreePool(SymbolicLinkName
->Buffer
);
758 /* Write symbolic link name in registry */
759 Status
= ZwSetValueKey(
764 SymbolicLinkName
->Buffer
,
765 SymbolicLinkName
->Length
);
766 if (!NT_SUCCESS(Status
))
768 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
769 ExFreePool(SymbolicLinkName
->Buffer
);
772 ZwClose(InterfaceKey
);
774 ExFreePool(SubKeyName
.Buffer
);
775 ExFreePool(BaseKeyName
.Buffer
);
785 IoSetDeviceInterfaceState(
786 IN PUNICODE_STRING SymbolicLinkName
,
789 DPRINT("IoSetDeviceInterfaceState called (UNIMPLEMENTED)\n");
790 return STATUS_SUCCESS
;