/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: subsystems/win32/win32k/ntuser/display.c
- * PURPOSE: display settings
- * COPYRIGHT: Copyright 2007 ReactOS
- *
+ * 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)
*/
-/* INCLUDES ******************************************************************/
-
#include <w32k.h>
+#include <intrin.h>
+
#define NDEBUG
#include <debug.h>
-#define SIZEOF_DEVMODEW_300 188
-#define SIZEOF_DEVMODEW_400 212
-#define SIZEOF_DEVMODEW_500 220
+PDEVOBJ *gpdevPrimary;
-/* PUBLIC FUNCTIONS ***********************************************************/
+const PWCHAR KEY_ROOT = L"";
+const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
NTSTATUS
-APIENTRY
-NtUserEnumDisplaySettings(
- PUNICODE_STRING pusDeviceName,
- DWORD iModeNum,
- LPDEVMODEW lpDevMode, /* FIXME is this correct? */
- DWORD dwFlags )
+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;
- LPDEVMODEW pSafeDevMode;
- PUNICODE_STRING pusSafeDeviceName = NULL;
- UNICODE_STRING usSafeDeviceName;
- USHORT Size = 0, ExtraSize = 0;
+ ULONG cbSize = sizeof(DWORD);
+ Status = RegQueryValue(hkey, pwszValue, REG_DWORD, pdwData, &cbSize);
+ return NT_SUCCESS(Status);
+}
- /* Copy the devmode */
- _SEH2_TRY
+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))
{
- ProbeForRead(lpDevMode, sizeof(DEVMODEW), 1);
- Size = lpDevMode->dmSize;
- ExtraSize = lpDevMode->dmDriverExtra;
+ pdm->dmDisplayFrequency = dwValue;
+ pdm->dmFields |= DM_DISPLAYFREQUENCY;
}
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ if (RegReadDWORD(hkey, L"DefaultSettings.XPanning", &dwValue))
{
- DPRINT("FIXME ? : Out of range of DEVMODEW size \n");
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ pdm->dmPanningWidth = dwValue;
+ pdm->dmFields |= DM_PANNINGWIDTH;
}
- _SEH2_END;
+ 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->);
+
+}
+
+
- if (Size != sizeof(DEVMODEW))
+
+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)
{
- return STATUS_BUFFER_TOO_SMALL;
+ 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;
+ }
}
- pSafeDevMode = ExAllocatePool(PagedPool, Size + ExtraSize);
- if (pSafeDevMode == NULL)
+#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);
+
{
- return STATUS_NO_MEMORY;
+ HANDLE hmod;
+
+ hmod = EngLoadImage(pwszDriverName);
+
+ /* Jump to next name */
+ pwszDriverName += wcslen(pwszDriverName) + 1;
}
- pSafeDevMode->dmSize = Size;
- pSafeDevMode->dmDriverExtra = ExtraSize;
+ while (pwszDriverName < 0);
+#endif
- /* Copy the device name */
- if (pusDeviceName != NULL)
+ 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] != '\\')
{
- Status = IntSafeCopyUnicodeString(&usSafeDeviceName, pusDeviceName);
- if (!NT_SUCCESS(Status))
+ /* 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)
{
- ExFreePool(pSafeDevMode);
- return Status;
+ Status = _SEH2_GetExceptionCode();
}
- pusSafeDeviceName = &usSafeDeviceName;
+ _SEH2_END
}
- /* Call internal function */
- Status = IntEnumDisplaySettings(pusSafeDeviceName, iModeNum, pSafeDevMode, dwFlags);
+ DPRINT1("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status);
+ /* Return the result */
+// return Status;
+ return NT_SUCCESS(Status); // FIXME
+}
- if (pusSafeDeviceName != NULL)
- RtlFreeUnicodeString(pusSafeDeviceName);
+NTSTATUS
+NTAPI
+UserEnumCurrentDisplaySettings(
+ PUNICODE_STRING pustrDevice,
+ PDEVMODEW *ppdm)
+{
+ PPDEVOBJ ppdev;
- if (!NT_SUCCESS(Status))
+ /* Get the PDEV for the device */
+ ppdev = EngpGetPDEV(pustrDevice);
+ if (!ppdev)
{
- ExFreePool(pSafeDevMode);
+ /* 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
}
- /* Copy some information back */
- _SEH2_TRY
+ /* 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)
{
- ProbeForWrite(lpDevMode,Size + ExtraSize, 1);
- lpDevMode->dmPelsWidth = pSafeDevMode->dmPelsWidth;
- lpDevMode->dmPelsHeight = pSafeDevMode->dmPelsHeight;
- lpDevMode->dmBitsPerPel = pSafeDevMode->dmBitsPerPel;
- lpDevMode->dmDisplayFrequency = pSafeDevMode->dmDisplayFrequency;
- lpDevMode->dmDisplayFlags = pSafeDevMode->dmDisplayFlags;
+ /* 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);
- /* output private/extra driver data */
- if (ExtraSize > 0)
+ /* Copy the string */
+ RtlCopyUnicodeString(&ustrDevice, pustrDevice);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- memcpy((PCHAR)lpDevMode + Size, (PCHAR)pSafeDevMode + Size, ExtraSize);
+ _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);
}
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ else
{
- Status = _SEH2_GetExceptionCode();
+ /* 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;
}
- _SEH2_END;
- ExFreePool(pSafeDevMode);
return Status;
}
LONG
APIENTRY
-NtUserChangeDisplaySettings(
- PUNICODE_STRING lpszDeviceName,
- LPDEVMODEW lpDevMode,
+UserChangeDisplaySettings(
+ PUNICODE_STRING pustrDevice,
+ LPDEVMODEW pdm,
HWND hwnd,
- DWORD dwflags,
+ DWORD flags,
LPVOID lParam)
{
- NTSTATUS Status = STATUS_SUCCESS;
- LPDEVMODEW lpSafeDevMode = NULL;
- DEVMODEW DevMode;
- PUNICODE_STRING pSafeDeviceName = NULL;
- UNICODE_STRING SafeDeviceName;
- LONG Ret;
-
- /* Check arguments */
-#ifdef CDS_VIDEOPARAMETERS
- if (dwflags != CDS_VIDEOPARAMETERS && lParam != NULL)
-#else
- if (lParam != NULL)
-#endif
+ DEVMODEW dmReg;
+ LONG lResult = DISP_CHANGE_SUCCESSFUL;
+ HKEY hkey;
+ NTSTATUS Status;
+ PPDEVOBJ ppdev;
+
+ /* If no DEVMODE is given, use registry settings */
+ if (!pdm)
{
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ /* 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;
}
- if (hwnd != NULL)
+ /* 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;
}
- /* Copy devmode */
- if (lpDevMode != NULL)
+ /* 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
{
- ProbeForRead(lpDevMode, sizeof(DevMode.dmSize), 1);
- DevMode.dmSize = lpDevMode->dmSize;
- DevMode.dmSize = min(sizeof(DevMode), DevMode.dmSize);
- ProbeForRead(lpDevMode, DevMode.dmSize, 1);
- RtlCopyMemory(&DevMode, lpDevMode, DevMode.dmSize);
+ /* 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)
{
- Status = _SEH2_GetExceptionCode();
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
}
_SEH2_END
- if (!NT_SUCCESS(Status))
+ pustrDevice = &ustrDevice;
+ }
+
+ /* Copy devmode */
+ if (lpDevMode)
+ {
+ _SEH2_TRY
{
- SetLastNtError(Status);
- return DISP_CHANGE_BADPARAM;
+ 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);
}
-
- if (DevMode.dmDriverExtra > 0)
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
- DevMode.dmDriverExtra = 0;
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
}
- lpSafeDevMode = &DevMode;
- }
+ _SEH2_END
- /* Copy the device name */
- if (lpszDeviceName != NULL)
- {
- Status = IntSafeCopyUnicodeString(&SafeDeviceName, lpszDeviceName);
- if (!NT_SUCCESS(Status))
+ if (dmLocal.dmDriverExtra > 0)
{
- SetLastNtError(Status);
- return DISP_CHANGE_BADPARAM;
+ DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
+ dmLocal.dmDriverExtra = 0;
}
- pSafeDeviceName = &SafeDeviceName;
+ lpDevMode = &dmLocal;
}
- /* Call internal function */
- Ret = IntChangeDisplaySettings(pSafeDeviceName, lpSafeDevMode, dwflags, lParam);
+ // FIXME: Copy videoparameters
- if (pSafeDeviceName != NULL)
- RtlFreeUnicodeString(pSafeDeviceName);
+ /* Call internal function */
+ Ret = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
return Ret;
}