xref: /reactos/win32ss/drivers/videoprt/registry.c (revision 9be382ec)
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     /* Open the software key: HKLM\System\CurrentControlSet\Control\Class\<ClassGUID>\<n> */
306     Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
307                                      PLUGPLAY_REGKEY_DRIVER,
308                                      KEY_ALL_ACCESS,
309                                      &DevInstRegKey);
310     if (Status != STATUS_SUCCESS)
311     {
312         ERR_(VIDEOPRT, "Failed to open device software key. Status 0x%lx\n", Status);
313         return Status;
314     }
315 
316     /* Open the 'Settings' sub-key */
317     InitializeObjectAttributes(&ObjectAttributes,
318                                &SettingsKeyName,
319                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
320                                DevInstRegKey,
321                                NULL);
322     Status = ZwOpenKey(&DestKeyHandle, KEY_WRITE, &ObjectAttributes);
323 
324     /* Close the device software key */
325     ObCloseHandle(DevInstRegKey, KernelMode);
326 
327     if (Status != STATUS_SUCCESS)
328     {
329         ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
330         return Status;
331     }
332 
333     /* Open the device profile key */
334     InitializeObjectAttributes(&ObjectAttributes,
335                                &DeviceExtension->RegistryPath,
336                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
337                                NULL,
338                                NULL);
339     Status = ZwOpenKey(&SourceKeyHandle, KEY_WRITE, &ObjectAttributes);
340     if (Status != STATUS_SUCCESS)
341     {
342         ERR_(VIDEOPRT, "ZwOpenKey failed for settings key: status 0x%lx\n", Status);
343         ObCloseHandle(DestKeyHandle, KernelMode);
344         return Status;
345     }
346 
347     IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"InstalledDisplayDrivers");
348     IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"Attach.ToDesktop");
349 
350     ObCloseHandle(SourceKeyHandle, KernelMode);
351     ObCloseHandle(DestKeyHandle, KernelMode);
352 
353     return STATUS_SUCCESS;
354 }
355 
356 NTSTATUS
357 NTAPI
358 IntCreateNewRegistryPath(
359     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
360 {
361     static UNICODE_STRING VideoIdValueName = RTL_CONSTANT_STRING(L"VideoId");
362     static UNICODE_STRING ControlVideoPathName =
363         RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\");
364     HANDLE DevInstRegKey, SettingsKey, NewKey;
365     UCHAR VideoIdBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + GUID_STRING_LENGTH];
366     UNICODE_STRING VideoIdString;
367     UUID VideoId;
368     PKEY_VALUE_PARTIAL_INFORMATION ValueInformation ;
369     NTSTATUS Status;
370     ULONG ResultLength;
371     USHORT KeyMaxLength;
372     OBJECT_ATTRIBUTES ObjectAttributes;
373     PWCHAR InstanceIdBuffer;
374 
375     /* Open the hardware key: HKLM\System\CurrentControlSet\Enum\... */
376     Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
377                                      PLUGPLAY_REGKEY_DEVICE,
378                                      KEY_ALL_ACCESS,
379                                      &DevInstRegKey);
380     if (Status != STATUS_SUCCESS)
381     {
382         ERR_(VIDEOPRT, "IoOpenDeviceRegistryKey failed: status 0x%lx\n", Status);
383         return Status;
384     }
385 
386     /* Query the VideoId value */
387     ValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)VideoIdBuffer;
388     Status = ZwQueryValueKey(DevInstRegKey,
389                              &VideoIdValueName,
390                              KeyValuePartialInformation,
391                              ValueInformation,
392                              sizeof(VideoIdBuffer),
393                              &ResultLength);
394     if (!NT_SUCCESS(Status))
395     {
396         /* Create a new video Id */
397         Status = ExUuidCreate(&VideoId);
398         if (!NT_SUCCESS(Status))
399         {
400             ERR_(VIDEOPRT, "ExUuidCreate failed: status 0x%lx\n", Status);
401             ObCloseHandle(DevInstRegKey, KernelMode);
402             return Status;
403         }
404 
405         /* Convert the GUID into a string */
406         Status = RtlStringFromGUID(&VideoId, &VideoIdString);
407         if (!NT_SUCCESS(Status))
408         {
409             ERR_(VIDEOPRT, "RtlStringFromGUID failed: status 0x%lx\n", Status);
410             ObCloseHandle(DevInstRegKey, KernelMode);
411             return Status;
412         }
413 
414         /* Copy the GUID String to our buffer */
415         ValueInformation->DataLength = min(VideoIdString.Length, GUID_STRING_LENGTH);
416         RtlCopyMemory(ValueInformation->Data,
417                       VideoIdString.Buffer,
418                       ValueInformation->DataLength);
419 
420         /* Free the GUID string */
421         RtlFreeUnicodeString(&VideoIdString);
422 
423         /* Write the VideoId registry value */
424         Status = ZwSetValueKey(DevInstRegKey,
425                                &VideoIdValueName,
426                                0,
427                                REG_SZ,
428                                ValueInformation->Data,
429                                ValueInformation->DataLength);
430         if (!NT_SUCCESS(Status))
431         {
432             ERR_(VIDEOPRT, "ZwSetValueKey failed: status 0x%lx\n", Status);
433             ObCloseHandle(DevInstRegKey, KernelMode);
434             return Status;
435         }
436     }
437 
438     /* Initialize the VideoId string from the registry data */
439     VideoIdString.Buffer = (PWCHAR)ValueInformation->Data;
440     VideoIdString.Length = (USHORT)ValueInformation->DataLength;
441     VideoIdString.MaximumLength = VideoIdString.Length;
442 
443     /* Close the hardware key */
444     ObCloseHandle(DevInstRegKey, KernelMode);
445 
446     /* Calculate the size needed for the new registry path name */
447     KeyMaxLength = ControlVideoPathName.Length +
448                    VideoIdString.Length +
449                    sizeof(L"\\0000");
450 
451     /* Allocate the path name buffer */
452     DeviceExtension->NewRegistryPath.Length = 0;
453     DeviceExtension->NewRegistryPath.MaximumLength = KeyMaxLength;
454     DeviceExtension->NewRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
455                                                                     KeyMaxLength,
456                                                                     TAG_VIDEO_PORT);
457     if (DeviceExtension->NewRegistryPath.Buffer == NULL)
458     {
459         ERR_(VIDEOPRT, "Failed to allocate key name buffer.\n");
460         return STATUS_INSUFFICIENT_RESOURCES;
461     }
462 
463     /* Copy the root key name and append the VideoId string */
464     RtlCopyUnicodeString(&DeviceExtension->NewRegistryPath,
465                          &ControlVideoPathName);
466     RtlAppendUnicodeStringToString(&DeviceExtension->NewRegistryPath,
467                                    &VideoIdString);
468 
469     /* Check if we have the key already */
470     Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
471                                  DeviceExtension->NewRegistryPath.Buffer);
472     if (Status != STATUS_SUCCESS)
473     {
474         /* Try to create the new key */
475         Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
476                                       DeviceExtension->NewRegistryPath.Buffer);
477     }
478 
479     /* Append a the instance path */ /// \todo HACK
480     RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"\\");
481     InstanceIdBuffer = DeviceExtension->NewRegistryPath.Buffer +
482         DeviceExtension->NewRegistryPath.Length / sizeof(WCHAR);
483     RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"0000");
484 
485     /* Write instance ID */
486     swprintf(InstanceIdBuffer, L"%04u", DeviceExtension->DisplayNumber);
487 
488     /* Check if the name exists */
489     Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
490                                  DeviceExtension->NewRegistryPath.Buffer);
491     if (Status != STATUS_SUCCESS)
492     {
493         /* Try to create the new key */
494         Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
495                                       DeviceExtension->NewRegistryPath.Buffer);
496         if (!NT_SUCCESS(Status))
497         {
498             ERR_(VIDEOPRT, "Failed create key '%wZ'\n", &DeviceExtension->NewRegistryPath);
499             return Status;
500         }
501     }
502 
503     /* Open the new key */
504     InitializeObjectAttributes(&ObjectAttributes,
505                                 &DeviceExtension->NewRegistryPath,
506                                 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
507                                 NULL,
508                                 NULL);
509     Status = ZwOpenKey(&NewKey, KEY_READ, &ObjectAttributes);
510     if (!NT_SUCCESS(Status))
511     {
512         ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
513         return Status;
514     }
515 
516     /* Open the device profile key */
517     InitializeObjectAttributes(&ObjectAttributes,
518                                 &DeviceExtension->RegistryPath,
519                                 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
520                                 NULL,
521                                 NULL);
522     Status = ZwOpenKey(&SettingsKey, KEY_READ, &ObjectAttributes);
523     if (!NT_SUCCESS(Status))
524     {
525         ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
526         ObCloseHandle(NewKey, KernelMode);
527         return Status;
528     }
529 
530     /* Copy the registry data from the legacy key */
531     Status = IntCopyRegistryKey(SettingsKey, NewKey);
532 
533     /* Close the key handles */
534     ObCloseHandle(SettingsKey, KernelMode);
535     ObCloseHandle(NewKey, KernelMode);
536 
537     return Status;
538 }
539 
540 NTSTATUS
541 NTAPI
542 IntCreateRegistryPath(
543     IN PCUNICODE_STRING DriverRegistryPath,
544     IN ULONG DeviceNumber,
545     OUT PUNICODE_STRING DeviceRegistryPath)
546 {
547     static WCHAR RegistryMachineSystem[] = L"\\REGISTRY\\MACHINE\\SYSTEM\\";
548     static WCHAR CurrentControlSet[] = L"CURRENTCONTROLSET\\";
549     static WCHAR ControlSet[] = L"CONTROLSET";
550     static WCHAR Insert1[] = L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
551     static WCHAR Insert2[] = L"\\Device";
552     UNICODE_STRING DeviceNumberString;
553     WCHAR DeviceNumberBuffer[20];
554     BOOLEAN Valid;
555     UNICODE_STRING AfterControlSet;
556     NTSTATUS Status;
557 
558     AfterControlSet = *DriverRegistryPath;
559 
560     /* Convert DeviceNumber to string */
561     DeviceNumberString.Length = 0;
562     DeviceNumberString.MaximumLength = sizeof(DeviceNumberBuffer);
563     DeviceNumberString.Buffer = DeviceNumberBuffer;
564     Status = RtlIntegerToUnicodeString(DeviceNumber, 10, &DeviceNumberString);
565     if (!NT_SUCCESS(Status))
566     {
567         ERR_(VIDEOPRT, "RtlIntegerToUnicodeString(%u) returned 0x%08x\n", DeviceNumber, Status);
568         return Status;
569     }
570 
571     /* Check if path begins with \\REGISTRY\\MACHINE\\SYSTEM\\ */
572     Valid = (DriverRegistryPath->Length > sizeof(RegistryMachineSystem) &&
573              0 == _wcsnicmp(DriverRegistryPath->Buffer, RegistryMachineSystem,
574                             wcslen(RegistryMachineSystem)));
575     if (Valid)
576     {
577         AfterControlSet.Buffer += wcslen(RegistryMachineSystem);
578         AfterControlSet.Length -= sizeof(RegistryMachineSystem) - sizeof(UNICODE_NULL);
579 
580         /* Check if path contains CURRENTCONTROLSET */
581         if (AfterControlSet.Length > sizeof(CurrentControlSet) &&
582             0 == _wcsnicmp(AfterControlSet.Buffer, CurrentControlSet, wcslen(CurrentControlSet)))
583         {
584             AfterControlSet.Buffer += wcslen(CurrentControlSet);
585             AfterControlSet.Length -= sizeof(CurrentControlSet) - sizeof(UNICODE_NULL);
586         }
587         /* Check if path contains CONTROLSETnum */
588         else if (AfterControlSet.Length > sizeof(ControlSet) &&
589                  0 == _wcsnicmp(AfterControlSet.Buffer, ControlSet, wcslen(ControlSet)))
590         {
591             AfterControlSet.Buffer += wcslen(ControlSet);
592             AfterControlSet.Length -= sizeof(ControlSet) - sizeof(UNICODE_NULL);
593             while (AfterControlSet.Length > 0 &&
594                     *AfterControlSet.Buffer >= L'0' &&
595                     *AfterControlSet.Buffer <= L'9')
596             {
597                 AfterControlSet.Buffer++;
598                 AfterControlSet.Length -= sizeof(WCHAR);
599             }
600 
601             Valid = (AfterControlSet.Length > 0 && L'\\' == *AfterControlSet.Buffer);
602             AfterControlSet.Buffer++;
603             AfterControlSet.Length -= sizeof(WCHAR);
604             AfterControlSet.MaximumLength = AfterControlSet.Length;
605         }
606         else
607         {
608             Valid = FALSE;
609         }
610     }
611 
612     if (Valid)
613     {
614         DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert1) + sizeof(Insert2)
615                                           + DeviceNumberString.Length;
616         DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(PagedPool,
617                                                            DeviceRegistryPath->MaximumLength,
618                                                            TAG_VIDEO_PORT);
619         if (DeviceRegistryPath->Buffer != NULL)
620         {
621             /* Build device path */
622             wcsncpy(DeviceRegistryPath->Buffer,
623                     DriverRegistryPath->Buffer,
624                     AfterControlSet.Buffer - DriverRegistryPath->Buffer);
625             DeviceRegistryPath->Length = (AfterControlSet.Buffer - DriverRegistryPath->Buffer) * sizeof(WCHAR);
626             RtlAppendUnicodeToString(DeviceRegistryPath, Insert1);
627             RtlAppendUnicodeStringToString(DeviceRegistryPath, &AfterControlSet);
628             RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
629             RtlAppendUnicodeStringToString(DeviceRegistryPath, &DeviceNumberString);
630 
631             /* Check if registry key exists */
632             Valid = NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, DeviceRegistryPath->Buffer));
633 
634             if (!Valid)
635                 ExFreePoolWithTag(DeviceRegistryPath->Buffer, TAG_VIDEO_PORT);
636         }
637         else
638         {
639             Valid = FALSE;
640         }
641     }
642     else
643     {
644         WARN_(VIDEOPRT, "Unparsable registry path %wZ\n", DriverRegistryPath);
645     }
646 
647     /* If path doesn't point to *ControlSet*, use DriverRegistryPath directly */
648     if (!Valid)
649     {
650         DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert2) + DeviceNumberString.Length;
651         DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
652                                                            DeviceRegistryPath->MaximumLength,
653                                                            TAG_VIDEO_PORT);
654 
655         if (!DeviceRegistryPath->Buffer)
656             return STATUS_NO_MEMORY;
657 
658         RtlCopyUnicodeString(DeviceRegistryPath, DriverRegistryPath);
659         RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
660         RtlAppendUnicodeStringToString(DeviceRegistryPath, &DeviceNumberString);
661     }
662 
663     DPRINT("Formatted registry key '%wZ' -> '%wZ'\n",
664            DriverRegistryPath, DeviceRegistryPath);
665 
666     return STATUS_SUCCESS;
667 }
668