reactos/subsystems/win32/win32k/ntuser/display.c
Jérôme Gardou aebd9f2971 [WIN32K]
More PDEVOBJ_vRelease fun

svn path=/branches/reactos-yarotows/; revision=46528
2010-03-28 22:09:45 +00:00

892 lines
23 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Video initialization and display settings
* FILE: subsystems/win32/win32k/ntuser/display.c
* PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
#include <w32k.h>
#include <intrin.h>
#define NDEBUG
#include <debug.h>
PDEVOBJ *gpdevPrimary;
const PWCHAR KEY_ROOT = L"";
const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
NTSTATUS
NTAPI
UserEnumDisplayDevices(
PUNICODE_STRING pustrDevice,
DWORD iDevNum,
PDISPLAY_DEVICEW pdispdev,
DWORD dwFlags);
VOID
RegWriteSZ(HKEY hkey, PWSTR pwszValue, PWSTR pwszData)
{
UNICODE_STRING ustrValue;
UNICODE_STRING ustrData;
RtlInitUnicodeString(&ustrValue, pwszValue);
RtlInitUnicodeString(&ustrData, pwszData);
ZwSetValueKey(hkey, &ustrValue, 0, REG_SZ, &ustrData, ustrData.Length + sizeof(WCHAR));
}
VOID
RegWriteDWORD(HKEY hkey, PWSTR pwszValue, DWORD dwData)
{
UNICODE_STRING ustrValue;
RtlInitUnicodeString(&ustrValue, pwszValue);
ZwSetValueKey(hkey, &ustrValue, 0, REG_DWORD, &dwData, sizeof(DWORD));
}
BOOL
RegReadDWORD(HKEY hkey, PWSTR pwszValue, PDWORD pdwData)
{
NTSTATUS Status;
ULONG cbSize = sizeof(DWORD);
Status = RegQueryValue(hkey, pwszValue, REG_DWORD, pdwData, &cbSize);
return NT_SUCCESS(Status);
}
VOID
RegWriteDisplaySettings(HKEY hkey, PDEVMODEW pdm)
{
RegWriteDWORD(hkey, L"DefaultSettings.BitsPerPel", pdm->dmBitsPerPel);
RegWriteDWORD(hkey, L"DefaultSettings.XResolution", pdm->dmPelsWidth);
RegWriteDWORD(hkey, L"DefaultSettings.YResolution", pdm->dmPelsHeight);
RegWriteDWORD(hkey, L"DefaultSettings.Flags", pdm->dmDisplayFlags);
RegWriteDWORD(hkey, L"DefaultSettings.VRefresh", pdm->dmDisplayFrequency);
RegWriteDWORD(hkey, L"DefaultSettings.XPanning", pdm->dmPanningWidth);
RegWriteDWORD(hkey, L"DefaultSettings.YPanning", pdm->dmPanningHeight);
RegWriteDWORD(hkey, L"DefaultSettings.Orientation", pdm->dmDisplayOrientation);
RegWriteDWORD(hkey, L"DefaultSettings.FixedOutput", pdm->dmDisplayFixedOutput);
RegWriteDWORD(hkey, L"Attach.RelativeX", pdm->dmPosition.x);
RegWriteDWORD(hkey, L"Attach.RelativeY", pdm->dmPosition.y);
// RegWriteDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", pdm->);
}
VOID
RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm)
{
DWORD dwValue;
RtlZeroMemory(pdm, sizeof(DEVMODEW));
if (RegReadDWORD(hkey, L"DefaultSettings.BitsPerPel", &dwValue))
{
pdm->dmBitsPerPel = dwValue;
pdm->dmFields |= DM_BITSPERPEL;
}
if (RegReadDWORD(hkey, L"DefaultSettings.XResolution", &dwValue))
{
pdm->dmPelsWidth = dwValue;
// pdm->dmFields |= DM_XRESOLUTION;
}
if (RegReadDWORD(hkey, L"DefaultSettings.YResolution", &dwValue))
{
pdm->dmPelsHeight = dwValue;
pdm->dmFields |= DM_YRESOLUTION;
}
if (RegReadDWORD(hkey, L"DefaultSettings.Flags", &dwValue))
{
pdm->dmDisplayFlags = dwValue;
pdm->dmFields |= DM_BITSPERPEL;
}
if (RegReadDWORD(hkey, L"DefaultSettings.VRefresh", &dwValue))
{
pdm->dmDisplayFrequency = dwValue;
pdm->dmFields |= DM_DISPLAYFREQUENCY;
}
if (RegReadDWORD(hkey, L"DefaultSettings.XPanning", &dwValue))
{
pdm->dmPanningWidth = dwValue;
pdm->dmFields |= DM_PANNINGWIDTH;
}
if (RegReadDWORD(hkey, L"DefaultSettings.YPanning", &dwValue))
{
pdm->dmPanningHeight = dwValue;
pdm->dmFields |= DM_PANNINGHEIGHT;
}
if (RegReadDWORD(hkey, L"DefaultSettings.Orientation", &dwValue))
{
pdm->dmDisplayOrientation = dwValue;
pdm->dmFields |= DM_DISPLAYORIENTATION;
}
if (RegReadDWORD(hkey, L"DefaultSettings.FixedOutput", &dwValue))
{
pdm->dmDisplayFixedOutput = dwValue;
pdm->dmFields |= DM_BITSPERPEL;
}
if (RegReadDWORD(hkey, L"Attach.RelativeX", &dwValue))
{
pdm->dmPosition.x = dwValue;
pdm->dmFields |= DM_POSITION;
}
if (RegReadDWORD(hkey, L"Attach.RelativeY", &dwValue))
{
pdm->dmPosition.y = dwValue;
pdm->dmFields |= DM_POSITION;
}
// RegReadDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", &pdm->);
}
enum
{
VF_USEVGA = 0x1,
};
BOOL
InitDisplayDriver(
PUNICODE_STRING pustrRegPath,
FLONG flags)
{
// PWSTR pwszDriverName;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
NTSTATUS Status;
/* Setup QueryTable for direct registry query */
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED|RTL_QUERY_REGISTRY_DIRECT;
/* Check if vga mode is requested */
if (flags & VF_USEVGA)
{
DWORD dwVgaCompatible;
/* */
QueryTable[0].Name = L"VgaCompatible";
QueryTable[0].EntryContext = &dwVgaCompatible;
/* Check if the driver is vga */
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
pustrRegPath->Buffer,
QueryTable,
NULL,
NULL);
if (!dwVgaCompatible)
{
/* This driver is not a vga driver */
return FALSE;
}
}
#if 0
/* Query the adapter's registry path */
swprintf(awcBuffer, L"\\Device\\Video%lu", iDevNum);
QueryTable[0].Name = pGraphicsDevice->szNtDeviceName;
/* Set string for the registry key */
ustrRegistryPath.Buffer = pdispdev->DeviceKey;
ustrRegistryPath.Length = 128;
ustrRegistryPath.MaximumLength = 128;
QueryTable[0].EntryContext = &ustrRegistryPath;
/* Query the registry */
Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
L"VIDEO",
QueryTable,
NULL,
NULL);
RegQueryValue(KEY_VIDEO, awcBuffer, REG_SZ, pdispdev->DeviceKey, 256);
{
HANDLE hmod;
hmod = EngLoadImage(pwszDriverName);
/* Jump to next name */
pwszDriverName += wcslen(pwszDriverName) + 1;
}
while (pwszDriverName < 0);
#endif
return 0;
}
NTSTATUS
NTAPI
DisplayDriverQueryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
PWSTR pwszRegKey = ValueData;
PGRAPHICS_DEVICE pGraphicsDevice;
UNICODE_STRING ustrDeviceName, ustrDisplayDrivers, ustrDescription;
NTSTATUS Status;
WCHAR awcBuffer[128];
ULONG cbSize;
HKEY hkey;
DEVMODEW dmDefault;
UNREFERENCED_PARAMETER(ValueLength);
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(EntryContext);
DPRINT1("DisplayDriverQueryRoutine(%S, %S);\n",
ValueName, pwszRegKey);
/* Check if we have a correct entry */
if (ValueType != REG_SZ || ValueName[0] != '\\')
{
/* Something else, just skip it */
return STATUS_SUCCESS;
}
/* Open the driver's registry key */
Status = RegOpenKey(pwszRegKey, &hkey);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open registry key\n");
return STATUS_SUCCESS;
}
// HACK: only use 1st adapter
//if (ValueName[13] != '0')
// return STATUS_SUCCESS;
/* Query the diplay drivers */
cbSize = sizeof(awcBuffer) - 10;
Status = RegQueryValue(hkey,
L"InstalledDisplayDrivers",
REG_MULTI_SZ,
awcBuffer,
&cbSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status);
ZwClose(hkey);
return STATUS_SUCCESS;
}
/* Initialize the UNICODE_STRING */
ustrDisplayDrivers.Buffer = awcBuffer;
ustrDisplayDrivers.MaximumLength = cbSize;
ustrDisplayDrivers.Length = cbSize;
/* Set Buffer for description and size of remaining buffer */
ustrDescription.Buffer = awcBuffer + (cbSize / sizeof(WCHAR));
cbSize = sizeof(awcBuffer) - cbSize;
/* Query the device string */
Status = RegQueryValue(hkey,
L"Device Description",
REG_SZ,
ustrDescription.Buffer,
&cbSize);
if (NT_SUCCESS(Status))
{
ustrDescription.MaximumLength = cbSize;
ustrDescription.Length = cbSize;
}
else
{
RtlInitUnicodeString(&ustrDescription, L"<unknown>");
}
/* Query the default settings */
RegReadDisplaySettings(hkey, &dmDefault);
/* Close the registry key */
ZwClose(hkey);
/* Register the device with GDI */
RtlInitUnicodeString(&ustrDeviceName, ValueName);
pGraphicsDevice = EngpRegisterGraphicsDevice(&ustrDeviceName,
&ustrDisplayDrivers,
&ustrDescription,
&dmDefault);
// FIXME: what to do with pGraphicsDevice?
return STATUS_SUCCESS;
}
BOOL InitSysParams();
BOOL
InitVideo(FLONG flags)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
NTSTATUS Status;
DPRINT1("----------------------------- InitVideo() -------------------------------\n");
/* Setup QueryTable for registry query */
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].QueryRoutine = DisplayDriverQueryRoutine;
/* Query the registry */
Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
L"VIDEO",
QueryTable,
NULL,
NULL);
InitSysParams();
return 0;
}
NTSTATUS
NTAPI
UserEnumDisplayDevices(
PUNICODE_STRING pustrDevice,
DWORD iDevNum,
PDISPLAY_DEVICEW pdispdev,
DWORD dwFlags)
{
PGRAPHICS_DEVICE pGraphicsDevice;
ULONG cbSize;
HKEY hkey;
NTSTATUS Status;
/* Ask gdi for the GRAPHICS_DEVICE */
pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, iDevNum, 0);
if (!pGraphicsDevice)
{
/* No device found */
DPRINT1("No GRAPHICS_DEVICE found\n");
return STATUS_UNSUCCESSFUL;
}
/* Open thhe device map registry key */
Status = RegOpenKey(KEY_VIDEO, &hkey);
if (!NT_SUCCESS(Status))
{
/* No device found */
DPRINT1("Could not open reg key\n");
return STATUS_UNSUCCESSFUL;
}
/* Query the registry path */
cbSize = sizeof(pdispdev->DeviceKey);
RegQueryValue(hkey,
pGraphicsDevice->szNtDeviceName,
REG_SZ,
pdispdev->DeviceKey,
&cbSize);
/* Close registry key */
ZwClose(hkey);
/* Copy device name, device string and StateFlags */
wcsncpy(pdispdev->DeviceName, pGraphicsDevice->szWinDeviceName, 32);
wcsncpy(pdispdev->DeviceString, pGraphicsDevice->pwszDescription, 128);
pdispdev->StateFlags = pGraphicsDevice->StateFlags;
// FIXME: fill in DEVICE ID
return STATUS_SUCCESS;
}
//NTSTATUS
BOOL
NTAPI
NtUserEnumDisplayDevices(
PUNICODE_STRING pustrDevice,
DWORD iDevNum,
PDISPLAY_DEVICEW pDisplayDevice,
DWORD dwFlags)
{
UNICODE_STRING ustrDevice;
WCHAR awcDevice[CCHDEVICENAME];
DISPLAY_DEVICEW dispdev;
NTSTATUS Status;
DPRINT1("Enter NtUserEnumDisplayDevices(%p, %ls, %ld)\n",
pustrDevice, pustrDevice ? pustrDevice->Buffer : 0, iDevNum);
// FIXME: HACK, desk.cpl passes broken crap
if (pustrDevice && iDevNum != 0)
return FALSE;
dispdev.cb = sizeof(DISPLAY_DEVICEW);
if (pustrDevice)
{
/* Initialize destination string */
RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
_SEH2_TRY
{
/* Probe the UNICODE_STRING and the buffer */
ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
/* Copy the string */
RtlCopyUnicodeString(&ustrDevice, pustrDevice);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
// _SEH2_YIELD(return _SEH2_GetExceptionCode());
_SEH2_YIELD(return NT_SUCCESS(_SEH2_GetExceptionCode()));
}
_SEH2_END
if (ustrDevice.Length > 0)
pustrDevice = &ustrDevice;
else
pustrDevice = NULL;
}
/* Acquire global USER lock */
UserEnterExclusive();
/* Call the internal function */
Status = UserEnumDisplayDevices(pustrDevice, iDevNum, &dispdev, dwFlags);
/* Release lock */
UserLeave();
/* On success copy data to caller */
if (NT_SUCCESS(Status))
{
/* Enter SEH */
_SEH2_TRY
{
/* First probe the cb field */
ProbeForWrite(&pDisplayDevice->cb, sizeof(DWORD), 1);
/* Check the buffer size */
if (pDisplayDevice->cb)
{
/* Probe the output buffer */
pDisplayDevice->cb = min(pDisplayDevice->cb, sizeof(dispdev));
ProbeForWrite(pDisplayDevice, pDisplayDevice->cb, 1);
/* Copy as much as the given buffer allows */
RtlCopyMemory(pDisplayDevice, &dispdev, pDisplayDevice->cb);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
}
DPRINT1("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status);
/* Return the result */
// return Status;
return NT_SUCCESS(Status); // FIXME
}
NTSTATUS
NTAPI
UserEnumCurrentDisplaySettings(
PUNICODE_STRING pustrDevice,
PDEVMODEW *ppdm)
{
PPDEVOBJ ppdev;
/* Get the PDEV for the device */
ppdev = EngpGetPDEV(pustrDevice);
if (!ppdev)
{
/* No device found */
DPRINT1("No PDEV found!\n");
return STATUS_UNSUCCESSFUL;
}
*ppdm = ppdev->pdmwDev;
PDEVOBJ_vRelease(ppdev);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
UserEnumDisplaySettings(
PUNICODE_STRING pustrDevice,
DWORD iModeNum,
LPDEVMODEW *ppdm,
DWORD dwFlags)
{
PGRAPHICS_DEVICE pGraphicsDevice;
PDEVMODEENTRY pdmentry;
ULONG i, iFoundMode;
DPRINT1("Enter UserEnumDisplaySettings('%ls', %ld)\n",
pustrDevice ? pustrDevice->Buffer : NULL, iModeNum);
/* Ask gdi for the GRAPHICS_DEVICE */
pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0, 0);
if (!pGraphicsDevice)
{
/* No device found */
DPRINT1("No device found!\n");
return FALSE;
}
if (iModeNum == 0)
{
DPRINT1("Should initialize modes somehow\n");
// Update DISPLAY_DEVICEs?
}
iFoundMode = 0;
for (i = 0; i < pGraphicsDevice->cDevModes; i++)
{
pdmentry = &pGraphicsDevice->pDevModeList[i];
// if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) || // FIXME!
// (dwFlags & EDS_RAWMODE))
{
/* Is this the one we want? */
if (iFoundMode == iModeNum)
{
*ppdm = pdmentry->pdm;
return STATUS_SUCCESS;
}
/* Increment number of found modes */
iFoundMode++;
}
}
/* Nothing was found */
return STATUS_INVALID_PARAMETER;
}
NTSTATUS
NTAPI
UserOpenDisplaySettingsKey(
OUT PHKEY phkey,
IN PUNICODE_STRING pustrDevice,
IN BOOL bGlobal)
{
HKEY hkey;
DISPLAY_DEVICEW dispdev;
NTSTATUS Status;
/* Get device info */
Status = UserEnumDisplayDevices(pustrDevice, 0, &dispdev, 0);
if (!NT_SUCCESS(Status))
return Status;
if (bGlobal)
{
// FIXME: need to fix the registry key somehow
}
/* Open the registry key */
Status = RegOpenKey(dispdev.DeviceKey, &hkey);
if (!NT_SUCCESS(Status))
return Status;
*phkey = hkey;
return Status;
}
NTSTATUS
NTAPI
UserEnumRegistryDisplaySettings(
IN PUNICODE_STRING pustrDevice,
OUT LPDEVMODEW pdm)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
APIENTRY
NtUserEnumDisplaySettings(
IN PUNICODE_STRING pustrDevice,
IN DWORD iModeNum,
OUT LPDEVMODEW lpDevMode,
IN DWORD dwFlags)
{
UNICODE_STRING ustrDevice;
WCHAR awcDevice[CCHDEVICENAME];
NTSTATUS Status;
ULONG cbSize, cbExtra;
DEVMODEW dmReg, *pdm;
DPRINT1("Enter NtUserEnumDisplaySettings(%ls, %ld)\n",
pustrDevice ? pustrDevice->Buffer:0, iModeNum);
if (pustrDevice)
{
/* Initialize destination string */
RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
_SEH2_TRY
{
/* Probe the UNICODE_STRING and the buffer */
ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
/* Copy the string */
RtlCopyUnicodeString(&ustrDevice, pustrDevice);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END
pustrDevice = &ustrDevice;
}
/* Acquire global USER lock */
UserEnterExclusive();
if (iModeNum == ENUM_REGISTRY_SETTINGS)
{
/* Get the registry settings */
Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
pdm = &dmReg;
}
else if (iModeNum == ENUM_CURRENT_SETTINGS)
{
/* Get the current settings */
Status = UserEnumCurrentDisplaySettings(pustrDevice, &pdm);
}
else
{
/* Get specified settings */
Status = UserEnumDisplaySettings(pustrDevice, iModeNum, &pdm, dwFlags);
}
/* Release lock */
UserLeave();
/* Did we succeed? */
if (NT_SUCCESS(Status))
{
/* Copy some information back */
_SEH2_TRY
{
ProbeForRead(lpDevMode, sizeof(DEVMODEW), 1);
cbSize = lpDevMode->dmSize;
cbExtra = lpDevMode->dmDriverExtra;
ProbeForWrite(lpDevMode, cbSize + cbExtra, 1);
lpDevMode->dmPelsWidth = pdm->dmPelsWidth;
lpDevMode->dmPelsHeight = pdm->dmPelsHeight;
lpDevMode->dmBitsPerPel = pdm->dmBitsPerPel;
lpDevMode->dmDisplayFrequency = pdm->dmDisplayFrequency;
lpDevMode->dmDisplayFlags = pdm->dmDisplayFlags;
/* output private/extra driver data */
if (cbExtra > 0 && pdm->dmDriverExtra > 0)
{
RtlCopyMemory((PCHAR)lpDevMode + cbSize,
(PCHAR)pdm + pdm->dmSize,
min(cbExtra, pdm->dmDriverExtra));
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
return Status;
}
LONG
APIENTRY
UserChangeDisplaySettings(
PUNICODE_STRING pustrDevice,
LPDEVMODEW pdm,
HWND hwnd,
DWORD flags,
LPVOID lParam)
{
DEVMODEW dmReg;
LONG lResult = DISP_CHANGE_SUCCESSFUL;
HKEY hkey;
NTSTATUS Status;
PPDEVOBJ ppdev;
/* If no DEVMODE is given, use registry settings */
if (!pdm)
{
/* Get the registry settings */
Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
if (!NT_SUCCESS(Status))
{
DPRINT1("Could not load registry settings\n");
return DISP_CHANGE_BADPARAM;
}
pdm = &dmReg;
}
/* Get the PDEV */
ppdev = EngpGetPDEV(pustrDevice);
if (!ppdev)
{
DPRINT1("failed to get PDEV\n");
return DISP_CHANGE_BADPARAM;
}
/* Look for the requested DEVMODE */
pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
if (!pdm)
{
DPRINT1("Could not find a matching DEVMODE\n");
lResult = DISP_CHANGE_BADMODE;
goto leave;
}
/* Shall we update the registry? */
if (flags & CDS_UPDATEREGISTRY)
{
/* Open the local or global settings key */
Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, flags & CDS_GLOBAL);
if (NT_SUCCESS(Status))
{
/* Store the settings */
RegWriteDisplaySettings(hkey, pdm);
/* Close the registry key */
ZwClose(hkey);
}
else
{
DPRINT1("Could not open registry key\n");
lResult = DISP_CHANGE_NOTUPDATED;
}
}
/* Check if DEVMODE matches the current mode */
if (pdm == ppdev->pdmwDev && !(flags & CDS_RESET))
{
DPRINT1("DEVMODE matches, nothing to do\n");
goto leave;
}
/* Shall we apply the settings? */
if (!(flags & CDS_NORESET))
{
if (!PDEVOBJ_bSwitchMode(ppdev, pdm))
{
DPRINT1("failed to set mode\n");
lResult = (lResult == DISP_CHANGE_NOTUPDATED) ?
DISP_CHANGE_FAILED : DISP_CHANGE_RESTART;
}
/* Send message */
}
leave:
PDEVOBJ_vRelease(ppdev);
return lResult;
}
LONG
APIENTRY
NtUserChangeDisplaySettings(
PUNICODE_STRING pustrDevice,
LPDEVMODEW lpDevMode,
HWND hwnd,
DWORD dwflags,
LPVOID lParam)
{
WCHAR awcDevice[CCHDEVICENAME];
UNICODE_STRING ustrDevice;
DEVMODEW dmLocal;
LONG Ret;
/* Check arguments */
if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
(hwnd != NULL))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return DISP_CHANGE_BADPARAM;
}
/* Check flags */
if ((dwflags & (CDS_GLOBAL|CDS_NORESET)) && !(dwflags & CDS_UPDATEREGISTRY))
{
return DISP_CHANGE_BADFLAGS;
}
/* Copy the device name */
if (pustrDevice)
{
/* Initialize destination string */
RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
_SEH2_TRY
{
/* Probe the UNICODE_STRING and the buffer */
ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
/* Copy the string */
RtlCopyUnicodeString(&ustrDevice, pustrDevice);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
_SEH2_YIELD(return DISP_CHANGE_BADPARAM);
}
_SEH2_END
pustrDevice = &ustrDevice;
}
/* Copy devmode */
if (lpDevMode)
{
_SEH2_TRY
{
ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1);
dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize);
ProbeForRead(lpDevMode, dmLocal.dmSize, 1);
RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize);
dmLocal.dmSize = sizeof(dmLocal);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
_SEH2_YIELD(return DISP_CHANGE_BADPARAM);
}
_SEH2_END
if (dmLocal.dmDriverExtra > 0)
{
DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
dmLocal.dmDriverExtra = 0;
}
lpDevMode = &dmLocal;
}
// FIXME: Copy videoparameters
/* Call internal function */
Ret = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
return Ret;
}