2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Functions for creation and destruction of DCs
5 * FILE: subsystem/win32/win32k/objects/device.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
14 // TODO: proper implementation of LDEVOBJ and PDEVOBJ interface
16 /*static*/ PDEVOBJ PrimarySurface
;
17 PPDEVOBJ pPrimarySurface
= &PrimarySurface
;
18 static KEVENT VideoDriverNeedsPreparation
;
19 static KEVENT VideoDriverPrepared
;
20 PDC defaultDCstate
= NULL
;
26 KeInitializeEvent(&VideoDriverNeedsPreparation
, SynchronizationEvent
, TRUE
);
27 KeInitializeEvent(&VideoDriverPrepared
, NotificationEvent
, FALSE
);
28 return STATUS_SUCCESS
;
32 static BOOLEAN FASTCALL
33 GetRegistryPath(PUNICODE_STRING RegistryPath
, ULONG DisplayNumber
)
35 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
36 WCHAR DeviceNameBuffer
[20];
39 swprintf(DeviceNameBuffer
, L
"\\Device\\Video%lu", DisplayNumber
);
40 RtlInitUnicodeString(RegistryPath
, NULL
);
41 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
42 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
43 QueryTable
[0].Name
= DeviceNameBuffer
;
44 QueryTable
[0].EntryContext
= RegistryPath
;
46 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
51 if (! NT_SUCCESS(Status
))
53 DPRINT1("No \\Device\\Video%lu value in DEVICEMAP\\VIDEO found\n", DisplayNumber
);
57 DPRINT("RegistryPath %wZ\n", RegistryPath
);
63 FindDriverFileNames(PUNICODE_STRING DriverFileNames
, ULONG DisplayNumber
)
65 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
66 UNICODE_STRING RegistryPath
;
69 if (! GetRegistryPath(&RegistryPath
, DisplayNumber
))
71 DPRINT("GetRegistryPath failed\n");
75 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
76 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
77 QueryTable
[0].Name
= L
"InstalledDisplayDrivers";
78 QueryTable
[0].EntryContext
= DriverFileNames
;
80 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
85 ExFreePoolWithTag(RegistryPath
.Buffer
, TAG_RTLREGISTRY
);
86 if (! NT_SUCCESS(Status
))
88 DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
92 DPRINT("DriverFileNames %S\n", DriverFileNames
->Buffer
);
98 static NTSTATUS APIENTRY
99 DevModeCallback(IN PWSTR ValueName
,
102 IN ULONG ValueLength
,
104 IN PVOID EntryContext
)
106 PDEVMODEW DevMode
= (PDEVMODEW
) Context
;
108 DPRINT("Found registry value for name %S: type %d, length %d\n",
109 ValueName
, ValueType
, ValueLength
);
111 if (REG_DWORD
== ValueType
&& sizeof(DWORD
) == ValueLength
)
113 if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.BitsPerPel"))
115 DevMode
->dmBitsPerPel
= *((DWORD
*) ValueData
);
117 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.Flags"))
119 DevMode
->dmDisplayFlags
= *((DWORD
*) ValueData
);
121 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.VRefresh"))
123 DevMode
->dmDisplayFrequency
= *((DWORD
*) ValueData
);
125 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.XPanning"))
127 DevMode
->dmPanningWidth
= *((DWORD
*) ValueData
);
129 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.XResolution"))
131 DevMode
->dmPelsWidth
= *((DWORD
*) ValueData
);
133 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.YPanning"))
135 DevMode
->dmPanningHeight
= *((DWORD
*) ValueData
);
137 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.YResolution"))
139 DevMode
->dmPelsHeight
= *((DWORD
*) ValueData
);
143 return STATUS_SUCCESS
;
148 SetupDevMode(PDEVMODEW DevMode
, ULONG DisplayNumber
)
150 UNICODE_STRING RegistryPath
;
151 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
153 BOOLEAN Valid
= TRUE
;
155 if (!GetRegistryPath(&RegistryPath
, DisplayNumber
))
157 DPRINT("GetRegistryPath failed\n");
161 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
162 QueryTable
[0].QueryRoutine
= DevModeCallback
;
163 QueryTable
[0].Flags
= 0;
164 QueryTable
[0].Name
= NULL
;
165 QueryTable
[0].EntryContext
= NULL
;
166 QueryTable
[0].DefaultType
= REG_NONE
;
167 QueryTable
[0].DefaultData
= NULL
;
168 QueryTable
[0].DefaultLength
= 0;
170 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
175 if (! NT_SUCCESS(Status
))
177 DPRINT("RtlQueryRegistryValues for %wZ failed with status 0x%08x\n",
178 &RegistryPath
, Status
);
183 DPRINT("dmBitsPerPel %d dmDisplayFrequency %d dmPelsWidth %d dmPelsHeight %d\n",
184 DevMode
->dmBitsPerPel
, DevMode
->dmDisplayFrequency
,
185 DevMode
->dmPelsWidth
, DevMode
->dmPelsHeight
);
186 if (0 == DevMode
->dmBitsPerPel
|| 0 == DevMode
->dmDisplayFrequency
187 || 0 == DevMode
->dmPelsWidth
|| 0 == DevMode
->dmPelsHeight
)
189 DPRINT("Not all required devmode members are set\n");
194 ExFreePoolWithTag(RegistryPath
.Buffer
, TAG_RTLREGISTRY
);
198 RtlZeroMemory(DevMode
, sizeof(DEVMODEW
));
207 PFN_DrvEnableDriver GDEnableDriver
;
209 UNICODE_STRING DriverFileNames
;
218 if (STATUS_SUCCESS
!= KeWaitForSingleObject(&VideoDriverNeedsPreparation
, Executive
, KernelMode
, TRUE
, &Zero
))
220 /* Concurrent access. Wait for VideoDriverPrepared event */
221 if (STATUS_SUCCESS
== KeWaitForSingleObject(&VideoDriverPrepared
, Executive
, KernelMode
, TRUE
, NULL
))
222 ret
= PrimarySurface
.PreparedDriver
;
225 // HAX! Fixme so I can support more than one! So how many?
226 for (DisplayNumber
= 0; ; DisplayNumber
++)
228 DPRINT("Trying to load display driver no. %d\n", DisplayNumber
);
230 RtlZeroMemory(&PrimarySurface
, sizeof(PrimarySurface
));
232 // if (!pPrimarySurface) pPrimarySurface = ExAllocatePoolWithTag(PagedPool, sizeof(PDEVOBJ), TAG_GDIPDEV);
234 PrimarySurface
.VideoFileObject
= DRIVER_FindMPDriver(DisplayNumber
);
236 /* Open the miniport driver */
237 if (PrimarySurface
.VideoFileObject
== NULL
)
239 DPRINT1("FindMPDriver failed\n");
243 /* Retrieve DDI driver names from registry */
244 RtlInitUnicodeString(&DriverFileNames
, NULL
);
245 if (!FindDriverFileNames(&DriverFileNames
, DisplayNumber
))
247 DPRINT1("FindDriverFileNames failed\n");
252 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
253 * scan all of them until a good one found.
255 CurrentName
= DriverFileNames
.Buffer
;
258 CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
260 /* Get the DDI driver's entry point */
261 GDEnableDriver
= DRIVER_FindDDIDriver(CurrentName
);
262 if (NULL
== GDEnableDriver
)
264 DPRINT("FindDDIDriver failed for %S\n", CurrentName
);
268 /* Call DDI driver's EnableDriver function */
269 RtlZeroMemory(&DED
, sizeof(DED
));
271 if (! GDEnableDriver(DDI_DRIVER_VERSION_NT5_01
, sizeof(DED
), &DED
))
273 DPRINT("DrvEnableDriver failed for %S\n", CurrentName
);
283 /* Skip to the next name but never get past the Unicode string */
284 while (L
'\0' != *CurrentName
&&
285 CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
289 if (CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
298 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
299 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
300 DPRINT1("No suitable DDI driver found\n");
304 DPRINT("Display driver %S loaded\n", CurrentName
);
306 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
308 DPRINT("Building DDI Functions\n");
310 /* Construct DDI driver function dispatch table */
311 if (!DRIVER_BuildDDIFunctions(&DED
, &PrimarySurface
.DriverFunctions
))
313 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
314 DPRINT1("BuildDDIFunctions failed\n");
318 /* Allocate a phyical device handle from the driver */
319 // Support DMW.dmSize + DMW.dmDriverExtra & Alloc DMW then set prt pdmwDev.
320 PrimarySurface
.DMW
.dmSize
= sizeof (PrimarySurface
.DMW
);
321 if (SetupDevMode(&PrimarySurface
.DMW
, DisplayNumber
))
323 PrimarySurface
.hPDev
= PrimarySurface
.DriverFunctions
.EnablePDEV(
327 PrimarySurface
.FillPatterns
,
328 sizeof(PrimarySurface
.GDIInfo
),
329 &PrimarySurface
.GDIInfo
,
330 sizeof(PrimarySurface
.DevInfo
),
331 &PrimarySurface
.DevInfo
,
334 (HANDLE
) (PrimarySurface
.VideoFileObject
->DeviceObject
));
335 DoDefault
= (NULL
== PrimarySurface
.hPDev
);
338 DPRINT1("DrvEnablePDev with registry parameters failed\n");
348 RtlZeroMemory(&(PrimarySurface
.DMW
), sizeof(DEVMODEW
));
349 PrimarySurface
.DMW
.dmSize
= sizeof (PrimarySurface
.DMW
);
350 PrimarySurface
.hPDev
= PrimarySurface
.DriverFunctions
.EnablePDEV(
354 PrimarySurface
.FillPatterns
,
355 sizeof(PrimarySurface
.GDIInfo
),
356 &PrimarySurface
.GDIInfo
,
357 sizeof(PrimarySurface
.DevInfo
),
358 &PrimarySurface
.DevInfo
,
361 (HANDLE
) (PrimarySurface
.VideoFileObject
->DeviceObject
));
363 if (NULL
== PrimarySurface
.hPDev
)
365 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
366 DPRINT1("DrvEnablePDEV with default parameters failed\n");
367 DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
371 // Update the primary surface with what we really got
372 PrimarySurface
.DMW
.dmPelsWidth
= PrimarySurface
.GDIInfo
.ulHorzRes
;
373 PrimarySurface
.DMW
.dmPelsHeight
= PrimarySurface
.GDIInfo
.ulVertRes
;
374 PrimarySurface
.DMW
.dmBitsPerPel
= PrimarySurface
.GDIInfo
.cBitsPixel
;
375 PrimarySurface
.DMW
.dmDisplayFrequency
= PrimarySurface
.GDIInfo
.ulVRefresh
;
378 if (!PrimarySurface
.DMW
.dmDriverExtra
)
380 PrimarySurface
.pdmwDev
= &PrimarySurface
.DMW
; // HAX!
384 DPRINT1("WARNING!!! Need to Alloc DMW !!!!!!\n");
386 // Dont remove until we finish testing other drivers.
387 if (PrimarySurface
.DMW
.dmDriverExtra
!= 0)
389 DPRINT1("**** DMW extra = %u bytes. Please report to ros-dev@reactos.org ****\n", PrimarySurface
.DMW
.dmDriverExtra
);
392 if (0 == PrimarySurface
.GDIInfo
.ulLogPixelsX
)
394 DPRINT("Adjusting GDIInfo.ulLogPixelsX\n");
395 PrimarySurface
.GDIInfo
.ulLogPixelsX
= 96;
397 if (0 == PrimarySurface
.GDIInfo
.ulLogPixelsY
)
399 DPRINT("Adjusting GDIInfo.ulLogPixelsY\n");
400 PrimarySurface
.GDIInfo
.ulLogPixelsY
= 96;
403 PrimarySurface
.Pointer
.Exclude
.right
= -1;
405 DPRINT("calling completePDev\n");
407 /* Complete initialization of the physical device */
408 PrimarySurface
.DriverFunctions
.CompletePDEV(
409 PrimarySurface
.hPDev
,
410 (HDEV
)&PrimarySurface
);
412 DPRINT("calling DRIVER_ReferenceDriver\n");
414 DRIVER_ReferenceDriver(L
"DISPLAY");
416 PrimarySurface
.PreparedDriver
= TRUE
;
417 PrimarySurface
.DisplayNumber
= DisplayNumber
;
418 PrimarySurface
.flFlags
= PDEV_DISPLAY
; // Hard set,, add more flags.
419 PrimarySurface
.hsemDevLock
= (PERESOURCE
)EngCreateSemaphore();
420 // Should be null,, but make sure for now.
421 PrimarySurface
.pvGammaRamp
= NULL
;
422 PrimarySurface
.ppdevNext
= NULL
; // Fixme! We need to support more than display drvs.
423 PrimarySurface
.ppdevParent
= NULL
; // Always NULL if primary.
424 PrimarySurface
.pGraphicsDev
= NULL
; // Fixme!
425 PrimarySurface
.pEDDgpl
= ExAllocatePoolWithTag(PagedPool
, sizeof(EDD_DIRECTDRAW_GLOBAL
), TAG_EDDGBL
);
426 if (PrimarySurface
.pEDDgpl
)
428 RtlZeroMemory( PrimarySurface
.pEDDgpl
,sizeof(EDD_DIRECTDRAW_GLOBAL
));
435 KeSetEvent(&VideoDriverPrepared
, 1, FALSE
);
440 IntPrepareDriverIfNeeded()
442 return (PrimarySurface
.PreparedDriver
? TRUE
: IntPrepareDriver());
450 IO_STATUS_BLOCK Iosb
;
452 ULONG Length
= sizeof(BOOL
);
453 PIO_STACK_LOCATION StackPtr
;
454 LARGE_INTEGER StartOffset
;
455 PFILE_OBJECT FileObject
= PrimarySurface
.VideoFileObject
;
456 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
458 DPRINT("PrepareVideoPrt() called\n");
460 KeClearEvent(&PrimarySurface
.VideoFileObject
->Event
);
462 ObReferenceObjectByPointer(FileObject
, 0, IoFileObjectType
, KernelMode
);
464 StartOffset
.QuadPart
= 0;
465 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
477 /* Set up IRP Data */
478 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
479 Irp
->RequestorMode
= KernelMode
;
480 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
481 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
= NULL
;
482 Irp
->Flags
|= IRP_WRITE_OPERATION
;
484 /* Setup Stack Data */
485 StackPtr
= IoGetNextIrpStackLocation(Irp
);
486 StackPtr
->FileObject
= PrimarySurface
.VideoFileObject
;
487 StackPtr
->Parameters
.Write
.Key
= 0;
489 Status
= IoCallDriver(DeviceObject
, Irp
);
491 if (STATUS_PENDING
== Status
)
493 KeWaitForSingleObject(&FileObject
->Event
, Executive
, KernelMode
, TRUE
, 0);
494 Status
= Iosb
.Status
;
497 return NT_SUCCESS(Status
);
502 IntCreatePrimarySurface()
509 if (! IntPrepareDriverIfNeeded())
514 if (! PrepareVideoPrt())
519 DPRINT("calling EnableSurface\n");
520 /* Enable the drawing surface */
521 PrimarySurface
.pSurface
=
522 PrimarySurface
.DriverFunctions
.EnableSurface(PrimarySurface
.hPDev
);
523 if (NULL
== PrimarySurface
.pSurface
)
525 /* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.hPDev, FALSE);*/
526 PrimarySurface
.DriverFunctions
.DisablePDEV(PrimarySurface
.hPDev
);
527 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
528 DPRINT1("DrvEnableSurface failed\n");
532 PrimarySurface
.DriverFunctions
.AssertMode(PrimarySurface
.hPDev
, TRUE
);
534 calledFromUser
= UserIsEntered(); //fixme: possibly upgrade a shared lock
537 UserEnterExclusive();
541 IntAttachMonitor(&PrimarySurface
, PrimarySurface
.DisplayNumber
);
543 SurfObj
= EngLockSurface(PrimarySurface
.pSurface
);
544 SurfObj
->dhpdev
= PrimarySurface
.hPDev
;
545 SurfSize
= SurfObj
->sizlBitmap
;
546 SurfaceRect
.left
= SurfaceRect
.top
= 0;
547 SurfaceRect
.right
= SurfObj
->sizlBitmap
.cx
;
548 SurfaceRect
.bottom
= SurfObj
->sizlBitmap
.cy
;
549 /* FIXME - why does EngEraseSurface() sometimes crash?
550 EngEraseSurface(SurfObj, &SurfaceRect, 0); */
552 /* Put the pointer in the center of the screen */
553 gpsi
->ptCursor
.x
= (SurfaceRect
.right
- SurfaceRect
.left
) / 2;
554 gpsi
->ptCursor
.y
= (SurfaceRect
.bottom
- SurfaceRect
.top
) / 2;
556 /* Give the PDEV a MovePointer function */
557 PrimarySurface
.pfnMovePointer
= PrimarySurface
.DriverFunctions
.MovePointer
;
558 if (!PrimarySurface
.pfnMovePointer
)
559 PrimarySurface
.pfnMovePointer
= EngMovePointer
;
561 EngUnlockSurface(SurfObj
);
562 co_IntShowDesktop(IntGetActiveDesktop(), SurfSize
.cx
, SurfSize
.cy
);
564 // Init Primary Displays Device Capabilities.
565 IntvGetDeviceCaps(&PrimarySurface
, &GdiHandleTable
->DevCaps
);
576 IntDestroyPrimarySurface()
580 DRIVER_UnreferenceDriver(L
"DISPLAY");
582 calledFromUser
= UserIsEntered();
585 UserEnterExclusive();
589 IntDetachMonitor(&PrimarySurface
);
597 * FIXME: Hide a mouse pointer there. Also because we have to prevent
598 * memory leaks with the Eng* mouse routines.
601 DPRINT("Reseting display\n" );
602 PrimarySurface
.DriverFunctions
.AssertMode(PrimarySurface
.hPDev
, FALSE
);
603 PrimarySurface
.DriverFunctions
.DisableSurface(PrimarySurface
.hPDev
);
604 PrimarySurface
.DriverFunctions
.DisablePDEV(PrimarySurface
.hPDev
);
605 PrimarySurface
.PreparedDriver
= FALSE
;
606 KeSetEvent(&VideoDriverNeedsPreparation
, 1, FALSE
);
607 KeResetEvent(&VideoDriverPrepared
);
611 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
616 IntcFonts(PPDEVOBJ pDevObj
)
619 // Msdn DrvQueryFont:
620 // If the number of fonts in DEVINFO is -1 and iFace is zero, the driver
621 // should return the number of fonts it supports.
622 if ( pDevObj
->DevInfo
.cFonts
== -1)
624 if (pDevObj
->DriverFunctions
.QueryFont
)
625 pDevObj
->DevInfo
.cFonts
=
626 (ULONG
)pDevObj
->DriverFunctions
.QueryFont(pDevObj
->hPDev
, 0, 0, &Junk
);
628 pDevObj
->DevInfo
.cFonts
= 0;
630 return pDevObj
->DevInfo
.cFonts
;
634 // Support multi display/device locks.
638 DC_LockDisplay(HDC hDC
)
641 PDC dc
= DC_LockDc(hDC
);
643 Resource
= dc
->ppdev
->hsemDevLock
;
645 if (!Resource
) return;
646 KeEnterCriticalRegion();
647 ExAcquireResourceExclusiveLite( Resource
, TRUE
);
652 DC_UnlockDisplay(HDC hDC
)
655 PDC dc
= DC_LockDc(hDC
);
657 Resource
= dc
->ppdev
->hsemDevLock
;
659 if (!Resource
) return;
660 ExReleaseResourceLite( Resource
);
661 KeLeaveCriticalRegion();
670 // I guess we will soon have more than one primary surface.
671 // This will do for now.
672 return &PrimarySurface
;
677 IntGdiReferencePdev(PPDEVOBJ ppdev
)
679 if (!hsemDriverMgmt
) hsemDriverMgmt
= EngCreateSemaphore(); // Hax, should be in dllmain.c
680 IntGdiAcquireSemaphore(hsemDriverMgmt
);
682 IntGdiReleaseSemaphore(hsemDriverMgmt
);
686 IntGdiUnreferencePdev(PPDEVOBJ ppdev
, DWORD CleanUpType
)
688 IntGdiAcquireSemaphore(hsemDriverMgmt
);
690 if (!ppdev
->cPdevRefs
)
692 // Handle the destruction of ppdev or PDEVOBJ or PDEVOBJ or PDEV etc.
694 IntGdiReleaseSemaphore(hsemDriverMgmt
);
701 IntGetColorManagementCaps(PPDEVOBJ pDevObj
)
705 if ( pDevObj
->flFlags
& PDEV_DISPLAY
)
707 if (pDevObj
->DevInfo
.iDitherFormat
== BMF_8BPP
||
708 pDevObj
->DevInfo
.flGraphicsCaps2
& GCAPS2_CHANGEGAMMARAMP
)
711 if (pDevObj
->DevInfo
.flGraphicsCaps
& GCAPS_CMYKCOLOR
)
712 ret
|= CM_CMYK_COLOR
;
713 if (pDevObj
->DevInfo
.flGraphicsCaps
& GCAPS_ICM
)
714 ret
|= CM_DEVICE_ICM
;
719 IntGdiGetDeviceCaps(PDC dc
, INT Index
)
722 PPDEVOBJ ppdev
= dc
->ppdev
;
723 /* Retrieve capability */
727 ret
= ppdev
->GDIInfo
.ulVersion
;
731 ret
= ppdev
->GDIInfo
.ulTechnology
;
735 ret
= ppdev
->GDIInfo
.ulHorzSize
;
739 ret
= ppdev
->GDIInfo
.ulVertSize
;
743 ret
= ppdev
->GDIInfo
.ulHorzRes
;
747 ret
= ppdev
->GDIInfo
.ulVertRes
;
751 ret
= ppdev
->GDIInfo
.ulLogPixelsX
;
755 ret
= ppdev
->GDIInfo
.ulLogPixelsY
;
759 if ( ppdev
->pGraphicsDev
&&
760 (((PGRAPHICS_DEVICE
)ppdev
->pGraphicsDev
)->StateFlags
&
761 DISPLAY_DEVICE_MIRRORING_DRIVER
))
766 ret
= ppdev
->GDIInfo
.cBitsPixel
;
770 ret
= ppdev
->GDIInfo
.cPlanes
;
778 ret
= ppdev
->GDIInfo
.ulNumColors
;
779 if ( ret
!= -1 ) ret
*= 5;
783 ret
= IntcFonts(ppdev
);
787 ret
= ppdev
->GDIInfo
.ulNumColors
;
791 ret
= ppdev
->GDIInfo
.ulAspectX
;
795 ret
= ppdev
->GDIInfo
.ulAspectY
;
799 ret
= ppdev
->GDIInfo
.ulAspectXY
;
807 ret
= ppdev
->GDIInfo
.ulNumPalReg
;
815 ret
= ppdev
->GDIInfo
.ulDACRed
+
816 ppdev
->GDIInfo
.ulDACGreen
+
817 ppdev
->GDIInfo
.ulDACBlue
;
821 ret
= ppdev
->GDIInfo
.ulVertRes
;
825 ret
= ppdev
->GDIInfo
.ulHorzRes
;
829 ret
= ppdev
->GDIInfo
.ulBltAlignment
;
833 ret
= ppdev
->GDIInfo
.flShadeBlend
;
837 ret
= IntGetColorManagementCaps(ppdev
);
841 ret
= ppdev
->GDIInfo
.szlPhysSize
.cx
;
845 ret
= ppdev
->GDIInfo
.szlPhysSize
.cy
;
848 case PHYSICALOFFSETX
:
849 ret
= ppdev
->GDIInfo
.ptlPhysOffset
.x
;
852 case PHYSICALOFFSETY
:
853 ret
= ppdev
->GDIInfo
.ptlPhysOffset
.y
;
857 ret
= ppdev
->GDIInfo
.ulVRefresh
;
861 ret
= ppdev
->GDIInfo
.flRaster
;
865 ret
= (CC_CIRCLES
| CC_PIE
| CC_CHORD
| CC_ELLIPSES
| CC_WIDE
|
866 CC_STYLED
| CC_WIDESTYLED
| CC_INTERIORS
| CC_ROUNDRECT
);
870 ret
= (LC_POLYLINE
| LC_MARKER
| LC_POLYMARKER
| LC_WIDE
|
871 LC_STYLED
| LC_WIDESTYLED
| LC_INTERIORS
);
875 ret
= (PC_POLYGON
| PC_RECTANGLE
| PC_WINDPOLYGON
| PC_SCANLINE
|
876 PC_WIDE
| PC_STYLED
| PC_WIDESTYLED
| PC_INTERIORS
);
880 ret
= ppdev
->GDIInfo
.flTextCaps
;
881 if (ppdev
->GDIInfo
.ulTechnology
) ret
|= TC_VA_ABLE
;
882 ret
|= (TC_SO_ABLE
|TC_UA_ABLE
);
897 NtGdiGetDeviceCaps(HDC hDC
,
906 SetLastWin32Error(ERROR_INVALID_HANDLE
);
910 ret
= IntGdiGetDeviceCaps(dc
, Index
);
912 DPRINT("(%04x,%d): returning %d\n", hDC
, Index
, ret
);
925 PGDIINFO pGdiInfo
= &pDevObj
->GDIInfo
;
927 pDevCaps
->ulVersion
= pGdiInfo
->ulVersion
;
928 pDevCaps
->ulTechnology
= pGdiInfo
->ulTechnology
;
929 pDevCaps
->ulHorzSizeM
= (pGdiInfo
->ulHorzSize
+ 500) / 1000;
930 pDevCaps
->ulVertSizeM
= (pGdiInfo
->ulVertSize
+ 500) / 1000;
931 pDevCaps
->ulHorzSize
= pGdiInfo
->ulHorzSize
;
932 pDevCaps
->ulVertSize
= pGdiInfo
->ulVertSize
;
933 pDevCaps
->ulHorzRes
= pGdiInfo
->ulHorzRes
;
934 pDevCaps
->ulVertRes
= pGdiInfo
->ulVertRes
;
935 pDevCaps
->ulVRefresh
= pGdiInfo
->ulVRefresh
;
936 pDevCaps
->ulDesktopHorzRes
= pGdiInfo
->ulHorzRes
;
937 pDevCaps
->ulDesktopVertRes
= pGdiInfo
->ulVertRes
;
938 pDevCaps
->ulBltAlignment
= pGdiInfo
->ulBltAlignment
;
939 pDevCaps
->ulPlanes
= pGdiInfo
->cPlanes
;
941 pDevCaps
->ulBitsPixel
= pGdiInfo
->cBitsPixel
;
942 if (pGdiInfo
->cBitsPixel
== 15) pDevCaps
->ulBitsPixel
= 16;
944 Tmp
= pGdiInfo
->ulNumColors
;
945 if ( Tmp
!= -1 ) Tmp
*= 5;
946 pDevCaps
->ulNumPens
= Tmp
;
947 pDevCaps
->ulNumColors
= pGdiInfo
->ulNumColors
;
949 pDevCaps
->ulNumFonts
= IntcFonts(pDevObj
);
951 pDevCaps
->ulRasterCaps
= pGdiInfo
->flRaster
;
952 pDevCaps
->ulShadeBlend
= pGdiInfo
->flShadeBlend
;
953 pDevCaps
->ulAspectX
= pGdiInfo
->ulAspectX
;
954 pDevCaps
->ulAspectY
= pGdiInfo
->ulAspectY
;
955 pDevCaps
->ulAspectXY
= pGdiInfo
->ulAspectXY
;
956 pDevCaps
->ulLogPixelsX
= pGdiInfo
->ulLogPixelsX
;
957 pDevCaps
->ulLogPixelsY
= pGdiInfo
->ulLogPixelsY
;
958 pDevCaps
->ulSizePalette
= pGdiInfo
->ulNumPalReg
;
959 pDevCaps
->ulColorRes
= pGdiInfo
->ulDACRed
+ pGdiInfo
->ulDACGreen
+ pGdiInfo
->ulDACBlue
;
960 pDevCaps
->ulPhysicalWidth
= pGdiInfo
->szlPhysSize
.cx
;
961 pDevCaps
->ulPhysicalHeight
= pGdiInfo
->szlPhysSize
.cy
;
962 pDevCaps
->ulPhysicalOffsetX
= pGdiInfo
->ptlPhysOffset
.x
;
963 pDevCaps
->ulPhysicalOffsetY
= pGdiInfo
->ptlPhysOffset
.y
;
964 pDevCaps
->ulPanningHorzRes
= pGdiInfo
->ulPanningHorzRes
;
965 pDevCaps
->ulPanningVertRes
= pGdiInfo
->ulPanningVertRes
;
966 pDevCaps
->xPanningAlignment
= pGdiInfo
->xPanningAlignment
;
967 pDevCaps
->yPanningAlignment
= pGdiInfo
->yPanningAlignment
;
970 Tmp
= pGdiInfo
->flTextCaps
| (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
972 pDevCaps
->ulTextCaps
= pGdiInfo
->flTextCaps
| (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
974 if (pGdiInfo
->ulTechnology
)
975 pDevCaps
->ulTextCaps
= Tmp
| TC_VA_ABLE
;
977 pDevCaps
->ulColorMgmtCaps
= IntGetColorManagementCaps(pDevObj
);
987 NtGdiGetDeviceCapsAll (
989 OUT PDEVCAPS pDevCaps
)
992 PDEVCAPS pSafeDevCaps
;
993 NTSTATUS Status
= STATUS_SUCCESS
;
998 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1002 pSafeDevCaps
= ExAllocatePoolWithTag(PagedPool
, sizeof(DEVCAPS
), TAG_TEMP
);
1010 IntvGetDeviceCaps(dc
->ppdev
, pSafeDevCaps
);
1014 ProbeForWrite(pDevCaps
,
1017 RtlCopyMemory(pDevCaps
, pSafeDevCaps
, sizeof(DEVCAPS
));
1019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1021 Status
= _SEH2_GetExceptionCode();
1025 ExFreePoolWithTag(pSafeDevCaps
, TAG_TEMP
);
1028 if (!NT_SUCCESS(Status
))
1030 SetLastNtError(Status
);
1045 PPDEVOBJ ppdev
, pGdiDevice
= (PPDEVOBJ
) hdev
;
1046 if (!pGdiDevice
) return NULL
;
1047 if ( pGdiDevice
< (PPDEVOBJ
)MmSystemRangeStart
) return NULL
;
1048 ppdev
= pPrimarySurface
;
1049 IntGdiAcquireSemaphore(hsemDriverMgmt
);
1052 if (pGdiDevice
== ppdev
) break;
1054 ppdev
= ppdev
->ppdevNext
;
1056 while (ppdev
!= NULL
);
1057 IntGdiReleaseSemaphore(hsemDriverMgmt
);
1058 if (!ppdev
) return NULL
;
1059 return pGdiDevice
->hPDev
;
1062 static NTSTATUS FASTCALL
1063 GetVideoRegistryKey(
1064 OUT PUNICODE_STRING RegistryPath
,
1065 IN PCUNICODE_STRING DeviceName
) /* ex: "\Device\Video0" */
1067 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1070 RtlInitUnicodeString(RegistryPath
, NULL
);
1071 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1072 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
1073 QueryTable
[0].Name
= DeviceName
->Buffer
;
1074 QueryTable
[0].EntryContext
= RegistryPath
;
1076 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
1081 if (!NT_SUCCESS(Status
))
1083 DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName
, Status
);
1084 return STATUS_NO_SUCH_DEVICE
;
1087 DPRINT("RegistryPath %wZ\n", RegistryPath
);
1088 return STATUS_SUCCESS
;
1092 static NTSTATUS FASTCALL
1094 OUT PUNICODE_STRING VideoDeviceName
,
1095 IN PCUNICODE_STRING DisplayDevice
) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
1097 UNICODE_STRING Prefix
= RTL_CONSTANT_STRING(L
"\\??\\");
1098 UNICODE_STRING ObjectName
;
1099 UNICODE_STRING KernelModeName
= { 0, };
1100 OBJECT_ATTRIBUTES ObjectAttributes
;
1103 HANDLE LinkHandle
= NULL
;
1106 RtlInitUnicodeString(VideoDeviceName
, NULL
);
1108 /* Get device name (DisplayDevice is "\.\xxx") */
1109 for (LastSlash
= DisplayDevice
->Length
/ sizeof(WCHAR
); LastSlash
> 0; LastSlash
--)
1111 if (DisplayDevice
->Buffer
[LastSlash
- 1] == L
'\\')
1117 DPRINT1("Invalid device name '%wZ'\n", DisplayDevice
);
1118 Status
= STATUS_OBJECT_NAME_INVALID
;
1121 ObjectName
= *DisplayDevice
;
1122 ObjectName
.Length
-= LastSlash
* sizeof(WCHAR
);
1123 ObjectName
.MaximumLength
-= LastSlash
* sizeof(WCHAR
);
1124 ObjectName
.Buffer
+= LastSlash
;
1126 /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
1127 KernelModeName
.MaximumLength
= Prefix
.Length
+ ObjectName
.Length
+ sizeof(UNICODE_NULL
);
1128 KernelModeName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1129 KernelModeName
.MaximumLength
,
1131 if (!KernelModeName
.Buffer
)
1133 Status
= STATUS_NO_MEMORY
;
1136 RtlCopyUnicodeString(&KernelModeName
, &Prefix
);
1137 Status
= RtlAppendUnicodeStringToString(&KernelModeName
, &ObjectName
);
1138 if (!NT_SUCCESS(Status
))
1141 /* Open \??\xxx (ex: "\??\DISPLAY1") */
1142 InitializeObjectAttributes(&ObjectAttributes
,
1147 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
,
1150 if (!NT_SUCCESS(Status
))
1152 DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1153 Status
= STATUS_NO_SUCH_DEVICE
;
1157 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, VideoDeviceName
, &Length
);
1158 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
1160 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1161 Status
= STATUS_NO_SUCH_DEVICE
;
1164 VideoDeviceName
->MaximumLength
= Length
;
1165 VideoDeviceName
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1166 VideoDeviceName
->MaximumLength
+ sizeof(UNICODE_NULL
),
1168 if (!VideoDeviceName
->Buffer
)
1170 Status
= STATUS_NO_MEMORY
;
1173 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, VideoDeviceName
, NULL
);
1174 VideoDeviceName
->Buffer
[VideoDeviceName
->MaximumLength
/ sizeof(WCHAR
) - 1] = UNICODE_NULL
;
1175 if (!NT_SUCCESS(Status
))
1177 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1178 Status
= STATUS_NO_SUCH_DEVICE
;
1181 Status
= STATUS_SUCCESS
;
1184 if (!NT_SUCCESS(Status
) && VideoDeviceName
->Buffer
)
1185 ExFreePoolWithTag(VideoDeviceName
->Buffer
, TAG_DC
);
1186 if (KernelModeName
.Buffer
)
1187 ExFreePoolWithTag(KernelModeName
.Buffer
, TAG_DC
);
1189 ZwClose(LinkHandle
);
1195 IntChangeDisplaySettings(
1196 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1197 IN LPDEVMODEW DevMode
,
1199 IN PVOID lParam OPTIONAL
)
1201 BOOLEAN Global
= FALSE
;
1202 BOOLEAN NoReset
= FALSE
;
1203 BOOLEAN Reset
= FALSE
;
1204 BOOLEAN SetPrimary
= FALSE
;
1205 LONG Ret
= DISP_CHANGE_SUCCESSFUL
;
1208 DPRINT1("display flags : %x\n",dwflags
);
1210 if ((dwflags
& CDS_UPDATEREGISTRY
) == CDS_UPDATEREGISTRY
)
1212 /* Check global, reset and noreset flags */
1213 if ((dwflags
& CDS_GLOBAL
) == CDS_GLOBAL
)
1215 if ((dwflags
& CDS_NORESET
) == CDS_NORESET
)
1217 dwflags
&= ~(CDS_GLOBAL
| CDS_NORESET
);
1219 if ((dwflags
& CDS_RESET
) == CDS_RESET
)
1221 if ((dwflags
& CDS_SET_PRIMARY
) == CDS_SET_PRIMARY
)
1223 dwflags
&= ~(CDS_RESET
| CDS_SET_PRIMARY
);
1225 if (Reset
&& NoReset
)
1226 return DISP_CHANGE_BADFLAGS
;
1230 /* Dynamically change graphics mode */
1231 DPRINT1("flag 0 UNIMPLEMENTED\n");
1232 return DISP_CHANGE_FAILED
;
1233 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED
);
1236 if ((dwflags
& CDS_TEST
) == CDS_TEST
)
1238 /* Test resolution */
1239 dwflags
&= ~CDS_TEST
;
1240 Status
= IntEnumDisplaySettings(pDeviceName
, ENUM_REGISTRY_SETTINGS
, DevMode
, 0);
1241 if (!NT_SUCCESS(Status
))
1242 Ret
= DISP_CHANGE_BADMODE
;
1246 if ((dwflags
& CDS_FULLSCREEN
) == CDS_FULLSCREEN
)
1250 dwflags
&= ~CDS_FULLSCREEN
;
1251 DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
1252 Ret
= DISP_CHANGE_FAILED
;
1254 RtlZeroMemory(&lpDevMode
, sizeof(DEVMODEW
));
1255 lpDevMode
.dmSize
= sizeof(DEVMODEW
);
1257 Status
= IntEnumDisplaySettings(pDeviceName
, ENUM_CURRENT_SETTINGS
, &lpDevMode
, 0);
1258 if (!NT_SUCCESS(Status
))
1259 return DISP_CHANGE_FAILED
;
1261 DPRINT1("Req Mode : %d x %d x %d\n", DevMode
->dmPelsWidth
,DevMode
->dmPelsHeight
,DevMode
->dmBitsPerPel
);
1262 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode
.dmPelsWidth
,lpDevMode
.dmPelsHeight
, lpDevMode
.dmBitsPerPel
);
1265 if ((lpDevMode
.dmBitsPerPel
== DevMode
->dmBitsPerPel
) &&
1266 (lpDevMode
.dmPelsWidth
== DevMode
->dmPelsWidth
) &&
1267 (lpDevMode
.dmPelsHeight
== DevMode
->dmPelsHeight
))
1268 Ret
= DISP_CHANGE_SUCCESSFUL
;
1271 if ((dwflags
& CDS_VIDEOPARAMETERS
) == CDS_VIDEOPARAMETERS
)
1273 dwflags
&= ~CDS_VIDEOPARAMETERS
;
1275 Ret
=DISP_CHANGE_BADPARAM
;
1278 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
1279 Ret
= DISP_CHANGE_FAILED
;
1280 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED
);
1285 if ((dwflags
& CDS_UPDATEREGISTRY
) == CDS_UPDATEREGISTRY
)
1288 UNICODE_STRING DeviceName
;
1289 UNICODE_STRING RegistryKey
;
1290 UNICODE_STRING InDeviceName
;
1291 OBJECT_ATTRIBUTES ObjectAttributes
;
1292 HANDLE DevInstRegKey
;
1295 DPRINT1("set CDS_UPDATEREGISTRY\n");
1297 dwflags
&= ~CDS_UPDATEREGISTRY
;
1299 /* Check if pDeviceName is NULL, we need to retrieve it */
1300 if (pDeviceName
== NULL
)
1302 WCHAR szBuffer
[MAX_DRIVER_NAME
];
1304 PWINDOW_OBJECT Wnd
=NULL
;
1308 hWnd
= IntGetDesktopWindow();
1309 if (!(Wnd
= UserGetWindowObject(hWnd
)))
1314 hDC
= UserGetWindowDC(Wnd
);
1316 DC
= DC_LockDc(hDC
);
1321 swprintf (szBuffer
, L
"\\\\.\\DISPLAY%lu", DC
->ppdev
->DisplayNumber
);
1324 RtlInitUnicodeString(&InDeviceName
, szBuffer
);
1325 pDeviceName
= &InDeviceName
;
1328 Status
= GetVideoDeviceName(&DeviceName
, pDeviceName
);
1329 if (!NT_SUCCESS(Status
))
1331 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName
, Status
);
1332 return DISP_CHANGE_FAILED
;
1334 Status
= GetVideoRegistryKey(&RegistryKey
, &DeviceName
);
1335 if (!NT_SUCCESS(Status
))
1337 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName
, Status
);
1338 ExFreePoolWithTag(DeviceName
.Buffer
, TAG_DC
);
1339 return DISP_CHANGE_FAILED
;
1341 ExFreePoolWithTag(DeviceName
.Buffer
, TAG_DC
);
1343 InitializeObjectAttributes(&ObjectAttributes
, &RegistryKey
,
1344 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1345 Status
= ZwOpenKey(&DevInstRegKey
, KEY_SET_VALUE
, &ObjectAttributes
);
1346 if (!NT_SUCCESS(Status
))
1348 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey
, Status
);
1349 ExFreePoolWithTag(RegistryKey
.Buffer
, TAG_RTLREGISTRY
);
1350 return DISP_CHANGE_FAILED
;
1352 ExFreePoolWithTag(RegistryKey
.Buffer
, TAG_RTLREGISTRY
);
1354 /* Update needed fields */
1355 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_BITSPERPEL
)
1357 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.BitsPerPel");
1358 NewValue
= DevMode
->dmBitsPerPel
;
1359 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1362 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_PELSWIDTH
)
1364 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.XResolution");
1365 NewValue
= DevMode
->dmPelsWidth
;
1366 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1369 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_PELSHEIGHT
)
1371 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.YResolution");
1372 NewValue
= DevMode
->dmPelsHeight
;
1373 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1376 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_DISPLAYFREQUENCY
)
1378 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.VRefresh");
1379 NewValue
= DevMode
->dmDisplayFrequency
;
1380 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1383 ZwClose(DevInstRegKey
);
1384 if (NT_SUCCESS(Status
))
1385 Ret
= DISP_CHANGE_RESTART
;
1387 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
1388 Ret
= DISP_CHANGE_NOTUPDATED
;
1392 Ret
= DISP_CHANGE_BADFLAGS
;
1394 DPRINT("IntChangeDisplaySettings returning %x\n", Ret
);
1400 #define SIZEOF_DEVMODEW_300 188
1401 #define SIZEOF_DEVMODEW_400 212
1402 #define SIZEOF_DEVMODEW_500 220
1404 static NTSTATUS FASTCALL
1405 GetDisplayNumberFromDeviceName(
1406 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1407 OUT ULONG
*DisplayNumber
)
1409 UNICODE_STRING DisplayString
= RTL_CONSTANT_STRING(L
"\\\\.\\DISPLAY");
1410 NTSTATUS Status
= STATUS_SUCCESS
;
1415 if (DisplayNumber
== NULL
)
1416 return STATUS_INVALID_PARAMETER_2
;
1418 /* Check if DeviceName is valid */
1420 pDeviceName
->Length
> 0 && pDeviceName
->Length
<= DisplayString
.Length
)
1421 return STATUS_OBJECT_NAME_INVALID
;
1423 if (pDeviceName
== NULL
|| pDeviceName
->Length
== 0)
1425 PWINDOW_OBJECT DesktopObject
;
1429 DesktopObject
= UserGetDesktopWindow();
1430 DesktopHDC
= UserGetWindowDC(DesktopObject
);
1431 pDC
= DC_LockDc(DesktopHDC
);
1433 *DisplayNumber
= pDC
->ppdev
->DisplayNumber
;
1436 UserReleaseDC(DesktopObject
, DesktopHDC
, FALSE
);
1438 return STATUS_SUCCESS
;
1441 /* Hack to check if the first parts are equal, by faking the device name length */
1442 Length
= pDeviceName
->Length
;
1443 pDeviceName
->Length
= DisplayString
.Length
;
1444 if (RtlEqualUnicodeString(&DisplayString
, pDeviceName
, FALSE
) == FALSE
)
1445 Status
= STATUS_OBJECT_NAME_INVALID
;
1446 pDeviceName
->Length
= Length
;
1448 if (NT_SUCCESS(Status
))
1450 /* Convert the last part of pDeviceName to a number */
1452 Length
= pDeviceName
->Length
/ sizeof(WCHAR
);
1453 for (i
= DisplayString
.Length
/ sizeof(WCHAR
); i
< Length
; i
++)
1455 WCHAR Char
= pDeviceName
->Buffer
[i
];
1456 if (Char
>= L
'0' && Char
<= L
'9')
1457 Number
= Number
* 10 + Char
- L
'0';
1458 else if (Char
!= L
'\0')
1459 return STATUS_OBJECT_NAME_INVALID
;
1462 *DisplayNumber
= Number
- 1;
1468 /*! \brief Enumerate possible display settings for the given display...
1470 * \todo Make thread safe!?
1471 * \todo Don't ignore pDeviceName
1472 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
1476 IntEnumDisplaySettings(
1477 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1479 IN OUT LPDEVMODEW pDevMode
,
1482 static DEVMODEW
*CachedDevModes
= NULL
, *CachedDevModesEnd
= NULL
;
1483 static DWORD SizeOfCachedDevModes
= 0;
1484 static UNICODE_STRING CachedDeviceName
;
1485 PDEVMODEW CachedMode
= NULL
;
1487 ULONG DisplayNumber
;
1490 Status
= GetDisplayNumberFromDeviceName(pDeviceName
, &DisplayNumber
);
1491 if (!NT_SUCCESS(Status
))
1496 DPRINT("DevMode->dmSize = %d\n", pDevMode
->dmSize
);
1497 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode
->dmDriverExtra
);
1498 if (pDevMode
->dmSize
!= SIZEOF_DEVMODEW_300
&&
1499 pDevMode
->dmSize
!= SIZEOF_DEVMODEW_400
&&
1500 pDevMode
->dmSize
!= SIZEOF_DEVMODEW_500
)
1502 return STATUS_BUFFER_TOO_SMALL
;
1505 if (iModeNum
== ENUM_CURRENT_SETTINGS
)
1507 CachedMode
= &PrimarySurface
.DMW
;
1508 ASSERT(CachedMode
->dmSize
> 0);
1510 else if (iModeNum
== ENUM_REGISTRY_SETTINGS
)
1512 RtlZeroMemory(&DevMode
, sizeof (DevMode
));
1513 DevMode
.dmSize
= sizeof (DevMode
);
1514 DevMode
.dmDriverExtra
= 0;
1515 if (SetupDevMode(&DevMode
, DisplayNumber
))
1516 CachedMode
= &DevMode
;
1519 return STATUS_UNSUCCESSFUL
; // FIXME: what status?
1521 /* FIXME: Maybe look for the matching devmode supplied by the
1522 * driver so we can provide driver private/extra data?
1527 BOOL IsCachedDevice
= (CachedDevModes
!= NULL
);
1529 if (CachedDevModes
&&
1530 ((pDeviceName
== NULL
&& CachedDeviceName
.Length
> 0) ||
1531 (pDeviceName
!= NULL
&& pDeviceName
->Buffer
!= NULL
&& CachedDeviceName
.Length
== 0) ||
1532 (pDeviceName
!= NULL
&& pDeviceName
->Buffer
!= NULL
&& CachedDeviceName
.Length
> 0 && RtlEqualUnicodeString(pDeviceName
, &CachedDeviceName
, TRUE
) == FALSE
)))
1534 IsCachedDevice
= FALSE
;
1537 if (iModeNum
== 0 || IsCachedDevice
== FALSE
) /* query modes from drivers */
1539 UNICODE_STRING DriverFileNames
;
1541 DRVENABLEDATA DrvEnableData
;
1543 /* Free resources from last driver cache */
1544 if (IsCachedDevice
== FALSE
&& CachedDeviceName
.Buffer
!= NULL
)
1546 RtlFreeUnicodeString(&CachedDeviceName
);
1549 /* Retrieve DDI driver names from registry */
1550 RtlInitUnicodeString(&DriverFileNames
, NULL
);
1551 if (!FindDriverFileNames(&DriverFileNames
, DisplayNumber
))
1553 DPRINT1("FindDriverFileNames failed\n");
1554 return STATUS_UNSUCCESSFUL
;
1557 if (!IntPrepareDriverIfNeeded())
1559 DPRINT1("IntPrepareDriverIfNeeded failed\n");
1560 return STATUS_UNSUCCESSFUL
;
1564 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
1565 * scan all of them until a good one found.
1567 CurrentName
= DriverFileNames
.Buffer
;
1568 for (;CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
));
1569 CurrentName
+= wcslen(CurrentName
) + 1)
1572 PFN_DrvEnableDriver GDEnableDriver
;
1573 PFN_DrvGetModes GetModes
= NULL
;
1574 INT SizeNeeded
, SizeUsed
;
1576 /* Get the DDI driver's entry point */
1577 //GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
1578 GDEnableDriver
= DRIVER_FindExistingDDIDriver(L
"DISPLAY");
1579 if (NULL
== GDEnableDriver
)
1581 DPRINT("FindDDIDriver failed for %S\n", CurrentName
);
1585 /* Call DDI driver's EnableDriver function */
1586 RtlZeroMemory(&DrvEnableData
, sizeof(DrvEnableData
));
1588 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01
, sizeof (DrvEnableData
), &DrvEnableData
))
1590 DPRINT("DrvEnableDriver failed for %S\n", CurrentName
);
1594 CachedDevModesEnd
= CachedDevModes
;
1596 /* find DrvGetModes function */
1597 for (i
= 0; i
< DrvEnableData
.c
; i
++)
1599 PDRVFN DrvFn
= DrvEnableData
.pdrvfn
+ i
;
1601 if (DrvFn
->iFunc
== INDEX_DrvGetModes
)
1603 GetModes
= (PFN_DrvGetModes
)DrvFn
->pfn
;
1608 if (GetModes
== NULL
)
1610 DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName
);
1614 /* make sure we have enough memory to hold the modes */
1615 SizeNeeded
= GetModes((HANDLE
)(PrimarySurface
.VideoFileObject
->DeviceObject
), 0, NULL
);
1616 if (SizeNeeded
<= 0)
1618 DPRINT("DrvGetModes failed for %S\n", CurrentName
);
1622 SizeUsed
= (PCHAR
)CachedDevModesEnd
- (PCHAR
)CachedDevModes
;
1623 if (SizeOfCachedDevModes
< SizeUsed
+ SizeNeeded
)
1627 SizeOfCachedDevModes
+= SizeNeeded
;
1628 NewBuffer
= ExAllocatePool(PagedPool
, SizeOfCachedDevModes
);
1629 if (NewBuffer
== NULL
)
1632 ExFreePool(CachedDevModes
);
1633 CachedDevModes
= NULL
;
1634 CachedDevModesEnd
= NULL
;
1635 SizeOfCachedDevModes
= 0;
1637 if (CachedDeviceName
.Buffer
!= NULL
)
1638 RtlFreeUnicodeString(&CachedDeviceName
);
1640 return STATUS_NO_MEMORY
;
1642 if (CachedDevModes
!= NULL
)
1644 RtlCopyMemory(NewBuffer
, CachedDevModes
, SizeUsed
);
1645 ExFreePool(CachedDevModes
);
1647 CachedDevModes
= NewBuffer
;
1648 CachedDevModesEnd
= (DEVMODEW
*)((PCHAR
)NewBuffer
+ SizeUsed
);
1651 if (!IsCachedDevice
)
1653 if (CachedDeviceName
.Buffer
!= NULL
)
1654 RtlFreeUnicodeString(&CachedDeviceName
);
1657 IntSafeCopyUnicodeString(&CachedDeviceName
, pDeviceName
);
1659 IsCachedDevice
= TRUE
;
1663 SizeNeeded
= GetModes((HANDLE
)(PrimarySurface
.VideoFileObject
->DeviceObject
),
1666 if (SizeNeeded
<= 0)
1668 DPRINT("DrvGetModes failed for %S\n", CurrentName
);
1672 CachedDevModesEnd
= (DEVMODEW
*)((PCHAR
)CachedDevModesEnd
+ SizeNeeded
);
1676 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
1679 /* return cached info */
1680 CachedMode
= CachedDevModes
;
1681 if (CachedMode
>= CachedDevModesEnd
)
1683 return STATUS_NO_MORE_ENTRIES
;
1685 while (iModeNum
-- > 0 && CachedMode
< CachedDevModesEnd
)
1687 assert(CachedMode
->dmSize
> 0);
1688 CachedMode
= (DEVMODEW
*)((PCHAR
)CachedMode
+ CachedMode
->dmSize
+ CachedMode
->dmDriverExtra
);
1690 if (CachedMode
>= CachedDevModesEnd
)
1692 return STATUS_NO_MORE_ENTRIES
;
1696 ASSERT(CachedMode
!= NULL
);
1698 RtlCopyMemory(pDevMode
, CachedMode
, min(pDevMode
->dmSize
, CachedMode
->dmSize
));
1699 RtlZeroMemory(pDevMode
+ pDevMode
->dmSize
, pDevMode
->dmDriverExtra
);
1700 RtlCopyMemory(pDevMode
+ min(pDevMode
->dmSize
, CachedMode
->dmSize
), CachedMode
+ CachedMode
->dmSize
, min(pDevMode
->dmDriverExtra
, CachedMode
->dmDriverExtra
));
1702 return STATUS_SUCCESS
;
1711 IN OPTIONAL LPSTR pjIn
)