📄 dc.c
字号:
/*
* ReactOS W32 Subsystem
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: dc.c 22176 2006-06-02 13:49:04Z amunger $
*
* DC.C - Device context functions
*
*/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
#ifndef OBJ_COLORSPACE
#define OBJ_COLORSPACE (14)
#endif
static GDIDEVICE PrimarySurface;
static KEVENT VideoDriverNeedsPreparation;
static KEVENT VideoDriverPrepared;
NTSTATUS FASTCALL
InitDcImpl(VOID)
{
KeInitializeEvent(&VideoDriverNeedsPreparation, SynchronizationEvent, TRUE);
KeInitializeEvent(&VideoDriverPrepared, NotificationEvent, FALSE);
return STATUS_SUCCESS;
}
/* FIXME: DCs should probably be thread safe */
/*
* DC device-independent Get/SetXXX functions
* (RJJ) swiped from WINE
*/
#define DC_GET_VAL( func_type, func_name, dc_field ) \
func_type STDCALL func_name( HDC hdc ) \
{ \
func_type ft; \
PDC dc = DC_LockDc( hdc ); \
if (!dc) \
{ \
SetLastWin32Error(ERROR_INVALID_HANDLE); \
return 0; \
} \
ft = dc->dc_field; \
DC_UnlockDc(dc); \
return ft; \
}
/* DC_GET_VAL_EX is used to define functions returning a POINT or a SIZE. It is
* important that the function has the right signature, for the implementation
* we can do whatever we want.
*/
#define DC_GET_VAL_EX( FuncName, ret_x, ret_y, type, ax, ay ) \
VOID FASTCALL Int##FuncName ( PDC dc, LP##type pt) \
{ \
ASSERT(dc); \
ASSERT(pt); \
pt->ax = dc->ret_x; \
pt->ay = dc->ret_y; \
} \
BOOL STDCALL NtGdi##FuncName ( HDC hdc, LP##type pt ) \
{ \
NTSTATUS Status = STATUS_SUCCESS; \
type Safept; \
PDC dc; \
if(!pt) \
{ \
SetLastWin32Error(ERROR_INVALID_PARAMETER); \
return FALSE; \
} \
if(!(dc = DC_LockDc(hdc))) \
{ \
SetLastWin32Error(ERROR_INVALID_HANDLE); \
return FALSE; \
} \
Int##FuncName( dc, &Safept); \
DC_UnlockDc(dc); \
_SEH_TRY \
{ \
ProbeForWrite(pt, \
sizeof( type ), \
1); \
*pt = Safept; \
} \
_SEH_HANDLE \
{ \
Status = _SEH_GetExceptionCode(); \
} \
_SEH_END; \
if(!NT_SUCCESS(Status)) \
{ \
SetLastNtError(Status); \
return FALSE; \
} \
return TRUE; \
}
#define DC_SET_MODE( func_name, dc_field, min_val, max_val ) \
INT STDCALL func_name( HDC hdc, INT mode ) \
{ \
INT prevMode; \
PDC dc; \
if ((mode < min_val) || (mode > max_val)) \
{ \
SetLastWin32Error(ERROR_INVALID_PARAMETER); \
return 0; \
} \
dc = DC_LockDc ( hdc ); \
if ( !dc ) \
{ \
SetLastWin32Error(ERROR_INVALID_HANDLE); \
return 0; \
} \
prevMode = dc->dc_field; \
dc->dc_field = mode; \
DC_UnlockDc ( dc ); \
return prevMode; \
}
// --------------------------------------------------------- File Statics
// ----------------------------------------------------- Public Functions
BOOL STDCALL
NtGdiCancelDC(HDC hDC)
{
UNIMPLEMENTED;
return FALSE;
}
HDC STDCALL
NtGdiCreateCompatibleDC(HDC hDC)
{
PDC NewDC, OrigDC;
HBITMAP hBitmap;
HDC hNewDC, DisplayDC;
HRGN hVisRgn;
UNICODE_STRING DriverName;
DisplayDC = NULL;
if (hDC == NULL)
{
RtlInitUnicodeString(&DriverName, L"DISPLAY");
DisplayDC = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, TRUE);
if (NULL == DisplayDC)
{
return NULL;
}
hDC = DisplayDC;
}
/* Allocate a new DC based on the original DC's device */
OrigDC = DC_LockDc(hDC);
if (NULL == OrigDC)
{
if (NULL != DisplayDC)
{
NtGdiDeleteObjectApp(DisplayDC);
}
return NULL;
}
hNewDC = DC_AllocDC(&OrigDC->DriverName);
if (NULL == hNewDC)
{
DC_UnlockDc(OrigDC);
if (NULL != DisplayDC)
{
NtGdiDeleteObjectApp(DisplayDC);
}
return NULL;
}
NewDC = DC_LockDc( hNewDC );
/* Copy information from original DC to new DC */
NewDC->hSelf = hNewDC;
NewDC->IsIC = FALSE;
NewDC->PDev = OrigDC->PDev;
memcpy(NewDC->FillPatternSurfaces,
OrigDC->FillPatternSurfaces,
sizeof OrigDC->FillPatternSurfaces);
NewDC->GDIInfo = OrigDC->GDIInfo;
NewDC->DevInfo = OrigDC->DevInfo;
NewDC->w.bitsPerPixel = OrigDC->w.bitsPerPixel;
/* DriverName is copied in the AllocDC routine */
NewDC->DeviceDriver = OrigDC->DeviceDriver;
NewDC->wndOrgX = OrigDC->wndOrgX;
NewDC->wndOrgY = OrigDC->wndOrgY;
NewDC->wndExtX = OrigDC->wndExtX;
NewDC->wndExtY = OrigDC->wndExtY;
NewDC->vportOrgX = OrigDC->vportOrgX;
NewDC->vportOrgY = OrigDC->vportOrgY;
NewDC->vportExtX = OrigDC->vportExtX;
NewDC->vportExtY = OrigDC->vportExtY;
/* Create default bitmap */
if (!(hBitmap = NtGdiCreateBitmap( 1, 1, 1, NewDC->w.bitsPerPixel, NULL )))
{
DC_UnlockDc( OrigDC );
DC_UnlockDc( NewDC );
DC_FreeDC( hNewDC );
if (NULL != DisplayDC)
{
NtGdiDeleteObjectApp(DisplayDC);
}
return NULL;
}
NewDC->w.flags = DC_MEMORY;
NewDC->w.hBitmap = hBitmap;
NewDC->w.hFirstBitmap = hBitmap;
NewDC->GDIDevice = OrigDC->GDIDevice;
NewDC->PalIndexed = OrigDC->PalIndexed;
NewDC->w.hPalette = OrigDC->w.hPalette;
NewDC->w.textColor = OrigDC->w.textColor;
NewDC->w.textAlign = OrigDC->w.textAlign;
NewDC->w.backgroundColor = OrigDC->w.backgroundColor;
NewDC->w.backgroundMode = OrigDC->w.backgroundMode;
NewDC->w.ROPmode = OrigDC->w.ROPmode;
DC_UnlockDc(NewDC);
DC_UnlockDc(OrigDC);
if (NULL != DisplayDC)
{
NtGdiDeleteObjectApp(DisplayDC);
}
hVisRgn = NtGdiCreateRectRgn(0, 0, 1, 1);
NtGdiSelectVisRgn(hNewDC, hVisRgn);
NtGdiDeleteObject(hVisRgn);
DC_InitDC(hNewDC);
return hNewDC;
}
static BOOL FASTCALL
GetRegistryPath(PUNICODE_STRING RegistryPath, ULONG DisplayNumber)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
WCHAR DeviceNameBuffer[20];
NTSTATUS Status;
swprintf(DeviceNameBuffer, L"\\Device\\Video%d", 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%d value in DEVICEMAP\\VIDEO found\n", DisplayNumber);
return FALSE;
}
DPRINT("RegistryPath %S\n", RegistryPath->Buffer);
return TRUE;
}
static BOOL FASTCALL
FindDriverFileNames(PUNICODE_STRING DriverFileNames, ULONG DisplayNumber)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
UNICODE_STRING RegistryPath;
NTSTATUS Status;
if (! GetRegistryPath(&RegistryPath, DisplayNumber))
{
DPRINT("GetRegistryPath failed\n");
return FALSE;
}
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
QueryTable[0].Name = L"InstalledDisplayDrivers";
QueryTable[0].EntryContext = DriverFileNames;
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
RegistryPath.Buffer,
QueryTable,
NULL,
NULL);
RtlFreeUnicodeString(&RegistryPath);
if (! NT_SUCCESS(Status))
{
DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
return FALSE;
}
DPRINT("DriverFileNames %S\n", DriverFileNames->Buffer);
return TRUE;
}
static NTSTATUS STDCALL
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)
{
static WCHAR RegistryMachineSystem[] = L"\\REGISTRY\\MACHINE\\SYSTEM\\";
static WCHAR CurrentControlSet[] = L"CURRENTCONTROLSET\\";
static WCHAR ControlSet[] = L"CONTROLSET";
static WCHAR Insert[] = L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
UNICODE_STRING RegistryPath;
BOOL Valid;
PWCHAR AfterControlSet;
PWCHAR ProfilePath;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
NTSTATUS Status;
if (! GetRegistryPath(&RegistryPath, DisplayNumber))
{
DPRINT("GetRegistryPath failed\n");
return FALSE;
}
Valid = (0 == _wcsnicmp(RegistryPath.Buffer, RegistryMachineSystem,
wcslen(RegistryMachineSystem)));
if (Valid)
{
AfterControlSet = RegistryPath.Buffer + wcslen(RegistryMachineSystem);
if (0 == _wcsnicmp(AfterControlSet, CurrentControlSet, wcslen(CurrentControlSet)))
{
AfterControlSet += wcslen(CurrentControlSet);
}
else if (0 == _wcsnicmp(AfterControlSet, ControlSet, wcslen(ControlSet)))
{
AfterControlSet += wcslen(ControlSet);
while (L'0' <= *AfterControlSet && L'9' <= *AfterControlSet)
{
AfterControlSet++;
}
Valid = (L'\\' == *AfterControlSet);
AfterControlSet++;
}
else
{
Valid = FALSE;
}
}
if (Valid)
{
ProfilePath = ExAllocatePoolWithTag(PagedPool,
(wcslen(RegistryPath.Buffer) +
wcslen(Insert) + 1) * sizeof(WCHAR),
TAG_DC);
if (NULL != ProfilePath)
{
wcsncpy(ProfilePath, RegistryPath.Buffer, AfterControlSet - RegistryPath.Buffer);
wcscpy(ProfilePath + (AfterControlSet - RegistryPath.Buffer), Insert);
wcscat(ProfilePath, AfterControlSet);
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,
ProfilePath,
QueryTable,
DevMode,
NULL);
if (! NT_SUCCESS(Status))
{
DPRINT("RtlQueryRegistryValues for %S failed with status 0x%08x\n",
ProfilePath, 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;
}
}
ExFreePool(ProfilePath);
}
else
{
Valid = FALSE;
}
}
else
{
DPRINT1("Unparsable registry path %S in DEVICEMAP\\VIDEO0", RegistryPath.Buffer);
}
RtlFreeUnicodeString(&RegistryPath);
if (! Valid)
{
RtlZeroMemory(DevMode, sizeof(DEVMODEW));
}
return Valid;
}
static BOOL FASTCALL
IntPrepareDriver()
{
PGD_ENABLEDRIVER 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -