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);
        }
Пример #2
0
            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);
            }
Пример #3
0
        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);
        }
Пример #4
0
        // 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;
        }
Пример #5
0
        /// <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));
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
 private unsafe static extern int DrawTextExW(
     Gdi32.HDC hdc,
     char *lpchText,
     int cchText,
     ref RECT lprc,
     DT format,
     ref DRAWTEXTPARAMS lpdtp);
Пример #8
0
        // 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));
        }
Пример #9
0
        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);
        }
Пример #12
0
        /// <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;
Пример #13
0
        public static int ReleaseDC(HandleRef hWnd, Gdi32.HDC hDC)
        {
            int result = ReleaseDC(hWnd.Handle, hDC);

            GC.KeepAlive(hWnd.Wrapper);
            return(result);
        }
Пример #14
0
        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);
        }
Пример #15
0
        /// <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);
Пример #16
0
 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);
        }
Пример #19
0
 /// <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);
 }
Пример #20
0
        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);
Пример #22
0
 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);
Пример #24
0
        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);
        }
Пример #25
0
 /// <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;
     }
 }
Пример #26
0
        /// <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));
        }
Пример #27
0
 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);
 }
Пример #28
0
 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);
Пример #29
0
        internal static void FillRectangle(this Gdi32.HDC hdc, Rectangle rectangle, Gdi32.HBRUSH hbrush)
        {
            RECT rect = rectangle;

            User32.FillRect(
                hdc,
                ref rect,
                hbrush);
        }
Пример #30
0
 internal DrawItemEventArgs(
     Gdi32.HDC hdc,
     Font font,
     Rectangle rect,
     uint index,
     User32.ODS state)
     : this(hdc, font, rect, index, state, SystemColors.WindowText, SystemColors.Window)
 {
 }