4 * Copyright (C) 2002-2004, 2007 ReactOS Team
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.
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.
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
27 _In_ HANDLE SourceKeyHandle
,
28 _In_ HANDLE DestKeyHandle
)
31 PKEY_BASIC_INFORMATION KeyInformation
;
32 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
33 OBJECT_ATTRIBUTES ObjectAttributes
;
34 ULONG Index
, InformationLength
, RequiredLength
;
35 UNICODE_STRING NameString
;
37 HANDLE SourceSubKeyHandle
, DestSubKeyHandle
;
39 /* Start with no buffer, set initial size */
41 InformationLength
= 256;
43 /* Start looping with key index 0 */
47 /* Check if we have no buffer */
48 if (InfoBuffer
== NULL
)
50 /* Allocate a new buffer */
51 InfoBuffer
= ExAllocatePoolWithTag(PagedPool
,
53 TAG_VIDEO_PORT_BUFFER
);
54 if (InfoBuffer
== NULL
)
56 ERR_(VIDEOPRT
, "Could not allocate buffer for key info\n");
61 /* Enumerate the next sub-key */
62 KeyInformation
= InfoBuffer
;
63 Status
= ZwEnumerateKey(SourceKeyHandle
,
69 if ((Status
== STATUS_BUFFER_OVERFLOW
) ||
70 (Status
== STATUS_BUFFER_TOO_SMALL
))
72 /* Free the buffer and remember the required size */
73 ExFreePoolWithTag(InfoBuffer
, TAG_VIDEO_PORT_BUFFER
);
75 InformationLength
= RequiredLength
;
80 else if (Status
== STATUS_NO_MORE_ENTRIES
)
82 /* We are done with the sub-keys */
85 else if (!NT_SUCCESS(Status
))
87 ERR_(VIDEOPRT
, "ZwEnumerateKey failed, status 0x%lx\n", Status
);
91 /* Initialize a unicode string from the key name */
92 NameString
.Buffer
= KeyInformation
->Name
;
93 NameString
.Length
= (USHORT
)KeyInformation
->NameLength
;
94 NameString
.MaximumLength
= NameString
.Length
;
96 /* Initialize object attributes and open the source sub-key */
97 InitializeObjectAttributes(&ObjectAttributes
,
99 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
102 Status
= ZwOpenKey(&SourceSubKeyHandle
, KEY_READ
, &ObjectAttributes
);
103 if (!NT_SUCCESS(Status
))
105 ERR_(VIDEOPRT
, "failed to open the source key.\n");
109 /* Initialize object attributes and create the dest sub-key */
110 InitializeObjectAttributes(&ObjectAttributes
,
112 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
115 Status
= ZwCreateKey(&DestSubKeyHandle
,
122 if (!NT_SUCCESS(Status
))
124 ERR_(VIDEOPRT
, "failed to create the destination key.\n");
125 ObCloseHandle(SourceSubKeyHandle
, KernelMode
);
129 /* Recursively copy the sub-key */
130 Status
= IntCopyRegistryKey(SourceSubKeyHandle
, DestSubKeyHandle
);
131 if (!NT_SUCCESS(Status
))
133 /* Just warn, but continue with the remaining sub-keys */
134 WARN_(VIDEOPRT
, "failed to copy subkey '%wZ'.\n", &NameString
);
137 /* Close the sub-key handles */
138 ObCloseHandle(SourceSubKeyHandle
, KernelMode
);
139 ObCloseHandle(DestSubKeyHandle
, KernelMode
);
145 /* Start looping with value index 0 */
149 /* Check if we have no buffer */
150 if (InfoBuffer
== NULL
)
152 /* Allocate a new buffer */
153 InfoBuffer
= ExAllocatePoolWithTag(PagedPool
,
155 TAG_VIDEO_PORT_BUFFER
);
156 if (InfoBuffer
== NULL
)
158 ERR_(VIDEOPRT
, "Could not allocate buffer for key values\n");
163 /* Enumerate the next value */
164 KeyValueInformation
= InfoBuffer
;
165 Status
= ZwEnumerateValueKey(SourceKeyHandle
,
167 KeyValueFullInformation
,
171 if ((Status
== STATUS_BUFFER_OVERFLOW
) ||
172 (Status
== STATUS_BUFFER_TOO_SMALL
))
174 /* Free the buffer and remember the required size */
175 ExFreePoolWithTag(InfoBuffer
, TAG_VIDEO_PORT_BUFFER
);
177 InformationLength
= RequiredLength
;
182 else if (Status
== STATUS_NO_MORE_ENTRIES
)
184 /* We are done with the values */
185 Status
= STATUS_SUCCESS
;
188 else if (!NT_SUCCESS(Status
))
190 ERR_(VIDEOPRT
, "ZwEnumerateValueKey failed, status 0x%lx\n", Status
);
194 /* Initialize a unicode string from the value name */
195 NameString
.Buffer
= KeyValueInformation
->Name
;
196 NameString
.Length
= (USHORT
)KeyValueInformation
->NameLength
;
197 NameString
.MaximumLength
= NameString
.Length
;
199 /* Create the key value in the destination key */
200 Status
= ZwSetValueKey(DestKeyHandle
,
202 KeyValueInformation
->TitleIndex
,
203 KeyValueInformation
->Type
,
204 (PUCHAR
)KeyValueInformation
+ KeyValueInformation
->DataOffset
,
205 KeyValueInformation
->DataLength
);
206 if (!NT_SUCCESS(Status
))
208 /* Just warn, but continue with the remaining sub-keys */
209 WARN_(VIDEOPRT
, "failed to set value '%wZ'.\n", NameString
);
217 /* Free the buffer and return the failure code */
218 if (InfoBuffer
!= NULL
)
219 ExFreePoolWithTag(InfoBuffer
, TAG_VIDEO_PORT_BUFFER
);
225 IntCopyRegistryValue(
226 HANDLE SourceKeyHandle
,
227 HANDLE DestKeyHandle
,
230 PKEY_VALUE_PARTIAL_INFORMATION ValueInformation
;
231 UNICODE_STRING ValueNameString
;
235 RtlInitUnicodeString(&ValueNameString
, ValueName
);
237 /* Query the value length */
238 Status
= ZwQueryValueKey(SourceKeyHandle
,
240 KeyValuePartialInformation
,
244 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
245 (Status
!= STATUS_BUFFER_TOO_SMALL
))
247 /* The key seems not present */
248 NT_ASSERT(!NT_SUCCESS(Status
));
252 /* Allocate a buffer */
253 ValueInformation
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_VIDEO_PORT_BUFFER
);
254 if (ValueInformation
== NULL
)
259 /* Query the value */
260 Status
= ZwQueryValueKey(SourceKeyHandle
,
262 KeyValuePartialInformation
,
266 if (!NT_SUCCESS(Status
))
268 ExFreePoolWithTag(ValueInformation
, TAG_VIDEO_PORT_BUFFER
);
272 /* Write the registry value */
273 Status
= ZwSetValueKey(DestKeyHandle
,
275 ValueInformation
->TitleIndex
,
276 ValueInformation
->Type
,
277 ValueInformation
->Data
,
278 ValueInformation
->DataLength
);
280 ExFreePoolWithTag(ValueInformation
, TAG_VIDEO_PORT_BUFFER
);
282 if (!NT_SUCCESS(Status
))
284 ERR_(VIDEOPRT
, "ZwSetValueKey failed: status 0x%lx\n", Status
);
292 IntSetupDeviceSettingsKey(
293 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
)
295 static UNICODE_STRING SettingsKeyName
= RTL_CONSTANT_STRING(L
"Settings");
296 HANDLE DevInstRegKey
, SourceKeyHandle
, DestKeyHandle
;
297 OBJECT_ATTRIBUTES ObjectAttributes
;
300 /* Open the software key: HKLM\System\CurrentControlSet\Control\Class\<ClassGUID>\<n> */
301 Status
= IoOpenDeviceRegistryKey(DeviceExtension
->PhysicalDeviceObject
,
302 PLUGPLAY_REGKEY_DRIVER
,
305 if (Status
!= STATUS_SUCCESS
)
307 ERR_(VIDEOPRT
, "Failed to open device software key. Status 0x%lx", Status
);
311 /* Open the 'Settings' sub-key */
312 InitializeObjectAttributes(&ObjectAttributes
,
314 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
317 Status
= ZwOpenKey(&DestKeyHandle
, KEY_WRITE
, &ObjectAttributes
);
319 /* Close the device software key */
320 ObCloseHandle(DevInstRegKey
, KernelMode
);
322 if (Status
!= STATUS_SUCCESS
)
324 ERR_(VIDEOPRT
, "Failed to open settings key. Status 0x%lx", Status
);
328 /* Open the device profile key */
329 InitializeObjectAttributes(&ObjectAttributes
,
330 &DeviceExtension
->RegistryPath
,
331 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
334 Status
= ZwOpenKey(&SourceKeyHandle
, KEY_WRITE
, &ObjectAttributes
);
335 if (Status
!= STATUS_SUCCESS
)
337 ERR_(VIDEOPRT
, "ZwOpenKey failed for settings key: status 0x%lx", Status
);
338 ObCloseHandle(DestKeyHandle
, KernelMode
);
342 IntCopyRegistryValue(SourceKeyHandle
, DestKeyHandle
, L
"InstalledDisplayDrivers");
343 IntCopyRegistryValue(SourceKeyHandle
, DestKeyHandle
, L
"Attach.ToDesktop");
345 ObCloseHandle(SourceKeyHandle
, KernelMode
);
346 ObCloseHandle(DestKeyHandle
, KernelMode
);
348 return STATUS_SUCCESS
;
353 IntCreateNewRegistryPath(
354 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
)
356 static UNICODE_STRING VideoIdValueName
= RTL_CONSTANT_STRING(L
"VideoId");
357 static UNICODE_STRING ControlVideoPathName
=
358 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\");
359 HANDLE DevInstRegKey
, SettingsKey
, NewKey
;
360 UCHAR VideoIdBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + GUID_STRING_LENGTH
];
361 UNICODE_STRING VideoIdString
;
363 PKEY_VALUE_PARTIAL_INFORMATION ValueInformation
;
367 OBJECT_ATTRIBUTES ObjectAttributes
;
369 /* Open the hardware key: HKLM\System\CurrentControlSet\Enum\... */
370 Status
= IoOpenDeviceRegistryKey(DeviceExtension
->PhysicalDeviceObject
,
371 PLUGPLAY_REGKEY_DEVICE
,
374 if (Status
!= STATUS_SUCCESS
)
376 ERR_(VIDEOPRT
, "IoOpenDeviceRegistryKey failed: status 0x%lx\n", Status
);
380 /* Query the VideoId value */
381 ValueInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)VideoIdBuffer
;
382 Status
= ZwQueryValueKey(DevInstRegKey
,
384 KeyValuePartialInformation
,
386 sizeof(VideoIdBuffer
),
388 if (!NT_SUCCESS(Status
))
390 /* Create a new video Id */
391 Status
= ExUuidCreate(&VideoId
);
392 if (!NT_SUCCESS(Status
))
394 ERR_(VIDEOPRT
, "ExUuidCreate failed: status 0x%lx\n", Status
);
395 ObCloseHandle(DevInstRegKey
, KernelMode
);
399 /* Convert the GUID into a string */
400 Status
= RtlStringFromGUID(&VideoId
, &VideoIdString
);
401 if (!NT_SUCCESS(Status
))
403 ERR_(VIDEOPRT
, "RtlStringFromGUID failed: status 0x%lx\n", Status
);
404 ObCloseHandle(DevInstRegKey
, KernelMode
);
408 /* Copy the GUID String to our buffer */
409 ValueInformation
->DataLength
= min(VideoIdString
.Length
, GUID_STRING_LENGTH
);
410 RtlCopyMemory(ValueInformation
->Data
,
411 VideoIdString
.Buffer
,
412 ValueInformation
->DataLength
);
414 /* Free the GUID string */
415 RtlFreeUnicodeString(&VideoIdString
);
417 /* Write the VideoId registry value */
418 Status
= ZwSetValueKey(DevInstRegKey
,
422 ValueInformation
->Data
,
423 ValueInformation
->DataLength
);
424 if (!NT_SUCCESS(Status
))
426 ERR_(VIDEOPRT
, "ZwSetValueKey failed: status 0x%lx\n", Status
);
427 ObCloseHandle(DevInstRegKey
, KernelMode
);
432 /* Initialize the VideoId string from the registry data */
433 VideoIdString
.Buffer
= (PWCHAR
)ValueInformation
->Data
;
434 VideoIdString
.Length
= (USHORT
)ValueInformation
->DataLength
;
435 VideoIdString
.MaximumLength
= VideoIdString
.Length
;
437 /* Close the hardware key */
438 ObCloseHandle(DevInstRegKey
, KernelMode
);
440 /* Calculate the size needed for the new registry path name */
441 KeyMaxLength
= ControlVideoPathName
.Length
+
442 VideoIdString
.Length
+
445 /* Allocate the path name buffer */
446 DeviceExtension
->NewRegistryPath
.Length
= 0;
447 DeviceExtension
->NewRegistryPath
.MaximumLength
= KeyMaxLength
;
448 DeviceExtension
->NewRegistryPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
451 if (DeviceExtension
->NewRegistryPath
.Buffer
== NULL
)
453 ERR_(VIDEOPRT
, "Failed to allocate key name buffer.\n");
454 return STATUS_INSUFFICIENT_RESOURCES
;
457 /* Copy the root key name and append the VideoId string */
458 RtlCopyUnicodeString(&DeviceExtension
->NewRegistryPath
,
459 &ControlVideoPathName
);
460 RtlAppendUnicodeStringToString(&DeviceExtension
->NewRegistryPath
,
463 /* Check if we have the key already */
464 Status
= RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE
,
465 DeviceExtension
->NewRegistryPath
.Buffer
);
466 if (Status
!= STATUS_SUCCESS
)
468 /* Try to create the new key */
469 Status
= RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
,
470 DeviceExtension
->NewRegistryPath
.Buffer
);
473 /* Append a the instance path */ /// \todo HACK
474 RtlAppendUnicodeToString(&DeviceExtension
->NewRegistryPath
, L
"\\");
475 RtlAppendUnicodeToString(&DeviceExtension
->NewRegistryPath
, L
"0000");
477 /* Check this key again */
478 Status
= RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE
,
479 DeviceExtension
->NewRegistryPath
.Buffer
);
480 if (Status
!= STATUS_SUCCESS
)
482 /* Try to create the new key */
483 Status
= RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
,
484 DeviceExtension
->NewRegistryPath
.Buffer
);
485 if (!NT_SUCCESS(Status
))
487 ERR_(VIDEOPRT
, "Failed create key '%wZ'\n", &DeviceExtension
->NewRegistryPath
);
491 /* Open the new key */
492 InitializeObjectAttributes(&ObjectAttributes
,
493 &DeviceExtension
->NewRegistryPath
,
494 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
497 Status
= ZwOpenKey(&NewKey
, KEY_READ
, &ObjectAttributes
);
498 if (!NT_SUCCESS(Status
))
500 ERR_(VIDEOPRT
, "Failed to open settings key. Status 0x%lx\n", Status
);
504 /* Open the device profile key */
505 InitializeObjectAttributes(&ObjectAttributes
,
506 &DeviceExtension
->RegistryPath
,
507 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
510 Status
= ZwOpenKey(&SettingsKey
, KEY_READ
, &ObjectAttributes
);
511 if (!NT_SUCCESS(Status
))
513 ERR_(VIDEOPRT
, "Failed to open settings key. Status 0x%lx\n", Status
);
514 ObCloseHandle(NewKey
, KernelMode
);
518 /* Copy the registry data from the legacy key */
519 Status
= IntCopyRegistryKey(SettingsKey
, NewKey
);
528 IntCreateRegistryPath(
529 IN PCUNICODE_STRING DriverRegistryPath
,
530 OUT PUNICODE_STRING DeviceRegistryPath
)
532 static WCHAR RegistryMachineSystem
[] = L
"\\REGISTRY\\MACHINE\\SYSTEM\\";
533 static WCHAR CurrentControlSet
[] = L
"CURRENTCONTROLSET\\";
534 static WCHAR ControlSet
[] = L
"CONTROLSET";
535 static WCHAR Insert1
[] = L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
536 static WCHAR Insert2
[] = L
"\\Device0";
538 UNICODE_STRING AfterControlSet
;
540 AfterControlSet
= *DriverRegistryPath
;
542 /* Check if path begins with \\REGISTRY\\MACHINE\\SYSTEM\\ */
543 Valid
= (DriverRegistryPath
->Length
> sizeof(RegistryMachineSystem
) &&
544 0 == _wcsnicmp(DriverRegistryPath
->Buffer
, RegistryMachineSystem
,
545 wcslen(RegistryMachineSystem
)));
548 AfterControlSet
.Buffer
+= wcslen(RegistryMachineSystem
);
549 AfterControlSet
.Length
-= sizeof(RegistryMachineSystem
) - sizeof(UNICODE_NULL
);
551 /* Check if path contains CURRENTCONTROLSET */
552 if (AfterControlSet
.Length
> sizeof(CurrentControlSet
) &&
553 0 == _wcsnicmp(AfterControlSet
.Buffer
, CurrentControlSet
, wcslen(CurrentControlSet
)))
555 AfterControlSet
.Buffer
+= wcslen(CurrentControlSet
);
556 AfterControlSet
.Length
-= sizeof(CurrentControlSet
) - sizeof(UNICODE_NULL
);
558 /* Check if path contains CONTROLSETnum */
559 else if (AfterControlSet
.Length
> sizeof(ControlSet
) &&
560 0 == _wcsnicmp(AfterControlSet
.Buffer
, ControlSet
, wcslen(ControlSet
)))
562 AfterControlSet
.Buffer
+= wcslen(ControlSet
);
563 AfterControlSet
.Length
-= sizeof(ControlSet
) - sizeof(UNICODE_NULL
);
564 while (AfterControlSet
.Length
> 0 &&
565 *AfterControlSet
.Buffer
>= L
'0' &&
566 *AfterControlSet
.Buffer
<= L
'9')
568 AfterControlSet
.Buffer
++;
569 AfterControlSet
.Length
-= sizeof(WCHAR
);
572 Valid
= (AfterControlSet
.Length
> 0 && L
'\\' == *AfterControlSet
.Buffer
);
573 AfterControlSet
.Buffer
++;
574 AfterControlSet
.Length
-= sizeof(WCHAR
);
575 AfterControlSet
.MaximumLength
= AfterControlSet
.Length
;
585 DeviceRegistryPath
->MaximumLength
= DriverRegistryPath
->Length
+ sizeof(Insert1
) + sizeof(Insert2
);
586 DeviceRegistryPath
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
587 DeviceRegistryPath
->MaximumLength
,
589 if (DeviceRegistryPath
->Buffer
!= NULL
)
591 /* Build device path */
592 wcsncpy(DeviceRegistryPath
->Buffer
,
593 DriverRegistryPath
->Buffer
,
594 AfterControlSet
.Buffer
- DriverRegistryPath
->Buffer
);
595 DeviceRegistryPath
->Length
= (AfterControlSet
.Buffer
- DriverRegistryPath
->Buffer
) * sizeof(WCHAR
);
596 RtlAppendUnicodeToString(DeviceRegistryPath
, Insert1
);
597 RtlAppendUnicodeStringToString(DeviceRegistryPath
, &AfterControlSet
);
598 RtlAppendUnicodeToString(DeviceRegistryPath
, Insert2
);
600 /* Check if registry key exists */
601 Valid
= NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE
, DeviceRegistryPath
->Buffer
));
604 ExFreePoolWithTag(DeviceRegistryPath
->Buffer
, TAG_VIDEO_PORT
);
613 WARN_(VIDEOPRT
, "Unparsable registry path %wZ", DriverRegistryPath
);
616 /* If path doesn't point to *ControlSet*, use DriverRegistryPath directly */
619 DeviceRegistryPath
->MaximumLength
= DriverRegistryPath
->Length
+ sizeof(Insert2
);
620 DeviceRegistryPath
->Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
621 DeviceRegistryPath
->MaximumLength
,
624 if (!DeviceRegistryPath
->Buffer
)
625 return STATUS_NO_MEMORY
;
627 RtlCopyUnicodeString(DeviceRegistryPath
, DriverRegistryPath
);
628 RtlAppendUnicodeToString(DeviceRegistryPath
, Insert2
);
631 DbgPrint("Formatted registry key '%wZ' -> '%wZ'\n",
632 DriverRegistryPath
, DeviceRegistryPath
);
634 return STATUS_SUCCESS
;