mirror of
https://github.com/reactos/reactos.git
synced 2025-01-11 16:51:06 +00:00
912ce51ae6
Sync with trunk head (r48826) svn path=/branches/cmake-bringup/; revision=48831
1778 lines
54 KiB
C
1778 lines
54 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* PURPOSE: Functions for creation and destruction of DCs
|
|
* FILE: subsystem/win32/win32k/objects/device.c
|
|
* PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
|
|
*/
|
|
|
|
#include <win32k.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
// TODO: proper implementation of LDEVOBJ and PDEVOBJ interface
|
|
|
|
/*static*/ PDEVOBJ PrimarySurface;
|
|
PPDEVOBJ pPrimarySurface = &PrimarySurface;
|
|
static KEVENT VideoDriverNeedsPreparation;
|
|
static KEVENT VideoDriverPrepared;
|
|
PDC defaultDCstate = NULL;
|
|
|
|
PSIZEL
|
|
FASTCALL
|
|
PDEV_sizl(PPDEVOBJ ppdev, PSIZEL psizl)
|
|
{
|
|
if (ppdev->flFlags & PDEV_META_DEVICE)
|
|
{
|
|
psizl->cx = ppdev->ulHorzRes;
|
|
psizl->cy = ppdev->ulVertRes;
|
|
}
|
|
else
|
|
{
|
|
psizl->cx = ppdev->gdiinfo.ulHorzRes;
|
|
psizl->cy = ppdev->gdiinfo.ulVertRes;
|
|
}
|
|
return psizl;
|
|
}
|
|
|
|
NTSTATUS FASTCALL
|
|
InitDcImpl(VOID)
|
|
{
|
|
KeInitializeEvent(&VideoDriverNeedsPreparation, SynchronizationEvent, TRUE);
|
|
KeInitializeEvent(&VideoDriverPrepared, NotificationEvent, FALSE);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static BOOLEAN FASTCALL
|
|
GetRegistryPath(PUNICODE_STRING RegistryPath, ULONG DisplayNumber)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
WCHAR DeviceNameBuffer[20];
|
|
NTSTATUS Status;
|
|
|
|
swprintf(DeviceNameBuffer, L"\\Device\\Video%lu", DisplayNumber);
|
|
RtlInitUnicodeString(RegistryPath, NULL);
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[0].Name = DeviceNameBuffer;
|
|
QueryTable[0].EntryContext = RegistryPath;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
|
|
L"VIDEO",
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("No \\Device\\Video%lu value in DEVICEMAP\\VIDEO found\n", DisplayNumber);
|
|
return FALSE;
|
|
}
|
|
|
|
DPRINT("RegistryPath %wZ\n", RegistryPath);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
EnumDisplayQueryRoutine(IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext)
|
|
{
|
|
if ((Context == NULL) && ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)))
|
|
{
|
|
*(PULONG)EntryContext = ValueLength;
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Value data: %S %d\n", ValueData, ValueLength);
|
|
RtlCopyMemory(Context, ValueData, ValueLength);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static BOOL FASTCALL
|
|
FindDriverFileNames(PUNICODE_STRING DriverFileNames, ULONG DisplayNumber)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
UNICODE_STRING RegistryPath;
|
|
NTSTATUS Status;
|
|
PWCHAR DriverNames = NULL;
|
|
ULONG Length = 0;
|
|
|
|
if (! GetRegistryPath(&RegistryPath, DisplayNumber))
|
|
{
|
|
DPRINT("GetRegistryPath failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
QueryTable[0].Name = L"InstalledDisplayDrivers";
|
|
QueryTable[0].EntryContext = &Length;
|
|
QueryTable[0].QueryRoutine = EnumDisplayQueryRoutine;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryPath.Buffer,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
// DPRINT1("Status: %lx\n", Status);
|
|
if (Length)
|
|
{
|
|
DriverNames = ExAllocatePoolWithTag(PagedPool, Length, TAG_DRIVER);
|
|
// DPRINT1("Length allocated: %d\n", Length);
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryPath.Buffer,
|
|
QueryTable,
|
|
DriverNames,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) DriverNames = NULL;
|
|
}
|
|
|
|
ExFreePoolWithTag(RegistryPath.Buffer, TAG_RTLREGISTRY);
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
|
|
return FALSE;
|
|
}
|
|
|
|
RtlInitUnicodeString(DriverFileNames, DriverNames);
|
|
DriverFileNames->Length = Length;
|
|
DriverFileNames->MaximumLength = Length;
|
|
//DPRINT1("DriverFileNames %wZ\n", DriverFileNames);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static NTSTATUS APIENTRY
|
|
DevModeCallback(IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext)
|
|
{
|
|
PDEVMODEW DevMode = (PDEVMODEW) Context;
|
|
|
|
DPRINT("Found registry value for name %S: type %d, length %d\n",
|
|
ValueName, ValueType, ValueLength);
|
|
|
|
if (REG_DWORD == ValueType && sizeof(DWORD) == ValueLength)
|
|
{
|
|
if (0 == _wcsicmp(ValueName, L"DefaultSettings.BitsPerPel"))
|
|
{
|
|
DevMode->dmBitsPerPel = *((DWORD *) ValueData);
|
|
}
|
|
else if (0 == _wcsicmp(ValueName, L"DefaultSettings.Flags"))
|
|
{
|
|
DevMode->dmDisplayFlags = *((DWORD *) ValueData);
|
|
}
|
|
else if (0 == _wcsicmp(ValueName, L"DefaultSettings.VRefresh"))
|
|
{
|
|
DevMode->dmDisplayFrequency = *((DWORD *) ValueData);
|
|
}
|
|
else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XPanning"))
|
|
{
|
|
DevMode->dmPanningWidth = *((DWORD *) ValueData);
|
|
}
|
|
else if (0 == _wcsicmp(ValueName, L"DefaultSettings.XResolution"))
|
|
{
|
|
DevMode->dmPelsWidth = *((DWORD *) ValueData);
|
|
}
|
|
else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YPanning"))
|
|
{
|
|
DevMode->dmPanningHeight = *((DWORD *) ValueData);
|
|
}
|
|
else if (0 == _wcsicmp(ValueName, L"DefaultSettings.YResolution"))
|
|
{
|
|
DevMode->dmPelsHeight = *((DWORD *) ValueData);
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static BOOL FASTCALL
|
|
SetupDevMode(PDEVMODEW DevMode, ULONG DisplayNumber)
|
|
{
|
|
UNICODE_STRING RegistryPath;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
NTSTATUS Status;
|
|
BOOLEAN Valid = TRUE;
|
|
|
|
if (!GetRegistryPath(&RegistryPath, DisplayNumber))
|
|
{
|
|
DPRINT("GetRegistryPath failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].QueryRoutine = DevModeCallback;
|
|
QueryTable[0].Flags = 0;
|
|
QueryTable[0].Name = NULL;
|
|
QueryTable[0].EntryContext = NULL;
|
|
QueryTable[0].DefaultType = REG_NONE;
|
|
QueryTable[0].DefaultData = NULL;
|
|
QueryTable[0].DefaultLength = 0;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryPath.Buffer,
|
|
QueryTable,
|
|
DevMode,
|
|
NULL);
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("RtlQueryRegistryValues for %wZ failed with status 0x%08x\n",
|
|
&RegistryPath, Status);
|
|
Valid = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("dmBitsPerPel %d dmDisplayFrequency %d dmPelsWidth %d dmPelsHeight %d\n",
|
|
DevMode->dmBitsPerPel, DevMode->dmDisplayFrequency,
|
|
DevMode->dmPelsWidth, DevMode->dmPelsHeight);
|
|
if (0 == DevMode->dmBitsPerPel || 0 == DevMode->dmDisplayFrequency
|
|
|| 0 == DevMode->dmPelsWidth || 0 == DevMode->dmPelsHeight)
|
|
{
|
|
DPRINT("Not all required devmode members are set\n");
|
|
Valid = FALSE;
|
|
}
|
|
}
|
|
|
|
ExFreePoolWithTag(RegistryPath.Buffer, TAG_RTLREGISTRY);
|
|
|
|
if (! Valid)
|
|
{
|
|
RtlZeroMemory(DevMode, sizeof(DEVMODEW));
|
|
}
|
|
|
|
return Valid;
|
|
}
|
|
|
|
static BOOL FASTCALL
|
|
IntPrepareDriver(VOID)
|
|
{
|
|
PFN_DrvEnableDriver GDEnableDriver;
|
|
DRVENABLEDATA DED;
|
|
UNICODE_STRING DriverFileNames;
|
|
PWSTR CurrentName;
|
|
BOOL GotDriver;
|
|
BOOL DoDefault;
|
|
ULONG DisplayNumber;
|
|
LARGE_INTEGER Zero;
|
|
BOOLEAN ret = FALSE;
|
|
|
|
Zero.QuadPart = 0;
|
|
if (STATUS_SUCCESS != KeWaitForSingleObject(&VideoDriverNeedsPreparation, Executive, KernelMode, TRUE, &Zero))
|
|
{
|
|
/* Concurrent access. Wait for VideoDriverPrepared event */
|
|
if (STATUS_SUCCESS == KeWaitForSingleObject(&VideoDriverPrepared, Executive, KernelMode, TRUE, NULL))
|
|
ret = PrimarySurface.PreparedDriver;
|
|
goto cleanup;
|
|
}
|
|
// HAX! Fixme so I can support more than one! So how many?
|
|
for (DisplayNumber = 0; ; DisplayNumber++)
|
|
{
|
|
DPRINT("Trying to load display driver no. %d\n", DisplayNumber);
|
|
|
|
RtlZeroMemory(&PrimarySurface, sizeof(PrimarySurface));
|
|
|
|
// if (!pPrimarySurface) pPrimarySurface = ExAllocatePoolWithTag(PagedPool, gdwDirectDrawContext + sizeof(PDEVOBJ), TAG_GDIPDEV);
|
|
|
|
PrimarySurface.VideoFileObject = DRIVER_FindMPDriver(DisplayNumber);
|
|
|
|
/* Open the miniport driver */
|
|
if (PrimarySurface.VideoFileObject == NULL)
|
|
{
|
|
DPRINT1("FindMPDriver failed\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Retrieve DDI driver names from registry */
|
|
RtlInitUnicodeString(&DriverFileNames, NULL);
|
|
if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
|
|
{
|
|
DPRINT1("FindDriverFileNames failed\n");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
|
|
* scan all of them until a good one found.
|
|
*/
|
|
CurrentName = DriverFileNames.Buffer;
|
|
GotDriver = FALSE;
|
|
while (!GotDriver &&
|
|
CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
|
|
{
|
|
/* Get the DDI driver's entry point */
|
|
GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
|
|
if (NULL == GDEnableDriver)
|
|
{
|
|
DPRINT("FindDDIDriver failed for %S\n", CurrentName);
|
|
}
|
|
else
|
|
{
|
|
/* Call DDI driver's EnableDriver function */
|
|
RtlZeroMemory(&DED, sizeof(DED));
|
|
|
|
if (! GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof(DED), &DED))
|
|
{
|
|
DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
|
|
}
|
|
else
|
|
{
|
|
GotDriver = TRUE;
|
|
}
|
|
}
|
|
|
|
if (! GotDriver)
|
|
{
|
|
/* Skip to the next name but never get past the Unicode string */
|
|
while (L'\0' != *CurrentName &&
|
|
CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
|
|
{
|
|
CurrentName++;
|
|
}
|
|
if (CurrentName < DriverFileNames.Buffer + (DriverFileNames.Length / sizeof (WCHAR)))
|
|
{
|
|
CurrentName++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!GotDriver)
|
|
{
|
|
ObDereferenceObject(PrimarySurface.VideoFileObject);
|
|
ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
|
|
DPRINT1("No suitable DDI driver found\n");
|
|
continue;
|
|
}
|
|
|
|
DPRINT1("Display driver %S loaded\n", CurrentName);
|
|
|
|
ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
|
|
|
|
DPRINT("Building DDI Functions\n");
|
|
|
|
/* Construct DDI driver function dispatch table */
|
|
if (!DRIVER_BuildDDIFunctions(&DED, &PrimarySurface.DriverFunctions))
|
|
{
|
|
ObDereferenceObject(PrimarySurface.VideoFileObject);
|
|
DPRINT1("BuildDDIFunctions failed\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Allocate a phyical device handle from the driver */
|
|
// Support DMW.dmSize + DMW.dmDriverExtra & Alloc DMW then set prt pdmwDev.
|
|
PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
|
|
if (SetupDevMode(&PrimarySurface.DMW, DisplayNumber))
|
|
{
|
|
PrimarySurface.dhpdev = PrimarySurface.DriverFunctions.EnablePDEV(
|
|
&PrimarySurface.DMW,
|
|
L"",
|
|
HS_DDI_MAX,
|
|
PrimarySurface.ahsurf,
|
|
sizeof(PrimarySurface.gdiinfo),
|
|
&PrimarySurface.gdiinfo,
|
|
sizeof(PrimarySurface.devinfo),
|
|
&PrimarySurface.devinfo,
|
|
NULL,
|
|
L"",
|
|
(HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
|
|
DoDefault = (NULL == PrimarySurface.dhpdev);
|
|
if (DoDefault)
|
|
{
|
|
DPRINT1("DrvEnablePDev with registry parameters failed\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DoDefault = TRUE;
|
|
}
|
|
|
|
if (DoDefault)
|
|
{
|
|
RtlZeroMemory(&(PrimarySurface.DMW), sizeof(DEVMODEW));
|
|
PrimarySurface.DMW.dmSize = sizeof (PrimarySurface.DMW);
|
|
PrimarySurface.dhpdev = PrimarySurface.DriverFunctions.EnablePDEV(
|
|
&PrimarySurface.DMW,
|
|
L"",
|
|
HS_DDI_MAX,
|
|
PrimarySurface.ahsurf,
|
|
sizeof(PrimarySurface.gdiinfo),
|
|
&PrimarySurface.gdiinfo,
|
|
sizeof(PrimarySurface.devinfo),
|
|
&PrimarySurface.devinfo,
|
|
NULL,
|
|
L"",
|
|
(HANDLE) (PrimarySurface.VideoFileObject->DeviceObject));
|
|
|
|
if (NULL == PrimarySurface.dhpdev)
|
|
{
|
|
ObDereferenceObject(PrimarySurface.VideoFileObject);
|
|
DPRINT1("DrvEnablePDEV with default parameters failed\n");
|
|
DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
|
|
continue;
|
|
}
|
|
|
|
// Update the primary surface with what we really got
|
|
PrimarySurface.DMW.dmPelsWidth = PrimarySurface.gdiinfo.ulHorzRes;
|
|
PrimarySurface.DMW.dmPelsHeight = PrimarySurface.gdiinfo.ulVertRes;
|
|
PrimarySurface.DMW.dmBitsPerPel = PrimarySurface.gdiinfo.cBitsPixel;
|
|
PrimarySurface.DMW.dmDisplayFrequency = PrimarySurface.gdiinfo.ulVRefresh;
|
|
}
|
|
|
|
if (!PrimarySurface.DMW.dmDriverExtra)
|
|
{
|
|
PrimarySurface.pdmwDev = &PrimarySurface.DMW; // HAX!
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("WARNING!!! Need to Alloc DMW !!!!!!\n");
|
|
}
|
|
// Dont remove until we finish testing other drivers.
|
|
if (PrimarySurface.DMW.dmDriverExtra != 0)
|
|
{
|
|
DPRINT1("**** DMW extra = %u bytes. Please report to ros-dev@reactos.org ****\n", PrimarySurface.DMW.dmDriverExtra);
|
|
}
|
|
|
|
if (0 == PrimarySurface.gdiinfo.ulLogPixelsX)
|
|
{
|
|
DPRINT("Adjusting gdiinfo.ulLogPixelsX\n");
|
|
PrimarySurface.gdiinfo.ulLogPixelsX = 96;
|
|
}
|
|
if (0 == PrimarySurface.gdiinfo.ulLogPixelsY)
|
|
{
|
|
DPRINT("Adjusting gdiinfo.ulLogPixelsY\n");
|
|
PrimarySurface.gdiinfo.ulLogPixelsY = 96;
|
|
}
|
|
|
|
PrimarySurface.Pointer.Exclude.right = -1;
|
|
|
|
DPRINT("calling completePDev\n");
|
|
|
|
/* Complete initialization of the physical device */
|
|
PrimarySurface.DriverFunctions.CompletePDEV(
|
|
PrimarySurface.dhpdev,
|
|
(HDEV)&PrimarySurface);
|
|
|
|
DPRINT("calling DRIVER_ReferenceDriver\n");
|
|
|
|
DRIVER_ReferenceDriver(L"DISPLAY");
|
|
|
|
PrimarySurface.PreparedDriver = TRUE;
|
|
PrimarySurface.DisplayNumber = DisplayNumber;
|
|
PrimarySurface.flFlags = PDEV_DISPLAY; // Hard set,, add more flags.
|
|
PrimarySurface.hsemDevLock = (PERESOURCE)EngCreateSemaphore();
|
|
// Should be null,, but make sure for now.
|
|
PrimarySurface.pvGammaRamp = NULL;
|
|
PrimarySurface.ppdevNext = NULL; // Fixme! We need to support more than display drvs.
|
|
PrimarySurface.ppdevParent = NULL; // Always NULL if primary.
|
|
PrimarySurface.pGraphicsDevice = NULL; // Fixme!
|
|
PrimarySurface.pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), TAG_EDDGBL);
|
|
if (PrimarySurface.pEDDgpl)
|
|
{
|
|
RtlZeroMemory( PrimarySurface.pEDDgpl ,sizeof(EDD_DIRECTDRAW_GLOBAL));
|
|
ret = TRUE;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
KeSetEvent(&VideoDriverPrepared, 1, FALSE);
|
|
return ret;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntPrepareDriverIfNeeded(VOID)
|
|
{
|
|
return (PrimarySurface.PreparedDriver ? TRUE : IntPrepareDriver());
|
|
}
|
|
|
|
static BOOL FASTCALL
|
|
PrepareVideoPrt(VOID)
|
|
{
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
BOOL Prepare = TRUE;
|
|
ULONG Length = sizeof(BOOL);
|
|
PIO_STACK_LOCATION StackPtr;
|
|
LARGE_INTEGER StartOffset;
|
|
PFILE_OBJECT FileObject = PrimarySurface.VideoFileObject;
|
|
PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
|
|
|
|
DPRINT("PrepareVideoPrt() called\n");
|
|
|
|
KeClearEvent(&PrimarySurface.VideoFileObject->Event);
|
|
|
|
ObReferenceObjectByPointer(FileObject, 0, IoFileObjectType, KernelMode);
|
|
|
|
StartOffset.QuadPart = 0;
|
|
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
|
|
DeviceObject,
|
|
(PVOID) &Prepare,
|
|
Length,
|
|
&StartOffset,
|
|
NULL,
|
|
&Iosb);
|
|
if (NULL == Irp)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* Set up IRP Data */
|
|
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
|
Irp->RequestorMode = KernelMode;
|
|
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
|
|
Irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
|
|
Irp->Flags |= IRP_WRITE_OPERATION;
|
|
|
|
/* Setup Stack Data */
|
|
StackPtr = IoGetNextIrpStackLocation(Irp);
|
|
StackPtr->FileObject = PrimarySurface.VideoFileObject;
|
|
StackPtr->Parameters.Write.Key = 0;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (STATUS_PENDING == Status)
|
|
{
|
|
KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, TRUE, 0);
|
|
Status = Iosb.Status;
|
|
}
|
|
|
|
return NT_SUCCESS(Status);
|
|
}
|
|
|
|
|
|
BOOL FASTCALL
|
|
IntCreatePrimarySurface(VOID)
|
|
{
|
|
SIZEL SurfSize;
|
|
RECTL SurfaceRect;
|
|
SURFOBJ *SurfObj;
|
|
BOOL calledFromUser;
|
|
|
|
if (! IntPrepareDriverIfNeeded())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (! PrepareVideoPrt())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DPRINT("calling EnableSurface\n");
|
|
/* Enable the drawing surface */
|
|
PrimarySurface.pSurface =
|
|
PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.dhpdev);
|
|
if (NULL == PrimarySurface.pSurface)
|
|
{
|
|
/* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, FALSE);*/
|
|
PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.dhpdev);
|
|
ObDereferenceObject(PrimarySurface.VideoFileObject);
|
|
DPRINT1("DrvEnableSurface failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, TRUE);
|
|
|
|
calledFromUser = UserIsEntered(); //fixme: possibly upgrade a shared lock
|
|
if (!calledFromUser)
|
|
{
|
|
UserEnterExclusive();
|
|
}
|
|
|
|
/* attach monitor */
|
|
IntAttachMonitor(&PrimarySurface, PrimarySurface.DisplayNumber);
|
|
|
|
SurfObj = EngLockSurface(PrimarySurface.pSurface);
|
|
SurfObj->dhpdev = PrimarySurface.dhpdev;
|
|
SurfSize = SurfObj->sizlBitmap;
|
|
SurfaceRect.left = SurfaceRect.top = 0;
|
|
SurfaceRect.right = SurfObj->sizlBitmap.cx;
|
|
SurfaceRect.bottom = SurfObj->sizlBitmap.cy;
|
|
/* FIXME - why does EngEraseSurface() sometimes crash?
|
|
EngEraseSurface(SurfObj, &SurfaceRect, 0); */
|
|
|
|
/* Put the pointer in the center of the screen */
|
|
gpsi->ptCursor.x = (SurfaceRect.right - SurfaceRect.left) / 2;
|
|
gpsi->ptCursor.y = (SurfaceRect.bottom - SurfaceRect.top) / 2;
|
|
|
|
/* Give the PDEV a MovePointer function */
|
|
PrimarySurface.pfnMovePointer = PrimarySurface.DriverFunctions.MovePointer;
|
|
if (!PrimarySurface.pfnMovePointer)
|
|
PrimarySurface.pfnMovePointer = EngMovePointer;
|
|
|
|
EngUnlockSurface(SurfObj);
|
|
co_IntShowDesktop(IntGetActiveDesktop(), SurfSize.cx, SurfSize.cy);
|
|
|
|
// Init Primary Displays Device Capabilities.
|
|
IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
|
|
|
|
if (!calledFromUser)
|
|
{
|
|
UserLeave();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID FASTCALL
|
|
IntDestroyPrimarySurface(VOID)
|
|
{
|
|
BOOL calledFromUser;
|
|
|
|
DRIVER_UnreferenceDriver(L"DISPLAY");
|
|
|
|
calledFromUser = UserIsEntered();
|
|
if (!calledFromUser)
|
|
{
|
|
UserEnterExclusive();
|
|
}
|
|
|
|
/* detach monitor */
|
|
IntDetachMonitor(&PrimarySurface);
|
|
|
|
if (!calledFromUser)
|
|
{
|
|
UserLeave();
|
|
}
|
|
|
|
/*
|
|
* FIXME: Hide a mouse pointer there. Also because we have to prevent
|
|
* memory leaks with the Eng* mouse routines.
|
|
*/
|
|
|
|
DPRINT("Reseting display\n" );
|
|
PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, FALSE);
|
|
PrimarySurface.DriverFunctions.DisableSurface(PrimarySurface.dhpdev);
|
|
PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.dhpdev);
|
|
PrimarySurface.PreparedDriver = FALSE;
|
|
KeSetEvent(&VideoDriverNeedsPreparation, 1, FALSE);
|
|
KeResetEvent(&VideoDriverPrepared);
|
|
|
|
DceEmptyCache();
|
|
|
|
ObDereferenceObject(PrimarySurface.VideoFileObject);
|
|
}
|
|
|
|
INT
|
|
FASTCALL
|
|
IntcFonts(PPDEVOBJ pDevObj)
|
|
{
|
|
ULONG_PTR Junk;
|
|
// Msdn DrvQueryFont:
|
|
// If the number of fonts in DEVINFO is -1 and iFace is zero, the driver
|
|
// should return the number of fonts it supports.
|
|
if ( pDevObj->devinfo.cFonts == -1)
|
|
{
|
|
if (pDevObj->DriverFunctions.QueryFont)
|
|
pDevObj->devinfo.cFonts =
|
|
(ULONG)pDevObj->DriverFunctions.QueryFont(pDevObj->dhpdev, 0, 0, &Junk);
|
|
else
|
|
pDevObj->devinfo.cFonts = 0;
|
|
}
|
|
return pDevObj->devinfo.cFonts;
|
|
}
|
|
|
|
//
|
|
// Support multi display/device locks.
|
|
//
|
|
VOID
|
|
FASTCALL
|
|
DC_LockDisplay(HDC hDC)
|
|
{
|
|
PERESOURCE Resource;
|
|
PDC dc = DC_LockDc(hDC);
|
|
if (!dc) return;
|
|
Resource = dc->ppdev->hsemDevLock;
|
|
DC_UnlockDc(dc);
|
|
if (!Resource) return;
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite( Resource , TRUE);
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
DC_UnlockDisplay(HDC hDC)
|
|
{
|
|
PERESOURCE Resource;
|
|
PDC dc = DC_LockDc(hDC);
|
|
if (!dc) return;
|
|
Resource = dc->ppdev->hsemDevLock;
|
|
DC_UnlockDc(dc);
|
|
if (!Resource) return;
|
|
ExReleaseResourceLite( Resource );
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
|
|
//
|
|
// Enumerate HDev
|
|
//
|
|
PPDEVOBJ FASTCALL
|
|
IntEnumHDev(VOID)
|
|
{
|
|
// I guess we will soon have more than one primary surface.
|
|
// This will do for now.
|
|
return &PrimarySurface;
|
|
}
|
|
|
|
|
|
VOID FASTCALL
|
|
IntGdiReferencePdev(PPDEVOBJ ppdev)
|
|
{
|
|
if (!hsemDriverMgmt) hsemDriverMgmt = EngCreateSemaphore(); // Hax, should be in dllmain.c
|
|
IntGdiAcquireSemaphore(hsemDriverMgmt);
|
|
ppdev->cPdevRefs++;
|
|
IntGdiReleaseSemaphore(hsemDriverMgmt);
|
|
}
|
|
|
|
VOID FASTCALL
|
|
IntGdiUnreferencePdev(PPDEVOBJ ppdev, DWORD CleanUpType)
|
|
{
|
|
IntGdiAcquireSemaphore(hsemDriverMgmt);
|
|
ppdev->cPdevRefs--;
|
|
if (!ppdev->cPdevRefs)
|
|
{
|
|
// Handle the destruction of ppdev or PDEVOBJ or PDEVOBJ or PDEV etc.
|
|
}
|
|
IntGdiReleaseSemaphore(hsemDriverMgmt);
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
FASTCALL
|
|
IntGetColorManagementCaps(PPDEVOBJ pDevObj)
|
|
{
|
|
INT ret = CM_NONE;
|
|
|
|
if ( pDevObj->flFlags & PDEV_DISPLAY)
|
|
{
|
|
if (pDevObj->devinfo.iDitherFormat == BMF_8BPP ||
|
|
pDevObj->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP)
|
|
ret = CM_GAMMA_RAMP;
|
|
}
|
|
if (pDevObj->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR)
|
|
ret |= CM_CMYK_COLOR;
|
|
if (pDevObj->devinfo.flGraphicsCaps & GCAPS_ICM)
|
|
ret |= CM_DEVICE_ICM;
|
|
return ret;
|
|
}
|
|
|
|
INT FASTCALL
|
|
IntGdiGetDeviceCaps(PDC dc, INT Index)
|
|
{
|
|
INT ret = 0;
|
|
PPDEVOBJ ppdev = dc->ppdev;
|
|
/* Retrieve capability */
|
|
switch (Index)
|
|
{
|
|
case DRIVERVERSION:
|
|
ret = ppdev->gdiinfo.ulVersion;
|
|
break;
|
|
|
|
case TECHNOLOGY:
|
|
ret = ppdev->gdiinfo.ulTechnology;
|
|
break;
|
|
|
|
case HORZSIZE:
|
|
ret = ppdev->gdiinfo.ulHorzSize;
|
|
break;
|
|
|
|
case VERTSIZE:
|
|
ret = ppdev->gdiinfo.ulVertSize;
|
|
break;
|
|
|
|
case HORZRES:
|
|
ret = ppdev->gdiinfo.ulHorzRes;
|
|
break;
|
|
|
|
case VERTRES:
|
|
ret = ppdev->gdiinfo.ulVertRes;
|
|
break;
|
|
|
|
case LOGPIXELSX:
|
|
ret = ppdev->gdiinfo.ulLogPixelsX;
|
|
break;
|
|
|
|
case LOGPIXELSY:
|
|
ret = ppdev->gdiinfo.ulLogPixelsY;
|
|
break;
|
|
|
|
case CAPS1:
|
|
if ( ppdev->pGraphicsDevice &&
|
|
(((PGRAPHICS_DEVICE)ppdev->pGraphicsDevice)->StateFlags &
|
|
DISPLAY_DEVICE_MIRRORING_DRIVER))
|
|
ret = C1_MIRRORING;
|
|
break;
|
|
|
|
case BITSPIXEL:
|
|
ret = ppdev->gdiinfo.cBitsPixel;
|
|
break;
|
|
|
|
case PLANES:
|
|
ret = ppdev->gdiinfo.cPlanes;
|
|
break;
|
|
|
|
case NUMBRUSHES:
|
|
ret = -1;
|
|
break;
|
|
|
|
case NUMPENS:
|
|
ret = ppdev->gdiinfo.ulNumColors;
|
|
if ( ret != -1 ) ret *= 5;
|
|
break;
|
|
|
|
case NUMFONTS:
|
|
ret = IntcFonts(ppdev);
|
|
break;
|
|
|
|
case NUMCOLORS:
|
|
ret = ppdev->gdiinfo.ulNumColors;
|
|
break;
|
|
|
|
case ASPECTX:
|
|
ret = ppdev->gdiinfo.ulAspectX;
|
|
break;
|
|
|
|
case ASPECTY:
|
|
ret = ppdev->gdiinfo.ulAspectY;
|
|
break;
|
|
|
|
case ASPECTXY:
|
|
ret = ppdev->gdiinfo.ulAspectXY;
|
|
break;
|
|
|
|
case CLIPCAPS:
|
|
ret = CP_RECTANGLE;
|
|
break;
|
|
|
|
case SIZEPALETTE:
|
|
ret = ppdev->gdiinfo.ulNumPalReg;
|
|
break;
|
|
|
|
case NUMRESERVED:
|
|
ret = 20;
|
|
break;
|
|
|
|
case COLORRES:
|
|
ret = ppdev->gdiinfo.ulDACRed +
|
|
ppdev->gdiinfo.ulDACGreen +
|
|
ppdev->gdiinfo.ulDACBlue;
|
|
break;
|
|
|
|
case DESKTOPVERTRES:
|
|
ret = ppdev->gdiinfo.ulVertRes;
|
|
break;
|
|
|
|
case DESKTOPHORZRES:
|
|
ret = ppdev->gdiinfo.ulHorzRes;
|
|
break;
|
|
|
|
case BLTALIGNMENT:
|
|
ret = ppdev->gdiinfo.ulBltAlignment;
|
|
break;
|
|
|
|
case SHADEBLENDCAPS:
|
|
ret = ppdev->gdiinfo.flShadeBlend;
|
|
break;
|
|
|
|
case COLORMGMTCAPS:
|
|
ret = IntGetColorManagementCaps(ppdev);
|
|
break;
|
|
|
|
case PHYSICALWIDTH:
|
|
ret = ppdev->gdiinfo.szlPhysSize.cx;
|
|
break;
|
|
|
|
case PHYSICALHEIGHT:
|
|
ret = ppdev->gdiinfo.szlPhysSize.cy;
|
|
break;
|
|
|
|
case PHYSICALOFFSETX:
|
|
ret = ppdev->gdiinfo.ptlPhysOffset.x;
|
|
break;
|
|
|
|
case PHYSICALOFFSETY:
|
|
ret = ppdev->gdiinfo.ptlPhysOffset.y;
|
|
break;
|
|
|
|
case VREFRESH:
|
|
ret = ppdev->gdiinfo.ulVRefresh;
|
|
break;
|
|
|
|
case RASTERCAPS:
|
|
ret = ppdev->gdiinfo.flRaster;
|
|
break;
|
|
|
|
case CURVECAPS:
|
|
ret = (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
|
|
CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
|
|
break;
|
|
|
|
case LINECAPS:
|
|
ret = (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
|
|
LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
|
|
break;
|
|
|
|
case POLYGONALCAPS:
|
|
ret = (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
|
|
PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
|
|
break;
|
|
|
|
case TEXTCAPS:
|
|
ret = ppdev->gdiinfo.flTextCaps;
|
|
if (ppdev->gdiinfo.ulTechnology) ret |= TC_VA_ABLE;
|
|
ret |= (TC_SO_ABLE|TC_UA_ABLE);
|
|
break;
|
|
|
|
case PDEVICESIZE:
|
|
case SCALINGFACTORX:
|
|
case SCALINGFACTORY:
|
|
default:
|
|
ret = 0;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
INT APIENTRY
|
|
NtGdiGetDeviceCaps(HDC hDC,
|
|
INT Index)
|
|
{
|
|
PDC dc;
|
|
INT ret;
|
|
|
|
dc = DC_LockDc(hDC);
|
|
if (dc == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
ret = IntGdiGetDeviceCaps(dc, Index);
|
|
|
|
DPRINT("(%04x,%d): returning %d\n", hDC, Index, ret);
|
|
|
|
DC_UnlockDc( dc );
|
|
return ret;
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
IntvGetDeviceCaps(
|
|
PPDEVOBJ pDevObj,
|
|
PDEVCAPS pDevCaps)
|
|
{
|
|
ULONG Tmp = 0;
|
|
PGDIINFO pGdiInfo = &pDevObj->gdiinfo;
|
|
|
|
pDevCaps->ulVersion = pGdiInfo->ulVersion;
|
|
pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
|
|
pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000;
|
|
pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000;
|
|
pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize;
|
|
pDevCaps->ulVertSize = pGdiInfo->ulVertSize;
|
|
pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes;
|
|
pDevCaps->ulVertRes = pGdiInfo->ulVertRes;
|
|
pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh;
|
|
pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes;
|
|
pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes;
|
|
pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
|
|
pDevCaps->ulPlanes = pGdiInfo->cPlanes;
|
|
|
|
pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel;
|
|
if (pGdiInfo->cBitsPixel == 15) pDevCaps->ulBitsPixel = 16;
|
|
|
|
Tmp = pGdiInfo->ulNumColors;
|
|
if ( Tmp != -1 ) Tmp *= 5;
|
|
pDevCaps->ulNumPens = Tmp;
|
|
pDevCaps->ulNumColors = pGdiInfo->ulNumColors;
|
|
|
|
pDevCaps->ulNumFonts = IntcFonts(pDevObj);
|
|
|
|
pDevCaps->ulRasterCaps = pGdiInfo->flRaster;
|
|
pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend;
|
|
pDevCaps->ulAspectX = pGdiInfo->ulAspectX;
|
|
pDevCaps->ulAspectY = pGdiInfo->ulAspectY;
|
|
pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY;
|
|
pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX;
|
|
pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY;
|
|
pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg;
|
|
pDevCaps->ulColorRes = pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue;
|
|
pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx;
|
|
pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy;
|
|
pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x;
|
|
pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
|
|
pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes;
|
|
pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes;
|
|
pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment;
|
|
pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment;
|
|
|
|
Tmp = 0;
|
|
Tmp = pGdiInfo->flTextCaps | (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
|
|
|
|
pDevCaps->ulTextCaps = pGdiInfo->flTextCaps | (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
|
|
|
|
if (pGdiInfo->ulTechnology)
|
|
pDevCaps->ulTextCaps = Tmp | TC_VA_ABLE;
|
|
|
|
pDevCaps->ulColorMgmtCaps = IntGetColorManagementCaps(pDevObj);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiGetDeviceCapsAll (
|
|
IN HDC hDC,
|
|
OUT PDEVCAPS pDevCaps)
|
|
{
|
|
PDC dc;
|
|
PDEVCAPS pSafeDevCaps;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
dc = DC_LockDc(hDC);
|
|
if (!dc)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
pSafeDevCaps = ExAllocatePoolWithTag(PagedPool, sizeof(DEVCAPS), TAG_TEMP);
|
|
|
|
if (!pSafeDevCaps)
|
|
{
|
|
DC_UnlockDc(dc);
|
|
return FALSE;
|
|
}
|
|
|
|
IntvGetDeviceCaps(dc->ppdev, pSafeDevCaps);
|
|
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForWrite(pDevCaps,
|
|
sizeof(DEVCAPS),
|
|
1);
|
|
RtlCopyMemory(pDevCaps, pSafeDevCaps, sizeof(DEVCAPS));
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
ExFreePoolWithTag(pSafeDevCaps, TAG_TEMP);
|
|
DC_UnlockDc(dc);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DHPDEV
|
|
APIENTRY
|
|
NtGdiGetDhpdev(
|
|
IN HDEV hdev)
|
|
{
|
|
PPDEVOBJ ppdev, pGdiDevice = (PPDEVOBJ) hdev;
|
|
if (!pGdiDevice) return NULL;
|
|
if ( pGdiDevice < (PPDEVOBJ)MmSystemRangeStart) return NULL;
|
|
ppdev = pPrimarySurface;
|
|
IntGdiAcquireSemaphore(hsemDriverMgmt);
|
|
do
|
|
{
|
|
if (pGdiDevice == ppdev) break;
|
|
else
|
|
ppdev = ppdev->ppdevNext;
|
|
}
|
|
while (ppdev != NULL);
|
|
IntGdiReleaseSemaphore(hsemDriverMgmt);
|
|
if (!ppdev) return NULL;
|
|
return pGdiDevice->dhpdev;
|
|
}
|
|
|
|
static NTSTATUS FASTCALL
|
|
GetVideoRegistryKey(
|
|
OUT PUNICODE_STRING RegistryPath,
|
|
IN PCUNICODE_STRING DeviceName) /* ex: "\Device\Video0" */
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(RegistryPath, NULL);
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[0].Name = DeviceName->Buffer;
|
|
QueryTable[0].EntryContext = RegistryPath;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
|
|
L"VIDEO",
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName, Status);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DPRINT("RegistryPath %wZ\n", RegistryPath);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static NTSTATUS FASTCALL
|
|
GetVideoDeviceName(
|
|
OUT PUNICODE_STRING VideoDeviceName,
|
|
IN PCUNICODE_STRING DisplayDevice) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
|
|
{
|
|
UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\??\\");
|
|
UNICODE_STRING ObjectName;
|
|
UNICODE_STRING KernelModeName = { 0, };
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
USHORT LastSlash;
|
|
ULONG Length;
|
|
HANDLE LinkHandle = NULL;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(VideoDeviceName, NULL);
|
|
|
|
/* Get device name (DisplayDevice is "\.\xxx") */
|
|
for (LastSlash = DisplayDevice->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
|
|
{
|
|
if (DisplayDevice->Buffer[LastSlash - 1] == L'\\')
|
|
break;
|
|
}
|
|
|
|
if (LastSlash == 0)
|
|
{
|
|
DPRINT1("Invalid device name '%wZ'\n", DisplayDevice);
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
goto cleanup;
|
|
}
|
|
ObjectName = *DisplayDevice;
|
|
ObjectName.Length -= LastSlash * sizeof(WCHAR);
|
|
ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
|
|
ObjectName.Buffer += LastSlash;
|
|
|
|
/* Create "\??\xxx" (ex: "\??\DISPLAY1") */
|
|
KernelModeName.MaximumLength = Prefix.Length + ObjectName.Length + sizeof(UNICODE_NULL);
|
|
KernelModeName.Buffer = ExAllocatePoolWithTag(PagedPool,
|
|
KernelModeName.MaximumLength,
|
|
TAG_DC);
|
|
if (!KernelModeName.Buffer)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
RtlCopyUnicodeString(&KernelModeName, &Prefix);
|
|
Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName);
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
/* Open \??\xxx (ex: "\??\DISPLAY1") */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KernelModeName,
|
|
OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
Status = ZwOpenSymbolicLinkObject(&LinkHandle,
|
|
GENERIC_READ,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, &Length);
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
goto cleanup;
|
|
}
|
|
VideoDeviceName->MaximumLength = Length;
|
|
VideoDeviceName->Buffer = ExAllocatePoolWithTag(PagedPool,
|
|
VideoDeviceName->MaximumLength + sizeof(UNICODE_NULL),
|
|
TAG_DC);
|
|
if (!VideoDeviceName->Buffer)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
Status = ZwQuerySymbolicLinkObject(LinkHandle, VideoDeviceName, NULL);
|
|
VideoDeviceName->Buffer[VideoDeviceName->MaximumLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName, Status);
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
goto cleanup;
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
if (!NT_SUCCESS(Status) && VideoDeviceName->Buffer)
|
|
ExFreePoolWithTag(VideoDeviceName->Buffer, TAG_DC);
|
|
if (KernelModeName.Buffer)
|
|
ExFreePoolWithTag(KernelModeName.Buffer, TAG_DC);
|
|
if (LinkHandle)
|
|
ZwClose(LinkHandle);
|
|
return Status;
|
|
}
|
|
|
|
LONG
|
|
FASTCALL
|
|
IntChangeDisplaySettings(
|
|
IN PUNICODE_STRING pDeviceName OPTIONAL,
|
|
IN LPDEVMODEW DevMode,
|
|
IN DWORD dwflags,
|
|
IN PVOID lParam OPTIONAL)
|
|
{
|
|
BOOLEAN NoReset = FALSE;
|
|
BOOLEAN Reset = FALSE;
|
|
LONG Ret = DISP_CHANGE_SUCCESSFUL;
|
|
NTSTATUS Status ;
|
|
|
|
DPRINT1("display flags : %x\n",dwflags);
|
|
|
|
if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
|
|
{
|
|
/* Check global, reset and noreset flags */
|
|
if ((dwflags & CDS_GLOBAL) == CDS_GLOBAL)
|
|
DPRINT1("CDS_GLOBAL unhandled");
|
|
if ((dwflags & CDS_NORESET) == CDS_NORESET)
|
|
NoReset = TRUE;
|
|
dwflags &= ~(CDS_GLOBAL | CDS_NORESET);
|
|
}
|
|
if ((dwflags & CDS_RESET) == CDS_RESET)
|
|
Reset = TRUE;
|
|
if ((dwflags & CDS_SET_PRIMARY) == CDS_SET_PRIMARY)
|
|
DPRINT1("CDS_SET_PRIMARY unhandled");
|
|
dwflags &= ~(CDS_RESET | CDS_SET_PRIMARY);
|
|
|
|
if (Reset && NoReset)
|
|
return DISP_CHANGE_BADFLAGS;
|
|
|
|
if (dwflags == 0)
|
|
{
|
|
/* Dynamically change graphics mode */
|
|
DPRINT1("flag 0 UNIMPLEMENTED\n");
|
|
SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return DISP_CHANGE_FAILED;
|
|
}
|
|
|
|
if ((dwflags & CDS_TEST) == CDS_TEST)
|
|
{
|
|
/* Test resolution */
|
|
dwflags &= ~CDS_TEST;
|
|
Status = IntEnumDisplaySettings(pDeviceName, ENUM_REGISTRY_SETTINGS, DevMode, 0);
|
|
if (!NT_SUCCESS(Status))
|
|
Ret = DISP_CHANGE_BADMODE;
|
|
return Ret;
|
|
}
|
|
|
|
if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN)
|
|
{
|
|
DEVMODEW lpDevMode;
|
|
/* Full Screen */
|
|
dwflags &= ~CDS_FULLSCREEN;
|
|
DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
|
|
Ret = DISP_CHANGE_FAILED;
|
|
|
|
RtlZeroMemory(&lpDevMode, sizeof(DEVMODEW));
|
|
lpDevMode.dmSize = sizeof(DEVMODEW);
|
|
|
|
Status = IntEnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &lpDevMode, 0);
|
|
if (!NT_SUCCESS(Status))
|
|
return DISP_CHANGE_FAILED;
|
|
|
|
DPRINT1("Req Mode : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel);
|
|
DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel);
|
|
|
|
|
|
if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) &&
|
|
(lpDevMode.dmPelsWidth == DevMode->dmPelsWidth) &&
|
|
(lpDevMode.dmPelsHeight == DevMode->dmPelsHeight))
|
|
Ret = DISP_CHANGE_SUCCESSFUL;
|
|
}
|
|
|
|
if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS)
|
|
{
|
|
dwflags &= ~CDS_VIDEOPARAMETERS;
|
|
if (lParam == NULL)
|
|
Ret=DISP_CHANGE_BADPARAM;
|
|
else
|
|
{
|
|
DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
|
|
Ret = DISP_CHANGE_FAILED;
|
|
SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
}
|
|
|
|
if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
|
|
{
|
|
|
|
UNICODE_STRING DeviceName;
|
|
UNICODE_STRING RegistryKey;
|
|
UNICODE_STRING InDeviceName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE DevInstRegKey;
|
|
ULONG NewValue;
|
|
|
|
DPRINT1("set CDS_UPDATEREGISTRY\n");
|
|
|
|
dwflags &= ~CDS_UPDATEREGISTRY;
|
|
|
|
/* Check if pDeviceName is NULL, we need to retrieve it */
|
|
if (pDeviceName == NULL)
|
|
{
|
|
WCHAR szBuffer[MAX_DRIVER_NAME];
|
|
PDC DC;
|
|
PWINDOW_OBJECT Wnd=NULL;
|
|
HWND hWnd;
|
|
HDC hDC;
|
|
|
|
hWnd = IntGetDesktopWindow();
|
|
if (!(Wnd = UserGetWindowObject(hWnd)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hDC = UserGetWindowDC(Wnd);
|
|
|
|
DC = DC_LockDc(hDC);
|
|
if (NULL == DC)
|
|
{
|
|
return FALSE;
|
|
}
|
|
swprintf (szBuffer, L"\\\\.\\DISPLAY%lu", DC->ppdev->DisplayNumber);
|
|
DC_UnlockDc(DC);
|
|
|
|
RtlInitUnicodeString(&InDeviceName, szBuffer);
|
|
pDeviceName = &InDeviceName;
|
|
}
|
|
|
|
Status = GetVideoDeviceName(&DeviceName, pDeviceName);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName, Status);
|
|
return DISP_CHANGE_FAILED;
|
|
}
|
|
Status = GetVideoRegistryKey(&RegistryKey, &DeviceName);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName, Status);
|
|
ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
|
|
return DISP_CHANGE_FAILED;
|
|
}
|
|
ExFreePoolWithTag(DeviceName.Buffer, TAG_DC);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, &RegistryKey,
|
|
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
Status = ZwOpenKey(&DevInstRegKey, KEY_SET_VALUE, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey, Status);
|
|
ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
|
|
return DISP_CHANGE_FAILED;
|
|
}
|
|
ExFreePoolWithTag(RegistryKey.Buffer, TAG_RTLREGISTRY);
|
|
|
|
/* Update needed fields */
|
|
if (NT_SUCCESS(Status) && DevMode->dmFields & DM_BITSPERPEL)
|
|
{
|
|
RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel");
|
|
NewValue = DevMode->dmBitsPerPel;
|
|
Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
|
|
}
|
|
|
|
if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH)
|
|
{
|
|
RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution");
|
|
NewValue = DevMode->dmPelsWidth;
|
|
Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
|
|
}
|
|
|
|
if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT)
|
|
{
|
|
RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution");
|
|
NewValue = DevMode->dmPelsHeight;
|
|
Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
|
|
}
|
|
|
|
if (NT_SUCCESS(Status) && DevMode->dmFields & DM_DISPLAYFREQUENCY)
|
|
{
|
|
RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.VRefresh");
|
|
NewValue = DevMode->dmDisplayFrequency;
|
|
Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));
|
|
}
|
|
|
|
ZwClose(DevInstRegKey);
|
|
if (NT_SUCCESS(Status))
|
|
Ret = DISP_CHANGE_RESTART;
|
|
else
|
|
/* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
|
|
Ret = DISP_CHANGE_NOTUPDATED;
|
|
}
|
|
|
|
if (dwflags != 0)
|
|
Ret = DISP_CHANGE_BADFLAGS;
|
|
|
|
DPRINT("IntChangeDisplaySettings returning %x\n", Ret);
|
|
return Ret;
|
|
}
|
|
|
|
|
|
|
|
#define SIZEOF_DEVMODEW_300 188
|
|
#define SIZEOF_DEVMODEW_400 212
|
|
#define SIZEOF_DEVMODEW_500 220
|
|
|
|
static NTSTATUS FASTCALL
|
|
GetDisplayNumberFromDeviceName(
|
|
IN PUNICODE_STRING pDeviceName OPTIONAL,
|
|
OUT ULONG *DisplayNumber)
|
|
{
|
|
UNICODE_STRING DisplayString = RTL_CONSTANT_STRING(L"\\\\.\\DISPLAY");
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG Length;
|
|
ULONG Number;
|
|
ULONG i;
|
|
|
|
if (DisplayNumber == NULL)
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
/* Check if DeviceName is valid */
|
|
if (pDeviceName &&
|
|
pDeviceName->Length > 0 && pDeviceName->Length <= DisplayString.Length)
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
if (pDeviceName == NULL || pDeviceName->Length == 0)
|
|
{
|
|
PWINDOW_OBJECT DesktopObject;
|
|
HDC DesktopHDC;
|
|
PDC pDC;
|
|
|
|
DesktopObject = UserGetDesktopWindow();
|
|
DesktopHDC = UserGetWindowDC(DesktopObject);
|
|
pDC = DC_LockDc(DesktopHDC);
|
|
|
|
*DisplayNumber = pDC->ppdev->DisplayNumber;
|
|
|
|
DC_UnlockDc(pDC);
|
|
UserReleaseDC(DesktopObject, DesktopHDC, FALSE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Hack to check if the first parts are equal, by faking the device name length */
|
|
Length = pDeviceName->Length;
|
|
pDeviceName->Length = DisplayString.Length;
|
|
if (RtlEqualUnicodeString(&DisplayString, pDeviceName, FALSE) == FALSE)
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
pDeviceName->Length = Length;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Convert the last part of pDeviceName to a number */
|
|
Number = 0;
|
|
Length = pDeviceName->Length / sizeof(WCHAR);
|
|
for (i = DisplayString.Length / sizeof(WCHAR); i < Length; i++)
|
|
{
|
|
WCHAR Char = pDeviceName->Buffer[i];
|
|
if (Char >= L'0' && Char <= L'9')
|
|
Number = Number * 10 + Char - L'0';
|
|
else if (Char != L'\0')
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}
|
|
|
|
*DisplayNumber = Number - 1;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*! \brief Enumerate possible display settings for the given display...
|
|
*
|
|
* \todo Make thread safe!?
|
|
* \todo Don't ignore pDeviceName
|
|
* \todo Implement non-raw mode (only return settings valid for driver and monitor)
|
|
*/
|
|
NTSTATUS
|
|
FASTCALL
|
|
IntEnumDisplaySettings(
|
|
IN PUNICODE_STRING pDeviceName OPTIONAL,
|
|
IN DWORD iModeNum,
|
|
IN OUT LPDEVMODEW pDevMode,
|
|
IN DWORD dwFlags)
|
|
{
|
|
static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL;
|
|
static DWORD SizeOfCachedDevModes = 0;
|
|
static UNICODE_STRING CachedDeviceName;
|
|
PDEVMODEW CachedMode = NULL;
|
|
DEVMODEW DevMode;
|
|
ULONG DisplayNumber;
|
|
NTSTATUS Status;
|
|
|
|
Status = GetDisplayNumberFromDeviceName(pDeviceName, &DisplayNumber);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (pDevMode != NULL)
|
|
{
|
|
DPRINT("DevMode->dmSize = %d\n", pDevMode->dmSize);
|
|
DPRINT("DevMode->dmExtraSize = %d\n", pDevMode->dmDriverExtra);
|
|
if (pDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
|
|
pDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
|
|
pDevMode->dmSize != SIZEOF_DEVMODEW_500)
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
return STATUS_UNSUCCESSFUL; // FIXME: what status?
|
|
}
|
|
/* FIXME: Maybe look for the matching devmode supplied by the
|
|
* driver so we can provide driver private/extra data?
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
BOOL IsCachedDevice = (CachedDevModes != NULL);
|
|
|
|
if (CachedDevModes &&
|
|
((pDeviceName == NULL && CachedDeviceName.Length > 0) ||
|
|
(pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length == 0) ||
|
|
(pDeviceName != NULL && pDeviceName->Buffer != NULL && CachedDeviceName.Length > 0 && RtlEqualUnicodeString(pDeviceName, &CachedDeviceName, TRUE) == FALSE)))
|
|
{
|
|
IsCachedDevice = FALSE;
|
|
}
|
|
|
|
if (iModeNum == 0 || IsCachedDevice == FALSE) /* query modes from drivers */
|
|
{
|
|
UNICODE_STRING DriverFileNames;
|
|
LPWSTR CurrentName;
|
|
DRVENABLEDATA DrvEnableData;
|
|
|
|
/* Free resources from last driver cache */
|
|
if (IsCachedDevice == FALSE && CachedDeviceName.Buffer != NULL)
|
|
{
|
|
RtlFreeUnicodeString(&CachedDeviceName);
|
|
}
|
|
|
|
/* Retrieve DDI driver names from registry */
|
|
RtlInitUnicodeString(&DriverFileNames, NULL);
|
|
if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
|
|
{
|
|
DPRINT1("FindDriverFileNames failed\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (!IntPrepareDriverIfNeeded())
|
|
{
|
|
DPRINT1("IntPrepareDriverIfNeeded failed\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
PFN_DrvEnableDriver GDEnableDriver;
|
|
PFN_DrvGetModes GetModes = NULL;
|
|
INT SizeNeeded, SizeUsed;
|
|
|
|
/* Get the DDI driver's entry point */
|
|
//GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
|
|
GDEnableDriver = DRIVER_FindExistingDDIDriver(L"DISPLAY");
|
|
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;
|
|
|
|
if (DrvFn->iFunc == INDEX_DrvGetModes)
|
|
{
|
|
GetModes = (PFN_DrvGetModes)DrvFn->pfn;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (GetModes == NULL)
|
|
{
|
|
DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName);
|
|
continue;
|
|
}
|
|
|
|
/* 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 = (PCHAR)CachedDevModesEnd - (PCHAR)CachedDevModes;
|
|
if (SizeOfCachedDevModes < SizeUsed + SizeNeeded)
|
|
{
|
|
PVOID NewBuffer;
|
|
|
|
SizeOfCachedDevModes += SizeNeeded;
|
|
NewBuffer = ExAllocatePoolWithTag(PagedPool, SizeOfCachedDevModes, GDITAG_DEVMODE);
|
|
if (NewBuffer == NULL)
|
|
{
|
|
/* clean up */
|
|
ExFreePool(CachedDevModes);
|
|
CachedDevModes = NULL;
|
|
CachedDevModesEnd = NULL;
|
|
SizeOfCachedDevModes = 0;
|
|
|
|
if (CachedDeviceName.Buffer != NULL)
|
|
RtlFreeUnicodeString(&CachedDeviceName);
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
if (CachedDevModes != NULL)
|
|
{
|
|
RtlCopyMemory(NewBuffer, CachedDevModes, SizeUsed);
|
|
ExFreePool(CachedDevModes);
|
|
}
|
|
CachedDevModes = NewBuffer;
|
|
CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed);
|
|
}
|
|
|
|
if (!IsCachedDevice)
|
|
{
|
|
if (CachedDeviceName.Buffer != NULL)
|
|
RtlFreeUnicodeString(&CachedDeviceName);
|
|
|
|
if (pDeviceName)
|
|
IntSafeCopyUnicodeString(&CachedDeviceName, pDeviceName);
|
|
|
|
IsCachedDevice = TRUE;
|
|
}
|
|
|
|
/* query modes */
|
|
SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject),
|
|
SizeNeeded,
|
|
CachedDevModesEnd);
|
|
if (SizeNeeded <= 0)
|
|
{
|
|
DPRINT("DrvGetModes failed for %S\n", CurrentName);
|
|
}
|
|
else
|
|
{
|
|
CachedDevModesEnd = (DEVMODEW *)((PCHAR)CachedDevModesEnd + SizeNeeded);
|
|
}
|
|
}
|
|
|
|
ExFreePoolWithTag(DriverFileNames.Buffer, TAG_RTLREGISTRY);
|
|
}
|
|
|
|
/* return cached info */
|
|
CachedMode = CachedDevModes;
|
|
if (CachedMode >= CachedDevModesEnd)
|
|
{
|
|
return STATUS_NO_MORE_ENTRIES;
|
|
}
|
|
while (iModeNum-- > 0 && CachedMode < CachedDevModesEnd)
|
|
{
|
|
ASSERT(CachedMode->dmSize > 0);
|
|
CachedMode = (DEVMODEW *)((PCHAR)CachedMode + CachedMode->dmSize + CachedMode->dmDriverExtra);
|
|
}
|
|
if (CachedMode >= CachedDevModesEnd)
|
|
{
|
|
return STATUS_NO_MORE_ENTRIES;
|
|
}
|
|
}
|
|
|
|
ASSERT(CachedMode != NULL);
|
|
|
|
if (pDevMode != NULL)
|
|
{
|
|
RtlCopyMemory(pDevMode, CachedMode, min(pDevMode->dmSize, CachedMode->dmSize));
|
|
RtlZeroMemory(pDevMode + pDevMode->dmSize, pDevMode->dmDriverExtra);
|
|
RtlCopyMemory(pDevMode + min(pDevMode->dmSize, CachedMode->dmSize), CachedMode + CachedMode->dmSize, min(pDevMode->dmDriverExtra, CachedMode->dmDriverExtra));
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
INT
|
|
APIENTRY
|
|
NtGdiDrawEscape(
|
|
IN HDC hdc,
|
|
IN INT iEsc,
|
|
IN INT cjIn,
|
|
IN OPTIONAL LPSTR pjIn)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return 0;
|
|
}
|
|
|