public static HRESULT GetThemeBackgroundExtent(IHandle hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, ref RECT pContentRect, out RECT pExtentRect) { HRESULT hr = GetThemeBackgroundExtent(hTheme.Handle, hdc, iPartId, iStateId, ref pContentRect, out pExtentRect); GC.KeepAlive(hTheme); return(hr); }
public static BOOL Draw(IHandle himl, int i, Gdi32.HDC hdcDst, int x, int y, ILD fStyle) { BOOL result = Draw(himl.Handle, i, hdcDst, x, y, fStyle); GC.KeepAlive(himl); return(result); }
public Gdi32.HDC GetCachedItemDC(Gdi32.HDC toolStripHDC, Size bitmapSize) { if (_cachedHDCSize.Width < bitmapSize.Width || _cachedHDCSize.Height < bitmapSize.Height) { if (_cachedItemHDC.IsNull) { // Create a new DC - we dont have one yet. _cachedItemHDC = Gdi32.CreateCompatibleDC(toolStripHDC); } // Create compatible bitmap with the correct size. _cachedItemBitmap = Gdi32.CreateCompatibleBitmap(toolStripHDC, bitmapSize.Width, bitmapSize.Height); Gdi32.HGDIOBJ oldBitmap = Gdi32.SelectObject(_cachedItemHDC, _cachedItemBitmap); // Delete the old bitmap if (!oldBitmap.IsNull) { Gdi32.DeleteObject(oldBitmap); } // remember what size we created. _cachedHDCSize = bitmapSize; } return(_cachedItemHDC); }
// Not all state is handled yet. Backfilling in as we write specific tests. Of special note is that we don't // have tracking for Save/RestoreDC yet. /// <summary> /// Initialize the current state of <paramref name="hdc"/>. /// </summary> public DeviceContextState(Gdi32.HDC hdc) { MapMode = Gdi32.GetMapMode(hdc); BackColor = Gdi32.GetBkColor(hdc); TextColor = Gdi32.GetTextColor(hdc); Rop2Mode = Gdi32.GetROP2(hdc); TextAlign = Gdi32.GetTextAlign(hdc); BackgroundMode = Gdi32.GetBkMode(hdc); Point point = default; Gdi32.GetBrushOrgEx(hdc, ref point); BrushOrigin = point; var hfont = Gdi32.GetCurrentObject(hdc, Gdi32.OBJ.FONT); Gdi32.GetObjectW(hfont, out User32.LOGFONTW logfont); SelectedFont = logfont; var hpen = Gdi32.GetCurrentObject(hdc, Gdi32.OBJ.PEN); Gdi32.GetObjectW(hpen, out Gdi32.LOGPEN logpen); SelectedPen = logpen; var hbrush = Gdi32.GetCurrentObject(hdc, Gdi32.OBJ.BRUSH); Gdi32.GetObjectW(hbrush, out Gdi32.LOGBRUSH logbrush); SelectedBrush = logbrush; }
/// <summary> /// Creates a WindowsFont from the font selected in the supplied dc. /// </summary> public static WindowsFont FromHdc(Gdi32.HDC hdc) { Gdi32.HFONT hFont = (Gdi32.HFONT)Gdi32.GetCurrentObject(hdc, Gdi32.ObjectType.OBJ_FONT); // don't call DeleteObject on handle from GetCurrentObject, it is the one selected in the hdc. return(FromHfont(hFont)); }
/// <summary> /// Returns the Size in logical units of the given text using the given Font, and according to the formatting flags. /// The proposed size is used to create a bounding rectangle as follows: /// - If there are multiple lines of text, DrawText uses the width of the rectangle pointed to by /// the lpRect parameter and extends the base of the rectangle to bound the last line of text. /// - If the largest word is wider than the rectangle, the width is expanded. /// - If the text is less than the width of the rectangle, the width is reduced. /// - If there is only one line of text, DrawText modifies the right side of the rectangle so that /// it bounds the last character in the line. /// If the font is null, the hdc's current font will be used. /// /// Note for vertical fonts (if ever supported): DrawTextEx uses GetTextExtentPoint32 for measuring the text and this /// function has the following limitation (from MSDN): /// - This function assumes that the text is horizontal, that is, that the escapement is always 0. This is true for both /// the horizontal and vertical measurements of the text. The application must convert it explicitly. /// </summary> public static Size MeasureText( this Gdi32.HDC hdc, ReadOnlySpan <char> text, FontCache.Scope font, Size proposedSize, User32.DT flags) { ValidateFlags(flags); if (text.IsEmpty) { return(Size.Empty); } // DrawText returns a rectangle useful for aligning, but not guaranteed to encompass all // pixels (its not a FitBlackBox, if the text is italicized, it will overhang on the right.) // So we need to account for this. User32.DRAWTEXTPARAMS dtparams = GetTextMargins(font); // If Width / Height are < 0, we need to make them larger or DrawText will return // an unbounded measurement when we actually trying to make it very narrow. int minWidth = 1 + dtparams.iLeftMargin + dtparams.iRightMargin; if (proposedSize.Width <= minWidth) { proposedSize.Width = minWidth; } if (proposedSize.Height <= 0) { proposedSize.Height = 1; } var rect = new RECT(0, 0, proposedSize.Width, proposedSize.Height); using var fontSelection = new Gdi32.SelectObjectScope(hdc, font.Object); // If proposedSize.Height >= MaxSize.Height it is assumed bounds needed. If flags contain SINGLELINE and // VCENTER or BOTTOM options, DrawTextEx does not bind the rectangle to the actual text height since // it assumes the text is to be vertically aligned; we need to clear the VCENTER and BOTTOM flags to // get the actual text bounds. if (proposedSize.Height >= TextRenderer.MaxSize.Height && (flags & User32.DT.SINGLELINE) != 0) { // Clear vertical-alignment flags. flags &= ~(User32.DT.BOTTOM | User32.DT.VCENTER); } if (proposedSize.Width == TextRenderer.MaxSize.Width) { // PERF: No constraining width means no word break. // in this case, we dont care about word wrapping - there should be enough room to fit it all flags &= ~(User32.DT.WORDBREAK); } flags |= User32.DT.CALCRECT; User32.DrawTextExW(hdc, text, ref rect, flags, ref dtparams); return(rect.Size); }
private unsafe static extern int DrawTextExW( Gdi32.HDC hdc, char *lpchText, int cchText, ref RECT lprc, DT format, ref DRAWTEXTPARAMS lpdtp);
// Helper method to overcome the poor GDI ellipse drawing routine private static void DrawAndFillEllipse(Gdi32.HDC hdc, Gdi32.HPEN borderPen, Gdi32.HBRUSH fieldBrush, Rectangle bounds) { Debug.Assert(!hdc.IsNull, "Calling DrawAndFillEllipse with null wg"); if (hdc.IsNull) { return; } hdc.FillRectangle(fieldBrush, new Rectangle(bounds.X + 2, bounds.Y + 2, 8, 8)); hdc.FillRectangle(fieldBrush, new Rectangle(bounds.X + 4, bounds.Y + 1, 4, 10)); hdc.FillRectangle(fieldBrush, new Rectangle(bounds.X + 1, bounds.Y + 4, 10, 4)); hdc.DrawLine(borderPen, new Point(bounds.X + 4, bounds.Y + 0), new Point(bounds.X + 8, bounds.Y + 0)); hdc.DrawLine(borderPen, new Point(bounds.X + 4, bounds.Y + 11), new Point(bounds.X + 8, bounds.Y + 11)); hdc.DrawLine(borderPen, new Point(bounds.X + 2, bounds.Y + 1), new Point(bounds.X + 4, bounds.Y + 1)); hdc.DrawLine(borderPen, new Point(bounds.X + 8, bounds.Y + 1), new Point(bounds.X + 10, bounds.Y + 1)); hdc.DrawLine(borderPen, new Point(bounds.X + 2, bounds.Y + 10), new Point(bounds.X + 4, bounds.Y + 10)); hdc.DrawLine(borderPen, new Point(bounds.X + 8, bounds.Y + 10), new Point(bounds.X + 10, bounds.Y + 10)); hdc.DrawLine(borderPen, new Point(bounds.X + 0, bounds.Y + 4), new Point(bounds.X + 0, bounds.Y + 8)); hdc.DrawLine(borderPen, new Point(bounds.X + 11, bounds.Y + 4), new Point(bounds.X + 11, bounds.Y + 8)); hdc.DrawLine(borderPen, new Point(bounds.X + 1, bounds.Y + 2), new Point(bounds.X + 1, bounds.Y + 4)); hdc.DrawLine(borderPen, new Point(bounds.X + 1, bounds.Y + 8), new Point(bounds.X + 1, bounds.Y + 10)); hdc.DrawLine(borderPen, new Point(bounds.X + 10, bounds.Y + 2), new Point(bounds.X + 10, bounds.Y + 4)); hdc.DrawLine(borderPen, new Point(bounds.X + 10, bounds.Y + 8), new Point(bounds.X + 10, bounds.Y + 10)); }
public static HRESULT GetThemeFont(IHandle hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, int iPropId, out User32.LOGFONTW pFont) { HRESULT result = GetThemeFont(hTheme.Handle, hdc, iPartId, iStateId, iPropId, out pFont); GC.KeepAlive(hTheme); return(result); }
public static extern HRESULT GetThemeBackgroundContentRect( IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, ref RECT pBoundingRect, out RECT pContentRect);
internal Rectangle DrawEdge(Gdi32.HDC dc, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects) { if (!ClientUtils.IsEnumValid_Masked(edges, (int)edges, (uint)(Edges.Left | Edges.Top | Edges.Right | Edges.Bottom | Edges.Diagonal))) { throw new InvalidEnumArgumentException(nameof(edges), (int)edges, typeof(Edges)); } if (!ClientUtils.IsEnumValid_NotSequential(style, (int)style, (int)EdgeStyle.Raised, (int)EdgeStyle.Sunken, (int)EdgeStyle.Etched, (int)EdgeStyle.Bump)) { throw new InvalidEnumArgumentException(nameof(style), (int)style, typeof(EdgeStyle)); } if (!ClientUtils.IsEnumValid_Masked(effects, (int)effects, (uint)(EdgeEffects.FillInterior | EdgeEffects.Flat | EdgeEffects.Soft | EdgeEffects.Mono))) { throw new InvalidEnumArgumentException(nameof(effects), (int)effects, typeof(EdgeEffects)); } RECT destRect = bounds; var contentRect = new RECT(); _lastHResult = DrawThemeEdge( this, dc, Part, State, ref destRect, (User32.EDGE)style, (User32.BF)edges | (User32.BF)effects | User32.BF.ADJUST, ref contentRect); return(contentRect); }
/// <summary> /// Gets the <see cref="Gdi32.HDC"/> from the the given <paramref name="deviceContext"/>. /// </summary> /// <remarks> /// When a <see cref="Graphics"/> object is created from a <see cref="Gdi32.HDC"/> the clipping region and /// the viewport origin are applied (<see cref="Gdi32.GetViewportExtEx(Gdi32.HDC, out Size)"/>). The clipping /// region isn't reflected in <see cref="Graphics.Clip"/>, which is combined with the HDC HRegion. /// /// The Graphics object saves and restores DC state when performing operations that would modify the DC to /// maintain the DC in its original or returned state after <see cref="Graphics.ReleaseHdc()"/>. /// </remarks> /// <param name="applyGraphicsState"> /// Applies the origin transform and clipping region of the <paramref name="deviceContext"/> if it is an /// object of type <see cref="Graphics"/>. Otherwise this is a no-op. /// </param> /// <param name="saveHdcState"> /// When true, saves and restores the <see cref="Gdi32.HDC"/> state. /// </param> public DeviceContextHdcScope( IDeviceContext deviceContext, bool applyGraphicsState = true, bool saveHdcState = false) { DeviceContext = deviceContext ?? throw new ArgumentNullException(nameof(deviceContext)); ApplyGraphicsProperties apply = applyGraphicsState ? ApplyGraphicsProperties.All : ApplyGraphicsProperties.None; _savedHdcState = 0; if (apply == ApplyGraphicsProperties.None || !(DeviceContext is Graphics graphics)) { // GetHdc() locks the Graphics object, it cannot be used until ReleaseHdc() is called HDC = (Gdi32.HDC)DeviceContext.GetHdc(); _savedHdcState = saveHdcState ? Gdi32.SaveDC(HDC) : 0; return; } bool applyTransform = apply.HasFlag(ApplyGraphicsProperties.TranslateTransform); bool applyClipping = apply.HasFlag(ApplyGraphicsProperties.Clipping); // This API is very expensive object[]? data = applyTransform || applyClipping ? (object[])graphics.GetContextInfo() : null; using Region? clipRegion = (Region?)data?[0]; using Matrix? worldTransform = (Matrix?)data?[1]; // elements (XFORM) = [eM11, eM12, eM21, eM22, eDx, eDy], eDx/eDy specify the translation offset. float[]? elements = applyTransform ? worldTransform?.Elements : null; int dx = elements != null ? (int)elements[4] : 0; int dy = elements != null ? (int)elements[5] : 0; applyTransform = applyTransform && elements != null && (dx != 0 || dy != 0); using var graphicsRegion = applyClipping ? new Gdi32.RegionScope(clipRegion !, graphics) : default;
public static int ReleaseDC(HandleRef hWnd, Gdi32.HDC hDC) { int result = ReleaseDC(hWnd.Handle, hDC); GC.KeepAlive(hWnd.Wrapper); return(result); }
public unsafe static HRESULT GetThemeTextExtent( IHandle hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, string pszText, int cchCharCount, uint dwTextFlags, RECT *pBoundingRect, out RECT pExtentRect) { HRESULT hr = GetThemeTextExtent( hTheme.Handle, hdc, iPartId, iStateId, pszText, cchCharCount, dwTextFlags, pBoundingRect, out pExtentRect); GC.KeepAlive(hTheme); return(hr); }
/// <summary> /// Create a cache with space for the specified number of HDCs. /// </summary> public ScreenDcCache(int cacheSpace = 10) { _worker = new ThreadWorker(_tokenSource.Token); // We need a thread that doesn't ever finish to create HDCs on so they'll stay valid for all threads // in the process for the life of the process. _thread = new Thread(_worker.Start) { Name = "WinForms Background Worker", IsBackground = true }; _thread.Start(); Debug.Assert(cacheSpace >= 0); _itemsCache = new IntPtr[cacheSpace]; // Create an initial stash of screen dc's _worker.QueueAndWaitForCompletion(() => { int max = Math.Min(cacheSpace, 5); for (int i = 0; i < max; i++) { Gdi32.HDC hdc = Gdi32.CreateCompatibleDC(default);
public static extern HRESULT GetThemeBackgroundRegion( IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, ref RECT pRect, out Gdi32.HRGN pRegion);
public unsafe static HRESULT GetThemeTextMetrics(IHandle hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, out TextMetrics ptm) { HRESULT hr = GetThemeTextMetrics(hTheme.Handle, hdc, iPartId, iStateId, out ptm); GC.KeepAlive(hTheme); return(hr); }
public static HRESULT DrawThemeParentBackground(IHandle hwnd, Gdi32.HDC hdc, ref RECT prc) { HRESULT hr = DrawThemeParentBackground(hwnd.Handle, hdc, ref prc); GC.KeepAlive(hwnd); return(hr); }
/// <summary> /// Internal version of constructor for performance. We try to avoid getting the graphics object until needed. /// </summary> internal PaintEventArgs( Gdi32.HDC hdc, Rectangle clipRect, DrawingEventFlags flags = DrawingEventFlags.CheckState) { _event = new DrawingEventArgs(hdc, clipRect, flags); }
internal unsafe void DrawBackground(Gdi32.HDC dc, Rectangle bounds, Rectangle clipRectangle, IntPtr hwnd) { if (bounds.Width < 0 || bounds.Height < 0 || clipRectangle.Width < 0 || clipRectangle.Height < 0) { return; } if (IntPtr.Zero != hwnd) { using var htheme = new UxTheme.OpenThemeDataScope(hwnd, Class); if (htheme.IsNull) { throw new InvalidOperationException(SR.VisualStyleHandleCreationFailed); } RECT rect = bounds; RECT clipRect = clipRectangle; _lastHResult = DrawThemeBackground(htheme, dc, Part, State, ref rect, &clipRect); } else { RECT rect = bounds; RECT clipRect = clipRectangle; _lastHResult = DrawThemeBackground(this, dc, Part, State, ref rect, &clipRect); } }
public static unsafe partial HRESULT DrawThemeBackground( IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, ref RECT pRect, RECT *pClipRect);
public unsafe static extern HRESULT GetThemeMargins( IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, int iPropId, RECT *prc, out MARGINS pMargins);
public unsafe static extern HRESULT GetThemePartSize( IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, RECT *prc, ThemeSizeType eSize, out Size psz);
internal static void DrawRectangle(this Gdi32.HDC hdc, Rectangle rectangle, Gdi32.HPEN hpen) { using var penScope = new Gdi32.SelectObjectScope(hdc, hpen); using var ropScope = new Gdi32.SetRop2Scope(hdc, Gdi32.R2.COPYPEN); using var brushScope = new Gdi32.SelectObjectScope(hdc, Gdi32.GetStockObject(Gdi32.StockObject.HOLLOW_BRUSH)); Gdi32.Rectangle(hdc, rectangle.X, rectangle.Y, rectangle.Right, rectangle.Bottom); }
/// <summary> /// If the object was created from a DC, this object doesn't 'own' the dc so we just ignore /// this call. /// </summary> void IDeviceContext.ReleaseHdc() { if (!_hDC.IsNull && DeviceContextType == DeviceContextType.Display) { User32.ReleaseDC(new HandleRef(this, _hWnd), _hDC); _hDC = default; } }
/// <summary> /// Creates a DeviceContext object wrapping a memory DC compatible with the specified device. /// </summary> /// <param name="hdc"> /// If <see cref="Gdi32.HDC"/> is default a memory DC compatible with the application's current screen is /// created. In this case the returned DC is only valid for the lifetime of the creating thread. /// </param> public static DeviceContext FromCompatibleDC(Gdi32.HDC hdc) { // In this case the thread that calls CreateCompatibleDC owns the HDC that is created. When this thread is destroyed, // the HDC is no longer valid. Gdi32.HDC compatibleDc = Gdi32.CreateCompatibleDC(hdc); return(new DeviceContext(compatibleDc, DeviceContextType.Memory)); }
internal PaintEventArgs( PaintEventArgs e, Rectangle clipRect) { Gdi32.HDC hdc = e.HDC; _event = hdc.IsNull ? new DrawingEventArgs(e.GraphicsInternal, clipRect, e._event.Flags) : new DrawingEventArgs(hdc, clipRect, e._event.Flags); }
internal static void DrawTextInternal( Gdi32.HDC hdc, string?text, Font?font, Rectangle bounds, Color foreColor, Gdi32.QUALITY fontQuality, TextFormatFlags flags) => DrawTextInternal(hdc, text, font, bounds, foreColor, fontQuality, Color.Empty, flags);
internal static void FillRectangle(this Gdi32.HDC hdc, Rectangle rectangle, Gdi32.HBRUSH hbrush) { RECT rect = rectangle; User32.FillRect( hdc, ref rect, hbrush); }
internal DrawItemEventArgs( Gdi32.HDC hdc, Font font, Rectangle rect, uint index, User32.ODS state) : this(hdc, font, rect, index, state, SystemColors.WindowText, SystemColors.Window) { }