2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
37 /* GLOBALS *******************************************************************/
39 /* NOTE - I think we should store this per window station (including gdi objects) */
41 static PDCE FirstDce
= NULL
;
42 static HDC defaultDCstate
= NULL
;
43 //static INT DCECount = 0;
45 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
46 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
48 /* FUNCTIONS *****************************************************************/
51 DceCreateDisplayDC(VOID
)
54 UNICODE_STRING DriverName
;
55 RtlInitUnicodeString(&DriverName
, L
"DISPLAY");
56 hDC
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
68 DceGetVisRgn(PWINDOW_OBJECT Window
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
72 VisRgn
= VIS_ComputeVisibleRegion(Window
,
73 0 == (Flags
& DCX_WINDOW
),
74 0 != (Flags
& DCX_CLIPCHILDREN
),
75 0 != (Flags
& DCX_CLIPSIBLINGS
));
78 VisRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
86 * The NtUserGetWindowDC function retrieves the device context (DC) for the
87 * entire window, including title bar, menus, and scroll bars. A window device
88 * context permits painting anywhere in a window, because the origin of the
89 * device context is the upper-left corner of the window instead of the client
97 NtUserGetWindowDC(HWND hWnd
)
99 return (DWORD
)NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
103 UserGetWindowDC(PWINDOW_OBJECT Wnd
)
105 return (DWORD
)UserGetDCEx(Wnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
109 NtUserGetDC(HWND hWnd
)
111 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
115 DceAllocDCE(PWINDOW_OBJECT Window OPTIONAL
, DCE_TYPE Type
)
119 pDce
= ExAllocatePoolWithTag(PagedPool
, sizeof(DCE
), TAG_PDCE
);
123 pDce
->hDC
= DceCreateDisplayDC();
126 ExFreePoolWithTag(pDce
, TAG_PDCE
);
130 if (NULL
== defaultDCstate
) // Ultra HAX! Dedicated to GvG!
131 { // This is a cheesy way to do this.
132 // But, due to the right way of creating gdi handles there is no choice.
133 defaultDCstate
= IntGdiGetDCState(pDce
->hDC
);
134 DC_SetOwnership( defaultDCstate
, NULL
);
137 pDce
->hwndCurrent
= (Window
? Window
->hSelf
: NULL
);
138 pDce
->hClipRgn
= NULL
;
139 pDce
->pProcess
= NULL
;
141 pDce
->next
= FirstDce
;
144 if (Type
== DCE_WINDOW_DC
) //Window DCE have ownership.
146 DC_SetOwnership(pDce
->hDC
, PsGetCurrentProcess());
147 pDce
->pProcess
= PsGetCurrentProcess();
151 DC_SetOwnership(pDce
->hDC
, NULL
); // This hDC is inaccessible!
154 if (Type
!= DCE_CACHE_DC
)
156 pDce
->DCXFlags
= DCX_DCEBUSY
;
160 if (Window
->Style
& WS_CLIPCHILDREN
)
162 pDce
->DCXFlags
|= DCX_CLIPCHILDREN
;
164 if (Window
->Style
& WS_CLIPSIBLINGS
)
166 pDce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
172 pDce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
179 DceSetDrawable(PWINDOW_OBJECT Window OPTIONAL
, HDC hDC
, ULONG Flags
,
182 DC
*dc
= DC_LockDc(hDC
);
193 if (Flags
& DCX_WINDOW
)
195 dc
->w
.DCOrgX
= Window
->WindowRect
.left
;
196 dc
->w
.DCOrgY
= Window
->WindowRect
.top
;
200 dc
->w
.DCOrgX
= Window
->ClientRect
.left
;
201 dc
->w
.DCOrgY
= Window
->ClientRect
.top
;
209 DceDeleteClipRgn(DCE
* Dce
)
211 Dce
->DCXFlags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
);
213 if (Dce
->DCXFlags
& DCX_KEEPCLIPRGN
)
215 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
217 else if (Dce
->hClipRgn
!= NULL
)
219 NtGdiDeleteObject(Dce
->hClipRgn
);
222 Dce
->hClipRgn
= NULL
;
224 /* make it dirty so that the vis rgn gets recomputed next time */
225 Dce
->DCXFlags
|= DCX_DCEDIRTY
;
229 DceReleaseDC(DCE
* dce
, BOOL EndPaint
)
231 if (DCX_DCEBUSY
!= (dce
->DCXFlags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)))
236 /* restore previous visible region */
238 if ((dce
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
239 ((dce
->DCXFlags
& DCX_CACHE
) || EndPaint
))
241 DceDeleteClipRgn(dce
);
244 if (dce
->DCXFlags
& DCX_CACHE
)
246 /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
247 IntGdiSetHookFlags(dce
->hDC
, DCHF_VALIDATEVISRGN
);
249 if( dce
->pProcess
) // Attempt to fix Dc_Attr problem.
250 DC_SetOwnership( defaultDCstate
, dce
->pProcess
);
252 DC_SetOwnership( defaultDCstate
, PsGetCurrentProcess());
254 NtGdiSetDCState(dce
->hDC
, defaultDCstate
);
255 DC_SetOwnership( defaultDCstate
, NULL
); // Return default dc state to inaccessible mode.
257 dce
->DCXFlags
&= ~DCX_DCEBUSY
;
258 if (dce
->DCXFlags
& DCX_DCEDIRTY
)
260 /* don't keep around invalidated entries
261 * because SetDCState() disables hVisRgn updates
262 * by removing dirty bit. */
263 dce
->hwndCurrent
= 0;
264 dce
->DCXFlags
&= DCX_CACHE
;
265 dce
->DCXFlags
|= DCX_DCEEMPTY
;
272 DceUpdateVisRgn(DCE
*Dce
, PWINDOW_OBJECT Window
, ULONG Flags
)
274 HANDLE hRgnVisible
= NULL
;
276 PWINDOW_OBJECT DesktopWindow
;
278 if (Flags
& DCX_PARENTCLIP
)
280 PWINDOW_OBJECT Parent
;
282 Parent
= Window
->Parent
;
289 if (Parent
->Style
& WS_CLIPSIBLINGS
)
291 DcxFlags
= DCX_CLIPSIBLINGS
|
292 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
296 DcxFlags
= Flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
298 hRgnVisible
= DceGetVisRgn(Parent
, DcxFlags
, Window
->hSelf
, Flags
);
300 else if (Window
== NULL
)
302 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
303 if (NULL
!= DesktopWindow
)
305 hRgnVisible
= UnsafeIntCreateRectRgnIndirect(&DesktopWindow
->WindowRect
);
314 hRgnVisible
= DceGetVisRgn(Window
, Flags
, 0, 0);
318 if (Flags
& DCX_INTERSECTRGN
)
320 if(Dce
->hClipRgn
!= NULL
)
322 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hClipRgn
, RGN_AND
);
326 if(hRgnVisible
!= NULL
)
328 NtGdiDeleteObject(hRgnVisible
);
330 hRgnVisible
= NtGdiCreateRectRgn(0, 0, 0, 0);
334 if (Flags
& DCX_EXCLUDERGN
&& Dce
->hClipRgn
!= NULL
)
336 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hClipRgn
, RGN_DIFF
);
339 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
340 IntGdiSelectVisRgn(Dce
->hDC
, hRgnVisible
);
344 IntEngWindowChanged(Window
, WOC_RGN_CLIENT
);
347 if (hRgnVisible
!= NULL
)
349 NtGdiDeleteObject(hRgnVisible
);
354 UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
356 PWINDOW_OBJECT Parent
;
359 BOOL UpdateVisRgn
= TRUE
;
360 BOOL UpdateClipOrigin
= FALSE
;
364 Flags
&= ~DCX_USESTYLE
;
367 if (NULL
== Window
|| NULL
== Window
->Dce
)
372 if (Flags
& DCX_USESTYLE
)
374 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
376 if (Window
->Style
& WS_CLIPSIBLINGS
)
378 Flags
|= DCX_CLIPSIBLINGS
;
381 if (!(Flags
& DCX_WINDOW
))
383 if (Window
->Class
->Style
& CS_PARENTDC
)
385 Flags
|= DCX_PARENTCLIP
;
388 if (Window
->Style
& WS_CLIPCHILDREN
&&
389 !(Window
->Style
& WS_MINIMIZE
))
391 Flags
|= DCX_CLIPCHILDREN
;
400 if (Flags
& DCX_NOCLIPCHILDREN
)
403 Flags
|= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
406 if (Flags
& DCX_WINDOW
)
408 Flags
= (Flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
411 Parent
= (Window
? Window
->Parent
: NULL
);
413 if (NULL
== Window
|| !(Window
->Style
& WS_CHILD
) || NULL
== Parent
)
415 Flags
&= ~DCX_PARENTCLIP
;
417 else if (Flags
& DCX_PARENTCLIP
)
420 if ((Window
->Style
& WS_VISIBLE
) &&
421 (Parent
->Style
& WS_VISIBLE
))
423 Flags
&= ~DCX_CLIPCHILDREN
;
424 if (Parent
->Style
& WS_CLIPSIBLINGS
)
426 Flags
|= DCX_CLIPSIBLINGS
;
431 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
433 if (Flags
& DCX_CACHE
)
435 DCE
* DceEmpty
= NULL
;
436 DCE
* DceUnused
= NULL
;
438 for (Dce
= FirstDce
; Dce
!= NULL
; Dce
= Dce
->next
)
440 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
443 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
447 else if (Dce
->hwndCurrent
== (Window
? Window
->hSelf
: NULL
) &&
448 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
451 UpdateVisRgn
= FALSE
;
454 UpdateClipOrigin
= TRUE
;
463 Dce
= (DceEmpty
== NULL
) ? DceUnused
: DceEmpty
;
468 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
474 if (NULL
!= Dce
&& Dce
->hwndCurrent
== (Window
? Window
->hSelf
: NULL
))
476 UpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
489 Dce
->hwndCurrent
= (Window
? Window
->hSelf
: NULL
);
490 Dce
->DCXFlags
= Flags
| DCX_DCEBUSY
;
492 if (0 == (Flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) && NULL
!= ClipRegion
)
494 if (Flags
& DCX_KEEPCLIPRGN
)
495 NtGdiDeleteObject(ClipRegion
);
500 if (NULL
!= Dce
->hClipRgn
)
502 DceDeleteClipRgn(Dce
);
503 Dce
->hClipRgn
= NULL
;
507 if (0 != (Flags
& DCX_INTERSECTUPDATE
) && NULL
== ClipRegion
)
509 Flags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
510 Dce
->DCXFlags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
511 ClipRegion
= Window
->UpdateRegion
;
514 if (ClipRegion
== (HRGN
) 1)
516 if (!(Flags
& DCX_WINDOW
))
518 Dce
->hClipRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
522 Dce
->hClipRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
525 else if (ClipRegion
!= NULL
)
527 Dce
->hClipRgn
= ClipRegion
;
530 DceSetDrawable(Window
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
534 DceUpdateVisRgn(Dce
, Window
, Flags
);
543 NtUserGetDCEx(HWND hWnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
545 PWINDOW_OBJECT Wnd
=NULL
;
548 DPRINT("Enter NtUserGetDCEx\n");
549 UserEnterExclusive();
551 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
556 RETURN( UserGetDCEx(Wnd
, ClipRegion
, Flags
));
559 DPRINT("Leave NtUserGetDCEx, ret=%i\n",_ret_
);
566 DCE_Cleanup(PDCE pDce
)
570 if (pDce
== FirstDce
)
572 FirstDce
= pDce
->next
;
577 for (PrevInList
= FirstDce
; NULL
!= PrevInList
; PrevInList
= PrevInList
->next
)
579 if (pDce
== PrevInList
->next
)
581 PrevInList
->next
= pDce
->next
;
585 assert(NULL
!= PrevInList
);
588 return NULL
!= PrevInList
;
592 IntWindowFromDC(HDC hDc
)
596 for (Dce
= FirstDce
; Dce
!= NULL
; Dce
= Dce
->next
)
600 return Dce
->hwndCurrent
;
609 UserReleaseDC(PWINDOW_OBJECT Window
, HDC hDc
, BOOL EndPaint
)
616 DPRINT("%p %p\n", Window
, hDc
);
618 while (dce
&& (dce
->hDC
!= hDc
))
623 if (dce
&& (dce
->DCXFlags
& DCX_DCEBUSY
))
625 nRet
= DceReleaseDC(dce
, EndPaint
);
632 // Win 3.1 throw back, hWnd should be ignored and not used.
633 // Replace with NtUserCallOneParam ((DWORD) hDC, ONEPARAM_ROUTINE_RELEASEDC);
635 NtUserReleaseDC(HWND hWnd
, HDC hDc
)
639 DPRINT("Enter NtUserReleaseDC\n");
640 UserEnterExclusive();
642 RETURN(UserReleaseDC(NULL
, hDc
, FALSE
));
645 DPRINT("Leave NtUserReleaseDC, ret=%i\n",_ret_
);
650 /***********************************************************************
654 DceFreeDCE(PDCE pdce
, BOOLEAN Force
)
667 SetDCHook(pdce
->hDC
, NULL
, 0L);
670 if(Force
&& !GDIOBJ_OwnedByCurrentProcess(GdiHandleTable
, pdce
->hDC
))
672 DC_SetOwnership( pdce
->hDC
, PsGetCurrentProcess());
675 NtGdiDeleteObjectApp(pdce
->hDC
);
676 if (pdce
->hClipRgn
&& ! (pdce
->DCXFlags
& DCX_KEEPCLIPRGN
))
678 NtGdiDeleteObject(pdce
->hClipRgn
);
682 ExFreePoolWithTag(pdce
, TAG_PDCE
);
686 /***********************************************************************
689 * Remove owned DCE and reset unreleased cache DCEs.
692 DceFreeWindowDCE(PWINDOW_OBJECT Window
)
699 if (pDCE
->hwndCurrent
== Window
->hSelf
)
701 if (pDCE
== Window
->Dce
) /* owned or Class DCE*/
703 if (Window
->Class
->Style
& CS_OWNDC
) /* owned DCE*/
705 pDCE
= DceFreeDCE(pDCE
, FALSE
);
709 else if (pDCE
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) /* Class DCE*/
711 DceDeleteClipRgn(pDCE
);
712 pDCE
->hwndCurrent
= 0;
717 if (pDCE
->DCXFlags
& DCX_DCEBUSY
) /* shared cache DCE */
719 /* FIXME: AFAICS we are doing the right thing here so
720 * this should be a DPRINT. But this is best left as an ERR
721 * because the 'application error' is likely to come from
722 * another part of Wine (i.e. it's our fault after all).
723 * We should change this to DPRINT when ReactOS is more stable
726 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window
->hSelf
);
727 DceReleaseDC(pDCE
, FALSE
);
730 pDCE
->DCXFlags
&= DCX_CACHE
;
731 pDCE
->DCXFlags
|= DCX_DCEEMPTY
;
732 pDCE
->hwndCurrent
= 0;
742 while (FirstDce
!= NULL
)
744 FirstDce
= DceFreeDCE(FirstDce
, TRUE
);
749 DceResetActiveDCEs(PWINDOW_OBJECT Window
)
753 PWINDOW_OBJECT CurrentWindow
;
765 if (0 == (pDCE
->DCXFlags
& DCX_DCEEMPTY
))
767 if (Window
->hSelf
== pDCE
->hwndCurrent
)
769 CurrentWindow
= Window
;
773 CurrentWindow
= UserGetWindowObject(pDCE
->hwndCurrent
);
774 if (NULL
== CurrentWindow
)
781 dc
= DC_LockDc(pDCE
->hDC
);
784 // if (Window->hSelf != pDCE->hwndCurrent)
786 // UserDerefObject(CurrentWindow);
791 if (Window
== CurrentWindow
|| IntIsChildWindow(Window
, CurrentWindow
))
793 if (pDCE
->DCXFlags
& DCX_WINDOW
)
795 DeltaX
= CurrentWindow
->WindowRect
.left
- dc
->w
.DCOrgX
;
796 DeltaY
= CurrentWindow
->WindowRect
.top
- dc
->w
.DCOrgY
;
797 dc
->w
.DCOrgX
= CurrentWindow
->WindowRect
.left
;
798 dc
->w
.DCOrgY
= CurrentWindow
->WindowRect
.top
;
802 DeltaX
= CurrentWindow
->ClientRect
.left
- dc
->w
.DCOrgX
;
803 DeltaY
= CurrentWindow
->ClientRect
.top
- dc
->w
.DCOrgY
;
804 dc
->w
.DCOrgX
= CurrentWindow
->ClientRect
.left
;
805 dc
->w
.DCOrgY
= CurrentWindow
->ClientRect
.top
;
807 if (NULL
!= dc
->w
.hClipRgn
)
809 int FASTCALL
CLIPPING_UpdateGCRegion(DC
* Dc
);
810 NtGdiOffsetRgn(dc
->w
.hClipRgn
, DeltaX
, DeltaY
);
811 CLIPPING_UpdateGCRegion(dc
);
813 if (NULL
!= pDCE
->hClipRgn
)
815 NtGdiOffsetRgn(pDCE
->hClipRgn
, DeltaX
, DeltaY
);
820 DceUpdateVisRgn(pDCE
, CurrentWindow
, pDCE
->DCXFlags
);
822 if (Window
->hSelf
!= pDCE
->hwndCurrent
)
824 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
825 // UserDerefObject(CurrentWindow);
835 #define COPY_DEVMODE_VALUE_TO_CALLER(dst, src, member) \
836 Status = MmCopyToCaller(&(dst)->member, &(src)->member, sizeof ((src)->member)); \
837 if (!NT_SUCCESS(Status)) \
839 SetLastNtError(Status); \
846 NtUserEnumDisplaySettings(
847 PUNICODE_STRING lpszDeviceName
,
849 LPDEVMODEW lpDevMode
, /* FIXME is this correct? */
853 LPDEVMODEW pSafeDevMode
;
854 PUNICODE_STRING pSafeDeviceName
= NULL
;
855 UNICODE_STRING SafeDeviceName
;
856 USHORT Size
= 0, ExtraSize
= 0;
858 /* Copy the devmode */
859 Status
= MmCopyFromCaller(&Size
, &lpDevMode
->dmSize
, sizeof (Size
));
860 if (!NT_SUCCESS(Status
))
862 SetLastNtError(Status
);
865 Status
= MmCopyFromCaller(&ExtraSize
, &lpDevMode
->dmDriverExtra
, sizeof (ExtraSize
));
866 if (!NT_SUCCESS(Status
))
868 SetLastNtError(Status
);
871 pSafeDevMode
= ExAllocatePool(PagedPool
, Size
+ ExtraSize
);
872 if (pSafeDevMode
== NULL
)
874 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
877 pSafeDevMode
->dmSize
= Size
;
878 pSafeDevMode
->dmDriverExtra
= ExtraSize
;
880 /* Copy the device name */
881 if (lpszDeviceName
!= NULL
)
883 Status
= IntSafeCopyUnicodeString(&SafeDeviceName
, lpszDeviceName
);
884 if (!NT_SUCCESS(Status
))
886 ExFreePool(pSafeDevMode
);
887 SetLastNtError(Status
);
890 pSafeDeviceName
= &SafeDeviceName
;
893 /* Call internal function */
894 if (!IntEnumDisplaySettings(pSafeDeviceName
, iModeNum
, pSafeDevMode
, dwFlags
))
896 if (pSafeDeviceName
!= NULL
)
897 RtlFreeUnicodeString(pSafeDeviceName
);
898 ExFreePool(pSafeDevMode
);
901 if (pSafeDeviceName
!= NULL
)
902 RtlFreeUnicodeString(pSafeDeviceName
);
904 /* Copy some information back */
905 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmPelsWidth
);
906 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmPelsHeight
);
907 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmBitsPerPel
);
908 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmDisplayFrequency
);
909 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmDisplayFlags
);
911 /* output private/extra driver data */
914 Status
= MmCopyToCaller((PCHAR
)lpDevMode
+ Size
, (PCHAR
)pSafeDevMode
+ Size
, ExtraSize
);
915 if (!NT_SUCCESS(Status
))
917 SetLastNtError(Status
);
918 ExFreePool(pSafeDevMode
);
923 ExFreePool(pSafeDevMode
);
927 #undef COPY_DEVMODE_VALUE_TO_CALLER
932 NtUserChangeDisplaySettings(
933 PUNICODE_STRING lpszDeviceName
,
934 LPDEVMODEW lpDevMode
,
941 PUNICODE_STRING pSafeDeviceName
= NULL
;
942 UNICODE_STRING SafeDeviceName
;
945 /* Check arguments */
946 #ifdef CDS_VIDEOPARAMETERS
948 if (dwflags
!= CDS_VIDEOPARAMETERS
&& lParam
!= NULL
)
955 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
956 return DISP_CHANGE_BADPARAM
;
960 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
961 return DISP_CHANGE_BADPARAM
;
965 Status
= MmCopyFromCaller(&DevMode
.dmSize
, &lpDevMode
->dmSize
, sizeof (DevMode
.dmSize
));
966 if (!NT_SUCCESS(Status
))
968 SetLastNtError(Status
);
969 return DISP_CHANGE_BADPARAM
;
971 DevMode
.dmSize
= min(sizeof (DevMode
), DevMode
.dmSize
);
972 Status
= MmCopyFromCaller(&DevMode
, lpDevMode
, DevMode
.dmSize
);
973 if (!NT_SUCCESS(Status
))
975 SetLastNtError(Status
);
976 return DISP_CHANGE_BADPARAM
;
978 if (DevMode
.dmDriverExtra
> 0)
980 DbgPrint("(%s:%i) WIN32K: %s lpDevMode->dmDriverExtra is IGNORED!\n", __FILE__
, __LINE__
, __FUNCTION__
);
981 DevMode
.dmDriverExtra
= 0;
984 /* Copy the device name */
985 if (lpszDeviceName
!= NULL
)
987 Status
= IntSafeCopyUnicodeString(&SafeDeviceName
, lpszDeviceName
);
988 if (!NT_SUCCESS(Status
))
990 SetLastNtError(Status
);
991 return DISP_CHANGE_BADPARAM
;
993 pSafeDeviceName
= &SafeDeviceName
;
996 /* Call internal function */
997 Ret
= IntChangeDisplaySettings(pSafeDeviceName
, &DevMode
, dwflags
, lParam
);
999 if (pSafeDeviceName
!= NULL
)
1000 RtlFreeUnicodeString(pSafeDeviceName
);