Manipulate system/visible clipping region in Windows 1809
Solution 1:
This seems to be a bug in the relevant versions of Windows which has apparently been fixed in more recent versions.
Solution 2:
If we take ReactOS as an example, the clipping region is at dc->dclevel.prgnClip
and the system region is at dc->prgnVis
. When you call BeginPaint
on a window, it calls NtUserBeginPaint
stub which traps to its kernel counterpart through the win32k SSDT, which calls IntBeginPaint
, which passes the window's update region (Window->hrgnUpdate
) to UserGetDCEx
, which copies this to Dce->hrgnClip
and calls DceUpdateVisRgn
, which then gets the visible region by calling DceGetVisRgn
which calculates the visible region using VIS_ComputeVisibleRegion
, which develops a complex region by traversing all child windows, all parent windows and all siblings at each level (a top level window has a parent as the desktop (((PCLIENTINFO)(NtCurrentTeb()->Win32ClientInfo))->pDeskInfo->spwnd
) and all top level windows are siblings; the desktop's parent is NULL
and removing the parts they cover up – this does not appear to perform any special handling for the desktop window when it gets to it like clipping to the client area, and is treated like any other window in the z order, where only what it is covering is removed). DceGetVisRgn
then combines this returned visible region and combines it wil the clipping region Dce->hrgnClip
and combines them into RgnVisible
using IntGdiCombineRgn(RgnVisible, RgnVisible, RgnClip, RGN_AND)
, which is then copied into dc->prgnVis
using GdiSelectVisRgn(Dce->hDC, RgnVisible)
. DC
is the device context and DCE
is the device context entry for the DC in the DC cache. Therefore, the system region of the DC is now the intersection of the visible region and the update region of the window. IntBeginPaint
also calls GdiGetClipBox(Ps->hdc, &Ps->rcPaint)
, which calls REGION_GetRgnBox(pdc->prgnVis, prc)
to copy the bound of the region pdc->prgnVis
(pdc->prgnVis->rdh.rcBound
) to Ps->rcPaint
and then GdiGetClipBox
calls IntDPtoLP(pdc, (LPPOINT)prc, 2)
to convert the bound from physical coordinates to logical coordinates, which DPI-unaware apps use. The paintstruct now contains the smallest logical rectangle that contains the complex intersection of the update region and the visible region.
GetClipRgn
calls NtGdiGetRandomRgn
, which returns pdc->dclevel.prgnClip
when called with CLIPRGN
, which is application defined using SetClipRgn
An application-defined clipping region is a clipping region identified by the SelectClipRgn function. It is not a clipping region created when the application calls the BeginPaint function.
There are 2 clipping regions. One is an application defined one created by the application using SelectClipRgn
and the pointer is stored in pdc->dclevel.prgnClip
, and the other clipping region is system region, after it has been updated to the intersection of the system region and the update region by a BeginPaint
call, where it is presented to the application as a logical clipping rectangle in the PAINTSTRUCT
.
GetClipBox
calls NtGdiGetAppClipBox
, which calls GdiGetClipBox
, which of course returns the smallest logical rect boundary of the current system region, which may be the visible region if GetDC
was used, or it may be the system region intersected with a custom clipping region with GetDCEx
, or it may be the system region intersected with the window update region when using BeginPaint
. Your issue would imply that the system region, when calculated, is now performing special handling for the desktop window in VIS_ComputeVisibleRegion
To actually access the DC directly, and hence the System region, you'd have to start and interact with a driver to do it from the application.