From 57da2ced7678abd5a6e3cae80e380ff2e6472ff4 Mon Sep 17 00:00:00 2001 From: Gregor Anich Date: Tue, 3 Aug 2004 19:55:58 +0000 Subject: [PATCH] Implement NtUserEnumDisplaySettings/IntEnumDisplaySettings. svn path=/trunk/; revision=10377 --- reactos/subsys/win32k/ntuser/stubs.c | 15 +- reactos/subsys/win32k/ntuser/windc.c | 81 +++++++++- reactos/subsys/win32k/objects/dc.c | 213 ++++++++++++++++++++++++++- 3 files changed, 290 insertions(+), 19 deletions(-) diff --git a/reactos/subsys/win32k/ntuser/stubs.c b/reactos/subsys/win32k/ntuser/stubs.c index 0f7455b9fe3..28a022e2c24 100644 --- a/reactos/subsys/win32k/ntuser/stubs.c +++ b/reactos/subsys/win32k/ntuser/stubs.c @@ -1,4 +1,4 @@ -/* $Id: stubs.c,v 1.45 2004/04/29 20:26:35 weiden Exp $ +/* $Id: stubs.c,v 1.46 2004/08/03 19:55:57 blight Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -259,19 +259,6 @@ NtUserEnumDisplayMonitors( return 0; } -BOOL -STDCALL -NtUserEnumDisplaySettings( - PUNICODE_STRING lpszDeviceName, - DWORD iModeNum, - LPDEVMODEW lpDevMode, /* FIXME is this correct? */ - DWORD dwFlags ) -{ - UNIMPLEMENTED - - return 0; -} - DWORD STDCALL NtUserEvent( diff --git a/reactos/subsys/win32k/ntuser/windc.c b/reactos/subsys/win32k/ntuser/windc.c index 1d19421a186..962cdc4aebe 100644 --- a/reactos/subsys/win32k/ntuser/windc.c +++ b/reactos/subsys/win32k/ntuser/windc.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: windc.c,v 1.66 2004/05/10 17:07:18 weiden Exp $ +/* $Id: windc.c,v 1.67 2004/08/03 19:55:57 blight Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -833,4 +833,83 @@ DceResetActiveDCEs(PWINDOW_OBJECT Window, int DeltaX, int DeltaY) DCE_UnlockList(); } +/* FIXME: find header file for this prototype. */ +extern BOOL FASTCALL +IntEnumDisplaySettings( + PUNICODE_STRING lpszDeviceName, + DWORD iModeNum, + LPDEVMODEW lpDevMode, + DWORD dwFlags); + +#define COPY_DEVMODE_VALUE_TO_CALLER(dst, src, member) \ + Status = MmCopyToCaller(&(dst)->member, &(src)->member, sizeof ((src)->member)); \ + if (!NT_SUCCESS(Status)) \ + { \ + SetLastNtError(Status); \ + ExFreePool(src); \ + return FALSE; \ + } + +BOOL +STDCALL +NtUserEnumDisplaySettings( + PUNICODE_STRING lpszDeviceName, + DWORD iModeNum, + LPDEVMODEW lpDevMode, /* FIXME is this correct? */ + DWORD dwFlags ) +{ + NTSTATUS Status; + LPDEVMODEW pSafeDevMode; + DWORD Size = 0, ExtraSize = 0; + + Status = MmCopyFromCaller(&Size, &lpDevMode->dmSize, sizeof (lpDevMode->dmSize)); + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); + return FALSE; + } + Status = MmCopyFromCaller(&ExtraSize, &lpDevMode->dmDriverExtra, sizeof (lpDevMode->dmDriverExtra)); + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); + return FALSE; + } + pSafeDevMode = ExAllocatePool(PagedPool, Size + ExtraSize); + if (pSafeDevMode == NULL) + { + SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); + return DISP_CHANGE_FAILED; + } + pSafeDevMode->dmSize = Size; + pSafeDevMode->dmDriverExtra = ExtraSize; + + if (!IntEnumDisplaySettings(lpszDeviceName, iModeNum, pSafeDevMode, dwFlags)) + { + ExFreePool(pSafeDevMode); + return FALSE; + } + + COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsWidth); + COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsHeight); + COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmBitsPerPel); + COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFrequency); + COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFlags); + + /* output private/extra driver data */ + if (ExtraSize > 0) + { + Status = MmCopyToCaller((PCHAR)lpDevMode + Size, (PCHAR)pSafeDevMode + Size, ExtraSize); + if (!NT_SUCCESS(Status)) + { + SetLastNtError(Status); + ExFreePool(pSafeDevMode); + return FALSE; + } + } + + return TRUE; +} + +#undef COPY_DEVMODE_VALUE_TO_CALLER + /* EOF */ diff --git a/reactos/subsys/win32k/objects/dc.c b/reactos/subsys/win32k/objects/dc.c index aa914c8bc87..e525934e42b 100644 --- a/reactos/subsys/win32k/objects/dc.c +++ b/reactos/subsys/win32k/objects/dc.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: dc.c,v 1.145 2004/07/17 21:10:25 weiden Exp $ +/* $Id: dc.c,v 1.146 2004/08/03 19:55:58 blight Exp $ * * DC.C - Device context functions * @@ -497,7 +497,7 @@ IntCreatePrimarySurface() CurrentName = DriverFileNames.Buffer; GotDriver = FALSE; while (!GotDriver && - CurrentName < DriverFileNames.Buffer + DriverFileNames.Length) + CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR))) { /* Get the DDI driver's entry point */ GDEnableDriver = DRIVER_FindDDIDriver(CurrentName); @@ -524,11 +524,11 @@ IntCreatePrimarySurface() { /* Skip to the next name but never get past the Unicode string */ while (L'\0' != *CurrentName && - CurrentName < DriverFileNames.Buffer + DriverFileNames.Length) + CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR))) { CurrentName++; } - if (CurrentName < DriverFileNames.Buffer + DriverFileNames.Length) + if (CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR))) { CurrentName++; } @@ -558,6 +558,7 @@ IntCreatePrimarySurface() } /* Allocate a phyical device handle from the driver */ + PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW); if (SetupDevMode(&PrimarySurface.DMW, DisplayNumber)) { PrimarySurface.PDev = PrimarySurface.DriverFunctions.EnablePDEV( @@ -586,6 +587,7 @@ IntCreatePrimarySurface() if (DoDefault) { RtlZeroMemory(&(PrimarySurface.DMW), sizeof(DEVMODEW)); + PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW); PrimarySurface.PDev = PrimarySurface.DriverFunctions.EnablePDEV( &PrimarySurface.DMW, L"", @@ -2163,4 +2165,207 @@ IntSetDCColor(HDC hDC, ULONG Object, COLORREF Color) return CLR_INVALID; } +#define SIZEOF_DEVMODEW_300 188 +#define SIZEOF_DEVMODEW_400 212 +#define SIZEOF_DEVMODEW_500 220 + +/*! \brief Enumerate possible display settings for the given display... + * + * \todo Make thread safe!? + * \todo Don't ignore lpszDeviceName + * \todo Implement non-raw mode (only return settings valid for driver and monitor) + */ +BOOL FASTCALL +IntEnumDisplaySettings( + PUNICODE_STRING lpszDeviceName, + DWORD iModeNum, + LPDEVMODEW lpDevMode, + DWORD dwFlags) +{ + static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL; + static DWORD SizeOfCachedDevModes = 0; + LPDEVMODEW CachedMode = NULL; + DEVMODEW DevMode; + INT Size, OldSize; + ULONG DisplayNumber = 0; /* only default display supported */ + + if (lpDevMode->dmSize != SIZEOF_DEVMODEW_300 && + lpDevMode->dmSize != SIZEOF_DEVMODEW_400 && + lpDevMode->dmSize != SIZEOF_DEVMODEW_500) + { + SetLastWin32Error(STATUS_INVALID_PARAMETER); + return FALSE; + } + + if (iModeNum == ENUM_CURRENT_SETTINGS) + { + CachedMode = &PrimarySurface.DMW; + assert(CachedMode->dmSize > 0); + } + else if (iModeNum == ENUM_REGISTRY_SETTINGS) + { + RtlZeroMemory(&DevMode, sizeof (DevMode)); + DevMode.dmSize = sizeof (DevMode); + DevMode.dmDriverExtra = 0; + if (SetupDevMode(&DevMode, DisplayNumber)) + CachedMode = &DevMode; + else + { + SetLastWin32Error(0); /* FIXME: use error code */ + return FALSE; + } + /* FIXME: Maybe look for the matching devmode supplied by the + * driver so we can provide driver private/extra data? + */ + } + else + { + if (iModeNum == 0 || CachedDevModes == NULL) /* query modes from drivers */ + { + UNICODE_STRING DriverFileNames; + LPWSTR CurrentName; + DRVENABLEDATA DrvEnableData; + + /* Retrieve DDI driver names from registry */ + RtlInitUnicodeString(&DriverFileNames, NULL); + if (!FindDriverFileNames(&DriverFileNames, DisplayNumber)) + { + DPRINT1("FindDriverFileNames failed\n"); + return FALSE; + } + + /* + * DriverFileNames may be a list of drivers in REG_SZ_MULTI format, + * scan all of them until a good one found. + */ + CurrentName = DriverFileNames.Buffer; + for (;CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)); + CurrentName += wcslen(CurrentName) + 1) + { + INT i; + PGD_ENABLEDRIVER GDEnableDriver; + + /* Get the DDI driver's entry point */ + GDEnableDriver = DRIVER_FindDDIDriver(CurrentName); + if (NULL == GDEnableDriver) + { + DPRINT("FindDDIDriver failed for %S\n", CurrentName); + continue; + } + + /* Call DDI driver's EnableDriver function */ + RtlZeroMemory(&DrvEnableData, sizeof (DrvEnableData)); + + if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof (DrvEnableData), &DrvEnableData)) + { + DPRINT("DrvEnableDriver failed for %S\n", CurrentName); + continue; + } + + CachedDevModesEnd = CachedDevModes; + + /* find DrvGetModes function */ + for (i = 0; i < DrvEnableData.c; i++) + { + PDRVFN DrvFn = DrvEnableData.pdrvfn + i; + PGD_GETMODES GetModes; + INT SizeNeeded, SizeUsed; + + if (DrvFn->iFunc != INDEX_DrvGetModes) + continue; + + GetModes = (PGD_GETMODES)DrvFn->pfn; + + /* make sure we have enough memory to hold the modes */ + SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), 0, NULL); + if (SizeNeeded <= 0) + { + DPRINT("DrvGetModes failed for %S\n", CurrentName); + break; + } + + SizeUsed = CachedDevModesEnd - CachedDevModes; + if (SizeOfCachedDevModes - SizeUsed < SizeNeeded) + { + PVOID NewBuffer; + + SizeOfCachedDevModes += SizeNeeded; + NewBuffer = ExAllocatePool(PagedPool, SizeOfCachedDevModes); + if (NewBuffer == NULL) + { + /* clean up */ + ExFreePool(CachedDevModes); + SizeOfCachedDevModes = 0; + CachedDevModes = NULL; + CachedDevModesEnd = NULL; + SetLastWin32Error(STATUS_NO_MEMORY); + return FALSE; + } + if (CachedDevModes != NULL) + { + RtlCopyMemory(NewBuffer, CachedDevModes, SizeUsed); + ExFreePool(CachedDevModes); + } + CachedDevModes = NewBuffer; + CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed); + } + + /* query modes */ + SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), + SizeOfCachedDevModes - SizeUsed, + CachedDevModesEnd); + if (SizeNeeded <= 0) + { + DPRINT("DrvGetModes failed for %S\n", CurrentName); + } + else + { + CachedDevModesEnd = (DEVMODEW *)((PCHAR)CachedDevModesEnd + SizeNeeded); + } + break; + } + } + + RtlFreeUnicodeString(&DriverFileNames); + } + + /* return cached info */ + CachedMode = CachedDevModes; + if (CachedMode >= CachedDevModesEnd) + { + SetLastWin32Error(STATUS_NO_MORE_ENTRIES); + return FALSE; + } + while (iModeNum-- > 0 && CachedMode < CachedDevModesEnd) + { + assert(CachedMode->dmSize > 0); + CachedMode = (DEVMODEW *)((PCHAR)CachedMode + CachedMode->dmSize + CachedMode->dmDriverExtra); + } + if (CachedMode >= CachedDevModesEnd) + { + SetLastWin32Error(STATUS_NO_MORE_ENTRIES); + return FALSE; + } + } + + assert(CachedMode != NULL); + + Size = OldSize = lpDevMode->dmSize; + if (Size > CachedMode->dmSize) + Size = CachedMode->dmSize; + RtlCopyMemory(lpDevMode, CachedMode, Size); + RtlZeroMemory((PCHAR)lpDevMode + Size, OldSize - Size); + lpDevMode->dmSize = OldSize; + + Size = OldSize = lpDevMode->dmDriverExtra; + if (Size > CachedMode->dmDriverExtra) + Size = CachedMode->dmDriverExtra; + RtlCopyMemory((PCHAR)lpDevMode + lpDevMode->dmSize, + (PCHAR)CachedMode + CachedMode->dmSize, Size); + RtlZeroMemory((PCHAR)lpDevMode + lpDevMode->dmSize + Size, OldSize - Size); + lpDevMode->dmDriverExtra = OldSize; + + return TRUE; +} + /* EOF */