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
;
24 PDEV_sizl(PPDEVOBJ ppdev
, PSIZEL psizl
)
26 if (ppdev
->flFlags
& PDEV_META_DEVICE
)
28 psizl
->cx
= ppdev
->ulHorzRes
;
29 psizl
->cy
= ppdev
->ulVertRes
;
33 psizl
->cx
= ppdev
->gdiinfo
.ulHorzRes
;
34 psizl
->cy
= ppdev
->gdiinfo
.ulVertRes
;
42 KeInitializeEvent(&VideoDriverNeedsPreparation
, SynchronizationEvent
, TRUE
);
43 KeInitializeEvent(&VideoDriverPrepared
, NotificationEvent
, FALSE
);
44 return STATUS_SUCCESS
;
48 static BOOLEAN FASTCALL
49 GetRegistryPath(PUNICODE_STRING RegistryPath
, ULONG DisplayNumber
)
51 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
52 WCHAR DeviceNameBuffer
[20];
55 swprintf(DeviceNameBuffer
, L
"\\Device\\Video%lu", DisplayNumber
);
56 RtlInitUnicodeString(RegistryPath
, NULL
);
57 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
58 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
59 QueryTable
[0].Name
= DeviceNameBuffer
;
60 QueryTable
[0].EntryContext
= RegistryPath
;
62 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
67 if (! NT_SUCCESS(Status
))
69 DPRINT1("No \\Device\\Video%lu value in DEVICEMAP\\VIDEO found\n", DisplayNumber
);
73 DPRINT("RegistryPath %wZ\n", RegistryPath
);
81 EnumDisplayQueryRoutine(IN PWSTR ValueName
,
86 IN PVOID EntryContext
)
88 if ((Context
== NULL
) && ((ValueType
== REG_SZ
) || (ValueType
== REG_MULTI_SZ
)))
90 *(PULONG
)EntryContext
= ValueLength
;
94 DPRINT1("Value data: %S %d\n", ValueData
, ValueLength
);
95 RtlCopyMemory(Context
, ValueData
, ValueLength
);
98 return STATUS_SUCCESS
;
102 FindDriverFileNames(PUNICODE_STRING DriverFileNames
, ULONG DisplayNumber
)
104 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
105 UNICODE_STRING RegistryPath
;
107 PWCHAR DriverNames
= NULL
;
110 if (! GetRegistryPath(&RegistryPath
, DisplayNumber
))
112 DPRINT("GetRegistryPath failed\n");
116 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
117 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_NOEXPAND
;
118 QueryTable
[0].Name
= L
"InstalledDisplayDrivers";
119 QueryTable
[0].EntryContext
= &Length
;
120 QueryTable
[0].QueryRoutine
= EnumDisplayQueryRoutine
;
122 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
127 // DPRINT1("Status: %lx\n", Status);
130 DriverNames
= ExAllocatePool(PagedPool
, Length
);
131 // DPRINT1("Length allocated: %d\n", Length);
132 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
137 if (!NT_SUCCESS(Status
)) DriverNames
= NULL
;
140 ExFreePoolWithTag(RegistryPath
.Buffer
, TAG_RTLREGISTRY
);
141 if (! NT_SUCCESS(Status
))
143 DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
147 RtlInitUnicodeString(DriverFileNames
, DriverNames
);
148 DriverFileNames
->Length
= Length
;
149 DriverFileNames
->MaximumLength
= Length
;
150 //DPRINT1("DriverFileNames %wZ\n", DriverFileNames);
156 static NTSTATUS APIENTRY
157 DevModeCallback(IN PWSTR ValueName
,
160 IN ULONG ValueLength
,
162 IN PVOID EntryContext
)
164 PDEVMODEW DevMode
= (PDEVMODEW
) Context
;
166 DPRINT("Found registry value for name %S: type %d, length %d\n",
167 ValueName
, ValueType
, ValueLength
);
169 if (REG_DWORD
== ValueType
&& sizeof(DWORD
) == ValueLength
)
171 if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.BitsPerPel"))
173 DevMode
->dmBitsPerPel
= *((DWORD
*) ValueData
);
175 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.Flags"))
177 DevMode
->dmDisplayFlags
= *((DWORD
*) ValueData
);
179 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.VRefresh"))
181 DevMode
->dmDisplayFrequency
= *((DWORD
*) ValueData
);
183 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.XPanning"))
185 DevMode
->dmPanningWidth
= *((DWORD
*) ValueData
);
187 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.XResolution"))
189 DevMode
->dmPelsWidth
= *((DWORD
*) ValueData
);
191 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.YPanning"))
193 DevMode
->dmPanningHeight
= *((DWORD
*) ValueData
);
195 else if (0 == _wcsicmp(ValueName
, L
"DefaultSettings.YResolution"))
197 DevMode
->dmPelsHeight
= *((DWORD
*) ValueData
);
201 return STATUS_SUCCESS
;
206 SetupDevMode(PDEVMODEW DevMode
, ULONG DisplayNumber
)
208 UNICODE_STRING RegistryPath
;
209 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
211 BOOLEAN Valid
= TRUE
;
213 if (!GetRegistryPath(&RegistryPath
, DisplayNumber
))
215 DPRINT("GetRegistryPath failed\n");
219 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
220 QueryTable
[0].QueryRoutine
= DevModeCallback
;
221 QueryTable
[0].Flags
= 0;
222 QueryTable
[0].Name
= NULL
;
223 QueryTable
[0].EntryContext
= NULL
;
224 QueryTable
[0].DefaultType
= REG_NONE
;
225 QueryTable
[0].DefaultData
= NULL
;
226 QueryTable
[0].DefaultLength
= 0;
228 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
233 if (! NT_SUCCESS(Status
))
235 DPRINT("RtlQueryRegistryValues for %wZ failed with status 0x%08x\n",
236 &RegistryPath
, Status
);
241 DPRINT("dmBitsPerPel %d dmDisplayFrequency %d dmPelsWidth %d dmPelsHeight %d\n",
242 DevMode
->dmBitsPerPel
, DevMode
->dmDisplayFrequency
,
243 DevMode
->dmPelsWidth
, DevMode
->dmPelsHeight
);
244 if (0 == DevMode
->dmBitsPerPel
|| 0 == DevMode
->dmDisplayFrequency
245 || 0 == DevMode
->dmPelsWidth
|| 0 == DevMode
->dmPelsHeight
)
247 DPRINT("Not all required devmode members are set\n");
252 ExFreePoolWithTag(RegistryPath
.Buffer
, TAG_RTLREGISTRY
);
256 RtlZeroMemory(DevMode
, sizeof(DEVMODEW
));
263 IntPrepareDriver(VOID
)
265 PFN_DrvEnableDriver GDEnableDriver
;
267 UNICODE_STRING DriverFileNames
;
276 if (STATUS_SUCCESS
!= KeWaitForSingleObject(&VideoDriverNeedsPreparation
, Executive
, KernelMode
, TRUE
, &Zero
))
278 /* Concurrent access. Wait for VideoDriverPrepared event */
279 if (STATUS_SUCCESS
== KeWaitForSingleObject(&VideoDriverPrepared
, Executive
, KernelMode
, TRUE
, NULL
))
280 ret
= PrimarySurface
.PreparedDriver
;
283 // HAX! Fixme so I can support more than one! So how many?
284 for (DisplayNumber
= 0; ; DisplayNumber
++)
286 DPRINT("Trying to load display driver no. %d\n", DisplayNumber
);
288 RtlZeroMemory(&PrimarySurface
, sizeof(PrimarySurface
));
290 // if (!pPrimarySurface) pPrimarySurface = ExAllocatePoolWithTag(PagedPool, gdwDirectDrawContext + sizeof(PDEVOBJ), TAG_GDIPDEV);
292 PrimarySurface
.VideoFileObject
= DRIVER_FindMPDriver(DisplayNumber
);
294 /* Open the miniport driver */
295 if (PrimarySurface
.VideoFileObject
== NULL
)
297 DPRINT1("FindMPDriver failed\n");
301 /* Retrieve DDI driver names from registry */
302 RtlInitUnicodeString(&DriverFileNames
, NULL
);
303 if (!FindDriverFileNames(&DriverFileNames
, DisplayNumber
))
305 DPRINT1("FindDriverFileNames failed\n");
310 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
311 * scan all of them until a good one found.
313 CurrentName
= DriverFileNames
.Buffer
;
316 CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
318 /* Get the DDI driver's entry point */
319 GDEnableDriver
= DRIVER_FindDDIDriver(CurrentName
);
320 if (NULL
== GDEnableDriver
)
322 DPRINT("FindDDIDriver failed for %S\n", CurrentName
);
326 /* Call DDI driver's EnableDriver function */
327 RtlZeroMemory(&DED
, sizeof(DED
));
329 if (! GDEnableDriver(DDI_DRIVER_VERSION_NT5_01
, sizeof(DED
), &DED
))
331 DPRINT("DrvEnableDriver failed for %S\n", CurrentName
);
341 /* Skip to the next name but never get past the Unicode string */
342 while (L
'\0' != *CurrentName
&&
343 CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
347 if (CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
)))
356 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
357 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
358 DPRINT1("No suitable DDI driver found\n");
362 DPRINT1("Display driver %S loaded\n", CurrentName
);
364 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
366 DPRINT("Building DDI Functions\n");
368 /* Construct DDI driver function dispatch table */
369 if (!DRIVER_BuildDDIFunctions(&DED
, &PrimarySurface
.DriverFunctions
))
371 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
372 DPRINT1("BuildDDIFunctions failed\n");
376 /* Allocate a phyical device handle from the driver */
377 // Support DMW.dmSize + DMW.dmDriverExtra & Alloc DMW then set prt pdmwDev.
378 PrimarySurface
.DMW
.dmSize
= sizeof (PrimarySurface
.DMW
);
379 if (SetupDevMode(&PrimarySurface
.DMW
, DisplayNumber
))
381 PrimarySurface
.dhpdev
= PrimarySurface
.DriverFunctions
.EnablePDEV(
385 PrimarySurface
.ahsurf
,
386 sizeof(PrimarySurface
.gdiinfo
),
387 &PrimarySurface
.gdiinfo
,
388 sizeof(PrimarySurface
.devinfo
),
389 &PrimarySurface
.devinfo
,
392 (HANDLE
) (PrimarySurface
.VideoFileObject
->DeviceObject
));
393 DoDefault
= (NULL
== PrimarySurface
.dhpdev
);
396 DPRINT1("DrvEnablePDev with registry parameters failed\n");
406 RtlZeroMemory(&(PrimarySurface
.DMW
), sizeof(DEVMODEW
));
407 PrimarySurface
.DMW
.dmSize
= sizeof (PrimarySurface
.DMW
);
408 PrimarySurface
.dhpdev
= PrimarySurface
.DriverFunctions
.EnablePDEV(
412 PrimarySurface
.ahsurf
,
413 sizeof(PrimarySurface
.gdiinfo
),
414 &PrimarySurface
.gdiinfo
,
415 sizeof(PrimarySurface
.devinfo
),
416 &PrimarySurface
.devinfo
,
419 (HANDLE
) (PrimarySurface
.VideoFileObject
->DeviceObject
));
421 if (NULL
== PrimarySurface
.dhpdev
)
423 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
424 DPRINT1("DrvEnablePDEV with default parameters failed\n");
425 DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
429 // Update the primary surface with what we really got
430 PrimarySurface
.DMW
.dmPelsWidth
= PrimarySurface
.gdiinfo
.ulHorzRes
;
431 PrimarySurface
.DMW
.dmPelsHeight
= PrimarySurface
.gdiinfo
.ulVertRes
;
432 PrimarySurface
.DMW
.dmBitsPerPel
= PrimarySurface
.gdiinfo
.cBitsPixel
;
433 PrimarySurface
.DMW
.dmDisplayFrequency
= PrimarySurface
.gdiinfo
.ulVRefresh
;
436 if (!PrimarySurface
.DMW
.dmDriverExtra
)
438 PrimarySurface
.pdmwDev
= &PrimarySurface
.DMW
; // HAX!
442 DPRINT1("WARNING!!! Need to Alloc DMW !!!!!!\n");
444 // Dont remove until we finish testing other drivers.
445 if (PrimarySurface
.DMW
.dmDriverExtra
!= 0)
447 DPRINT1("**** DMW extra = %u bytes. Please report to ros-dev@reactos.org ****\n", PrimarySurface
.DMW
.dmDriverExtra
);
450 if (0 == PrimarySurface
.gdiinfo
.ulLogPixelsX
)
452 DPRINT("Adjusting gdiinfo.ulLogPixelsX\n");
453 PrimarySurface
.gdiinfo
.ulLogPixelsX
= 96;
455 if (0 == PrimarySurface
.gdiinfo
.ulLogPixelsY
)
457 DPRINT("Adjusting gdiinfo.ulLogPixelsY\n");
458 PrimarySurface
.gdiinfo
.ulLogPixelsY
= 96;
461 PrimarySurface
.Pointer
.Exclude
.right
= -1;
463 DPRINT("calling completePDev\n");
465 /* Complete initialization of the physical device */
466 PrimarySurface
.DriverFunctions
.CompletePDEV(
467 PrimarySurface
.dhpdev
,
468 (HDEV
)&PrimarySurface
);
470 DPRINT("calling DRIVER_ReferenceDriver\n");
472 DRIVER_ReferenceDriver(L
"DISPLAY");
474 PrimarySurface
.PreparedDriver
= TRUE
;
475 PrimarySurface
.DisplayNumber
= DisplayNumber
;
476 PrimarySurface
.flFlags
= PDEV_DISPLAY
; // Hard set,, add more flags.
477 PrimarySurface
.hsemDevLock
= (PERESOURCE
)EngCreateSemaphore();
478 // Should be null,, but make sure for now.
479 PrimarySurface
.pvGammaRamp
= NULL
;
480 PrimarySurface
.ppdevNext
= NULL
; // Fixme! We need to support more than display drvs.
481 PrimarySurface
.ppdevParent
= NULL
; // Always NULL if primary.
482 PrimarySurface
.pGraphicsDevice
= NULL
; // Fixme!
483 PrimarySurface
.pEDDgpl
= ExAllocatePoolWithTag(PagedPool
, sizeof(EDD_DIRECTDRAW_GLOBAL
), TAG_EDDGBL
);
484 if (PrimarySurface
.pEDDgpl
)
486 RtlZeroMemory( PrimarySurface
.pEDDgpl
,sizeof(EDD_DIRECTDRAW_GLOBAL
));
493 KeSetEvent(&VideoDriverPrepared
, 1, FALSE
);
498 IntPrepareDriverIfNeeded(VOID
)
500 return (PrimarySurface
.PreparedDriver
? TRUE
: IntPrepareDriver());
504 PrepareVideoPrt(VOID
)
508 IO_STATUS_BLOCK Iosb
;
510 ULONG Length
= sizeof(BOOL
);
511 PIO_STACK_LOCATION StackPtr
;
512 LARGE_INTEGER StartOffset
;
513 PFILE_OBJECT FileObject
= PrimarySurface
.VideoFileObject
;
514 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
516 DPRINT("PrepareVideoPrt() called\n");
518 KeClearEvent(&PrimarySurface
.VideoFileObject
->Event
);
520 ObReferenceObjectByPointer(FileObject
, 0, IoFileObjectType
, KernelMode
);
522 StartOffset
.QuadPart
= 0;
523 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
535 /* Set up IRP Data */
536 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
537 Irp
->RequestorMode
= KernelMode
;
538 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
539 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
= NULL
;
540 Irp
->Flags
|= IRP_WRITE_OPERATION
;
542 /* Setup Stack Data */
543 StackPtr
= IoGetNextIrpStackLocation(Irp
);
544 StackPtr
->FileObject
= PrimarySurface
.VideoFileObject
;
545 StackPtr
->Parameters
.Write
.Key
= 0;
547 Status
= IoCallDriver(DeviceObject
, Irp
);
549 if (STATUS_PENDING
== Status
)
551 KeWaitForSingleObject(&FileObject
->Event
, Executive
, KernelMode
, TRUE
, 0);
552 Status
= Iosb
.Status
;
555 return NT_SUCCESS(Status
);
560 IntCreatePrimarySurface(VOID
)
567 if (! IntPrepareDriverIfNeeded())
572 if (! PrepareVideoPrt())
577 DPRINT("calling EnableSurface\n");
578 /* Enable the drawing surface */
579 PrimarySurface
.pSurface
=
580 PrimarySurface
.DriverFunctions
.EnableSurface(PrimarySurface
.dhpdev
);
581 if (NULL
== PrimarySurface
.pSurface
)
583 /* PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.dhpdev, FALSE);*/
584 PrimarySurface
.DriverFunctions
.DisablePDEV(PrimarySurface
.dhpdev
);
585 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
586 DPRINT1("DrvEnableSurface failed\n");
590 PrimarySurface
.DriverFunctions
.AssertMode(PrimarySurface
.dhpdev
, TRUE
);
592 calledFromUser
= UserIsEntered(); //fixme: possibly upgrade a shared lock
595 UserEnterExclusive();
599 IntAttachMonitor(&PrimarySurface
, PrimarySurface
.DisplayNumber
);
601 SurfObj
= EngLockSurface(PrimarySurface
.pSurface
);
602 SurfObj
->dhpdev
= PrimarySurface
.dhpdev
;
603 SurfSize
= SurfObj
->sizlBitmap
;
604 SurfaceRect
.left
= SurfaceRect
.top
= 0;
605 SurfaceRect
.right
= SurfObj
->sizlBitmap
.cx
;
606 SurfaceRect
.bottom
= SurfObj
->sizlBitmap
.cy
;
607 /* FIXME - why does EngEraseSurface() sometimes crash?
608 EngEraseSurface(SurfObj, &SurfaceRect, 0); */
610 /* Put the pointer in the center of the screen */
611 gpsi
->ptCursor
.x
= (SurfaceRect
.right
- SurfaceRect
.left
) / 2;
612 gpsi
->ptCursor
.y
= (SurfaceRect
.bottom
- SurfaceRect
.top
) / 2;
614 /* Give the PDEV a MovePointer function */
615 PrimarySurface
.pfnMovePointer
= PrimarySurface
.DriverFunctions
.MovePointer
;
616 if (!PrimarySurface
.pfnMovePointer
)
617 PrimarySurface
.pfnMovePointer
= EngMovePointer
;
619 EngUnlockSurface(SurfObj
);
620 co_IntShowDesktop(IntGetActiveDesktop(), SurfSize
.cx
, SurfSize
.cy
);
622 // Init Primary Displays Device Capabilities.
623 IntvGetDeviceCaps(&PrimarySurface
, &GdiHandleTable
->DevCaps
);
634 IntDestroyPrimarySurface(VOID
)
638 DRIVER_UnreferenceDriver(L
"DISPLAY");
640 calledFromUser
= UserIsEntered();
643 UserEnterExclusive();
647 IntDetachMonitor(&PrimarySurface
);
655 * FIXME: Hide a mouse pointer there. Also because we have to prevent
656 * memory leaks with the Eng* mouse routines.
659 DPRINT("Reseting display\n" );
660 PrimarySurface
.DriverFunctions
.AssertMode(PrimarySurface
.dhpdev
, FALSE
);
661 PrimarySurface
.DriverFunctions
.DisableSurface(PrimarySurface
.dhpdev
);
662 PrimarySurface
.DriverFunctions
.DisablePDEV(PrimarySurface
.dhpdev
);
663 PrimarySurface
.PreparedDriver
= FALSE
;
664 KeSetEvent(&VideoDriverNeedsPreparation
, 1, FALSE
);
665 KeResetEvent(&VideoDriverPrepared
);
669 ObDereferenceObject(PrimarySurface
.VideoFileObject
);
674 IntcFonts(PPDEVOBJ pDevObj
)
677 // Msdn DrvQueryFont:
678 // If the number of fonts in DEVINFO is -1 and iFace is zero, the driver
679 // should return the number of fonts it supports.
680 if ( pDevObj
->devinfo
.cFonts
== -1)
682 if (pDevObj
->DriverFunctions
.QueryFont
)
683 pDevObj
->devinfo
.cFonts
=
684 (ULONG
)pDevObj
->DriverFunctions
.QueryFont(pDevObj
->dhpdev
, 0, 0, &Junk
);
686 pDevObj
->devinfo
.cFonts
= 0;
688 return pDevObj
->devinfo
.cFonts
;
692 // Support multi display/device locks.
696 DC_LockDisplay(HDC hDC
)
699 PDC dc
= DC_LockDc(hDC
);
701 Resource
= dc
->ppdev
->hsemDevLock
;
703 if (!Resource
) return;
704 KeEnterCriticalRegion();
705 ExAcquireResourceExclusiveLite( Resource
, TRUE
);
710 DC_UnlockDisplay(HDC hDC
)
713 PDC dc
= DC_LockDc(hDC
);
715 Resource
= dc
->ppdev
->hsemDevLock
;
717 if (!Resource
) return;
718 ExReleaseResourceLite( Resource
);
719 KeLeaveCriticalRegion();
728 // I guess we will soon have more than one primary surface.
729 // This will do for now.
730 return &PrimarySurface
;
735 IntGdiReferencePdev(PPDEVOBJ ppdev
)
737 if (!hsemDriverMgmt
) hsemDriverMgmt
= EngCreateSemaphore(); // Hax, should be in dllmain.c
738 IntGdiAcquireSemaphore(hsemDriverMgmt
);
740 IntGdiReleaseSemaphore(hsemDriverMgmt
);
744 IntGdiUnreferencePdev(PPDEVOBJ ppdev
, DWORD CleanUpType
)
746 IntGdiAcquireSemaphore(hsemDriverMgmt
);
748 if (!ppdev
->cPdevRefs
)
750 // Handle the destruction of ppdev or PDEVOBJ or PDEVOBJ or PDEV etc.
752 IntGdiReleaseSemaphore(hsemDriverMgmt
);
759 IntGetColorManagementCaps(PPDEVOBJ pDevObj
)
763 if ( pDevObj
->flFlags
& PDEV_DISPLAY
)
765 if (pDevObj
->devinfo
.iDitherFormat
== BMF_8BPP
||
766 pDevObj
->devinfo
.flGraphicsCaps2
& GCAPS2_CHANGEGAMMARAMP
)
769 if (pDevObj
->devinfo
.flGraphicsCaps
& GCAPS_CMYKCOLOR
)
770 ret
|= CM_CMYK_COLOR
;
771 if (pDevObj
->devinfo
.flGraphicsCaps
& GCAPS_ICM
)
772 ret
|= CM_DEVICE_ICM
;
777 IntGdiGetDeviceCaps(PDC dc
, INT Index
)
780 PPDEVOBJ ppdev
= dc
->ppdev
;
781 /* Retrieve capability */
785 ret
= ppdev
->gdiinfo
.ulVersion
;
789 ret
= ppdev
->gdiinfo
.ulTechnology
;
793 ret
= ppdev
->gdiinfo
.ulHorzSize
;
797 ret
= ppdev
->gdiinfo
.ulVertSize
;
801 ret
= ppdev
->gdiinfo
.ulHorzRes
;
805 ret
= ppdev
->gdiinfo
.ulVertRes
;
809 ret
= ppdev
->gdiinfo
.ulLogPixelsX
;
813 ret
= ppdev
->gdiinfo
.ulLogPixelsY
;
817 if ( ppdev
->pGraphicsDevice
&&
818 (((PGRAPHICS_DEVICE
)ppdev
->pGraphicsDevice
)->StateFlags
&
819 DISPLAY_DEVICE_MIRRORING_DRIVER
))
824 ret
= ppdev
->gdiinfo
.cBitsPixel
;
828 ret
= ppdev
->gdiinfo
.cPlanes
;
836 ret
= ppdev
->gdiinfo
.ulNumColors
;
837 if ( ret
!= -1 ) ret
*= 5;
841 ret
= IntcFonts(ppdev
);
845 ret
= ppdev
->gdiinfo
.ulNumColors
;
849 ret
= ppdev
->gdiinfo
.ulAspectX
;
853 ret
= ppdev
->gdiinfo
.ulAspectY
;
857 ret
= ppdev
->gdiinfo
.ulAspectXY
;
865 ret
= ppdev
->gdiinfo
.ulNumPalReg
;
873 ret
= ppdev
->gdiinfo
.ulDACRed
+
874 ppdev
->gdiinfo
.ulDACGreen
+
875 ppdev
->gdiinfo
.ulDACBlue
;
879 ret
= ppdev
->gdiinfo
.ulVertRes
;
883 ret
= ppdev
->gdiinfo
.ulHorzRes
;
887 ret
= ppdev
->gdiinfo
.ulBltAlignment
;
891 ret
= ppdev
->gdiinfo
.flShadeBlend
;
895 ret
= IntGetColorManagementCaps(ppdev
);
899 ret
= ppdev
->gdiinfo
.szlPhysSize
.cx
;
903 ret
= ppdev
->gdiinfo
.szlPhysSize
.cy
;
906 case PHYSICALOFFSETX
:
907 ret
= ppdev
->gdiinfo
.ptlPhysOffset
.x
;
910 case PHYSICALOFFSETY
:
911 ret
= ppdev
->gdiinfo
.ptlPhysOffset
.y
;
915 ret
= ppdev
->gdiinfo
.ulVRefresh
;
919 ret
= ppdev
->gdiinfo
.flRaster
;
923 ret
= (CC_CIRCLES
| CC_PIE
| CC_CHORD
| CC_ELLIPSES
| CC_WIDE
|
924 CC_STYLED
| CC_WIDESTYLED
| CC_INTERIORS
| CC_ROUNDRECT
);
928 ret
= (LC_POLYLINE
| LC_MARKER
| LC_POLYMARKER
| LC_WIDE
|
929 LC_STYLED
| LC_WIDESTYLED
| LC_INTERIORS
);
933 ret
= (PC_POLYGON
| PC_RECTANGLE
| PC_WINDPOLYGON
| PC_SCANLINE
|
934 PC_WIDE
| PC_STYLED
| PC_WIDESTYLED
| PC_INTERIORS
);
938 ret
= ppdev
->gdiinfo
.flTextCaps
;
939 if (ppdev
->gdiinfo
.ulTechnology
) ret
|= TC_VA_ABLE
;
940 ret
|= (TC_SO_ABLE
|TC_UA_ABLE
);
955 NtGdiGetDeviceCaps(HDC hDC
,
964 SetLastWin32Error(ERROR_INVALID_HANDLE
);
968 ret
= IntGdiGetDeviceCaps(dc
, Index
);
970 DPRINT("(%04x,%d): returning %d\n", hDC
, Index
, ret
);
983 PGDIINFO pGdiInfo
= &pDevObj
->gdiinfo
;
985 pDevCaps
->ulVersion
= pGdiInfo
->ulVersion
;
986 pDevCaps
->ulTechnology
= pGdiInfo
->ulTechnology
;
987 pDevCaps
->ulHorzSizeM
= (pGdiInfo
->ulHorzSize
+ 500) / 1000;
988 pDevCaps
->ulVertSizeM
= (pGdiInfo
->ulVertSize
+ 500) / 1000;
989 pDevCaps
->ulHorzSize
= pGdiInfo
->ulHorzSize
;
990 pDevCaps
->ulVertSize
= pGdiInfo
->ulVertSize
;
991 pDevCaps
->ulHorzRes
= pGdiInfo
->ulHorzRes
;
992 pDevCaps
->ulVertRes
= pGdiInfo
->ulVertRes
;
993 pDevCaps
->ulVRefresh
= pGdiInfo
->ulVRefresh
;
994 pDevCaps
->ulDesktopHorzRes
= pGdiInfo
->ulHorzRes
;
995 pDevCaps
->ulDesktopVertRes
= pGdiInfo
->ulVertRes
;
996 pDevCaps
->ulBltAlignment
= pGdiInfo
->ulBltAlignment
;
997 pDevCaps
->ulPlanes
= pGdiInfo
->cPlanes
;
999 pDevCaps
->ulBitsPixel
= pGdiInfo
->cBitsPixel
;
1000 if (pGdiInfo
->cBitsPixel
== 15) pDevCaps
->ulBitsPixel
= 16;
1002 Tmp
= pGdiInfo
->ulNumColors
;
1003 if ( Tmp
!= -1 ) Tmp
*= 5;
1004 pDevCaps
->ulNumPens
= Tmp
;
1005 pDevCaps
->ulNumColors
= pGdiInfo
->ulNumColors
;
1007 pDevCaps
->ulNumFonts
= IntcFonts(pDevObj
);
1009 pDevCaps
->ulRasterCaps
= pGdiInfo
->flRaster
;
1010 pDevCaps
->ulShadeBlend
= pGdiInfo
->flShadeBlend
;
1011 pDevCaps
->ulAspectX
= pGdiInfo
->ulAspectX
;
1012 pDevCaps
->ulAspectY
= pGdiInfo
->ulAspectY
;
1013 pDevCaps
->ulAspectXY
= pGdiInfo
->ulAspectXY
;
1014 pDevCaps
->ulLogPixelsX
= pGdiInfo
->ulLogPixelsX
;
1015 pDevCaps
->ulLogPixelsY
= pGdiInfo
->ulLogPixelsY
;
1016 pDevCaps
->ulSizePalette
= pGdiInfo
->ulNumPalReg
;
1017 pDevCaps
->ulColorRes
= pGdiInfo
->ulDACRed
+ pGdiInfo
->ulDACGreen
+ pGdiInfo
->ulDACBlue
;
1018 pDevCaps
->ulPhysicalWidth
= pGdiInfo
->szlPhysSize
.cx
;
1019 pDevCaps
->ulPhysicalHeight
= pGdiInfo
->szlPhysSize
.cy
;
1020 pDevCaps
->ulPhysicalOffsetX
= pGdiInfo
->ptlPhysOffset
.x
;
1021 pDevCaps
->ulPhysicalOffsetY
= pGdiInfo
->ptlPhysOffset
.y
;
1022 pDevCaps
->ulPanningHorzRes
= pGdiInfo
->ulPanningHorzRes
;
1023 pDevCaps
->ulPanningVertRes
= pGdiInfo
->ulPanningVertRes
;
1024 pDevCaps
->xPanningAlignment
= pGdiInfo
->xPanningAlignment
;
1025 pDevCaps
->yPanningAlignment
= pGdiInfo
->yPanningAlignment
;
1028 Tmp
= pGdiInfo
->flTextCaps
| (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
1030 pDevCaps
->ulTextCaps
= pGdiInfo
->flTextCaps
| (TC_SO_ABLE
|TC_UA_ABLE
|TC_CP_STROKE
|TC_OP_STROKE
|TC_OP_CHARACTER
);
1032 if (pGdiInfo
->ulTechnology
)
1033 pDevCaps
->ulTextCaps
= Tmp
| TC_VA_ABLE
;
1035 pDevCaps
->ulColorMgmtCaps
= IntGetColorManagementCaps(pDevObj
);
1045 NtGdiGetDeviceCapsAll (
1047 OUT PDEVCAPS pDevCaps
)
1050 PDEVCAPS pSafeDevCaps
;
1051 NTSTATUS Status
= STATUS_SUCCESS
;
1053 dc
= DC_LockDc(hDC
);
1056 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1060 pSafeDevCaps
= ExAllocatePoolWithTag(PagedPool
, sizeof(DEVCAPS
), TAG_TEMP
);
1068 IntvGetDeviceCaps(dc
->ppdev
, pSafeDevCaps
);
1072 ProbeForWrite(pDevCaps
,
1075 RtlCopyMemory(pDevCaps
, pSafeDevCaps
, sizeof(DEVCAPS
));
1077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1079 Status
= _SEH2_GetExceptionCode();
1083 ExFreePoolWithTag(pSafeDevCaps
, TAG_TEMP
);
1086 if (!NT_SUCCESS(Status
))
1088 SetLastNtError(Status
);
1103 PPDEVOBJ ppdev
, pGdiDevice
= (PPDEVOBJ
) hdev
;
1104 if (!pGdiDevice
) return NULL
;
1105 if ( pGdiDevice
< (PPDEVOBJ
)MmSystemRangeStart
) return NULL
;
1106 ppdev
= pPrimarySurface
;
1107 IntGdiAcquireSemaphore(hsemDriverMgmt
);
1110 if (pGdiDevice
== ppdev
) break;
1112 ppdev
= ppdev
->ppdevNext
;
1114 while (ppdev
!= NULL
);
1115 IntGdiReleaseSemaphore(hsemDriverMgmt
);
1116 if (!ppdev
) return NULL
;
1117 return pGdiDevice
->dhpdev
;
1120 static NTSTATUS FASTCALL
1121 GetVideoRegistryKey(
1122 OUT PUNICODE_STRING RegistryPath
,
1123 IN PCUNICODE_STRING DeviceName
) /* ex: "\Device\Video0" */
1125 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1128 RtlInitUnicodeString(RegistryPath
, NULL
);
1129 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1130 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
1131 QueryTable
[0].Name
= DeviceName
->Buffer
;
1132 QueryTable
[0].EntryContext
= RegistryPath
;
1134 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
1139 if (!NT_SUCCESS(Status
))
1141 DPRINT1("No %wZ value in DEVICEMAP\\VIDEO found (Status 0x%08lx)\n", DeviceName
, Status
);
1142 return STATUS_NO_SUCH_DEVICE
;
1145 DPRINT("RegistryPath %wZ\n", RegistryPath
);
1146 return STATUS_SUCCESS
;
1150 static NTSTATUS FASTCALL
1152 OUT PUNICODE_STRING VideoDeviceName
,
1153 IN PCUNICODE_STRING DisplayDevice
) /* ex: "\.\DISPLAY1" or "\??\DISPLAY1" */
1155 UNICODE_STRING Prefix
= RTL_CONSTANT_STRING(L
"\\??\\");
1156 UNICODE_STRING ObjectName
;
1157 UNICODE_STRING KernelModeName
= { 0, };
1158 OBJECT_ATTRIBUTES ObjectAttributes
;
1161 HANDLE LinkHandle
= NULL
;
1164 RtlInitUnicodeString(VideoDeviceName
, NULL
);
1166 /* Get device name (DisplayDevice is "\.\xxx") */
1167 for (LastSlash
= DisplayDevice
->Length
/ sizeof(WCHAR
); LastSlash
> 0; LastSlash
--)
1169 if (DisplayDevice
->Buffer
[LastSlash
- 1] == L
'\\')
1175 DPRINT1("Invalid device name '%wZ'\n", DisplayDevice
);
1176 Status
= STATUS_OBJECT_NAME_INVALID
;
1179 ObjectName
= *DisplayDevice
;
1180 ObjectName
.Length
-= LastSlash
* sizeof(WCHAR
);
1181 ObjectName
.MaximumLength
-= LastSlash
* sizeof(WCHAR
);
1182 ObjectName
.Buffer
+= LastSlash
;
1184 /* Create "\??\xxx" (ex: "\??\DISPLAY1") */
1185 KernelModeName
.MaximumLength
= Prefix
.Length
+ ObjectName
.Length
+ sizeof(UNICODE_NULL
);
1186 KernelModeName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1187 KernelModeName
.MaximumLength
,
1189 if (!KernelModeName
.Buffer
)
1191 Status
= STATUS_NO_MEMORY
;
1194 RtlCopyUnicodeString(&KernelModeName
, &Prefix
);
1195 Status
= RtlAppendUnicodeStringToString(&KernelModeName
, &ObjectName
);
1196 if (!NT_SUCCESS(Status
))
1199 /* Open \??\xxx (ex: "\??\DISPLAY1") */
1200 InitializeObjectAttributes(&ObjectAttributes
,
1205 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
,
1208 if (!NT_SUCCESS(Status
))
1210 DPRINT1("Unable to open symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1211 Status
= STATUS_NO_SUCH_DEVICE
;
1215 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, VideoDeviceName
, &Length
);
1216 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
1218 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1219 Status
= STATUS_NO_SUCH_DEVICE
;
1222 VideoDeviceName
->MaximumLength
= Length
;
1223 VideoDeviceName
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1224 VideoDeviceName
->MaximumLength
+ sizeof(UNICODE_NULL
),
1226 if (!VideoDeviceName
->Buffer
)
1228 Status
= STATUS_NO_MEMORY
;
1231 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, VideoDeviceName
, NULL
);
1232 VideoDeviceName
->Buffer
[VideoDeviceName
->MaximumLength
/ sizeof(WCHAR
) - 1] = UNICODE_NULL
;
1233 if (!NT_SUCCESS(Status
))
1235 DPRINT1("Unable to query symbolic link %wZ (Status 0x%08lx)\n", &KernelModeName
, Status
);
1236 Status
= STATUS_NO_SUCH_DEVICE
;
1239 Status
= STATUS_SUCCESS
;
1242 if (!NT_SUCCESS(Status
) && VideoDeviceName
->Buffer
)
1243 ExFreePoolWithTag(VideoDeviceName
->Buffer
, TAG_DC
);
1244 if (KernelModeName
.Buffer
)
1245 ExFreePoolWithTag(KernelModeName
.Buffer
, TAG_DC
);
1247 ZwClose(LinkHandle
);
1253 IntChangeDisplaySettings(
1254 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1255 IN LPDEVMODEW DevMode
,
1257 IN PVOID lParam OPTIONAL
)
1259 BOOLEAN Global
= FALSE
;
1260 BOOLEAN NoReset
= FALSE
;
1261 BOOLEAN Reset
= FALSE
;
1262 BOOLEAN SetPrimary
= FALSE
;
1263 LONG Ret
= DISP_CHANGE_SUCCESSFUL
;
1266 DPRINT1("display flags : %x\n",dwflags
);
1268 if ((dwflags
& CDS_UPDATEREGISTRY
) == CDS_UPDATEREGISTRY
)
1270 /* Check global, reset and noreset flags */
1271 if ((dwflags
& CDS_GLOBAL
) == CDS_GLOBAL
)
1273 if ((dwflags
& CDS_NORESET
) == CDS_NORESET
)
1275 dwflags
&= ~(CDS_GLOBAL
| CDS_NORESET
);
1277 if ((dwflags
& CDS_RESET
) == CDS_RESET
)
1279 if ((dwflags
& CDS_SET_PRIMARY
) == CDS_SET_PRIMARY
)
1281 dwflags
&= ~(CDS_RESET
| CDS_SET_PRIMARY
);
1283 if (Reset
&& NoReset
)
1284 return DISP_CHANGE_BADFLAGS
;
1288 /* Dynamically change graphics mode */
1289 DPRINT1("flag 0 UNIMPLEMENTED\n");
1290 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED
);
1291 return DISP_CHANGE_FAILED
;
1294 if ((dwflags
& CDS_TEST
) == CDS_TEST
)
1296 /* Test resolution */
1297 dwflags
&= ~CDS_TEST
;
1298 Status
= IntEnumDisplaySettings(pDeviceName
, ENUM_REGISTRY_SETTINGS
, DevMode
, 0);
1299 if (!NT_SUCCESS(Status
))
1300 Ret
= DISP_CHANGE_BADMODE
;
1304 if ((dwflags
& CDS_FULLSCREEN
) == CDS_FULLSCREEN
)
1308 dwflags
&= ~CDS_FULLSCREEN
;
1309 DPRINT1("flag CDS_FULLSCREEN partially implemented\n");
1310 Ret
= DISP_CHANGE_FAILED
;
1312 RtlZeroMemory(&lpDevMode
, sizeof(DEVMODEW
));
1313 lpDevMode
.dmSize
= sizeof(DEVMODEW
);
1315 Status
= IntEnumDisplaySettings(pDeviceName
, ENUM_CURRENT_SETTINGS
, &lpDevMode
, 0);
1316 if (!NT_SUCCESS(Status
))
1317 return DISP_CHANGE_FAILED
;
1319 DPRINT1("Req Mode : %d x %d x %d\n", DevMode
->dmPelsWidth
,DevMode
->dmPelsHeight
,DevMode
->dmBitsPerPel
);
1320 DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode
.dmPelsWidth
,lpDevMode
.dmPelsHeight
, lpDevMode
.dmBitsPerPel
);
1323 if ((lpDevMode
.dmBitsPerPel
== DevMode
->dmBitsPerPel
) &&
1324 (lpDevMode
.dmPelsWidth
== DevMode
->dmPelsWidth
) &&
1325 (lpDevMode
.dmPelsHeight
== DevMode
->dmPelsHeight
))
1326 Ret
= DISP_CHANGE_SUCCESSFUL
;
1329 if ((dwflags
& CDS_VIDEOPARAMETERS
) == CDS_VIDEOPARAMETERS
)
1331 dwflags
&= ~CDS_VIDEOPARAMETERS
;
1333 Ret
=DISP_CHANGE_BADPARAM
;
1336 DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENTED\n");
1337 Ret
= DISP_CHANGE_FAILED
;
1338 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED
);
1343 if ((dwflags
& CDS_UPDATEREGISTRY
) == CDS_UPDATEREGISTRY
)
1346 UNICODE_STRING DeviceName
;
1347 UNICODE_STRING RegistryKey
;
1348 UNICODE_STRING InDeviceName
;
1349 OBJECT_ATTRIBUTES ObjectAttributes
;
1350 HANDLE DevInstRegKey
;
1353 DPRINT1("set CDS_UPDATEREGISTRY\n");
1355 dwflags
&= ~CDS_UPDATEREGISTRY
;
1357 /* Check if pDeviceName is NULL, we need to retrieve it */
1358 if (pDeviceName
== NULL
)
1360 WCHAR szBuffer
[MAX_DRIVER_NAME
];
1362 PWINDOW_OBJECT Wnd
=NULL
;
1366 hWnd
= IntGetDesktopWindow();
1367 if (!(Wnd
= UserGetWindowObject(hWnd
)))
1372 hDC
= UserGetWindowDC(Wnd
);
1374 DC
= DC_LockDc(hDC
);
1379 swprintf (szBuffer
, L
"\\\\.\\DISPLAY%lu", DC
->ppdev
->DisplayNumber
);
1382 RtlInitUnicodeString(&InDeviceName
, szBuffer
);
1383 pDeviceName
= &InDeviceName
;
1386 Status
= GetVideoDeviceName(&DeviceName
, pDeviceName
);
1387 if (!NT_SUCCESS(Status
))
1389 DPRINT1("Unable to get destination of '%wZ' (Status 0x%08lx)\n", pDeviceName
, Status
);
1390 return DISP_CHANGE_FAILED
;
1392 Status
= GetVideoRegistryKey(&RegistryKey
, &DeviceName
);
1393 if (!NT_SUCCESS(Status
))
1395 DPRINT1("Unable to get registry key for '%wZ' (Status 0x%08lx)\n", &DeviceName
, Status
);
1396 ExFreePoolWithTag(DeviceName
.Buffer
, TAG_DC
);
1397 return DISP_CHANGE_FAILED
;
1399 ExFreePoolWithTag(DeviceName
.Buffer
, TAG_DC
);
1401 InitializeObjectAttributes(&ObjectAttributes
, &RegistryKey
,
1402 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1403 Status
= ZwOpenKey(&DevInstRegKey
, KEY_SET_VALUE
, &ObjectAttributes
);
1404 if (!NT_SUCCESS(Status
))
1406 DPRINT1("Unable to open registry key %wZ (Status 0x%08lx)\n", &RegistryKey
, Status
);
1407 ExFreePoolWithTag(RegistryKey
.Buffer
, TAG_RTLREGISTRY
);
1408 return DISP_CHANGE_FAILED
;
1410 ExFreePoolWithTag(RegistryKey
.Buffer
, TAG_RTLREGISTRY
);
1412 /* Update needed fields */
1413 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_BITSPERPEL
)
1415 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.BitsPerPel");
1416 NewValue
= DevMode
->dmBitsPerPel
;
1417 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1420 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_PELSWIDTH
)
1422 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.XResolution");
1423 NewValue
= DevMode
->dmPelsWidth
;
1424 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1427 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_PELSHEIGHT
)
1429 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.YResolution");
1430 NewValue
= DevMode
->dmPelsHeight
;
1431 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1434 if (NT_SUCCESS(Status
) && DevMode
->dmFields
& DM_DISPLAYFREQUENCY
)
1436 RtlInitUnicodeString(&RegistryKey
, L
"DefaultSettings.VRefresh");
1437 NewValue
= DevMode
->dmDisplayFrequency
;
1438 Status
= ZwSetValueKey(DevInstRegKey
, &RegistryKey
, 0, REG_DWORD
, &NewValue
, sizeof(NewValue
));
1441 ZwClose(DevInstRegKey
);
1442 if (NT_SUCCESS(Status
))
1443 Ret
= DISP_CHANGE_RESTART
;
1445 /* return DISP_CHANGE_NOTUPDATED when we can save to reg only valid for NT */
1446 Ret
= DISP_CHANGE_NOTUPDATED
;
1450 Ret
= DISP_CHANGE_BADFLAGS
;
1452 DPRINT("IntChangeDisplaySettings returning %x\n", Ret
);
1458 #define SIZEOF_DEVMODEW_300 188
1459 #define SIZEOF_DEVMODEW_400 212
1460 #define SIZEOF_DEVMODEW_500 220
1462 static NTSTATUS FASTCALL
1463 GetDisplayNumberFromDeviceName(
1464 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1465 OUT ULONG
*DisplayNumber
)
1467 UNICODE_STRING DisplayString
= RTL_CONSTANT_STRING(L
"\\\\.\\DISPLAY");
1468 NTSTATUS Status
= STATUS_SUCCESS
;
1473 if (DisplayNumber
== NULL
)
1474 return STATUS_INVALID_PARAMETER_2
;
1476 /* Check if DeviceName is valid */
1478 pDeviceName
->Length
> 0 && pDeviceName
->Length
<= DisplayString
.Length
)
1479 return STATUS_OBJECT_NAME_INVALID
;
1481 if (pDeviceName
== NULL
|| pDeviceName
->Length
== 0)
1483 PWINDOW_OBJECT DesktopObject
;
1487 DesktopObject
= UserGetDesktopWindow();
1488 DesktopHDC
= UserGetWindowDC(DesktopObject
);
1489 pDC
= DC_LockDc(DesktopHDC
);
1491 *DisplayNumber
= pDC
->ppdev
->DisplayNumber
;
1494 UserReleaseDC(DesktopObject
, DesktopHDC
, FALSE
);
1496 return STATUS_SUCCESS
;
1499 /* Hack to check if the first parts are equal, by faking the device name length */
1500 Length
= pDeviceName
->Length
;
1501 pDeviceName
->Length
= DisplayString
.Length
;
1502 if (RtlEqualUnicodeString(&DisplayString
, pDeviceName
, FALSE
) == FALSE
)
1503 Status
= STATUS_OBJECT_NAME_INVALID
;
1504 pDeviceName
->Length
= Length
;
1506 if (NT_SUCCESS(Status
))
1508 /* Convert the last part of pDeviceName to a number */
1510 Length
= pDeviceName
->Length
/ sizeof(WCHAR
);
1511 for (i
= DisplayString
.Length
/ sizeof(WCHAR
); i
< Length
; i
++)
1513 WCHAR Char
= pDeviceName
->Buffer
[i
];
1514 if (Char
>= L
'0' && Char
<= L
'9')
1515 Number
= Number
* 10 + Char
- L
'0';
1516 else if (Char
!= L
'\0')
1517 return STATUS_OBJECT_NAME_INVALID
;
1520 *DisplayNumber
= Number
- 1;
1526 /*! \brief Enumerate possible display settings for the given display...
1528 * \todo Make thread safe!?
1529 * \todo Don't ignore pDeviceName
1530 * \todo Implement non-raw mode (only return settings valid for driver and monitor)
1534 IntEnumDisplaySettings(
1535 IN PUNICODE_STRING pDeviceName OPTIONAL
,
1537 IN OUT LPDEVMODEW pDevMode
,
1540 static DEVMODEW
*CachedDevModes
= NULL
, *CachedDevModesEnd
= NULL
;
1541 static DWORD SizeOfCachedDevModes
= 0;
1542 static UNICODE_STRING CachedDeviceName
;
1543 PDEVMODEW CachedMode
= NULL
;
1545 ULONG DisplayNumber
;
1548 Status
= GetDisplayNumberFromDeviceName(pDeviceName
, &DisplayNumber
);
1549 if (!NT_SUCCESS(Status
))
1554 if (pDevMode
!= NULL
)
1556 DPRINT("DevMode->dmSize = %d\n", pDevMode
->dmSize
);
1557 DPRINT("DevMode->dmExtraSize = %d\n", pDevMode
->dmDriverExtra
);
1558 if (pDevMode
->dmSize
!= SIZEOF_DEVMODEW_300
&&
1559 pDevMode
->dmSize
!= SIZEOF_DEVMODEW_400
&&
1560 pDevMode
->dmSize
!= SIZEOF_DEVMODEW_500
)
1562 return STATUS_BUFFER_TOO_SMALL
;
1566 if (iModeNum
== ENUM_CURRENT_SETTINGS
)
1568 CachedMode
= &PrimarySurface
.DMW
;
1569 ASSERT(CachedMode
->dmSize
> 0);
1571 else if (iModeNum
== ENUM_REGISTRY_SETTINGS
)
1573 RtlZeroMemory(&DevMode
, sizeof (DevMode
));
1574 DevMode
.dmSize
= sizeof (DevMode
);
1575 DevMode
.dmDriverExtra
= 0;
1576 if (SetupDevMode(&DevMode
, DisplayNumber
))
1577 CachedMode
= &DevMode
;
1580 return STATUS_UNSUCCESSFUL
; // FIXME: what status?
1582 /* FIXME: Maybe look for the matching devmode supplied by the
1583 * driver so we can provide driver private/extra data?
1588 BOOL IsCachedDevice
= (CachedDevModes
!= NULL
);
1590 if (CachedDevModes
&&
1591 ((pDeviceName
== NULL
&& CachedDeviceName
.Length
> 0) ||
1592 (pDeviceName
!= NULL
&& pDeviceName
->Buffer
!= NULL
&& CachedDeviceName
.Length
== 0) ||
1593 (pDeviceName
!= NULL
&& pDeviceName
->Buffer
!= NULL
&& CachedDeviceName
.Length
> 0 && RtlEqualUnicodeString(pDeviceName
, &CachedDeviceName
, TRUE
) == FALSE
)))
1595 IsCachedDevice
= FALSE
;
1598 if (iModeNum
== 0 || IsCachedDevice
== FALSE
) /* query modes from drivers */
1600 UNICODE_STRING DriverFileNames
;
1602 DRVENABLEDATA DrvEnableData
;
1604 /* Free resources from last driver cache */
1605 if (IsCachedDevice
== FALSE
&& CachedDeviceName
.Buffer
!= NULL
)
1607 RtlFreeUnicodeString(&CachedDeviceName
);
1610 /* Retrieve DDI driver names from registry */
1611 RtlInitUnicodeString(&DriverFileNames
, NULL
);
1612 if (!FindDriverFileNames(&DriverFileNames
, DisplayNumber
))
1614 DPRINT1("FindDriverFileNames failed\n");
1615 return STATUS_UNSUCCESSFUL
;
1618 if (!IntPrepareDriverIfNeeded())
1620 DPRINT1("IntPrepareDriverIfNeeded failed\n");
1621 return STATUS_UNSUCCESSFUL
;
1625 * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
1626 * scan all of them until a good one found.
1628 CurrentName
= DriverFileNames
.Buffer
;
1629 for (;CurrentName
< DriverFileNames
.Buffer
+ (DriverFileNames
.Length
/ sizeof (WCHAR
));
1630 CurrentName
+= wcslen(CurrentName
) + 1)
1633 PFN_DrvEnableDriver GDEnableDriver
;
1634 PFN_DrvGetModes GetModes
= NULL
;
1635 INT SizeNeeded
, SizeUsed
;
1637 /* Get the DDI driver's entry point */
1638 //GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
1639 GDEnableDriver
= DRIVER_FindExistingDDIDriver(L
"DISPLAY");
1640 if (NULL
== GDEnableDriver
)
1642 DPRINT("FindDDIDriver failed for %S\n", CurrentName
);
1646 /* Call DDI driver's EnableDriver function */
1647 RtlZeroMemory(&DrvEnableData
, sizeof(DrvEnableData
));
1649 if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01
, sizeof (DrvEnableData
), &DrvEnableData
))
1651 DPRINT("DrvEnableDriver failed for %S\n", CurrentName
);
1655 CachedDevModesEnd
= CachedDevModes
;
1657 /* find DrvGetModes function */
1658 for (i
= 0; i
< DrvEnableData
.c
; i
++)
1660 PDRVFN DrvFn
= DrvEnableData
.pdrvfn
+ i
;
1662 if (DrvFn
->iFunc
== INDEX_DrvGetModes
)
1664 GetModes
= (PFN_DrvGetModes
)DrvFn
->pfn
;
1669 if (GetModes
== NULL
)
1671 DPRINT("DrvGetModes doesn't exist for %S\n", CurrentName
);
1675 /* make sure we have enough memory to hold the modes */
1676 SizeNeeded
= GetModes((HANDLE
)(PrimarySurface
.VideoFileObject
->DeviceObject
), 0, NULL
);
1677 if (SizeNeeded
<= 0)
1679 DPRINT("DrvGetModes failed for %S\n", CurrentName
);
1683 SizeUsed
= (PCHAR
)CachedDevModesEnd
- (PCHAR
)CachedDevModes
;
1684 if (SizeOfCachedDevModes
< SizeUsed
+ SizeNeeded
)
1688 SizeOfCachedDevModes
+= SizeNeeded
;
1689 NewBuffer
= ExAllocatePool(PagedPool
, SizeOfCachedDevModes
);
1690 if (NewBuffer
== NULL
)
1693 ExFreePool(CachedDevModes
);
1694 CachedDevModes
= NULL
;
1695 CachedDevModesEnd
= NULL
;
1696 SizeOfCachedDevModes
= 0;
1698 if (CachedDeviceName
.Buffer
!= NULL
)
1699 RtlFreeUnicodeString(&CachedDeviceName
);
1701 return STATUS_NO_MEMORY
;
1703 if (CachedDevModes
!= NULL
)
1705 RtlCopyMemory(NewBuffer
, CachedDevModes
, SizeUsed
);
1706 ExFreePool(CachedDevModes
);
1708 CachedDevModes
= NewBuffer
;
1709 CachedDevModesEnd
= (DEVMODEW
*)((PCHAR
)NewBuffer
+ SizeUsed
);
1712 if (!IsCachedDevice
)
1714 if (CachedDeviceName
.Buffer
!= NULL
)
1715 RtlFreeUnicodeString(&CachedDeviceName
);
1718 IntSafeCopyUnicodeString(&CachedDeviceName
, pDeviceName
);
1720 IsCachedDevice
= TRUE
;
1724 SizeNeeded
= GetModes((HANDLE
)(PrimarySurface
.VideoFileObject
->DeviceObject
),
1727 if (SizeNeeded
<= 0)
1729 DPRINT("DrvGetModes failed for %S\n", CurrentName
);
1733 CachedDevModesEnd
= (DEVMODEW
*)((PCHAR
)CachedDevModesEnd
+ SizeNeeded
);
1737 ExFreePoolWithTag(DriverFileNames
.Buffer
, TAG_RTLREGISTRY
);
1740 /* return cached info */
1741 CachedMode
= CachedDevModes
;
1742 if (CachedMode
>= CachedDevModesEnd
)
1744 return STATUS_NO_MORE_ENTRIES
;
1746 while (iModeNum
-- > 0 && CachedMode
< CachedDevModesEnd
)
1748 assert(CachedMode
->dmSize
> 0);
1749 CachedMode
= (DEVMODEW
*)((PCHAR
)CachedMode
+ CachedMode
->dmSize
+ CachedMode
->dmDriverExtra
);
1751 if (CachedMode
>= CachedDevModesEnd
)
1753 return STATUS_NO_MORE_ENTRIES
;
1757 ASSERT(CachedMode
!= NULL
);
1759 if (pDevMode
!= NULL
)
1761 RtlCopyMemory(pDevMode
, CachedMode
, min(pDevMode
->dmSize
, CachedMode
->dmSize
));
1762 RtlZeroMemory(pDevMode
+ pDevMode
->dmSize
, pDevMode
->dmDriverExtra
);
1763 RtlCopyMemory(pDevMode
+ min(pDevMode
->dmSize
, CachedMode
->dmSize
), CachedMode
+ CachedMode
->dmSize
, min(pDevMode
->dmDriverExtra
, CachedMode
->dmDriverExtra
));
1766 return STATUS_SUCCESS
;
1775 IN OPTIONAL LPSTR pjIn
)