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