/// <summary> /// Creates a new clipping region from the intersection of the current clipping region and /// the specified rectangle. /// </summary> public void IntersectClip(WindowsRegion wr) { //if the incoming windowsregion is infinite, there is no need to do any intersecting. if (wr.HRegion == IntPtr.Zero) { return; } WindowsRegion clip = new WindowsRegion(0, 0, 0, 0); try { int result = Gdi32.GetClipRgn(new HandleRef(this, Hdc), new HandleRef(clip, clip.HRegion)); // If the function succeeds and there is a clipping region for the given device context, the return value is 1. if (result == 1) { Debug.Assert(clip.HRegion != IntPtr.Zero); wr.CombineRegion(clip, wr, Gdi32.CombineMode.RGN_AND); } SetClip(wr); } finally { clip.Dispose(); } }
/// <summary> /// Draw a themed background element. /// </summary> /// <param name="g">Graphics object reference.</param> /// <param name="draw">Rectangle for drawing.</param> /// <param name="exclude">Rectangle to exclude from drawing.</param> /// <param name="part">Theme part.</param> /// <param name="state">Theme state of part.</param> public void DrawThemeBackground(Graphics g, Rectangle draw, Rectangle exclude, int part, int state) { if (IsControlThemed) { // Create a Win32 version of the drawing Rectangle Win32.RECT drawWin32 = new Win32.RECT(); drawWin32.left = draw.X; drawWin32.top = draw.Y; drawWin32.right = draw.Right; drawWin32.bottom = draw.Bottom; // Create a Win32 version of the clipping Rectangle Win32.RECT excludeWin32 = new Win32.RECT(); excludeWin32.left = exclude.X; excludeWin32.top = exclude.Y; excludeWin32.right = exclude.Right; excludeWin32.bottom = exclude.Bottom; // Get access to the underlying HDC IntPtr hDC = g.GetHdc(); // Make a note of the original clipping region IntPtr hOldClipRgn = IntPtr.Zero; Gdi32.GetClipRgn(hDC, ref hOldClipRgn); // Create region that excludes area from drawing rectangle IntPtr hDrawRgn = Gdi32.CreateRectRgnIndirect(ref drawWin32); IntPtr hExcludeRgn = Gdi32.CreateRectRgnIndirect(ref excludeWin32); Gdi32.CombineRgn(hExcludeRgn, hDrawRgn, hExcludeRgn, (int)CombineFlags.RGN_DIFF); // Define required clipping rectangle Gdi32.SelectClipRgn(hDC, hExcludeRgn); // Perform actual drawing work Uxtheme.DrawThemeBackground(_hTheme, hDC, part, state, ref drawWin32, IntPtr.Zero); // Put clipping region back again Gdi32.SelectClipRgn(hDC, hOldClipRgn); // Delete objects no longer needed Gdi32.DeleteObject(hDrawRgn); Gdi32.DeleteObject(hExcludeRgn); // Must release the resource to prevent leaks! g.ReleaseHdc(hDC); } }
public unsafe DCMapping(IntPtr hDC, Rectangle bounds) { if (hDC == IntPtr.Zero) { throw new ArgumentNullException(nameof(hDC)); } bool success; IntPtr hOriginalClippingRegion = IntPtr.Zero; _translatedBounds = bounds; _graphics = null; _dc = DeviceContext.FromHdc(hDC); _dc.SaveHdc(); // Retrieve the x-coordinates and y-coordinates of the viewport origin for the specified device context. success = Gdi32.GetViewportOrgEx(hDC, out Point viewportOrg).IsTrue(); Debug.Assert(success, "GetViewportOrgEx() failed."); // Create a new rectangular clipping region based off of the bounds specified, shifted over by the x & y specified in the viewport origin. IntPtr hClippingRegion = Gdi32.CreateRectRgn(viewportOrg.X + bounds.Left, viewportOrg.Y + bounds.Top, viewportOrg.X + bounds.Right, viewportOrg.Y + bounds.Bottom); Debug.Assert(hClippingRegion != IntPtr.Zero, "CreateRectRgn() failed."); try { // Create an empty region oriented at 0,0 so we can populate it with the original clipping region of the hDC passed in. hOriginalClippingRegion = Gdi32.CreateRectRgn(0, 0, 0, 0); Debug.Assert(hOriginalClippingRegion != IntPtr.Zero, "CreateRectRgn() failed."); // Get the clipping region from the hDC: result = {-1 = error, 0 = no region, 1 = success} per MSDN int result = Gdi32.GetClipRgn(hDC, hOriginalClippingRegion); Debug.Assert(result != -1, "GetClipRgn() failed."); // Shift the viewpoint origint by coordinates specified in "bounds". var lastViewPort = new Point(); success = Gdi32.SetViewportOrgEx(hDC, viewportOrg.X + bounds.Left, viewportOrg.Y + bounds.Top, &lastViewPort).IsTrue(); Debug.Assert(success, "SetViewportOrgEx() failed."); RegionType originalRegionType; if (result != 0) { // Get the origninal clipping region so we can determine its type (we'll check later if we've restored the region back properly.) RECT originalClipRect = new RECT(); originalRegionType = Gdi32.GetRgnBox(hOriginalClippingRegion, ref originalClipRect); Debug.Assert(originalRegionType != RegionType.ERROR, "ERROR returned from SelectClipRgn while selecting the original clipping region.."); if (originalRegionType == RegionType.SIMPLEREGION) { // Find the intersection of our clipping region and the current clipping region (our parent's) // Returns a NULLREGION, the two didn't intersect. // Returns a SIMPLEREGION, the two intersected // Resulting region (stuff that was in hOriginalClippingRegion AND hClippingRegion is placed in hClippingRegion RegionType combineResult = Gdi32.CombineRgn(hClippingRegion, hClippingRegion, hOriginalClippingRegion, Gdi32.CombineMode.RGN_AND); Debug.Assert((combineResult == RegionType.SIMPLEREGION) || (combineResult == RegionType.NULLREGION), "SIMPLEREGION or NULLREGION expected."); } } else { // If there was no clipping region, then the result is a simple region. // We don't need to keep track of the original now, since it is empty. Gdi32.DeleteObject(hOriginalClippingRegion); hOriginalClippingRegion = IntPtr.Zero; originalRegionType = RegionType.SIMPLEREGION; } // Select the new clipping region; make sure it's a SIMPLEREGION or NULLREGION RegionType selectResult = Gdi32.SelectClipRgn(hDC, hClippingRegion); Debug.Assert((selectResult == RegionType.SIMPLEREGION || selectResult == RegionType.NULLREGION), "SIMPLEREGION or NULLLREGION expected."); } catch (Exception ex) when(!ClientUtils.IsSecurityOrCriticalException(ex)) { _dc.RestoreHdc(); _dc.Dispose(); } finally { // Delete the new clipping region, as the clipping region for the HDC is now set // to this rectangle. Hold on to hOriginalClippingRegion, as we'll need to restore // it when this object is disposed. success = Gdi32.DeleteObject(hClippingRegion).IsTrue(); Debug.Assert(success, "DeleteObject(hClippingRegion) failed."); if (hOriginalClippingRegion != IntPtr.Zero) { success = Gdi32.DeleteObject(hOriginalClippingRegion).IsTrue(); Debug.Assert(success, "DeleteObject(hOriginalClippingRegion) failed."); } } }