+
+static NTSTATUS FASTCALL
+GetVideoDeviceName(
+ OUT PUNICODE_STRING VideoDeviceName,
+ IN PCUNICODE_STRING DisplayDevice) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
+{
+ UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\??\\");
+ UNICODE_STRING ObjectName;
+ UNICODE_STRING KernelModeName = { 0, };
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ USHORT LastSlash;
+ ULONG Length;
+ HANDLE LinkHandle = NULL;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString(VideoDeviceName, NULL);
+
+ /* Get device name (DisplayDevice is "\.\xxx") */
+ for (LastSlash = DisplayDevice->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
+ {
+ if (DisplayDevice->Buffer[LastSlash - 1] == L'\\')
+ break;
+ }
+
+ if (LastSlash == 0)
+ {
+ DPRINT1("Invalid device name '%wZ'\n", DisplayDevice);
+ Status = STATUS_OBJECT_NAME_INVALID;
+ goto cleanup;
+ }
+ ObjectName = *DisplayDevice;
+ ObjectName.Length -= LastSlash * sizeof(WCHAR);
+ ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
+ ObjectName.Buffer += LastSlash;
+
+ /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
+ KernelModeName.MaximumLength = Prefix.Length + ObjectName.Length + sizeof(UNICODE_NULL);
+ KernelModeName.Buffer = ExAllocatePoolWithTag(PagedPool,
+ KernelModeName.MaximumLength,
+ TAG_DC);
+ if (!KernelModeName.Buffer)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ RtlCopyUnicodeString(&KernelModeName, &Prefix);
+ Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName);
+ if (!NT_SUCCESS(Status))
+ goto cleanup;
+
+ /* Open \??\xxx (ex: "\??\DISPLAY1") */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KernelModeName,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+ Status = ZwOpenSymbolicLinkObject(&LinkHandle,
+ GENERIC_READ,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
+ Status = STATUS_NO_SUCH_DEVICE;
+ goto cleanup;
+ }
+
+ Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, &Length);
+ if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
+ Status = STATUS_NO_SUCH_DEVICE;
+ goto cleanup;
+ }
+ VideoDeviceName->MaximumLength = Length;
+ VideoDeviceName->Buffer = ExAllocatePoolWithTag(PagedPool,
+ VideoDeviceName->MaximumLength + sizeof(UNICODE_NULL),
+ TAG_DC);
+ if (!VideoDeviceName->Buffer)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, NULL);
+ VideoDeviceName->Buffer[VideoDeviceName->MaximumLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
+ Status = STATUS_NO_SUCH_DEVICE;
+ goto cleanup;
+ }
+ Status = STATUS_SUCCESS;
+
+cleanup:
+ if (!NT_SUCCESS(Status) && VideoDeviceName->Buffer)
+ ExFreePoolWithTag(VideoDeviceName->Buffer, TAG_DC);
+ if (KernelModeName.Buffer)
+ ExFreePoolWithTag(KernelModeName.Buffer, TAG_DC);
+ if (LinkHandle)
+ ZwClose(LinkHandle);
+ return Status;
+}
+
+static NTSTATUS FASTCALL
+GetVideoRegistryKey(
+ OUT PUNICODE_STRING RegistryPath,
+ IN PCUNICODE_STRING DeviceName) /* ex: "\Device\Video0" */
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ NTSTATUS Status;
+
+ RtlInitUnicodeString(RegistryPath, NULL);
+ RtlZeroMemory(QueryTable, sizeof(QueryTable));
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
+ QueryTable[0].Name = DeviceName->Buffer;
+ QueryTable[0].EntryContext = RegistryPath;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
+ L"VIDEO",
+ QueryTable,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName, Status);
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ DPRINT("RegistryPath %wZ\n", RegistryPath);
+ return STATUS_SUCCESS;
+}
+