xref: /reactos/win32ss/drivers/videoprt/registry.c (revision 1734f297)
1 /*
2  * VideoPort driver
3  *
4  * Copyright (C) 2002-2004, 2007 ReactOS Team
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 #include "videoprt.h"
23 #include <ndk/obfuncs.h>
24 #include <stdio.h>
25 
26 #define NDEBUG
27 #include <debug.h>
28 
29 NTSTATUS
30 NTAPI
31 IntCopyRegistryKey(
32     _In_ HANDLE SourceKeyHandle,
33     _In_ HANDLE DestKeyHandle)
34 {
35     PVOID InfoBuffer;
36     PKEY_BASIC_INFORMATION KeyInformation;
37     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
38     OBJECT_ATTRIBUTES ObjectAttributes;
39     ULONG Index, InformationLength, RequiredLength;
40     UNICODE_STRING NameString;
41     NTSTATUS Status;
42     HANDLE SourceSubKeyHandle, DestSubKeyHandle;
43 
44     /* Start with no buffer, set initial size */
45     InfoBuffer = NULL;
46     InformationLength = 256;
47 
48     /* Start looping with key index 0 */
49     Index = 0;
50     while (TRUE)
51     {
52         /* Check if we have no buffer */
53         if (InfoBuffer == NULL)
54         {
55             /* Allocate a new buffer */
56             InfoBuffer = ExAllocatePoolWithTag(PagedPool,
57                                                InformationLength,
58                                                TAG_VIDEO_PORT_BUFFER);
59             if (InfoBuffer == NULL)
60             {
61                 ERR_(VIDEOPRT, "Could not allocate buffer for key info\n");
62                 return STATUS_INSUFFICIENT_RESOURCES;
63             }
64         }
65 
66         /* Enumerate the next sub-key */
67         KeyInformation = InfoBuffer;
68         Status = ZwEnumerateKey(SourceKeyHandle,
69                                 Index,
70                                 KeyBasicInformation,
71                                 KeyInformation,
72                                 InformationLength,
73                                 &RequiredLength);
74         if ((Status == STATUS_BUFFER_OVERFLOW) ||
75             (Status == STATUS_BUFFER_TOO_SMALL))
76         {
77             /* Free the buffer and remember the required size */
78             ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
79             InfoBuffer = NULL;
80             InformationLength = RequiredLength;
81 
82             /* Try again */
83             continue;
84         }
85         else if (Status == STATUS_NO_MORE_ENTRIES)
86         {
87             /* We are done with the sub-keys */
88             break;
89         }
90         else if (!NT_SUCCESS(Status))
91         {
92             ERR_(VIDEOPRT, "ZwEnumerateKey failed, status 0x%lx\n", Status);
93             goto Cleanup;
94         }
95 
96         /* Initialize a unicode string from the key name */
97         NameString.Buffer = KeyInformation->Name;
98         NameString.Length = (USHORT)KeyInformation->NameLength;
99         NameString.MaximumLength = NameString.Length;
100 
101         /* Initialize object attributes and open the source sub-key */
102         InitializeObjectAttributes(&ObjectAttributes,
103                                    &NameString,
104                                    OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
105                                    SourceKeyHandle,
106                                    NULL);
107         Status = ZwOpenKey(&SourceSubKeyHandle, KEY_READ, &ObjectAttributes);
108         if (!NT_SUCCESS(Status))
109         {
110             ERR_(VIDEOPRT, "failed to open the source key.\n");
111             goto Cleanup;
112         }
113 
114         /* Initialize object attributes and create the dest sub-key */
115         InitializeObjectAttributes(&ObjectAttributes,
116                                    &NameString,
117                                    OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
118                                    DestKeyHandle,
119                                    NULL);
120         Status = ZwCreateKey(&DestSubKeyHandle,
121                              KEY_WRITE,
122                              &ObjectAttributes,
123                              0,
124                              NULL,
125                              REG_OPTION_NON_VOLATILE,
126                              NULL);
127         if (!NT_SUCCESS(Status))
128         {
129             ERR_(VIDEOPRT, "failed to create the destination key.\n");
130             ObCloseHandle(SourceSubKeyHandle, KernelMode);
131             goto Cleanup;
132         }
133 
134         /* Recursively copy the sub-key */
135         Status = IntCopyRegistryKey(SourceSubKeyHandle, DestSubKeyHandle);
136         if (!NT_SUCCESS(Status))
137         {
138             /* Just warn, but continue with the remaining sub-keys */
139             WARN_(VIDEOPRT, "failed to copy subkey '%wZ'.\n", &NameString);
140         }
141 
142         /* Close the sub-key handles */
143         ObCloseHandle(SourceSubKeyHandle, KernelMode);
144         ObCloseHandle(DestSubKeyHandle, KernelMode);
145 
146         /* Next sub-key */
147         Index++;
148     }
149 
150     /* Start looping with value index 0 */
151     Index = 0;
152     while (TRUE)
153     {
154         /* Check if we have no buffer */
155         if (InfoBuffer == NULL)
156         {
157             /* Allocate a new buffer */
158             InfoBuffer = ExAllocatePoolWithTag(PagedPool,
159                                                InformationLength,
160                                                TAG_VIDEO_PORT_BUFFER);
161             if (InfoBuffer == NULL)
162             {
163                 ERR_(VIDEOPRT, "Could not allocate buffer for key values\n");
164                 return Status;
165             }
166         }
167 
168         /* Enumerate the next value */
169         KeyValueInformation = InfoBuffer;
170         Status = ZwEnumerateValueKey(SourceKeyHandle,
171                                      Index,
172                                      KeyValueFullInformation,
173                                      KeyValueInformation,
174                                      InformationLength,
175                                      &RequiredLength);
176         if ((Status == STATUS_BUFFER_OVERFLOW) ||
177             (Status == STATUS_BUFFER_TOO_SMALL))
178         {
179             /* Free the buffer and remember the required size */
180             ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
181             InfoBuffer = NULL;
182             InformationLength = RequiredLength;
183 
184             /* Try again */
185             continue;
186         }
187         else if (Status == STATUS_NO_MORE_ENTRIES)
188         {
189             /* We are done with the values */
190             Status = STATUS_SUCCESS;
191             break;
192         }
193         else if (!NT_SUCCESS(Status))
194         {
195             ERR_(VIDEOPRT, "ZwEnumerateValueKey failed, status 0x%lx\n", Status);
196             goto Cleanup;
197         }
198 
199         /* Initialize a unicode string from the value name */
200         NameString.Buffer = KeyValueInformation->Name;
201         NameString.Length = (USHORT)KeyValueInformation->NameLength;
202         NameString.MaximumLength = NameString.Length;
203 
204         /* Create the key value in the destination key */
205         Status = ZwSetValueKey(DestKeyHandle,
206                                &NameString,
207                                KeyValueInformation->TitleIndex,
208                                KeyValueInformation->Type,
209                                (PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
210                                KeyValueInformation->DataLength);
211         if (!NT_SUCCESS(Status))
212         {
213             /* Just warn, but continue with the remaining sub-keys */
214             WARN_(VIDEOPRT, "failed to set value '%wZ'.\n", &NameString);
215         }
216 
217         /* Next subkey */
218         Index++;
219     }
220 
221 Cleanup:
222     /* Free the buffer and return the failure code */
223     if (InfoBuffer != NULL)
224 		ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
225     return Status;
226 }
227 
228 NTSTATUS
229 NTAPI
230 IntCopyRegistryValue(
231     HANDLE SourceKeyHandle,
232     HANDLE DestKeyHandle,
233     PWSTR ValueName)
234 {
235     PKEY_VALUE_PARTIAL_INFORMATION ValueInformation;
236     UNICODE_STRING ValueNameString;
237     ULONG Length;
238     NTSTATUS Status;
239 
240     RtlInitUnicodeString(&ValueNameString, ValueName);
241 
242     /* Query the value length */
243     Status = ZwQueryValueKey(SourceKeyHandle,
244                              &ValueNameString,
245                              KeyValuePartialInformation,
246                              NULL,
247                              0,
248                              &Length);
249     if ((Status != STATUS_BUFFER_OVERFLOW) &&
250         (Status != STATUS_BUFFER_TOO_SMALL))
251     {
252         /* The key seems not present */
253         NT_ASSERT(!NT_SUCCESS(Status));
254         return Status;
255     }
256 
257     /* Allocate a buffer */
258     ValueInformation = ExAllocatePoolWithTag(PagedPool, Length, TAG_VIDEO_PORT_BUFFER);
259     if (ValueInformation == NULL)
260     {
261         return Status;
262     }
263 
264     /* Query the value */
265     Status = ZwQueryValueKey(SourceKeyHandle,
266                              &ValueNameString,
267                              KeyValuePartialInformation,
268                              ValueInformation,
269                              Length,
270                              &Length);
271     if (!NT_SUCCESS(Status))
272     {
273         ExFreePoolWithTag(ValueInformation, TAG_VIDEO_PORT_BUFFER);
274         return Status;
275     }
276 
277     /* Write the registry value */
278     Status = ZwSetValueKey(DestKeyHandle,
279                            &ValueNameString,
280                            ValueInformation->TitleIndex,
281                            ValueInformation->Type,
282                            ValueInformation->Data,
283                            ValueInformation->DataLength);
284 
285     ExFreePoolWithTag(ValueInformation, TAG_VIDEO_PORT_BUFFER);
286 
287     if (!NT_SUCCESS(Status))
288     {
289         ERR_(VIDEOPRT, "ZwSetValueKey failed: status 0x%lx\n", Status);
290     }
291 
292     return Status;
293 }
294 
295 NTSTATUS
296 NTAPI
297 IntSetupDeviceSettingsKey(
298     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
299 {
300     static UNICODE_STRING SettingsKeyName = RTL_CONSTANT_STRING(L"Settings");
301     HANDLE DevInstRegKey, SourceKeyHandle, DestKeyHandle;
302     OBJECT_ATTRIBUTES ObjectAttributes;
303     NTSTATUS Status;
304 
305     if (!DeviceExtension->PhysicalDeviceObject)
306         return STATUS_SUCCESS;
307 
308     /* Open the software key: HKLM\System\CurrentControlSet\Control\Class\<ClassGUID>\<n> */
309     Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
310                                      PLUGPLAY_REGKEY_DRIVER,
311                                      KEY_ALL_ACCESS,
312                                      &DevInstRegKey);
313     if (Status != STATUS_SUCCESS)
314     {
315         ERR_(VIDEOPRT, "Failed to open device software key. Status 0x%lx\n", Status);
316         return Status;
317     }
318 
319     /* Open the 'Settings' sub-key */
320     InitializeObjectAttributes(&ObjectAttributes,
321                                &SettingsKeyName,
322                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
323                                DevInstRegKey,
324                                NULL);
325     Status = ZwOpenKey(&DestKeyHandle, KEY_WRITE, &ObjectAttributes);
326 
327     /* Close the device software key */
328     ObCloseHandle(DevInstRegKey, KernelMode);
329 
330     if (Status != STATUS_SUCCESS)
331     {
332         ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
333         return Status;
334     }
335 
336     /* Open the device profile key */
337     InitializeObjectAttributes(&ObjectAttributes,
338                                &DeviceExtension->RegistryPath,
339                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
340                                NULL,
341                                NULL);
342     Status = ZwOpenKey(&SourceKeyHandle, KEY_READ, &ObjectAttributes);
343     if (Status != STATUS_SUCCESS)
344     {
345         ERR_(VIDEOPRT, "ZwOpenKey failed for settings key: status 0x%lx\n", Status);
346         ObCloseHandle(DestKeyHandle, KernelMode);
347         return Status;
348     }
349 
350     IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"InstalledDisplayDrivers");
351     IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"Attach.ToDesktop");
352 
353     ObCloseHandle(SourceKeyHandle, KernelMode);
354     ObCloseHandle(DestKeyHandle, KernelMode);
355 
356     return STATUS_SUCCESS;
357 }
358 
359 NTSTATUS
360 IntDuplicateUnicodeString(
361     IN ULONG Flags,
362     IN PCUNICODE_STRING SourceString,
363     OUT PUNICODE_STRING DestinationString)
364 {
365     if (SourceString == NULL ||
366         DestinationString == NULL ||
367         SourceString->Length > SourceString->MaximumLength ||
368         (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
369         Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING ||
370         Flags >= 4)
371     {
372         return STATUS_INVALID_PARAMETER;
373     }
374 
375     if ((SourceString->Length == 0) &&
376         (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
377                    RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
378     {
379         DestinationString->Length = 0;
380         DestinationString->MaximumLength = 0;
381         DestinationString->Buffer = NULL;
382     }
383     else
384     {
385         USHORT DestMaxLength = SourceString->Length;
386 
387         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
388             DestMaxLength += sizeof(UNICODE_NULL);
389 
390         DestinationString->Buffer = ExAllocatePoolWithTag(PagedPool, DestMaxLength, TAG_VIDEO_PORT);
391         if (DestinationString->Buffer == NULL)
392             return STATUS_NO_MEMORY;
393 
394         RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
395         DestinationString->Length = SourceString->Length;
396         DestinationString->MaximumLength = DestMaxLength;
397 
398         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
399             DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
400     }
401 
402     return STATUS_SUCCESS;
403 }
404 
405 NTSTATUS
406 NTAPI
407 IntCreateNewRegistryPath(
408     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
409 {
410     static UNICODE_STRING VideoIdValueName = RTL_CONSTANT_STRING(L"VideoId");
411     static UNICODE_STRING ControlVideoPathName =
412         RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\");
413     HANDLE DevInstRegKey, SettingsKey, NewKey;
414     UCHAR VideoIdBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + GUID_STRING_LENGTH];
415     UNICODE_STRING VideoIdString;
416     UUID VideoId;
417     PKEY_VALUE_PARTIAL_INFORMATION ValueInformation ;
418     NTSTATUS Status;
419     ULONG ResultLength;
420     USHORT KeyMaxLength;
421     OBJECT_ATTRIBUTES ObjectAttributes;
422     PWCHAR InstanceIdBuffer;
423 
424     if (!DeviceExtension->PhysicalDeviceObject)
425     {
426         Status = IntDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
427                                            &DeviceExtension->RegistryPath,
428                                            &DeviceExtension->NewRegistryPath);
429         if (!NT_SUCCESS(Status))
430             ERR_(VIDEOPRT, "IntDuplicateUnicodeString() failed with status 0x%lx\n", Status);
431         return Status;
432     }
433 
434     /* Open the hardware key: HKLM\System\CurrentControlSet\Enum\... */
435     Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
436                                      PLUGPLAY_REGKEY_DEVICE,
437                                      KEY_ALL_ACCESS,
438                                      &DevInstRegKey);
439     if (Status != STATUS_SUCCESS)
440     {
441         ERR_(VIDEOPRT, "IoOpenDeviceRegistryKey failed: status 0x%lx\n", Status);
442         return Status;
443     }
444 
445     /* Query the VideoId value */
446     ValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)VideoIdBuffer;
447     Status = ZwQueryValueKey(DevInstRegKey,
448                              &VideoIdValueName,
449                              KeyValuePartialInformation,
450                              ValueInformation,
451                              sizeof(VideoIdBuffer),
452                              &ResultLength);
453     if (!NT_SUCCESS(Status))
454     {
455         /* Create a new video Id */
456         Status = ExUuidCreate(&VideoId);
457         if (!NT_SUCCESS(Status))
458         {
459             ERR_(VIDEOPRT, "ExUuidCreate failed: status 0x%lx\n", Status);
460             ObCloseHandle(DevInstRegKey, KernelMode);
461             return Status;
462         }
463 
464         /* Convert the GUID into a string */
465         Status = RtlStringFromGUID(&VideoId, &VideoIdString);
466         if (!NT_SUCCESS(Status))
467         {
468             ERR_(VIDEOPRT, "RtlStringFromGUID failed: status 0x%lx\n", Status);
469             ObCloseHandle(DevInstRegKey, KernelMode);
470             return Status;
471         }
472 
473         /* Copy the GUID String to our buffer */
474         ValueInformation->DataLength = min(VideoIdString.Length, GUID_STRING_LENGTH);
475         RtlCopyMemory(ValueInformation->Data,
476                       VideoIdString.Buffer,
477                       ValueInformation->DataLength);
478 
479         /* Free the GUID string */
480         RtlFreeUnicodeString(&VideoIdString);
481 
482         /* Write the VideoId registry value */
483         Status = ZwSetValueKey(DevInstRegKey,
484                                &VideoIdValueName,
485                                0,
486                                REG_SZ,
487                                ValueInformation->Data,
488                                ValueInformation->DataLength);
489         if (!NT_SUCCESS(Status))
490         {
491             ERR_(VIDEOPRT, "ZwSetValueKey failed: status 0x%lx\n", Status);
492             ObCloseHandle(DevInstRegKey, KernelMode);
493             return Status;
494         }
495     }
496 
497     /* Initialize the VideoId string from the registry data */
498     VideoIdString.Buffer = (PWCHAR)ValueInformation->Data;
499     VideoIdString.Length = (USHORT)ValueInformation->DataLength;
500     VideoIdString.MaximumLength = VideoIdString.Length;
501 
502     /* Close the hardware key */
503     ObCloseHandle(DevInstRegKey, KernelMode);
504 
505     /* Calculate the size needed for the new registry path name */
506     KeyMaxLength = ControlVideoPathName.Length +
507                    VideoIdString.Length +
508                    sizeof(L"\\0000");
509 
510     /* Allocate the path name buffer */
511     DeviceExtension->NewRegistryPath.Length = 0;
512     DeviceExtension->NewRegistryPath.MaximumLength = KeyMaxLength;
513     DeviceExtension->NewRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
514                                                                     KeyMaxLength,
515                                                                     TAG_VIDEO_PORT);
516     if (DeviceExtension->NewRegistryPath.Buffer == NULL)
517     {
518         ERR_(VIDEOPRT, "Failed to allocate key name buffer.\n");
519         return STATUS_INSUFFICIENT_RESOURCES;
520     }
521 
522     /* Copy the root key name and append the VideoId string */
523     RtlCopyUnicodeString(&DeviceExtension->NewRegistryPath,
524                          &ControlVideoPathName);
525     RtlAppendUnicodeStringToString(&DeviceExtension->NewRegistryPath,
526                                    &VideoIdString);
527 
528     /* Check if we have the key already */
529     Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
530                                  DeviceExtension->NewRegistryPath.Buffer);
531     if (Status != STATUS_SUCCESS)
532     {
533         /* Try to create the new key */
534         Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
535                                       DeviceExtension->NewRegistryPath.Buffer);
536     }
537 
538     /* Append a the instance path */ /// \todo HACK
539     RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"\\");
540     InstanceIdBuffer = DeviceExtension->NewRegistryPath.Buffer +
541         DeviceExtension->NewRegistryPath.Length / sizeof(WCHAR);
542     RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"0000");
543 
544     /* Write instance ID */
545     swprintf(InstanceIdBuffer, L"%04u", DeviceExtension->DisplayNumber);
546 
547     /* Check if the name exists */
548     Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
549                                  DeviceExtension->NewRegistryPath.Buffer);
550     if (Status != STATUS_SUCCESS)
551     {
552         /* Try to create the new key */
553         Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
554                                       DeviceExtension->NewRegistryPath.Buffer);
555         if (!NT_SUCCESS(Status))
556         {
557             ERR_(VIDEOPRT, "Failed create key '%wZ'\n", &DeviceExtension->NewRegistryPath);
558             return Status;
559         }
560 
561         /* Open the new key */
562         InitializeObjectAttributes(&ObjectAttributes,
563                                    &DeviceExtension->NewRegistryPath,
564                                    OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
565                                    NULL,
566                                    NULL);
567         Status = ZwOpenKey(&NewKey, KEY_WRITE, &ObjectAttributes);
568         if (!NT_SUCCESS(Status))
569         {
570             ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
571             return Status;
572         }
573 
574         /* Open the device profile key */
575         InitializeObjectAttributes(&ObjectAttributes,
576                                    &DeviceExtension->RegistryPath,
577                                    OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
578                                    NULL,
579                                    NULL);
580         Status = ZwOpenKey(&SettingsKey, KEY_READ, &ObjectAttributes);
581         if (!NT_SUCCESS(Status))
582         {
583             ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
584             ObCloseHandle(NewKey, KernelMode);
585             return Status;
586         }
587 
588         /* Copy the registry data from the legacy key */
589         Status = IntCopyRegistryKey(SettingsKey, NewKey);
590 
591         /* Close the key handles */
592         ObCloseHandle(SettingsKey, KernelMode);
593         ObCloseHandle(NewKey, KernelMode);
594     }
595 
596     return Status;
597 }
598 
599 NTSTATUS
600 NTAPI
601 IntCreateRegistryPath(
602     IN PCUNICODE_STRING DriverRegistryPath,
603     IN ULONG DeviceNumber,
604     OUT PUNICODE_STRING DeviceRegistryPath)
605 {
606     static WCHAR RegistryMachineSystem[] = L"\\REGISTRY\\MACHINE\\SYSTEM\\";
607     static WCHAR CurrentControlSet[] = L"CURRENTCONTROLSET\\";
608     static WCHAR ControlSet[] = L"CONTROLSET";
609     static WCHAR Insert1[] = L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
610     static WCHAR Insert2[] = L"\\Device";
611     UNICODE_STRING DeviceNumberString;
612     WCHAR DeviceNumberBuffer[20];
613     BOOLEAN Valid;
614     UNICODE_STRING AfterControlSet;
615     NTSTATUS Status;
616 
617     AfterControlSet = *DriverRegistryPath;
618 
619     /* Convert DeviceNumber to string */
620     DeviceNumberString.Length = 0;
621     DeviceNumberString.MaximumLength = sizeof(DeviceNumberBuffer);
622     DeviceNumberString.Buffer = DeviceNumberBuffer;
623     Status = RtlIntegerToUnicodeString(DeviceNumber, 10, &DeviceNumberString);
624     if (!NT_SUCCESS(Status))
625     {
626         ERR_(VIDEOPRT, "RtlIntegerToUnicodeString(%u) returned 0x%08x\n", DeviceNumber, Status);
627         return Status;
628     }
629 
630     /* Check if path begins with \\REGISTRY\\MACHINE\\SYSTEM\\ */
631     Valid = (DriverRegistryPath->Length > sizeof(RegistryMachineSystem) &&
632              0 == _wcsnicmp(DriverRegistryPath->Buffer, RegistryMachineSystem,
633                             wcslen(RegistryMachineSystem)));
634     if (Valid)
635     {
636         AfterControlSet.Buffer += wcslen(RegistryMachineSystem);
637         AfterControlSet.Length -= sizeof(RegistryMachineSystem) - sizeof(UNICODE_NULL);
638 
639         /* Check if path contains CURRENTCONTROLSET */
640         if (AfterControlSet.Length > sizeof(CurrentControlSet) &&
641             0 == _wcsnicmp(AfterControlSet.Buffer, CurrentControlSet, wcslen(CurrentControlSet)))
642         {
643             AfterControlSet.Buffer += wcslen(CurrentControlSet);
644             AfterControlSet.Length -= sizeof(CurrentControlSet) - sizeof(UNICODE_NULL);
645         }
646         /* Check if path contains CONTROLSETnum */
647         else if (AfterControlSet.Length > sizeof(ControlSet) &&
648                  0 == _wcsnicmp(AfterControlSet.Buffer, ControlSet, wcslen(ControlSet)))
649         {
650             AfterControlSet.Buffer += wcslen(ControlSet);
651             AfterControlSet.Length -= sizeof(ControlSet) - sizeof(UNICODE_NULL);
652             while (AfterControlSet.Length > 0 &&
653                     *AfterControlSet.Buffer >= L'0' &&
654                     *AfterControlSet.Buffer <= L'9')
655             {
656                 AfterControlSet.Buffer++;
657                 AfterControlSet.Length -= sizeof(WCHAR);
658             }
659 
660             Valid = (AfterControlSet.Length > 0 && L'\\' == *AfterControlSet.Buffer);
661             AfterControlSet.Buffer++;
662             AfterControlSet.Length -= sizeof(WCHAR);
663             AfterControlSet.MaximumLength = AfterControlSet.Length;
664         }
665         else
666         {
667             Valid = FALSE;
668         }
669     }
670 
671     if (!VideoPortUseNewKey)
672     {
673         INFO_(VIDEOPRT, "Using old registry key as 'UseNewKey' is FALSE\n");
674         Valid = FALSE;
675     }
676     else if (Valid)
677     {
678         DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert1) + sizeof(Insert2)
679                                           + DeviceNumberString.Length;
680         DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(PagedPool,
681                                                            DeviceRegistryPath->MaximumLength,
682                                                            TAG_VIDEO_PORT);
683         if (DeviceRegistryPath->Buffer != NULL)
684         {
685             /* Build device path */
686             wcsncpy(DeviceRegistryPath->Buffer,
687                     DriverRegistryPath->Buffer,
688                     AfterControlSet.Buffer - DriverRegistryPath->Buffer);
689             DeviceRegistryPath->Length = (AfterControlSet.Buffer - DriverRegistryPath->Buffer) * sizeof(WCHAR);
690             RtlAppendUnicodeToString(DeviceRegistryPath, Insert1);
691             RtlAppendUnicodeStringToString(DeviceRegistryPath, &AfterControlSet);
692             RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
693             RtlAppendUnicodeStringToString(DeviceRegistryPath, &DeviceNumberString);
694 
695             /* Check if registry key exists */
696             Valid = NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, DeviceRegistryPath->Buffer));
697 
698             if (!Valid)
699                 ExFreePoolWithTag(DeviceRegistryPath->Buffer, TAG_VIDEO_PORT);
700         }
701         else
702         {
703             Valid = FALSE;
704         }
705     }
706     else
707     {
708         WARN_(VIDEOPRT, "Unparsable registry path %wZ\n", DriverRegistryPath);
709     }
710 
711     /* If path doesn't point to *ControlSet*, use DriverRegistryPath directly */
712     if (!Valid)
713     {
714         DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert2) + DeviceNumberString.Length;
715         DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
716                                                            DeviceRegistryPath->MaximumLength,
717                                                            TAG_VIDEO_PORT);
718 
719         if (!DeviceRegistryPath->Buffer)
720             return STATUS_NO_MEMORY;
721 
722         RtlCopyUnicodeString(DeviceRegistryPath, DriverRegistryPath);
723         RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
724         RtlAppendUnicodeStringToString(DeviceRegistryPath, &DeviceNumberString);
725     }
726 
727     DPRINT("Formatted registry key '%wZ' -> '%wZ'\n",
728            DriverRegistryPath, DeviceRegistryPath);
729 
730     return STATUS_SUCCESS;
731 }
732