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
);
65 EnumDisplayQueryRoutine(IN PWSTR ValueName
,
70 IN PVOID EntryContext
)
72 if ((Context
== NULL
) && ((ValueType
== REG_SZ
) || (ValueType
== REG_MULTI_SZ
)))
74 *(PULONG
)EntryContext
= ValueLength
;
78 DPRINT1("Value data: %S %d\n", ValueData
, ValueLength
);
79 RtlCopyMemory(Context
, ValueData
, ValueLength
);
82 return STATUS_SUCCESS
;
86 FindDriverFileNames(PUNICODE_STRING DriverFileNames
, ULONG DisplayNumber
)
88 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
89 UNICODE_STRING RegistryPath
;
91 PWCHAR DriverNames
= NULL
;
94 if (! GetRegistryPath(&RegistryPath
, DisplayNumber
))
96 DPRINT("GetRegistryPath failed\n");
100 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
101 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_NOEXPAND
;
102 QueryTable
[0].Name
= L
"InstalledDisplayDrivers";
103 QueryTable
[0].EntryContext
= &Length
;
104 QueryTable
[0].QueryRoutine
= EnumDisplayQueryRoutine
;
106 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
111 // DPRINT1("Status: %lx\n", Status);
114 DriverNames
= ExAllocatePool(PagedPool
, Length
);
115 // DPRINT1("Length allocated: %d\n", Length);
116 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
121 if (!NT_SUCCESS(Status
)) DriverNames
= NULL
;
124 ExFreePoolWithTag(RegistryPath
.Buffer
, TAG_RTLREGISTRY
);
125 if (! NT_SUCCESS(Status
))
127 DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
131 RtlInitUnicodeString(DriverFileNames
, DriverNames
);
132 DriverFileNames
->Length
= Length
;
133 DriverFileNames
->MaximumLength
= Length
;
134 //DPRINT1("DriverFileNames %wZ\n", DriverFileNames);
140 static NTSTATUS APIENTRY
141 DevModeCallback(IN PWSTR ValueName
,
144 IN ULONG ValueLength
,
146 IN PVOID EntryContext
)
148 PDEVMODEW DevMode
= (PDEVMODEW
) Context
;
150 DPRINT("Found registry value for name %S: type %d, length %d\n",
151 ValueName
, ValueType
, ValueLength
);
153 if (REG_DWORD
== ValueType
&& sizeof(DWORD
) == ValueLength
)
155 if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.BitsPerPel"))
157 DevMode
->dmBitsPerPel
= *((DWORD
*) ValueData
);
159 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.Flags"))
161 DevMode
->dmDisplayFlags
= *((DWORD
*) ValueData
);
163 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.VRefresh"))
165 DevMode
->dmDisplayFrequency
= *((DWORD
*) ValueData
);
167 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.XPanning"))
169 DevMode
->dmPanningWidth
= *((DWORD
*) ValueData
);
171 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.XResolution"))
173 DevMode
->dmPelsWidth
= *((DWORD
*) ValueData
);
175 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.YPanning"))
177 DevMode
->dmPanningHeight
= *((DWORD
*) ValueData
);
179 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.YResolution"))
181 DevMode
->dmPelsHeight
= *((DWORD
*) ValueData
);
185 return STATUS_SUCCESS
;
190 SetupDevMode(PDEVMODEW DevMode
, ULONG DisplayNumber
)
192 UNICODE_STRING RegistryPath
;
193 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
195 BOOLEAN Valid
= TRUE
;
197 if (!GetRegistryPath(&RegistryPath
, DisplayNumber
))
199 DPRINT("GetRegistryPath failed\n");
203 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
204 QueryTable
[0].QueryRoutine
= DevModeCallback
;
205 QueryTable
[0].Flags
= 0;
206 QueryTable
[0].Name
= NULL
;
207 QueryTable
[0].EntryContext
= NULL
;
208 QueryTable
[0].DefaultType
= REG_NONE
;
209 QueryTable
[0].DefaultData
= NULL
;
210 QueryTable
[0].DefaultLength
= 0;
212 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
217 if (! NT_SUCCESS(Status
))
219 DPRINT("RtlQueryRegistryValues for %wZ failed with status 0x%08x\n",
220 &RegistryPath
, Status
);
225 DPRINT("dmBitsPerPel %d dmDisplayFrequency %d dmPelsWidth %d dmPelsHeight %d\n",
226 DevMode
->dmBitsPerPel
, DevMode
->dmDisplayFrequency
,
227 DevMode
->dmPelsWidth
, DevMode
->dmPelsHeight
);
228 if (0 == DevMode
->dmBitsPerPel
|| 0 == DevMode
->dmDisplayFrequency
229 || 0 == DevMode
->dmPelsWidth
|| 0 == DevMode
->dmPelsHeight
)
231 DPRINT("Not all required devmode members are set\n");
236 ExFreePoolWithTag(RegistryPath
.Buffer
, TAG_RTLREGISTRY
);
240 RtlZeroMemory(DevMode
, sizeof(DEVMODEW
));
247 IntPrepareDriver(VOID
)
249 PFN_DrvEnableDriver GDEnableDriver
;
251 UNICODE_STRING DriverFileNames
;
260 if (STATUS_SUCCESS
!= KeWaitForSingleObject(&VideoDriverNeedsPreparation
, Executive
, KernelMode
, TRUE
, &Zero
))
262 /* Concurrent access. Wait for VideoDriverPrepared event */
263 if (STATUS_SUCCESS
== KeWaitForSingleObject(&VideoDriverPrepared
, Executive
, KernelMode
, TRUE
, NULL
))
264 ret
= PrimarySurface
.PreparedDriver
;
267 // HAX! Fixme so I can support more than one! So how many?
268 for (DisplayNumber
= 0; ; DisplayNumber
++)
270 DPRINT("Trying to load display driver no. %d\n", DisplayNumber
);
272 RtlZeroMemory(&PrimarySurface
, sizeof(PrimarySurface
));
274 // if (!pPrimarySurface) pPrimarySurface = ExAllocatePoolWithTag(PagedPool, gdwDirectDrawContext + sizeof(PDEVOBJ), TAG_GDIPDEV);
276 PrimarySurface
.VideoFileObject
= DRIVER_FindMPDriver(DisplayNumber
);
278 /* Open the miniport driver */
279 if (PrimarySurface
.VideoFileObject
== NULL
)
281 DPRINT1("FindMPDriver failed\n");
285 /* Retrieve DDI driver names from registry */
286 RtlInitUnicodeString(&DriverFileNames
, NULL
);
287 if (!FindDriverFileNames(&DriverFileNames
, DisplayNumber
))
289 DPRINT1("FindDriverFileNames failed\n");
294 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
295 * scan all of them until a good one found.
297 CurrentName
= DriverFileNames
.Buffer
;
300 CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
302 /* Get the DDI driver's entry point */
303 GDEnableDriver
= DRIVER_FindDDIDriver(CurrentName
);
304 if (NULL
== GDEnableDriver
)
306 DPRINT("FindDDIDriver failed for %S\n", CurrentName
);
310 /* Call DDI driver's EnableDriver function */
311 RtlZeroMemory(&DED
, sizeof(DED
));
313 if (! GDEnableDriver(DDI_DRIVER_VERSION_NT5_01
, sizeof(DED
), &DED
))
315 DPRINT("DrvEnableDriver failed for %S\n", CurrentName
);
325 /* Skip to the next name but never get past the Unicode string */
326 while (L
'\0' != *CurrentName
&&
327 CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
331 if (CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
340 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
341 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
342 DPRINT1("No suitable DDI driver found\n");
346 DPRINT1("Display driver %S loaded\n", CurrentName
);
348 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
350 DPRINT("Building DDI Functions\n");
352 /* Construct DDI driver function dispatch table */
353 if (!DRIVER_BuildDDIFunctions(&DED
, &PrimarySurface
.DriverFunctions
))
355 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
356 DPRINT1("BuildDDIFunctions failed\n");
360 /* Allocate a phyical device handle from the driver */
361 // Support DMW.dmSize + DMW.dmDriverExtra & Alloc DMW then set prt pdmwDev.
362 PrimarySurface
.DMW
.dmSize
= sizeof (PrimarySurface
.DMW
);
363 if (SetupDevMode(&PrimarySurface
.DMW
, DisplayNumber
))
365 PrimarySurface
.dhpdev
= PrimarySurface
.DriverFunctions
.EnablePDEV(
369 PrimarySurface
.ahsurf
,
370 sizeof(PrimarySurface
.gdiinfo
),
371 &PrimarySurface
.gdiinfo
,
372 sizeof(PrimarySurface
.devinfo
),
373 &PrimarySurface
.devinfo
,
376 (HANDLE
) (PrimarySurface
.VideoFileObject
->DeviceObject
));
377 DoDefault
= (NULL
== PrimarySurface
.dhpdev
);
380 DPRINT1("DrvEnablePDev with registry parameters failed\n");
390 RtlZeroMemory(&(PrimarySurface
.DMW
), sizeof(DEVMODEW
));
391 PrimarySurface
.DMW
.dmSize
= sizeof (PrimarySurface
.DMW
);
392 PrimarySurface
.dhpdev
= PrimarySurface
.DriverFunctions
.EnablePDEV(
396 PrimarySurface
.ahsurf
,
397 sizeof(PrimarySurface
.gdiinfo
),
398 &PrimarySurface
.gdiinfo
,
399 sizeof(PrimarySurface
.devinfo
),
400 &PrimarySurface
.devinfo
,
403 (HANDLE
) (PrimarySurface
.VideoFileObject
->DeviceObject
));
405 if (NULL
== PrimarySurface
.dhpdev
)
407 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
408 DPRINT1("DrvEnablePDEV with default parameters failed\n");
409 DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
413 // Update the primary surface with what we really got
414 PrimarySurface
.DMW
.dmPelsWidth
= PrimarySurface
.gdiinfo
.ulHorzRes
;
415 PrimarySurface
.DMW
.dmPelsHeight
= PrimarySurface
.gdiinfo
.ulVertRes
;
416 PrimarySurface
.DMW
.dmBitsPerPel
= PrimarySurface
.gdiinfo
.cBitsPixel
;
417 PrimarySurface
.DMW
.dmDisplayFrequency
= PrimarySurface
.gdiinfo
.ulVRefresh
;
420 if (!PrimarySurface
.DMW
.dmDriverExtra
)
422 PrimarySurface
.pdmwDev
= &PrimarySurface
.DMW
; // HAX!
426 DPRINT1("WARNING!!! Need to Alloc DMW !!!!!!\n");
428 // Dont remove until we finish testing other drivers.
429 if (PrimarySurface
.DMW
.dmDriverExtra
!= 0)
431 DPRINT1("**** DMW extra = %u bytes. Please report to ros-dev@reactos.org ****\n", PrimarySurface
.DMW
.dmDriverExtra
);
434 if (0 == PrimarySurface
.gdiinfo
.ulLogPixelsX
)
436 DPRINT("Adjusting gdiinfo.ulLogPixelsX\n");
437 PrimarySurface
.gdiinfo
.ulLogPixelsX
= 96;
439 if (0 == PrimarySurface
.gdiinfo
.ulLogPixelsY
)
441 DPRINT("Adjusting gdiinfo.ulLogPixelsY\n");
442 PrimarySurface
.gdiinfo
.ulLogPixelsY
= 96;
445 PrimarySurface
.Pointer
.Exclude
.right
= -1;
447 DPRINT("calling completePDev\n");
449 /* Complete initialization of the physical device */
450 PrimarySurface
.DriverFunctions
.CompletePDEV(
451 PrimarySurface
.dhpdev
,
452 (HDEV
)&PrimarySurface
);
454 DPRINT("calling DRIVER_ReferenceDriver\n");
456 DRIVER_ReferenceDriver(L
"DISPLAY");
458 PrimarySurface
.PreparedDriver
= TRUE
;
459 PrimarySurface
.DisplayNumber
= DisplayNumber
;
460 PrimarySurface
.flFlags
= PDEV_DISPLAY
; // Hard set,, add more flags.
461 PrimarySurface
.hsemDevLock
= (PERESOURCE
)EngCreateSemaphore();
462 // Should be null,, but make sure for now.
463 PrimarySurface
.pvGammaRamp
= NULL
;
464 PrimarySurface
.ppdevNext
= NULL
; // Fixme! We need to support more than display drvs.
465 PrimarySurface
.ppdevParent
= NULL
; // Always NULL if primary.
466 PrimarySurface
.pGraphicsDevice
= NULL
; // Fixme!
467 PrimarySurface
.pEDDgpl
= ExAllocatePoolWithTag(PagedPool
, sizeof(EDD_DIRECTDRAW_GLOBAL
), TAG_EDDGBL
);
468 if (PrimarySurface
.pEDDgpl
)
470 RtlZeroMemory( PrimarySurface
.pEDDgpl
,sizeof(EDD_DIRECTDRAW_GLOBAL
));
477 KeSetEvent(&VideoDriverPrepared
, 1, FALSE
);
482 IntPrepareDriverIfNeeded(VOID
)
484 return (PrimarySurface
.PreparedDriver
? TRUE
: IntPrepareDriver());
488 PrepareVideoPrt(VOID
)
492 IO_STATUS_BLOCK Iosb
;
494 ULONG Length
= sizeof(BOOL
);
495 PIO_STACK_LOCATION StackPtr
;
496 LARGE_INTEGER StartOffset
;
497 PFILE_OBJECT FileObject
= PrimarySurface
.VideoFileObject
;
498 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
500 DPRINT("PrepareVideoPrt() called\n");
502 KeClearEvent(&PrimarySurface
.VideoFileObject
->Event
);
504 ObReferenceObjectByPointer(FileObject
, 0, IoFileObjectType
, KernelMode
);
506 StartOffset
.QuadPart
= 0;
507 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
519 /* Set up IRP Data */
520 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
521 Irp
->RequestorMode
= KernelMode
;
522 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
523 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
= NULL
;
524 Irp
->Flags
|= IRP_WRITE_OPERATION
;
526 /* Setup Stack Data */
527 StackPtr
= IoGetNextIrpStackLocation(Irp
);
528 StackPtr
->FileObject
= PrimarySurface
.VideoFileObject
;
529 StackPtr
->Parameters
.Write
.Key
= 0;
531 Status
= IoCallDriver(DeviceObject
, Irp
);
533 if (STATUS_PENDING
== Status
)
535 KeWaitForSingleObject(&FileObject
->Event
, Executive
, KernelMode
, TRUE
, 0);
536 Status
= Iosb
.Status
;
539 return NT_SUCCESS(Status
);
544 IntCreatePrimarySurface(VOID
)
551 if (! IntPrepareDriverIfNeeded())
556 if (! PrepareVideoPrt())
561 DPRINT("calling EnableSurface\n");
562 /* Enable the drawing surface */
563 PrimarySurface
.pSurface
=
564 PrimarySurface
.DriverFunctions
.EnableSurface(PrimarySurface
.dhpdev
);
565 if (NULL
== PrimarySurface
.pSurface
)
567 /* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, FALSE);*/
568 PrimarySurface
.DriverFunctions
.DisablePDEV(PrimarySurface
.dhpdev
);
569 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
570 DPRINT1("DrvEnableSurface failed\n");
574 PrimarySurface
.DriverFunctions
.AssertMode(PrimarySurface
.dhpdev
, TRUE
);
576 calledFromUser
= UserIsEntered(); //fixme: possibly upgrade a shared lock
579 UserEnterExclusive();
583 IntAttachMonitor(&PrimarySurface
, PrimarySurface
.DisplayNumber
);
585 SurfObj
= EngLockSurface(PrimarySurface
.pSurface
);
586 SurfObj
->dhpdev
= PrimarySurface
.dhpdev
;
587 SurfSize
= SurfObj
->sizlBitmap
;
588 SurfaceRect
.left
= SurfaceRect
.top
= 0;
589 SurfaceRect
.right
= SurfObj
->sizlBitmap
.cx
;
590 SurfaceRect
.bottom
= SurfObj
->sizlBitmap
.cy
;
591 /* FIXME - why does EngEraseSurface() sometimes crash?
592 EngEraseSurface(SurfObj, &SurfaceRect, 0); */
594 /* Put the pointer in the center of the screen */
595 gpsi
->ptCursor
.x
= (SurfaceRect
.right
- SurfaceRect
.left
) / 2;
596 gpsi
->ptCursor
.y
= (SurfaceRect
.bottom
- SurfaceRect
.top
) / 2;
598 /* Give the PDEV a MovePointer function */
599 PrimarySurface
.pfnMovePointer
= PrimarySurface
.DriverFunctions
.MovePointer
;
600 if (!PrimarySurface
.pfnMovePointer
)
601 PrimarySurface
.pfnMovePointer
= EngMovePointer
;
603 EngUnlockSurface(SurfObj
);
604 co_IntShowDesktop(IntGetActiveDesktop(), SurfSize
.cx
, SurfSize
.cy
);
606 // Init Primary Displays Device Capabilities.
607 IntvGetDeviceCaps(&PrimarySurface
, &GdiHandleTable
->DevCaps
);
618 IntDestroyPrimarySurface(VOID
)
622 DRIVER_UnreferenceDriver(L
"DISPLAY");
624 calledFromUser
= UserIsEntered();
627 UserEnterExclusive();
631 IntDetachMonitor(&PrimarySurface
);
639 * FIXME: Hide a mouse pointer there. Also because we have to prevent
640 * memory leaks with the Eng* mouse routines.
643 DPRINT("Reseting display\n" );
644 PrimarySurface
.DriverFunctions
.AssertMode(PrimarySurface
.dhpdev
, FALSE
);
645 PrimarySurface
.DriverFunctions
.DisableSurface(PrimarySurface
.dhpdev
);
646 PrimarySurface
.DriverFunctions
.DisablePDEV(PrimarySurface
.dhpdev
);
647 PrimarySurface
.PreparedDriver
= FALSE
;
648 KeSetEvent(&VideoDriverNeedsPreparation
, 1, FALSE
);
649 KeResetEvent(&VideoDriverPrepared
);
653 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
658 IntcFonts(PPDEVOBJ pDevObj
)
661 // Msdn DrvQueryFont:
662 // If the number of fonts in DEVINFO is -1 and iFace is zero, the driver
663 // should return the number of fonts it supports.
664 if ( pDevObj
->devinfo
.cFonts
== -1)
666 if (pDevObj
->DriverFunctions
.QueryFont
)
667 pDevObj
->devinfo
.cFonts
=
668 (ULONG
)pDevObj
->DriverFunctions
.QueryFont(pDevObj
->dhpdev
, 0, 0, &Junk
);
670 pDevObj
->devinfo
.cFonts
= 0;
672 return pDevObj
->devinfo
.cFonts
;
676 // Support multi display/device locks.
680 DC_LockDisplay(HDC hDC
)
683 PDC dc
= DC_LockDc(hDC
);
685 Resource
= dc
->ppdev
->hsemDevLock
;
687 if (!Resource
) return;
688 KeEnterCriticalRegion();
689 ExAcquireResourceExclusiveLite( Resource
, TRUE
);
694 DC_UnlockDisplay(HDC hDC
)
697 PDC dc
= DC_LockDc(hDC
);
699 Resource
= dc
->ppdev
->hsemDevLock
;
701 if (!Resource
) return;
702 ExReleaseResourceLite( Resource
);
703 KeLeaveCriticalRegion();
712 // I guess we will soon have more than one primary surface.
713 // This will do for now.
714 return &PrimarySurface
;
719 IntGdiReferencePdev(PPDEVOBJ ppdev
)
721 if (!hsemDriverMgmt
) hsemDriverMgmt
= EngCreateSemaphore(); // Hax, should be in dllmain.c
722 IntGdiAcquireSemaphore(hsemDriverMgmt
);
724 IntGdiReleaseSemaphore(hsemDriverMgmt
);
728 IntGdiUnreferencePdev(PPDEVOBJ ppdev
, DWORD CleanUpType
)
730 IntGdiAcquireSemaphore(hsemDriverMgmt
);
732 if (!ppdev
->cPdevRefs
)
734 // Handle the destruction of ppdev or PDEVOBJ or PDEVOBJ or PDEV etc.
736 IntGdiReleaseSemaphore(hsemDriverMgmt
);
743 IntGetColorManagementCaps(PPDEVOBJ pDevObj
)
747 if ( pDevObj
->flFlags
& PDEV_DISPLAY
)
749 if (pDevObj
->devinfo
.iDitherFormat
== BMF_8BPP
||
750 pDevObj
->devinfo
.flGraphicsCaps2
& GCAPS2_CHANGEGAMMARAMP
)
753 if (pDevObj
->devinfo
.flGraphicsCaps
& GCAPS_CMYKCOLOR
)
754 ret
|= CM_CMYK_COLOR
;
755 if (pDevObj
->devinfo
.flGraphicsCaps
& GCAPS_ICM
)
756 ret
|= CM_DEVICE_ICM
;
761 IntGdiGetDeviceCaps(PDC dc
, INT Index
)
764 PPDEVOBJ ppdev
= dc
->ppdev
;
765 /* Retrieve capability */
769 ret
= ppdev
->gdiinfo
.ulVersion
;
773 ret
= ppdev
->gdiinfo
.ulTechnology
;
777 ret
= ppdev
->gdiinfo
.ulHorzSize
;
781 ret
= ppdev
->gdiinfo
.ulVertSize
;
785 ret
= ppdev
->gdiinfo
.ulHorzRes
;
789 ret
= ppdev
->gdiinfo
.ulVertRes
;
793 ret
= ppdev
->gdiinfo
.ulLogPixelsX
;
797 ret
= ppdev
->gdiinfo
.ulLogPixelsY
;
801 if ( ppdev
->pGraphicsDevice
&&
802 (((PGRAPHICS_DEVICE
)ppdev
->pGraphicsDevice
)->StateFlags
&
803 DISPLAY_DEVICE_MIRRORING_DRIVER
))
808 ret
= ppdev
->gdiinfo
.cBitsPixel
;
812 ret
= ppdev
->gdiinfo
.cPlanes
;
820 ret
= ppdev
->gdiinfo
.ulNumColors
;
821 if ( ret
!= -1 ) ret
*= 5;
825 ret
= IntcFonts(ppdev
);
829 ret
= ppdev
->gdiinfo
.ulNumColors
;
833 ret
= ppdev
->gdiinfo
.ulAspectX
;
837 ret
= ppdev
->gdiinfo
.ulAspectY
;
841 ret
= ppdev
->gdiinfo
.ulAspectXY
;
849 ret
= ppdev
->gdiinfo
.ulNumPalReg
;
857 ret
= ppdev
->gdiinfo
.ulDACRed
+
858 ppdev
->gdiinfo
.ulDACGreen
+
859 ppdev
->gdiinfo
.ulDACBlue
;
863 ret
= ppdev
->gdiinfo
.ulVertRes
;
867 ret
= ppdev
->gdiinfo
.ulHorzRes
;
871 ret
= ppdev
->gdiinfo
.ulBltAlignment
;
875 ret
= ppdev
->gdiinfo
.flShadeBlend
;
879 ret
= IntGetColorManagementCaps(ppdev
);
883 ret
= ppdev
->gdiinfo
.szlPhysSize
.cx
;
887 ret
= ppdev
->gdiinfo
.szlPhysSize
.cy
;
890 case PHYSICALOFFSETX
:
891 ret
= ppdev
->gdiinfo
.ptlPhysOffset
.x
;
894 case PHYSICALOFFSETY
:
895 ret
= ppdev
->gdiinfo
.ptlPhysOffset
.y
;
899 ret
= ppdev
->gdiinfo
.ulVRefresh
;
903 ret
= ppdev
->gdiinfo
.flRaster
;
907 ret
= (CC_CIRCLES
| CC_PIE
| CC_CHORD
| CC_ELLIPSES
| CC_WIDE
|
908 CC_STYLED
| CC_WIDESTYLED
| CC_INTERIORS
| CC_ROUNDRECT
);
912 ret
= (LC_POLYLINE
| LC_MARKER
| LC_POLYMARKER
| LC_WIDE
|
913 LC_STYLED
| LC_WIDESTYLED
| LC_INTERIORS
);
917 ret
= (PC_POLYGON
| PC_RECTANGLE
| PC_WINDPOLYGON
| PC_SCANLINE
|
918 PC_WIDE
| PC_STYLED
| PC_WIDESTYLED
| PC_INTERIORS
);
922 ret
= ppdev
->gdiinfo
.flTextCaps
;
923 if (ppdev
->gdiinfo
.ulTechnology
) ret
|= TC_VA_ABLE
;
924 ret
|= (TC_SO_ABLE
|TC_UA_ABLE
);
939 NtGdiGetDeviceCaps(HDC hDC
,
948 SetLastWin32Error(ERROR_INVALID_HANDLE
);
952 ret
= IntGdiGetDeviceCaps(dc
, Index
);
954 DPRINT("(%04x,%d): returning %d\n", hDC
, Index
, ret
);
967 PGDIINFO pGdiInfo
= &pDevObj
->gdiinfo
;
969 pDevCaps
->ulVersion
= pGdiInfo
->ulVersion
;
970 pDevCaps
->ulTechnology
= pGdiInfo
->ulTechnology
;
971 pDevCaps
->ulHorzSizeM
= (pGdiInfo
->ulHorzSize
+ 500) / 1000;
972 pDevCaps
->ulVertSizeM
= (pGdiInfo
->ulVertSize
+ 500) / 1000;
973 pDevCaps
->ulHorzSize
= pGdiInfo
->ulHorzSize
;
974 pDevCaps
->ulVertSize
= pGdiInfo
->ulVertSize
;
975 pDevCaps
->ulHorzRes
= pGdiInfo
->ulHorzRes
;
976 pDevCaps
->ulVertRes
= pGdiInfo
->ulVertRes
;
977 pDevCaps
->ulVRefresh
= pGdiInfo
->ulVRefresh
;
978 pDevCaps
->ulDesktopHorzRes
= pGdiInfo
->ulHorzRes
;
979 pDevCaps
->ulDesktopVertRes
= pGdiInfo
->ulVertRes
;
980 pDevCaps
->ulBltAlignment
= pGdiInfo
->ulBltAlignment
;
981 pDevCaps
->ulPlanes
= pGdiInfo
->cPlanes
;
983 pDevCaps
->ulBitsPixel
= pGdiInfo
->cBitsPixel
;
984 if (pGdiInfo
->cBitsPixel
== 15) pDevCaps
->ulBitsPixel
= 16;
986 Tmp
= pGdiInfo
->ulNumColors
;
987 if ( Tmp
!= -1 ) Tmp
*= 5;
988 pDevCaps
->ulNumPens
= Tmp
;
989 pDevCaps
->ulNumColors
= pGdiInfo
->ulNumColors
;
991 pDevCaps
->ulNumFonts
= IntcFonts(pDevObj
);
993 pDevCaps
->ulRasterCaps
= pGdiInfo
->flRaster
;
994 pDevCaps
->ulShadeBlend
= pGdiInfo
->flShadeBlend
;
995 pDevCaps
->ulAspectX
= pGdiInfo
->ulAspectX
;
996 pDevCaps
->ulAspectY
= pGdiInfo
->ulAspectY
;
997 pDevCaps
->ulAspectXY
= pGdiInfo
->ulAspectXY
;
998 pDevCaps
->ulLogPixelsX
= pGdiInfo
->ulLogPixelsX
;
999 pDevCaps
->ulLogPixelsY
= pGdiInfo
->ulLogPixelsY
;
1000 pDevCaps
->ulSizePalette
= pGdiInfo
->ulNumPalReg
;
1001 pDevCaps
->ulColorRes
= pGdiInfo
->ulDACRed
+ pGdiInfo
->ulDACGreen
+ pGdiInfo
->ulDACBlue
;
1002 pDevCaps
->ulPhysicalWidth
= pGdiInfo
->szlPhysSize
.cx
;
1003 pDevCaps
->ulPhysicalHeight
= pGdiInfo
->szlPhysSize
.cy
;
1004 pDevCaps
->ulPhysicalOffsetX
= pGdiInfo
->ptlPhysOffset
.x
;
1005 pDevCaps
->ulPhysicalOffsetY
= pGdiInfo
->ptlPhysOffset
.y
;
1006 pDevCaps
->ulPanningHorzRes
= pGdiInfo
->ulPanningHorzRes
;
1007 pDevCaps
->ulPanningVertRes
= pGdiInfo
->ulPanningVertRes
;
1008 pDevCaps
->xPanningAlignment
= pGdiInfo
->xPanningAlignment
;
1009 pDevCaps
->yPanningAlignment
= pGdiInfo
->yPanningAlignment
;
1012 Tmp
= pGdiInfo
->flTextCaps
| (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
1014 pDevCaps
->ulTextCaps
= pGdiInfo
->flTextCaps
| (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
1016 if (pGdiInfo
->ulTechnology
)
1017 pDevCaps
->ulTextCaps
= Tmp
| TC_VA_ABLE
;
1019 pDevCaps
->ulColorMgmtCaps
= IntGetColorManagementCaps(pDevObj
);
1029 NtGdiGetDeviceCapsAll (
1031 OUT PDEVCAPS pDevCaps
)
1034 PDEVCAPS pSafeDevCaps
;
1035 NTSTATUS Status
= STATUS_SUCCESS
;
1037 dc
= DC_LockDc(hDC
);
1040 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1044 pSafeDevCaps
= ExAllocatePoolWithTag(PagedPool
, sizeof(DEVCAPS
), TAG_TEMP
);
1052 IntvGetDeviceCaps(dc
->ppdev
, pSafeDevCaps
);
1056 ProbeForWrite(pDevCaps
,
1059 RtlCopyMemory(pDevCaps
, pSafeDevCaps
, sizeof(DEVCAPS
));
1061 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1063 Status
= _SEH2_GetExceptionCode();
1067 ExFreePoolWithTag(pSafeDevCaps
, TAG_TEMP
);
1070 if (!NT_SUCCESS(Status
))
1072 SetLastNtError(Status
);
1087 PPDEVOBJ ppdev
, pGdiDevice
= (PPDEVOBJ
) hdev
;
1088 if (!pGdiDevice
) return NULL
;
1089 if ( pGdiDevice
< (PPDEVOBJ
)MmSystemRangeStart
) return NULL
;
1090 ppdev
= pPrimarySurface
;
1091 IntGdiAcquireSemaphore(hsemDriverMgmt
);
1094 if (pGdiDevice
== ppdev
) break;
1096 ppdev
= ppdev
->ppdevNext
;
1098 while (ppdev
!= NULL
);
1099 IntGdiReleaseSemaphore(hsemDriverMgmt
);
1100 if (!ppdev
) return NULL
;
1101 return pGdiDevice
->dhpdev
;
1104 static NTSTATUS FASTCALL
1105 GetVideoRegistryKey(
1106 OUT PUNICODE_STRING RegistryPath
,
1107 IN PCUNICODE_STRING DeviceName
) /* ex: "\Device\Video0" */
1109 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1112 RtlInitUnicodeString(RegistryPath
, NULL
);
1113 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1114 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
1115 QueryTable
[0].Name
= DeviceName
->Buffer
;
1116 QueryTable
[0].EntryContext
= RegistryPath
;
1118 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
1123 if (!NT_SUCCESS(Status
))
1125 DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName
, Status
);
1126 return STATUS_NO_SUCH_DEVICE
;
1129 DPRINT("RegistryPath %wZ\n", RegistryPath
);
1130 return STATUS_SUCCESS
;
1134 static NTSTATUS FASTCALL
1136 OUT PUNICODE_STRING VideoDeviceName
,
1137 IN PCUNICODE_STRING DisplayDevice
) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
1139 UNICODE_STRING Prefix
= RTL_CONSTANT_STRING(L
"\\??\\");
1140 UNICODE_STRING ObjectName
;
1141 UNICODE_STRING KernelModeName
= { 0, };
1142 OBJECT_ATTRIBUTES ObjectAttributes
;
1145 HANDLE LinkHandle
= NULL
;
1148 RtlInitUnicodeString(VideoDeviceName
, NULL
);
1150 /* Get device name (DisplayDevice is "\.\xxx") */
1151 for (LastSlash
= DisplayDevice
->Length
/ sizeof(WCHAR
); LastSlash
> 0; LastSlash
--)
1153 if (DisplayDevice
->Buffer
[LastSlash
- 1] == L
'\\')
1159 DPRINT1("Invalid device name '%wZ'\n", DisplayDevice
);
1160 Status
= STATUS_OBJECT_NAME_INVALID
;
1163 ObjectName
= *DisplayDevice
;
1164 ObjectName
.Length
-= LastSlash
* sizeof(WCHAR
);
1165 ObjectName
.MaximumLength
-= LastSlash
* sizeof(WCHAR
);
1166 ObjectName
.Buffer
+= LastSlash
;
1168 /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
1169 KernelModeName
.MaximumLength
= Prefix
.Length
+ ObjectName
.Length
+ sizeof(UNICODE_NULL
);
1170 KernelModeName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1171 KernelModeName
.MaximumLength
,
1173 if (!KernelModeName
.Buffer
)
1175 Status
= STATUS_NO_MEMORY
;
1178 RtlCopyUnicodeString(&KernelModeName
, &Prefix
);
1179 Status
= RtlAppendUnicodeStringToString(&KernelModeName
, &ObjectName
);
1180 if (!NT_SUCCESS(Status
))
1183 /* Open \??\xxx (ex: "\??\DISPLAY1") */
1184 InitializeObjectAttributes(&ObjectAttributes
,
1189 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
,
1192 if (!NT_SUCCESS(Status
))
1194 DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1195 Status
= STATUS_NO_SUCH_DEVICE
;
1199 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, VideoDeviceName
, &Length
);
1200 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
1202 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1203 Status
= STATUS_NO_SUCH_DEVICE
;
1206 VideoDeviceName
->MaximumLength
= Length
;
1207 VideoDeviceName
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1208 VideoDeviceName
->MaximumLength
+ sizeof(UNICODE_NULL
),
1210 if (!VideoDeviceName
->Buffer
)
1212 Status
= STATUS_NO_MEMORY
;
1215 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, VideoDeviceName
, NULL
);
1216 VideoDeviceName
->Buffer
[VideoDeviceName
->MaximumLength
/ sizeof(WCHAR
) - 1] = UNICODE_NULL
;
1217 if (!NT_SUCCESS(Status
))
1219 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1220 Status
= STATUS_NO_SUCH_DEVICE
;
1223 Status
= STATUS_SUCCESS
;
1226 if (!NT_SUCCESS(Status
) && VideoDeviceName
->Buffer
)
1227 ExFreePoolWithTag(VideoDeviceName
->Buffer
, TAG_DC
);
1228 if (KernelModeName
.Buffer
)
1229 ExFreePoolWithTag(KernelModeName
.Buffer
, TAG_DC
);
1231 ZwClose(LinkHandle
);
1237 IntChangeDisplaySettings(
1238 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1239 IN LPDEVMODEW DevMode
,
1241 IN PVOID lParam OPTIONAL
)
1243 BOOLEAN Global
= FALSE
;
1244 BOOLEAN NoReset
= FALSE
;
1245 BOOLEAN Reset
= FALSE
;
1246 BOOLEAN SetPrimary
= FALSE
;
1247 LONG Ret
= DISP_CHANGE_SUCCESSFUL
;
1250 DPRINT1("display flags : %x\n",dwflags
);
1252 if ((dwflags
& CDS_UPDATEREGISTRY
) == CDS_UPDATEREGISTRY
)
1254 /* Check global, reset and noreset flags */
1255 if ((dwflags
& CDS_GLOBAL
) == CDS_GLOBAL
)
1257 if ((dwflags
& CDS_NORESET
) == CDS_NORESET
)
1259 dwflags
&= ~(CDS_GLOBAL
| CDS_NORESET
);
1261 if ((dwflags
& CDS_RESET
) == CDS_RESET
)
1263 if ((dwflags
& CDS_SET_PRIMARY
) == CDS_SET_PRIMARY
)
1265 dwflags
&= ~(CDS_RESET
| CDS_SET_PRIMARY
);
1267 if (Reset
&& NoReset
)
1268 return DISP_CHANGE_BADFLAGS
;
1272 /* Dynamically change graphics mode */
1273 DPRINT1("flag 0 UNIMPLEMENTED\n");
1274 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED
);
1275 return DISP_CHANGE_FAILED
;
1278 if ((dwflags
& CDS_TEST
) == CDS_TEST
)
1280 /* Test resolution */
1281 dwflags
&= ~CDS_TEST
;
1282 Status
= IntEnumDisplaySettings(pDeviceName
, ENUM_REGISTRY_SETTINGS
, DevMode
, 0);
1283 if (!NT_SUCCESS(Status
))
1284 Ret
= DISP_CHANGE_BADMODE
;
1288 if ((dwflags
& CDS_FULLSCREEN
) == CDS_FULLSCREEN
)
1292 dwflags
&= ~CDS_FULLSCREEN
;
1293 DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
1294 Ret
= DISP_CHANGE_FAILED
;
1296 RtlZeroMemory(&lpDevMode
, sizeof(DEVMODEW
));
1297 lpDevMode
.dmSize
= sizeof(DEVMODEW
);
1299 Status
= IntEnumDisplaySettings(pDeviceName
, ENUM_CURRENT_SETTINGS
, &lpDevMode
, 0);
1300 if (!NT_SUCCESS(Status
))
1301 return DISP_CHANGE_FAILED
;
1303 DPRINT1("Req Mode : %d x %d x %d\n", DevMode
->dmPelsWidth
,DevMode
->dmPelsHeight
,DevMode
->dmBitsPerPel
);
1304 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode
.dmPelsWidth
,lpDevMode
.dmPelsHeight
, lpDevMode
.dmBitsPerPel
);
1307 if ((lpDevMode
.dmBitsPerPel
== DevMode
->dmBitsPerPel
) &&
1308 (lpDevMode
.dmPelsWidth
== DevMode
->dmPelsWidth
) &&
1309 (lpDevMode
.dmPelsHeight
== DevMode
->dmPelsHeight
))
1310 Ret
= DISP_CHANGE_SUCCESSFUL
;
1313 if ((dwflags
& CDS_VIDEOPARAMETERS
) == CDS_VIDEOPARAMETERS
)
1315 dwflags
&= ~CDS_VIDEOPARAMETERS
;
1317 Ret
=DISP_CHANGE_BADPARAM
;
1320 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
1321 Ret
= DISP_CHANGE_FAILED
;
1322 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED
);
1327 if ((dwflags
& CDS_UPDATEREGISTRY
) == CDS_UPDATEREGISTRY
)
1330 UNICODE_STRING DeviceName
;
1331 UNICODE_STRING RegistryKey
;
1332 UNICODE_STRING InDeviceName
;
1333 OBJECT_ATTRIBUTES ObjectAttributes
;
1334 HANDLE DevInstRegKey
;
1337 DPRINT1("set CDS_UPDATEREGISTRY\n");
1339 dwflags
&= ~CDS_UPDATEREGISTRY
;
1341 /* Check if pDeviceName is NULL, we need to retrieve it */
1342 if (pDeviceName
== NULL
)
1344 WCHAR szBuffer
[MAX_DRIVER_NAME
];
1346 PWINDOW_OBJECT Wnd
=NULL
;
1350 hWnd
= IntGetDesktopWindow();
1351 if (!(Wnd
= UserGetWindowObject(hWnd
)))
1356 hDC
= UserGetWindowDC(Wnd
);
1358 DC
= DC_LockDc(hDC
);
1363 swprintf (szBuffer
, L
"\\\\.\\DISPLAY%lu", DC
->ppdev
->DisplayNumber
);
1366 RtlInitUnicodeString(&InDeviceName
, szBuffer
);
1367 pDeviceName
= &InDeviceName
;
1370 Status
= GetVideoDeviceName(&DeviceName
, pDeviceName
);
1371 if (!NT_SUCCESS(Status
))
1373 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName
, Status
);
1374 return DISP_CHANGE_FAILED
;
1376 Status
= GetVideoRegistryKey(&RegistryKey
, &DeviceName
);
1377 if (!NT_SUCCESS(Status
))
1379 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName
, Status
);
1380 ExFreePoolWithTag(DeviceName
.Buffer
, TAG_DC
);
1381 return DISP_CHANGE_FAILED
;
1383 ExFreePoolWithTag(DeviceName
.Buffer
, TAG_DC
);
1385 InitializeObjectAttributes(&ObjectAttributes
, &RegistryKey
,
1386 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1387 Status
= ZwOpenKey(&DevInstRegKey
, KEY_SET_VALUE
, &ObjectAttributes
);
1388 if (!NT_SUCCESS(Status
))
1390 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey
, Status
);
1391 ExFreePoolWithTag(RegistryKey
.Buffer
, TAG_RTLREGISTRY
);
1392 return DISP_CHANGE_FAILED
;
1394 ExFreePoolWithTag(RegistryKey
.Buffer
, TAG_RTLREGISTRY
);
1396 /* Update needed fields */
1397 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_BITSPERPEL
)
1399 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.BitsPerPel");
1400 NewValue
= DevMode
->dmBitsPerPel
;
1401 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1404 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_PELSWIDTH
)
1406 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.XResolution");
1407 NewValue
= DevMode
->dmPelsWidth
;
1408 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1411 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_PELSHEIGHT
)
1413 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.YResolution");
1414 NewValue
= DevMode
->dmPelsHeight
;
1415 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1418 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_DISPLAYFREQUENCY
)
1420 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.VRefresh");
1421 NewValue
= DevMode
->dmDisplayFrequency
;
1422 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1425 ZwClose(DevInstRegKey
);
1426 if (NT_SUCCESS(Status
))
1427 Ret
= DISP_CHANGE_RESTART
;
1429 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
1430 Ret
= DISP_CHANGE_NOTUPDATED
;
1434 Ret
= DISP_CHANGE_BADFLAGS
;
1436 DPRINT("IntChangeDisplaySettings returning %x\n", Ret
);
1442 #define SIZEOF_DEVMODEW_300 188
1443 #define SIZEOF_DEVMODEW_400 212
1444 #define SIZEOF_DEVMODEW_500 220
1446 static NTSTATUS FASTCALL
1447 GetDisplayNumberFromDeviceName(
1448 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1449 OUT ULONG
*DisplayNumber
)
1451 UNICODE_STRING DisplayString
= RTL_CONSTANT_STRING(L
"\\\\.\\DISPLAY");
1452 NTSTATUS Status
= STATUS_SUCCESS
;
1457 if (DisplayNumber
== NULL
)
1458 return STATUS_INVALID_PARAMETER_2
;
1460 /* Check if DeviceName is valid */
1462 pDeviceName
->Length
> 0 && pDeviceName
->Length
<= DisplayString
.Length
)
1463 return STATUS_OBJECT_NAME_INVALID
;
1465 if (pDeviceName
== NULL
|| pDeviceName
->Length
== 0)
1467 PWINDOW_OBJECT DesktopObject
;
1471 DesktopObject
= UserGetDesktopWindow();
1472 DesktopHDC
= UserGetWindowDC(DesktopObject
);
1473 pDC
= DC_LockDc(DesktopHDC
);
1475 *DisplayNumber
= pDC
->ppdev
->DisplayNumber
;
1478 UserReleaseDC(DesktopObject
, DesktopHDC
, FALSE
);
1480 return STATUS_SUCCESS
;
1483 /* Hack to check if the first parts are equal, by faking the device name length */
1484 Length
= pDeviceName
->Length
;
1485 pDeviceName
->Length
= DisplayString
.Length
;
1486 if (RtlEqualUnicodeString(&DisplayString
, pDeviceName
, FALSE
) == FALSE
)
1487 Status
= STATUS_OBJECT_NAME_INVALID
;
1488 pDeviceName
->Length
= Length
;
1490 if (NT_SUCCESS(Status
))
1492 /* Convert the last part of pDeviceName to a number */
1494 Length
= pDeviceName
->Length
/ sizeof(WCHAR
);
1495 for (i
= DisplayString
.Length
/ sizeof(WCHAR
); i
< Length
; i
++)
1497 WCHAR Char
= pDeviceName
->Buffer
[i
];
1498 if (Char
>= L
'0' && Char
<= L
'9')
1499 Number
= Number
* 10 + Char
- L
'0';
1500 else if (Char
!= L
'\0')
1501 return STATUS_OBJECT_NAME_INVALID
;
1504 *DisplayNumber
= Number
- 1;
1510 /*! \brief Enumerate possible display settings for the given display...
1512 * \todo Make thread safe!?
1513 * \todo Don't ignore pDeviceName
1514 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
1518 IntEnumDisplaySettings(
1519 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1521 IN OUT LPDEVMODEW pDevMode
,
1524 static DEVMODEW
*CachedDevModes
= NULL
, *CachedDevModesEnd
= NULL
;
1525 static DWORD SizeOfCachedDevModes
= 0;
1526 static UNICODE_STRING CachedDeviceName
;
1527 PDEVMODEW CachedMode
= NULL
;
1529 ULONG DisplayNumber
;
1532 Status
= GetDisplayNumberFromDeviceName(pDeviceName
, &DisplayNumber
);
1533 if (!NT_SUCCESS(Status
))
1538 if (pDevMode
!= NULL
)
1540 DPRINT("DevMode->dmSize = %d\n", pDevMode
->dmSize
);
1541 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode
->dmDriverExtra
);
1542 if (pDevMode
->dmSize
!= SIZEOF_DEVMODEW_300
&&
1543 pDevMode
->dmSize
!= SIZEOF_DEVMODEW_400
&&
1544 pDevMode
->dmSize
!= SIZEOF_DEVMODEW_500
)
1546 return STATUS_BUFFER_TOO_SMALL
;
1550 if (iModeNum
== ENUM_CURRENT_SETTINGS
)
1552 CachedMode
= &PrimarySurface
.DMW
;
1553 ASSERT(CachedMode
->dmSize
> 0);
1555 else if (iModeNum
== ENUM_REGISTRY_SETTINGS
)
1557 RtlZeroMemory(&DevMode
, sizeof (DevMode
));
1558 DevMode
.dmSize
= sizeof (DevMode
);
1559 DevMode
.dmDriverExtra
= 0;
1560 if (SetupDevMode(&DevMode
, DisplayNumber
))
1561 CachedMode
= &DevMode
;
1564 return STATUS_UNSUCCESSFUL
; // FIXME: what status?
1566 /* FIXME: Maybe look for the matching devmode supplied by the
1567 * driver so we can provide driver private/extra data?
1572 BOOL IsCachedDevice
= (CachedDevModes
!= NULL
);
1574 if (CachedDevModes
&&
1575 ((pDeviceName
== NULL
&& CachedDeviceName
.Length
> 0) ||
1576 (pDeviceName
!= NULL
&& pDeviceName
->Buffer
!= NULL
&& CachedDeviceName
.Length
== 0) ||
1577 (pDeviceName
!= NULL
&& pDeviceName
->Buffer
!= NULL
&& CachedDeviceName
.Length
> 0 && RtlEqualUnicodeString(pDeviceName
, &CachedDeviceName
, TRUE
) == FALSE
)))
1579 IsCachedDevice
= FALSE
;
1582 if (iModeNum
== 0 || IsCachedDevice
== FALSE
) /* query modes from drivers */
1584 UNICODE_STRING DriverFileNames
;
1586 DRVENABLEDATA DrvEnableData
;
1588 /* Free resources from last driver cache */
1589 if (IsCachedDevice
== FALSE
&& CachedDeviceName
.Buffer
!= NULL
)
1591 RtlFreeUnicodeString(&CachedDeviceName
);
1594 /* Retrieve DDI driver names from registry */
1595 RtlInitUnicodeString(&DriverFileNames
, NULL
);
1596 if (!FindDriverFileNames(&DriverFileNames
, DisplayNumber
))
1598 DPRINT1("FindDriverFileNames failed\n");
1599 return STATUS_UNSUCCESSFUL
;
1602 if (!IntPrepareDriverIfNeeded())
1604 DPRINT1("IntPrepareDriverIfNeeded failed\n");
1605 return STATUS_UNSUCCESSFUL
;
1609 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
1610 * scan all of them until a good one found.
1612 CurrentName
= DriverFileNames
.Buffer
;
1613 for (;CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
));
1614 CurrentName
+= wcslen(CurrentName
) + 1)
1617 PFN_DrvEnableDriver GDEnableDriver
;
1618 PFN_DrvGetModes GetModes
= NULL
;
1619 INT SizeNeeded
, SizeUsed
;
1621 /* Get the DDI driver's entry point */
1622 //GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
1623 GDEnableDriver
= DRIVER_FindExistingDDIDriver(L
"DISPLAY");
1624 if (NULL
== GDEnableDriver
)
1626 DPRINT("FindDDIDriver failed for %S\n", CurrentName
);
1630 /* Call DDI driver's EnableDriver function */
1631 RtlZeroMemory(&DrvEnableData
, sizeof(DrvEnableData
));
1633 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01
, sizeof (DrvEnableData
), &DrvEnableData
))
1635 DPRINT("DrvEnableDriver failed for %S\n", CurrentName
);
1639 CachedDevModesEnd
= CachedDevModes
;
1641 /* find DrvGetModes function */
1642 for (i
= 0; i
< DrvEnableData
.c
; i
++)
1644 PDRVFN DrvFn
= DrvEnableData
.pdrvfn
+ i
;
1646 if (DrvFn
->iFunc
== INDEX_DrvGetModes
)
1648 GetModes
= (PFN_DrvGetModes
)DrvFn
->pfn
;
1653 if (GetModes
== NULL
)
1655 DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName
);
1659 /* make sure we have enough memory to hold the modes */
1660 SizeNeeded
= GetModes((HANDLE
)(PrimarySurface
.VideoFileObject
->DeviceObject
), 0, NULL
);
1661 if (SizeNeeded
<= 0)
1663 DPRINT("DrvGetModes failed for %S\n", CurrentName
);
1667 SizeUsed
= (PCHAR
)CachedDevModesEnd
- (PCHAR
)CachedDevModes
;
1668 if (SizeOfCachedDevModes
< SizeUsed
+ SizeNeeded
)
1672 SizeOfCachedDevModes
+= SizeNeeded
;
1673 NewBuffer
= ExAllocatePool(PagedPool
, SizeOfCachedDevModes
);
1674 if (NewBuffer
== NULL
)
1677 ExFreePool(CachedDevModes
);
1678 CachedDevModes
= NULL
;
1679 CachedDevModesEnd
= NULL
;
1680 SizeOfCachedDevModes
= 0;
1682 if (CachedDeviceName
.Buffer
!= NULL
)
1683 RtlFreeUnicodeString(&CachedDeviceName
);
1685 return STATUS_NO_MEMORY
;
1687 if (CachedDevModes
!= NULL
)
1689 RtlCopyMemory(NewBuffer
, CachedDevModes
, SizeUsed
);
1690 ExFreePool(CachedDevModes
);
1692 CachedDevModes
= NewBuffer
;
1693 CachedDevModesEnd
= (DEVMODEW
*)((PCHAR
)NewBuffer
+ SizeUsed
);
1696 if (!IsCachedDevice
)
1698 if (CachedDeviceName
.Buffer
!= NULL
)
1699 RtlFreeUnicodeString(&CachedDeviceName
);
1702 IntSafeCopyUnicodeString(&CachedDeviceName
, pDeviceName
);
1704 IsCachedDevice
= TRUE
;
1708 SizeNeeded
= GetModes((HANDLE
)(PrimarySurface
.VideoFileObject
->DeviceObject
),
1711 if (SizeNeeded
<= 0)
1713 DPRINT("DrvGetModes failed for %S\n", CurrentName
);
1717 CachedDevModesEnd
= (DEVMODEW
*)((PCHAR
)CachedDevModesEnd
+ SizeNeeded
);
1721 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
1724 /* return cached info */
1725 CachedMode
= CachedDevModes
;
1726 if (CachedMode
>= CachedDevModesEnd
)
1728 return STATUS_NO_MORE_ENTRIES
;
1730 while (iModeNum
-- > 0 && CachedMode
< CachedDevModesEnd
)
1732 assert(CachedMode
->dmSize
> 0);
1733 CachedMode
= (DEVMODEW
*)((PCHAR
)CachedMode
+ CachedMode
->dmSize
+ CachedMode
->dmDriverExtra
);
1735 if (CachedMode
>= CachedDevModesEnd
)
1737 return STATUS_NO_MORE_ENTRIES
;
1741 ASSERT(CachedMode
!= NULL
);
1743 if (pDevMode
!= NULL
)
1745 RtlCopyMemory(pDevMode
, CachedMode
, min(pDevMode
->dmSize
, CachedMode
->dmSize
));
1746 RtlZeroMemory(pDevMode
+ pDevMode
->dmSize
, pDevMode
->dmDriverExtra
);
1747 RtlCopyMemory(pDevMode
+ min(pDevMode
->dmSize
, CachedMode
->dmSize
), CachedMode
+ CachedMode
->dmSize
, min(pDevMode
->dmDriverExtra
, CachedMode
->dmDriverExtra
));
1750 return STATUS_SUCCESS
;
1759 IN OPTIONAL LPSTR pjIn
)