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 #define DCX_USESTYLE 0x10000
39 /* GLOBALS *******************************************************************/
41 /* NOTE - I think we should store this per window station (including gdi objects) */
43 static PDCE FirstDce
= NULL
;
44 static HDC defaultDCstate
;
46 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
47 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
49 /* FUNCTIONS *****************************************************************/
59 DceGetVisRgn(PWINDOW_OBJECT Window
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
63 VisRgn
= VIS_ComputeVisibleRegion(Window
,
64 0 == (Flags
& DCX_WINDOW
),
65 0 != (Flags
& DCX_CLIPCHILDREN
),
66 0 != (Flags
& DCX_CLIPSIBLINGS
));
74 * The NtUserGetWindowDC function retrieves the device context (DC) for the
75 * entire window, including title bar, menus, and scroll bars. A window device
76 * context permits painting anywhere in a window, because the origin of the
77 * device context is the upper-left corner of the window instead of the client
85 NtUserGetWindowDC(HWND hWnd
)
87 return (DWORD
)NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
91 UserGetWindowDC(PWINDOW_OBJECT Wnd
)
93 return (DWORD
)UserGetDCEx(Wnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
97 NtUserGetDC(HWND hWnd
)
99 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
103 DceAllocDCE(PWINDOW_OBJECT Window OPTIONAL
, DCE_TYPE Type
)
107 UNICODE_STRING DriverName
;
109 DceHandle
= DCEOBJ_AllocDCE();
113 RtlInitUnicodeString(&DriverName
, L
"DISPLAY");
115 Dce
= DCEOBJ_LockDCE(DceHandle
);
116 /* No real locking, just get the pointer */
117 DCEOBJ_UnlockDCE(Dce
);
118 Dce
->Self
= DceHandle
;
119 Dce
->hDC
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
120 if (NULL
== defaultDCstate
)
122 defaultDCstate
= NtGdiGetDCState(Dce
->hDC
);
123 GDIOBJ_SetOwnership(defaultDCstate
, NULL
);
125 GDIOBJ_SetOwnership(Dce
->Self
, NULL
);
126 DC_SetOwnership(Dce
->hDC
, NULL
);
127 Dce
->hwndCurrent
= (Window
? Window
->hSelf
: NULL
);
128 Dce
->hClipRgn
= NULL
;
130 Dce
->next
= FirstDce
;
133 if (Type
!= DCE_CACHE_DC
)
135 Dce
->DCXFlags
= DCX_DCEBUSY
;
139 if (Window
->Style
& WS_CLIPCHILDREN
)
141 Dce
->DCXFlags
|= DCX_CLIPCHILDREN
;
143 if (Window
->Style
& WS_CLIPSIBLINGS
)
145 Dce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
151 Dce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
158 DceSetDrawable(PWINDOW_OBJECT Window OPTIONAL
, HDC hDC
, ULONG Flags
,
161 DC
*dc
= DC_LockDc(hDC
);
172 if (Flags
& DCX_WINDOW
)
174 dc
->w
.DCOrgX
= Window
->WindowRect
.left
;
175 dc
->w
.DCOrgY
= Window
->WindowRect
.top
;
179 dc
->w
.DCOrgX
= Window
->ClientRect
.left
;
180 dc
->w
.DCOrgY
= Window
->ClientRect
.top
;
188 DceDeleteClipRgn(DCE
* Dce
)
190 Dce
->DCXFlags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
| DCX_WINDOWPAINT
);
192 if (Dce
->DCXFlags
& DCX_KEEPCLIPRGN
)
194 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
196 else if (Dce
->hClipRgn
!= NULL
)
198 GDIOBJ_SetOwnership(Dce
->hClipRgn
, PsGetCurrentProcess());
199 NtGdiDeleteObject(Dce
->hClipRgn
);
202 Dce
->hClipRgn
= NULL
;
204 /* make it dirty so that the vis rgn gets recomputed next time */
205 Dce
->DCXFlags
|= DCX_DCEDIRTY
;
209 DceReleaseDC(DCE
* dce
)
211 if (DCX_DCEBUSY
!= (dce
->DCXFlags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)))
216 /* restore previous visible region */
218 if ((dce
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
219 (dce
->DCXFlags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
221 DceDeleteClipRgn(dce
);
224 if (dce
->DCXFlags
& DCX_CACHE
)
226 /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
227 NtGdiSetHookFlags(dce
->hDC
, DCHF_VALIDATEVISRGN
);
228 NtGdiSetDCState(dce
->hDC
, defaultDCstate
);
229 dce
->DCXFlags
&= ~DCX_DCEBUSY
;
230 if (dce
->DCXFlags
& DCX_DCEDIRTY
)
232 /* don't keep around invalidated entries
233 * because SetDCState() disables hVisRgn updates
234 * by removing dirty bit. */
235 dce
->hwndCurrent
= 0;
236 dce
->DCXFlags
&= DCX_CACHE
;
237 dce
->DCXFlags
|= DCX_DCEEMPTY
;
245 DceUpdateVisRgn(DCE
*Dce
, PWINDOW_OBJECT Window
, ULONG Flags
)
247 HANDLE hRgnVisible
= NULL
;
249 PWINDOW_OBJECT DesktopWindow
;
251 if (Flags
& DCX_PARENTCLIP
)
253 PWINDOW_OBJECT Parent
;
255 Parent
= Window
->Parent
;
262 if (Parent
->Style
& WS_CLIPSIBLINGS
)
264 DcxFlags
= DCX_CLIPSIBLINGS
|
265 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
269 DcxFlags
= Flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
271 hRgnVisible
= DceGetVisRgn(Parent
, DcxFlags
, Window
->hSelf
, Flags
);
272 if (hRgnVisible
== NULL
)
274 hRgnVisible
= NtGdiCreateRectRgn(0, 0, 0, 0);
278 if (0 == (Flags
& DCX_WINDOW
))
282 Parent
->ClientRect
.left
- Window
->ClientRect
.left
,
283 Parent
->ClientRect
.top
- Window
->ClientRect
.top
);
289 Parent
->WindowRect
.left
- Window
->WindowRect
.left
,
290 Parent
->WindowRect
.top
- Window
->WindowRect
.top
);
294 else if (Window
== NULL
)
296 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
297 if (NULL
!= DesktopWindow
)
299 hRgnVisible
= UnsafeIntCreateRectRgnIndirect(&DesktopWindow
->WindowRect
);
300 IntReleaseWindowObject(DesktopWindow
);
309 hRgnVisible
= DceGetVisRgn(Window
, Flags
, 0, 0);
313 if (Flags
& DCX_INTERSECTRGN
)
315 if(Dce
->hClipRgn
!= NULL
)
317 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hClipRgn
, RGN_AND
);
321 if(hRgnVisible
!= NULL
)
323 NtGdiDeleteObject(hRgnVisible
);
325 hRgnVisible
= NtGdiCreateRectRgn(0, 0, 0, 0);
329 if (Flags
& DCX_EXCLUDERGN
&& Dce
->hClipRgn
!= NULL
)
331 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hClipRgn
, RGN_DIFF
);
334 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
335 NtGdiSelectVisRgn(Dce
->hDC
, hRgnVisible
);
339 IntEngWindowChanged(Window
, WOC_RGN_CLIENT
);
342 if (hRgnVisible
!= NULL
)
344 NtGdiDeleteObject(hRgnVisible
);
349 UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
351 PWINDOW_OBJECT Parent
;
354 BOOL UpdateVisRgn
= TRUE
;
355 BOOL UpdateClipOrigin
= FALSE
;
359 Flags
&= ~DCX_USESTYLE
;
362 if (NULL
== Window
|| NULL
== Window
->Dce
)
368 if (Flags
& DCX_USESTYLE
)
370 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
372 if (Window
->Style
& WS_CLIPSIBLINGS
)
374 Flags
|= DCX_CLIPSIBLINGS
;
377 if (!(Flags
& DCX_WINDOW
))
379 if (Window
->Class
->style
& CS_PARENTDC
)
381 Flags
|= DCX_PARENTCLIP
;
384 if (Window
->Style
& WS_CLIPCHILDREN
&&
385 !(Window
->Style
& WS_MINIMIZE
))
387 Flags
|= DCX_CLIPCHILDREN
;
396 if (Flags
& DCX_NOCLIPCHILDREN
)
399 Flags
|= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
402 if (Flags
& DCX_WINDOW
)
404 Flags
= (Flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
407 Parent
= (Window
? Window
->Parent
: NULL
);
409 if (NULL
== Window
|| !(Window
->Style
& WS_CHILD
) || NULL
== Parent
)
411 Flags
&= ~DCX_PARENTCLIP
;
413 else if (Flags
& DCX_PARENTCLIP
)
416 if ((Window
->Style
& WS_VISIBLE
) &&
417 (Parent
->Style
& WS_VISIBLE
))
419 Flags
&= ~DCX_CLIPCHILDREN
;
420 if (Parent
->Style
& WS_CLIPSIBLINGS
)
422 Flags
|= DCX_CLIPSIBLINGS
;
427 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
429 if (Flags
& DCX_CACHE
)
431 DCE
* DceEmpty
= NULL
;
432 DCE
* DceUnused
= NULL
;
434 for (Dce
= FirstDce
; Dce
!= NULL
; Dce
= Dce
->next
)
436 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
439 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
443 else if (Dce
->hwndCurrent
== (Window
? Window
->hSelf
: NULL
) &&
444 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
447 UpdateVisRgn
= FALSE
;
450 UpdateClipOrigin
= TRUE
;
459 Dce
= (DceEmpty
== NULL
) ? DceUnused
: DceEmpty
;
464 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
470 if (NULL
!= Dce
&& Dce
->hwndCurrent
== (Window
? Window
->hSelf
: NULL
))
472 UpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
485 Dce
->hwndCurrent
= (Window
? Window
->hSelf
: NULL
);
486 Dce
->DCXFlags
= DcxFlags
| (Flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
488 if (0 == (Flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) && NULL
!= ClipRegion
)
490 NtGdiDeleteObject(ClipRegion
);
494 if (NULL
!= Dce
->hClipRgn
)
496 DceDeleteClipRgn(Dce
);
497 Dce
->hClipRgn
= NULL
;
500 if (0 != (Flags
& DCX_INTERSECTUPDATE
) && NULL
== ClipRegion
)
502 Dce
->hClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
503 if (Dce
->hClipRgn
&& Window
->UpdateRegion
)
505 GDIOBJ_SetOwnership(Dce
->hClipRgn
, NULL
);
506 NtGdiCombineRgn(Dce
->hClipRgn
, Window
->UpdateRegion
, NULL
, RGN_COPY
);
507 if(Window
->WindowRegion
&& !(Window
->Style
& WS_MINIMIZE
))
508 NtGdiCombineRgn(Dce
->hClipRgn
, Dce
->hClipRgn
, Window
->WindowRegion
, RGN_AND
);
509 if (!(Flags
& DCX_WINDOW
))
511 NtGdiOffsetRgn(Dce
->hClipRgn
,
512 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
513 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
516 Flags
|= DCX_INTERSECTRGN
;
519 if (ClipRegion
== (HRGN
) 1)
521 if (!(Flags
& DCX_WINDOW
))
523 Dce
->hClipRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
524 GDIOBJ_SetOwnership(Dce
->hClipRgn
, NULL
);
525 if(!Window
->WindowRegion
|| (Window
->Style
& WS_MINIMIZE
))
527 NtGdiOffsetRgn(Dce
->hClipRgn
, -Window
->ClientRect
.left
, -Window
->ClientRect
.top
);
531 NtGdiOffsetRgn(Dce
->hClipRgn
, -Window
->WindowRect
.left
, -Window
->WindowRect
.top
);
532 NtGdiCombineRgn(Dce
->hClipRgn
, Dce
->hClipRgn
, Window
->WindowRegion
, RGN_AND
);
533 NtGdiOffsetRgn(Dce
->hClipRgn
, -(Window
->ClientRect
.left
- Window
->WindowRect
.left
),
534 -(Window
->ClientRect
.top
- Window
->WindowRect
.top
));
539 Dce
->hClipRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
540 GDIOBJ_SetOwnership(Dce
->hClipRgn
, NULL
);
541 NtGdiOffsetRgn(Dce
->hClipRgn
, -Window
->WindowRect
.left
,
542 -Window
->WindowRect
.top
);
543 if(Window
->WindowRegion
&& !(Window
->Style
& WS_MINIMIZE
))
544 NtGdiCombineRgn(Dce
->hClipRgn
, Dce
->hClipRgn
, Window
->WindowRegion
, RGN_AND
);
547 else if (NULL
!= ClipRegion
)
549 Dce
->hClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
552 GDIOBJ_SetOwnership(Dce
->hClipRgn
, NULL
);
553 if(!Window
->WindowRegion
|| (Window
->Style
& WS_MINIMIZE
))
554 NtGdiCombineRgn(Dce
->hClipRgn
, ClipRegion
, NULL
, RGN_COPY
);
556 NtGdiCombineRgn(Dce
->hClipRgn
, ClipRegion
, Window
->WindowRegion
, RGN_AND
);
558 NtGdiDeleteObject(ClipRegion
);
561 DceSetDrawable(Window
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
565 DceUpdateVisRgn(Dce
, Window
, Flags
);
574 NtUserGetDCEx(HWND hWnd
, HANDLE ClipRegion
, ULONG Flags
)
576 PWINDOW_OBJECT Wnd
=NULL
;
580 DPRINT("Enter NtUserGetDCEx\n");
581 UserEnterExclusive();
585 if (!(Wnd
= IntGetWindowObject(hWnd
)))
587 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
592 ret
= UserGetDCEx(Wnd
, ClipRegion
, Flags
);
595 IntReleaseWindowObject(Wnd
);
600 DPRINT("Leave NtUserGetDCEx, ret=%i\n",_ret_
);
608 DCE_Cleanup(PVOID ObjectBody
)
611 PDCE pDce
= (PDCE
)ObjectBody
;
613 if (pDce
== FirstDce
)
615 FirstDce
= pDce
->next
;
620 for (PrevInList
= FirstDce
; NULL
!= PrevInList
; PrevInList
= PrevInList
->next
)
622 if (pDce
== PrevInList
->next
)
624 PrevInList
->next
= pDce
->next
;
628 assert(NULL
!= PrevInList
);
631 return NULL
!= PrevInList
;
635 IntWindowFromDC(HDC hDc
)
639 for (Dce
= FirstDce
; Dce
!= NULL
; Dce
= Dce
->next
)
643 return Dce
->hwndCurrent
;
652 UserReleaseDC(PWINDOW_OBJECT Window
, HDC hDc
)
659 DPRINT("%p %p\n", Window
, hDc
);
661 while (dce
&& (dce
->hDC
!= hDc
))
666 if (dce
&& (dce
->DCXFlags
& DCX_DCEBUSY
))
668 nRet
= DceReleaseDC(dce
);
677 NtUserReleaseDC(HWND hWnd
, HDC hDc
)
681 DPRINT("Enter NtUserReleaseDC\n");
682 UserEnterExclusive();
684 RETURN(UserReleaseDC(NULL
, hDc
));
687 DPRINT("Leave NtUserReleaseDC, ret=%i\n",_ret_
);
692 /***********************************************************************
696 DceFreeDCE(PDCE dce
, BOOLEAN Force
)
709 SetDCHook(dce
->hDC
, NULL
, 0L);
712 if(Force
&& !GDIOBJ_OwnedByCurrentProcess(dce
->hDC
))
714 GDIOBJ_SetOwnership(dce
->Self
, PsGetCurrentProcess());
715 DC_SetOwnership(dce
->hDC
, PsGetCurrentProcess());
718 NtGdiDeleteDC(dce
->hDC
);
719 if (dce
->hClipRgn
&& ! (dce
->DCXFlags
& DCX_KEEPCLIPRGN
))
721 GDIOBJ_SetOwnership(dce
->hClipRgn
, PsGetCurrentProcess());
722 NtGdiDeleteObject(dce
->hClipRgn
);
725 DCEOBJ_FreeDCE(dce
->Self
);
731 /***********************************************************************
734 * Remove owned DCE and reset unreleased cache DCEs.
737 DceFreeWindowDCE(PWINDOW_OBJECT Window
)
744 if (pDCE
->hwndCurrent
== Window
->hSelf
)
746 if (pDCE
== Window
->Dce
) /* owned or Class DCE*/
748 if (Window
->Class
->style
& CS_OWNDC
) /* owned DCE*/
750 pDCE
= DceFreeDCE(pDCE
, FALSE
);
754 else if (pDCE
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) /* Class DCE*/
756 DceDeleteClipRgn(pDCE
);
757 pDCE
->hwndCurrent
= 0;
762 if (pDCE
->DCXFlags
& DCX_DCEBUSY
) /* shared cache DCE */
764 /* FIXME: AFAICS we are doing the right thing here so
765 * this should be a DPRINT. But this is best left as an ERR
766 * because the 'application error' is likely to come from
767 * another part of Wine (i.e. it's our fault after all).
768 * We should change this to DPRINT when ReactOS is more stable
771 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window
->hSelf
);
775 pDCE
->DCXFlags
&= DCX_CACHE
;
776 pDCE
->DCXFlags
|= DCX_DCEEMPTY
;
777 pDCE
->hwndCurrent
= 0;
787 while (FirstDce
!= NULL
)
789 DceFreeDCE(FirstDce
, TRUE
);
794 DceResetActiveDCEs(PWINDOW_OBJECT Window
)
798 PWINDOW_OBJECT CurrentWindow
;
810 if (0 == (pDCE
->DCXFlags
& DCX_DCEEMPTY
))
812 if (Window
->hSelf
== pDCE
->hwndCurrent
)
814 CurrentWindow
= Window
;
818 CurrentWindow
= IntGetWindowObject(pDCE
->hwndCurrent
);
819 if (NULL
== CurrentWindow
)
826 dc
= DC_LockDc(pDCE
->hDC
);
829 if (Window
->hSelf
!= pDCE
->hwndCurrent
)
831 IntReleaseWindowObject(CurrentWindow
);
836 if (Window
== CurrentWindow
|| IntIsChildWindow(Window
->hSelf
, CurrentWindow
->hSelf
))
838 if (pDCE
->DCXFlags
& DCX_WINDOW
)
840 DeltaX
= CurrentWindow
->WindowRect
.left
- dc
->w
.DCOrgX
;
841 DeltaY
= CurrentWindow
->WindowRect
.top
- dc
->w
.DCOrgY
;
842 dc
->w
.DCOrgX
= CurrentWindow
->WindowRect
.left
;
843 dc
->w
.DCOrgY
= CurrentWindow
->WindowRect
.top
;
847 DeltaX
= CurrentWindow
->ClientRect
.left
- dc
->w
.DCOrgX
;
848 DeltaY
= CurrentWindow
->ClientRect
.top
- dc
->w
.DCOrgY
;
849 dc
->w
.DCOrgX
= CurrentWindow
->ClientRect
.left
;
850 dc
->w
.DCOrgY
= CurrentWindow
->ClientRect
.top
;
852 if (NULL
!= dc
->w
.hClipRgn
)
854 NtGdiOffsetRgn(dc
->w
.hClipRgn
, DeltaX
, DeltaY
);
856 if (NULL
!= pDCE
->hClipRgn
)
858 NtGdiOffsetRgn(pDCE
->hClipRgn
, DeltaX
, DeltaY
);
863 DceUpdateVisRgn(pDCE
, CurrentWindow
, pDCE
->DCXFlags
);
865 if (Window
->hSelf
!= pDCE
->hwndCurrent
)
867 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
868 IntReleaseWindowObject(CurrentWindow
);
878 #define COPY_DEVMODE_VALUE_TO_CALLER(dst, src, member) \
879 Status = MmCopyToCaller(&(dst)->member, &(src)->member, sizeof ((src)->member)); \
880 if (!NT_SUCCESS(Status)) \
882 SetLastNtError(Status); \
889 NtUserEnumDisplaySettings(
890 PUNICODE_STRING lpszDeviceName
,
892 LPDEVMODEW lpDevMode
, /* FIXME is this correct? */
896 LPDEVMODEW pSafeDevMode
;
897 PUNICODE_STRING pSafeDeviceName
= NULL
;
898 UNICODE_STRING SafeDeviceName
;
899 USHORT Size
= 0, ExtraSize
= 0;
901 /* Copy the devmode */
902 Status
= MmCopyFromCaller(&Size
, &lpDevMode
->dmSize
, sizeof (Size
));
903 if (!NT_SUCCESS(Status
))
905 SetLastNtError(Status
);
908 Status
= MmCopyFromCaller(&ExtraSize
, &lpDevMode
->dmDriverExtra
, sizeof (ExtraSize
));
909 if (!NT_SUCCESS(Status
))
911 SetLastNtError(Status
);
914 pSafeDevMode
= ExAllocatePool(PagedPool
, Size
+ ExtraSize
);
915 if (pSafeDevMode
== NULL
)
917 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
920 pSafeDevMode
->dmSize
= Size
;
921 pSafeDevMode
->dmDriverExtra
= ExtraSize
;
923 /* Copy the device name */
924 if (lpszDeviceName
!= NULL
)
926 Status
= IntSafeCopyUnicodeString(&SafeDeviceName
, lpszDeviceName
);
927 if (!NT_SUCCESS(Status
))
929 ExFreePool(pSafeDevMode
);
930 SetLastNtError(Status
);
933 pSafeDeviceName
= &SafeDeviceName
;
936 /* Call internal function */
937 if (!IntEnumDisplaySettings(pSafeDeviceName
, iModeNum
, pSafeDevMode
, dwFlags
))
939 if (pSafeDeviceName
!= NULL
)
940 RtlFreeUnicodeString(pSafeDeviceName
);
941 ExFreePool(pSafeDevMode
);
944 if (pSafeDeviceName
!= NULL
)
945 RtlFreeUnicodeString(pSafeDeviceName
);
947 /* Copy some information back */
948 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmPelsWidth
);
949 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmPelsHeight
);
950 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmBitsPerPel
);
951 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmDisplayFrequency
);
952 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode
, pSafeDevMode
, dmDisplayFlags
);
954 /* output private/extra driver data */
957 Status
= MmCopyToCaller((PCHAR
)lpDevMode
+ Size
, (PCHAR
)pSafeDevMode
+ Size
, ExtraSize
);
958 if (!NT_SUCCESS(Status
))
960 SetLastNtError(Status
);
961 ExFreePool(pSafeDevMode
);
966 ExFreePool(pSafeDevMode
);
970 #undef COPY_DEVMODE_VALUE_TO_CALLER
975 NtUserChangeDisplaySettings(
976 PUNICODE_STRING lpszDeviceName
,
977 LPDEVMODEW lpDevMode
,
984 PUNICODE_STRING pSafeDeviceName
= NULL
;
985 UNICODE_STRING SafeDeviceName
;
988 /* Check arguments */
989 #ifdef CDS_VIDEOPARAMETERS
991 if (dwflags
!= CDS_VIDEOPARAMETERS
&& lParam
!= NULL
)
998 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
999 return DISP_CHANGE_BADPARAM
;
1003 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1004 return DISP_CHANGE_BADPARAM
;
1008 Status
= MmCopyFromCaller(&DevMode
.dmSize
, &lpDevMode
->dmSize
, sizeof (DevMode
.dmSize
));
1009 if (!NT_SUCCESS(Status
))
1011 SetLastNtError(Status
);
1012 return DISP_CHANGE_BADPARAM
;
1014 DevMode
.dmSize
= min(sizeof (DevMode
), DevMode
.dmSize
);
1015 Status
= MmCopyFromCaller(&DevMode
, lpDevMode
, DevMode
.dmSize
);
1016 if (!NT_SUCCESS(Status
))
1018 SetLastNtError(Status
);
1019 return DISP_CHANGE_BADPARAM
;
1021 if (DevMode
.dmDriverExtra
> 0)
1023 DbgPrint("(%s:%i) WIN32K: %s lpDevMode->dmDriverExtra is IGNORED!\n", __FILE__
, __LINE__
, __FUNCTION__
);
1024 DevMode
.dmDriverExtra
= 0;
1027 /* Copy the device name */
1028 if (lpszDeviceName
!= NULL
)
1030 Status
= IntSafeCopyUnicodeString(&SafeDeviceName
, lpszDeviceName
);
1031 if (!NT_SUCCESS(Status
))
1033 SetLastNtError(Status
);
1034 return DISP_CHANGE_BADPARAM
;
1036 pSafeDeviceName
= &SafeDeviceName
;
1039 /* Call internal function */
1040 Ret
= IntChangeDisplaySettings(pSafeDeviceName
, &DevMode
, dwflags
, lParam
);
1042 if (pSafeDeviceName
!= NULL
)
1043 RtlFreeUnicodeString(pSafeDeviceName
);