2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Video initialization and display settings
5 * FILE: subsystems/win32/win32k/ntuser/display.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
20 static const PWCHAR KEY_ROOT
= L
"";
21 static const PWCHAR KEY_VIDEO
= L
"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
24 RegWriteDisplaySettings(HKEY hkey
, PDEVMODEW pdm
)
26 RegWriteDWORD(hkey
, L
"DefaultSettings.BitsPerPel", pdm
->dmBitsPerPel
);
27 RegWriteDWORD(hkey
, L
"DefaultSettings.XResolution", pdm
->dmPelsWidth
);
28 RegWriteDWORD(hkey
, L
"DefaultSettings.YResolution", pdm
->dmPelsHeight
);
29 RegWriteDWORD(hkey
, L
"DefaultSettings.Flags", pdm
->dmDisplayFlags
);
30 RegWriteDWORD(hkey
, L
"DefaultSettings.VRefresh", pdm
->dmDisplayFrequency
);
31 RegWriteDWORD(hkey
, L
"DefaultSettings.XPanning", pdm
->dmPanningWidth
);
32 RegWriteDWORD(hkey
, L
"DefaultSettings.YPanning", pdm
->dmPanningHeight
);
33 RegWriteDWORD(hkey
, L
"DefaultSettings.Orientation", pdm
->dmDisplayOrientation
);
34 RegWriteDWORD(hkey
, L
"DefaultSettings.FixedOutput", pdm
->dmDisplayFixedOutput
);
35 RegWriteDWORD(hkey
, L
"Attach.RelativeX", pdm
->dmPosition
.x
);
36 RegWriteDWORD(hkey
, L
"Attach.RelativeY", pdm
->dmPosition
.y
);
37 // RegWriteDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", pdm->);
41 RegReadDisplaySettings(HKEY hkey
, PDEVMODEW pdm
)
45 /* Zero out the structure */
46 RtlZeroMemory(pdm
, sizeof(DEVMODEW
));
49 #define READ(field, str, flag) \
50 if (RegReadDWORD(hkey, L##str, &dwValue)) \
52 pdm->field = dwValue; \
53 pdm->dmFields |= flag; \
56 /* Read all present settings */
57 READ(dmBitsPerPel
, "DefaultSettings.BitsPerPel", DM_BITSPERPEL
);
58 READ(dmPelsWidth
, "DefaultSettings.XResolution", DM_PELSWIDTH
);
59 READ(dmPelsHeight
, "DefaultSettings.YResolution", DM_PELSHEIGHT
);
60 READ(dmDisplayFlags
, "DefaultSettings.Flags", DM_DISPLAYFLAGS
);
61 READ(dmDisplayFrequency
, "DefaultSettings.VRefresh", DM_DISPLAYFREQUENCY
);
62 READ(dmPanningWidth
, "DefaultSettings.XPanning", DM_PANNINGWIDTH
);
63 READ(dmPanningHeight
, "DefaultSettings.YPanning", DM_PANNINGHEIGHT
);
64 READ(dmDisplayOrientation
, "DefaultSettings.Orientation", DM_DISPLAYORIENTATION
);
65 READ(dmDisplayFixedOutput
, "DefaultSettings.FixedOutput", DM_DISPLAYFIXEDOUTPUT
);
66 READ(dmPosition
.x
, "Attach.RelativeX", DM_POSITION
);
67 READ(dmPosition
.y
, "Attach.RelativeY", DM_POSITION
);
73 IN PWSTR pwszDeviceName
,
76 PGRAPHICS_DEVICE pGraphicsDevice
;
77 UNICODE_STRING ustrDeviceName
, ustrDisplayDrivers
, ustrDescription
;
84 DPRINT1("InitDisplayDriver(%S, %S);\n",
85 pwszDeviceName
, pwszRegKey
);
87 /* Open the driver's registry key */
88 Status
= RegOpenKey(pwszRegKey
, &hkey
);
89 if (!NT_SUCCESS(Status
))
91 DPRINT1("Failed to open registry key: %ls\n", pwszRegKey
);
95 /* Query the diplay drivers */
96 cbSize
= sizeof(awcBuffer
) - 10;
97 Status
= RegQueryValue(hkey
,
98 L
"InstalledDisplayDrivers",
102 if (!NT_SUCCESS(Status
))
104 DPRINT1("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status
);
109 /* Initialize the UNICODE_STRING */
110 ustrDisplayDrivers
.Buffer
= awcBuffer
;
111 ustrDisplayDrivers
.MaximumLength
= cbSize
;
112 ustrDisplayDrivers
.Length
= cbSize
;
114 /* Set Buffer for description and size of remaining buffer */
115 ustrDescription
.Buffer
= awcBuffer
+ (cbSize
/ sizeof(WCHAR
));
116 cbSize
= sizeof(awcBuffer
) - cbSize
;
118 /* Query the device string */
119 Status
= RegQueryValue(hkey
,
120 L
"Device Description",
122 ustrDescription
.Buffer
,
124 if (NT_SUCCESS(Status
))
126 ustrDescription
.MaximumLength
= cbSize
;
127 ustrDescription
.Length
= cbSize
;
131 RtlInitUnicodeString(&ustrDescription
, L
"<unknown>");
134 /* Query the default settings */
135 RegReadDisplaySettings(hkey
, &dmDefault
);
137 /* Close the registry key */
140 /* Register the device with GDI */
141 RtlInitUnicodeString(&ustrDeviceName
, pwszDeviceName
);
142 pGraphicsDevice
= EngpRegisterGraphicsDevice(&ustrDeviceName
,
147 return pGraphicsDevice
;
154 ULONG iDevNum
, iVGACompatible
= -1, ulMaxObjectNumber
= 0;
155 WCHAR awcDeviceName
[20];
156 WCHAR awcBuffer
[256];
158 PGRAPHICS_DEVICE pGraphicsDevice
;
162 DPRINT("----------------------------- InitVideo() -------------------------------\n");
164 /* Open the key for the boot command line */
165 Status
= RegOpenKey(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control", &hkey
);
166 if (NT_SUCCESS(Status
))
169 Status
= RegQueryValue(hkey
, L
"SystemStartOptions", REG_SZ
, awcBuffer
, &cbValue
);
170 if (NT_SUCCESS(Status
))
172 /* Check if VGA mode is requested. */
173 if (wcsstr(awcBuffer
, L
"/BASEVIDEO") != 0)
175 DPRINT1("VGA mode requested.\n");
183 /* Open the key for the adapters */
184 Status
= RegOpenKey(KEY_VIDEO
, &hkey
);
185 if (!NT_SUCCESS(Status
))
187 DPRINT1("Could not open device registry key!\n");
191 /* Read the name of the VGA adapter */
193 Status
= RegQueryValue(hkey
, L
"VgaCompatible", REG_SZ
, awcDeviceName
, &cbValue
);
194 if (NT_SUCCESS(Status
))
196 iVGACompatible
= _wtoi(&awcDeviceName
[13]);
197 DPRINT1("VGA adapter = %ld\n", iVGACompatible
);
200 /* Get the maximum mumber of adapters */
201 if (!RegReadDWORD(hkey
, L
"MaxObjectNumber", &ulMaxObjectNumber
))
203 DPRINT1("Could not read MaxObjectNumber, defaulting to 0.\n");
206 DPRINT("Found %ld devices\n", ulMaxObjectNumber
);
208 /* Loop through all adapters */
209 for (iDevNum
= 0; iDevNum
<= ulMaxObjectNumber
; iDevNum
++)
211 /* Create the adapter's key name */
212 swprintf(awcDeviceName
, L
"\\Device\\Video%lu", iDevNum
);
214 /* Read the reg key name */
215 cbValue
= sizeof(awcBuffer
);
216 Status
= RegQueryValue(hkey
, awcDeviceName
, REG_SZ
, awcBuffer
, &cbValue
);
217 if (!NT_SUCCESS(Status
))
219 DPRINT1("failed to query the registry path:0x%lx\n", Status
);
223 /* Initialize the driver for this device */
224 pGraphicsDevice
= InitDisplayDriver(awcDeviceName
, awcBuffer
);
225 if (!pGraphicsDevice
) continue;
227 /* Check if this is the VGA adapter */
228 if (iDevNum
== iVGACompatible
)
230 /* Set the VGA device as primary */
231 gpVgaGraphicsDevice
= pGraphicsDevice
;
232 DPRINT1("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice
);
235 /* Set the first one as primary device */
236 if (!gpPrimaryGraphicsDevice
)
237 gpPrimaryGraphicsDevice
= pGraphicsDevice
;
240 /* Close the device map registry key */
243 /* Check if we had any success */
244 if (!gpPrimaryGraphicsDevice
)
246 DPRINT1("No usable display driver was found.\n");
247 return STATUS_UNSUCCESSFUL
;
252 if (gpVgaGraphicsDevice
)
254 /* Set the VgaAdapter as primary */
255 gpPrimaryGraphicsDevice
= gpVgaGraphicsDevice
;
260 DPRINT1("Could not find VGA compatible driver. Trying normal.\n");
271 UserEnumDisplayDevices(
272 PUNICODE_STRING pustrDevice
,
274 PDISPLAY_DEVICEW pdispdev
,
277 PGRAPHICS_DEVICE pGraphicsDevice
;
282 /* Ask gdi for the GRAPHICS_DEVICE */
283 pGraphicsDevice
= EngpFindGraphicsDevice(pustrDevice
, iDevNum
, 0);
284 if (!pGraphicsDevice
)
286 /* No device found */
287 DPRINT1("No GRAPHICS_DEVICE found\n");
288 return STATUS_UNSUCCESSFUL
;
291 /* Open thhe device map registry key */
292 Status
= RegOpenKey(KEY_VIDEO
, &hkey
);
293 if (!NT_SUCCESS(Status
))
295 /* No device found */
296 DPRINT1("Could not open reg key\n");
297 return STATUS_UNSUCCESSFUL
;
300 /* Query the registry path */
301 cbSize
= sizeof(pdispdev
->DeviceKey
);
303 pGraphicsDevice
->szNtDeviceName
,
308 /* Close registry key */
311 /* Copy device name, device string and StateFlags */
312 wcsncpy(pdispdev
->DeviceName
, pGraphicsDevice
->szWinDeviceName
, 32);
313 wcsncpy(pdispdev
->DeviceString
, pGraphicsDevice
->pwszDescription
, 128);
314 pdispdev
->StateFlags
= pGraphicsDevice
->StateFlags
;
316 // FIXME: fill in DEVICE ID
318 return STATUS_SUCCESS
;
324 NtUserEnumDisplayDevices(
325 PUNICODE_STRING pustrDevice
,
327 PDISPLAY_DEVICEW pDisplayDevice
,
330 UNICODE_STRING ustrDevice
;
331 WCHAR awcDevice
[CCHDEVICENAME
];
332 DISPLAY_DEVICEW dispdev
;
335 DPRINT("Enter NtUserEnumDisplayDevices(%wZ, %ld)\n",
336 pustrDevice
, iDevNum
);
338 // FIXME: HACK, desk.cpl passes broken crap
339 if (pustrDevice
&& iDevNum
!= 0)
342 dispdev
.cb
= sizeof(DISPLAY_DEVICEW
);
346 /* Initialize destination string */
347 RtlInitEmptyUnicodeString(&ustrDevice
, awcDevice
, sizeof(awcDevice
));
351 /* Probe the UNICODE_STRING and the buffer */
352 ProbeForRead(pustrDevice
, sizeof(UNICODE_STRING
), 1);
353 ProbeForRead(pustrDevice
->Buffer
, pustrDevice
->Length
, 1);
355 /* Copy the string */
356 RtlCopyUnicodeString(&ustrDevice
, pustrDevice
);
358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
360 // _SEH2_YIELD(return _SEH2_GetExceptionCode());
361 _SEH2_YIELD(return NT_SUCCESS(_SEH2_GetExceptionCode()));
365 if (ustrDevice
.Length
> 0)
366 pustrDevice
= &ustrDevice
;
371 /* Acquire global USER lock */
372 UserEnterExclusive();
374 /* Call the internal function */
375 Status
= UserEnumDisplayDevices(pustrDevice
, iDevNum
, &dispdev
, dwFlags
);
380 /* On success copy data to caller */
381 if (NT_SUCCESS(Status
))
386 /* First probe the cb field */
387 ProbeForWrite(&pDisplayDevice
->cb
, sizeof(DWORD
), 1);
389 /* Check the buffer size */
390 if (pDisplayDevice
->cb
)
392 /* Probe the output buffer */
393 pDisplayDevice
->cb
= min(pDisplayDevice
->cb
, sizeof(dispdev
));
394 ProbeForWrite(pDisplayDevice
, pDisplayDevice
->cb
, 1);
396 /* Copy as much as the given buffer allows */
397 RtlCopyMemory(pDisplayDevice
, &dispdev
, pDisplayDevice
->cb
);
400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
402 Status
= _SEH2_GetExceptionCode();
407 DPRINT1("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status
);
408 /* Return the result */
410 return NT_SUCCESS(Status
); // FIXME
415 UserEnumCurrentDisplaySettings(
416 PUNICODE_STRING pustrDevice
,
421 /* Get the PDEV for the device */
422 ppdev
= EngpGetPDEV(pustrDevice
);
425 /* No device found */
426 DPRINT1("No PDEV found!\n");
427 return STATUS_UNSUCCESSFUL
;
430 *ppdm
= ppdev
->pdmwDev
;
431 PDEVOBJ_vRelease(ppdev
);
433 return STATUS_SUCCESS
;
438 UserEnumDisplaySettings(
439 PUNICODE_STRING pustrDevice
,
444 PGRAPHICS_DEVICE pGraphicsDevice
;
445 PDEVMODEENTRY pdmentry
;
448 DPRINT("Enter UserEnumDisplaySettings('%ls', %ld)\n",
449 pustrDevice
? pustrDevice
->Buffer
: NULL
, iModeNum
);
451 /* Ask gdi for the GRAPHICS_DEVICE */
452 pGraphicsDevice
= EngpFindGraphicsDevice(pustrDevice
, 0, 0);
454 if (!pGraphicsDevice
)
456 /* No device found */
457 DPRINT1("No device found!\n");
458 return STATUS_UNSUCCESSFUL
;
461 if (iModeNum
>= pGraphicsDevice
->cDevModes
)
462 return STATUS_NO_MORE_ENTRIES
;
465 for (i
= 0; i
< pGraphicsDevice
->cDevModes
; i
++)
467 pdmentry
= &pGraphicsDevice
->pDevModeList
[i
];
469 /* FIXME: consider EDS_RAWMODE */
471 if ((!(dwFlags
& EDS_RAWMODE
) && (pdmentry
->dwFlags
& 1)) ||!
472 (dwFlags
& EDS_RAWMODE
))
475 /* Is this the one we want? */
476 if (iFoundMode
== iModeNum
)
478 *ppdm
= pdmentry
->pdm
;
479 return STATUS_SUCCESS
;
482 /* Increment number of found modes */
487 /* Nothing was found */
488 return STATUS_INVALID_PARAMETER
;
493 UserOpenDisplaySettingsKey(
495 IN PUNICODE_STRING pustrDevice
,
499 DISPLAY_DEVICEW dispdev
;
502 /* Get device info */
503 Status
= UserEnumDisplayDevices(pustrDevice
, 0, &dispdev
, 0);
504 if (!NT_SUCCESS(Status
))
509 // FIXME: need to fix the registry key somehow
512 /* Open the registry key */
513 Status
= RegOpenKey(dispdev
.DeviceKey
, &hkey
);
514 if (!NT_SUCCESS(Status
))
524 UserEnumRegistryDisplaySettings(
525 IN PUNICODE_STRING pustrDevice
,
529 NTSTATUS Status
= UserOpenDisplaySettingsKey(&hkey
, pustrDevice
, 0);
530 if(NT_SUCCESS(Status
))
532 RegReadDisplaySettings(hkey
, pdm
);
534 return STATUS_SUCCESS
;
542 NtUserEnumDisplaySettings(
543 IN PUNICODE_STRING pustrDevice
,
545 OUT LPDEVMODEW lpDevMode
,
548 UNICODE_STRING ustrDevice
;
549 WCHAR awcDevice
[CCHDEVICENAME
];
551 ULONG cbSize
, cbExtra
;
552 DEVMODEW dmReg
, *pdm
;
554 DPRINT("Enter NtUserEnumDisplaySettings(%ls, %ld)\n",
555 pustrDevice
? pustrDevice
->Buffer
: 0, iModeNum
);
559 /* Initialize destination string */
560 RtlInitEmptyUnicodeString(&ustrDevice
, awcDevice
, sizeof(awcDevice
));
564 /* Probe the UNICODE_STRING and the buffer */
565 ProbeForRead(pustrDevice
, sizeof(UNICODE_STRING
), 1);
566 ProbeForRead(pustrDevice
->Buffer
, pustrDevice
->Length
, 1);
568 /* Copy the string */
569 RtlCopyUnicodeString(&ustrDevice
, pustrDevice
);
571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
573 _SEH2_YIELD(return _SEH2_GetExceptionCode());
577 pustrDevice
= &ustrDevice
;
580 /* Acquire global USER lock */
581 UserEnterExclusive();
583 if (iModeNum
== ENUM_REGISTRY_SETTINGS
)
585 /* Get the registry settings */
586 Status
= UserEnumRegistryDisplaySettings(pustrDevice
, &dmReg
);
589 else if (iModeNum
== ENUM_CURRENT_SETTINGS
)
591 /* Get the current settings */
592 Status
= UserEnumCurrentDisplaySettings(pustrDevice
, &pdm
);
596 /* Get specified settings */
597 Status
= UserEnumDisplaySettings(pustrDevice
, iModeNum
, &pdm
, dwFlags
);
603 /* Did we succeed? */
604 if (NT_SUCCESS(Status
))
606 /* Copy some information back */
609 ProbeForRead(lpDevMode
, sizeof(DEVMODEW
), 1);
610 cbSize
= lpDevMode
->dmSize
;
611 cbExtra
= lpDevMode
->dmDriverExtra
;
613 ProbeForWrite(lpDevMode
, cbSize
+ cbExtra
, 1);
614 /* Output what we got */
615 RtlCopyMemory(lpDevMode
, pdm
, min(cbSize
, pdm
->dmSize
));
617 /* output private/extra driver data */
618 if (cbExtra
> 0 && pdm
->dmDriverExtra
> 0)
620 RtlCopyMemory((PCHAR
)lpDevMode
+ cbSize
,
621 (PCHAR
)pdm
+ pdm
->dmSize
,
622 min(cbExtra
, pdm
->dmDriverExtra
));
625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
627 Status
= _SEH2_GetExceptionCode();
635 BOOL APIENTRY
UserClipCursor(RECTL
*prcl
);
636 VOID APIENTRY
UserRedrawDesktop();
637 HCURSOR FASTCALL
UserSetCursor(PCURICON_OBJECT NewCursor
, BOOL ForceChange
);
641 UserChangeDisplaySettings(
642 PUNICODE_STRING pustrDevice
,
649 LONG lResult
= DISP_CHANGE_SUCCESSFUL
;
655 /* If no DEVMODE is given, use registry settings */
658 /* Get the registry settings */
659 Status
= UserEnumRegistryDisplaySettings(pustrDevice
, &dm
);
660 if (!NT_SUCCESS(Status
))
662 DPRINT1("Could not load registry settings\n");
663 return DISP_CHANGE_BADPARAM
;
666 else if (pdm
->dmSize
< FIELD_OFFSET(DEVMODEW
, dmFields
))
667 return DISP_CHANGE_BADMODE
; /* This is what winXP SP3 returns */
672 if ((dm
.dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
)) != (DM_PELSWIDTH
| DM_PELSHEIGHT
))
674 DPRINT1("devmode doesn't specify the resolution.\n");
675 return DISP_CHANGE_BADMODE
;
679 ppdev
= EngpGetPDEV(pustrDevice
);
682 DPRINT1("failed to get PDEV\n");
683 return DISP_CHANGE_BADPARAM
;
687 if(dm
.dmBitsPerPel
== 0 || !(dm
.dmFields
& DM_BITSPERPEL
))
689 dm
.dmBitsPerPel
= ppdev
->pdmwDev
->dmBitsPerPel
;
690 dm
.dmFields
|= DM_BITSPERPEL
;
693 if((dm
.dmFields
& DM_DISPLAYFREQUENCY
) && (dm
.dmDisplayFrequency
== 0))
694 dm
.dmDisplayFrequency
= ppdev
->pdmwDev
->dmDisplayFrequency
;
696 /* Look for the requested DEVMODE */
697 pdm
= PDEVOBJ_pdmMatchDevMode(ppdev
, &dm
);
700 DPRINT1("Could not find a matching DEVMODE\n");
701 lResult
= DISP_CHANGE_BADMODE
;
704 else if (flags
& CDS_TEST
)
706 /* It's possible, go ahead! */
707 lResult
= DISP_CHANGE_SUCCESSFUL
;
711 /* Shall we update the registry? */
712 if (flags
& CDS_UPDATEREGISTRY
)
714 /* Open the local or global settings key */
715 Status
= UserOpenDisplaySettingsKey(&hkey
, pustrDevice
, flags
& CDS_GLOBAL
);
716 if (NT_SUCCESS(Status
))
718 /* Store the settings */
719 RegWriteDisplaySettings(hkey
, pdm
);
721 /* Close the registry key */
726 DPRINT1("Could not open registry key\n");
727 lResult
= DISP_CHANGE_NOTUPDATED
;
731 /* Check if DEVMODE matches the current mode */
732 if (pdm
== ppdev
->pdmwDev
&& !(flags
& CDS_RESET
))
734 DPRINT1("DEVMODE matches, nothing to do\n");
738 /* Shall we apply the settings? */
739 if (!(flags
& CDS_NORESET
))
743 /* Remove mouse pointer */
744 UserSetCursor(NULL
, TRUE
);
746 /* Do the mode switch */
747 ulResult
= PDEVOBJ_bSwitchMode(ppdev
, pdm
);
749 /* Restore mouse pointer, no hooks called */
750 UserSetCursorPos(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
, FALSE
);
752 /* Check for failure */
755 DPRINT1("failed to set mode\n");
756 lResult
= (lResult
== DISP_CHANGE_NOTUPDATED
) ?
757 DISP_CHANGE_FAILED
: DISP_CHANGE_RESTART
;
762 /* Update the system metrics */
765 //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
767 /* Remove all cursor clipping */
768 UserClipCursor(NULL
);
770 pdesk
= IntGetActiveDesktop();
771 //IntHideDesktop(pdesk);
773 /* Send WM_DISPLAYCHANGE to all toplevel windows */
774 co_IntSendMessageTimeout(HWND_BROADCAST
,
776 (WPARAM
)ppdev
->gdiinfo
.cBitsPixel
,
777 (LPARAM
)(ppdev
->gdiinfo
.ulHorzRes
+ (ppdev
->gdiinfo
.ulVertRes
<< 16)),
782 //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
788 /* Release the PDEV */
789 PDEVOBJ_vRelease(ppdev
);
796 NtUserChangeDisplaySettings(
797 PUNICODE_STRING pustrDevice
,
798 LPDEVMODEW lpDevMode
,
803 WCHAR awcDevice
[CCHDEVICENAME
];
804 UNICODE_STRING ustrDevice
;
808 /* Check arguments */
809 if ((dwflags
!= CDS_VIDEOPARAMETERS
&& lParam
!= NULL
) ||
812 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
813 return DISP_CHANGE_BADPARAM
;
817 if ((dwflags
& (CDS_GLOBAL
|CDS_NORESET
)) && !(dwflags
& CDS_UPDATEREGISTRY
))
819 return DISP_CHANGE_BADFLAGS
;
822 /* Copy the device name */
825 /* Initialize destination string */
826 RtlInitEmptyUnicodeString(&ustrDevice
, awcDevice
, sizeof(awcDevice
));
830 /* Probe the UNICODE_STRING and the buffer */
831 ProbeForRead(pustrDevice
, sizeof(UNICODE_STRING
), 1);
832 ProbeForRead(pustrDevice
->Buffer
, pustrDevice
->Length
, 1);
834 /* Copy the string */
835 RtlCopyUnicodeString(&ustrDevice
, pustrDevice
);
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
839 /* Set and return error */
840 SetLastNtError(_SEH2_GetExceptionCode());
841 _SEH2_YIELD(return DISP_CHANGE_BADPARAM
);
845 pustrDevice
= &ustrDevice
;
853 /* Probe the size field of the structure */
854 ProbeForRead(lpDevMode
, sizeof(dmLocal
.dmSize
), 1);
856 /* Calculate usable size */
857 dmLocal
.dmSize
= min(sizeof(dmLocal
), lpDevMode
->dmSize
);
859 /* Probe and copy the full DEVMODE */
860 ProbeForRead(lpDevMode
, dmLocal
.dmSize
, 1);
861 RtlCopyMemory(&dmLocal
, lpDevMode
, dmLocal
.dmSize
);
863 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
865 /* Set and return error */
866 SetLastNtError(_SEH2_GetExceptionCode());
867 _SEH2_YIELD(return DISP_CHANGE_BADPARAM
);
871 /* Check for extra parameters */
872 if (dmLocal
.dmDriverExtra
> 0)
875 DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
876 dmLocal
.dmDriverExtra
= 0;
879 /* Use the local structure */
880 lpDevMode
= &dmLocal
;
883 // FIXME: Copy videoparameters
885 /* Acquire global USER lock */
886 UserEnterExclusive();
888 /* Call internal function */
889 lRet
= UserChangeDisplaySettings(pustrDevice
, lpDevMode
, hwnd
, dwflags
, NULL
);