Remove most usages of WIndowsGraphicsWrapper (#3532)

- Refactor DpiHelper a bit, adding new API to avoid DC creation (using new GetDpiForSystem())
- Add PaintEvent HDC wrapper to favor getting the natvie HDC if the Graphics wrapper hasn't been created
- Extend DeviceContextHdcScope to support WindowsGraphicsWrapper migration
- Change HDC property on PaintEventArgs
- Add DrawLine to HDC extensions (from WindowsGraphics)
- Graphics.DpiX is no different than normal device DPI, removed from CheckableControlBaseAdapter.cs
- Remove Graphics from CheckBoxPopupAdapter.PaintPopupLayout
- Add SetBkMode scope
This commit is contained in:
Jeremy Kuhne 2020-07-06 19:02:56 -07:00 коммит произвёл GitHub
Родитель 6f85a5d9c7
Коммит e45b38a61c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
61 изменённых файлов: 1014 добавлений и 972 удалений

Просмотреть файл

@ -281,7 +281,7 @@ namespace System.Windows.Forms.Design
/// </summary>
public static void DrawGrabHandle(Graphics graphics, Rectangle bounds, bool isPrimary, Glyph glyph)
{
using var hDC = new DeviceContextHdcScope(graphics);
using var hDC = new DeviceContextHdcScope(graphics, applyGraphicsState: false);
// Set our pen and brush based on primary selection
using var brushSelection = new Gdi32.SelectObjectScope(hDC, isPrimary ? s_grabHandleFillBrushPrimary : s_grabHandleFillBrush);
@ -296,7 +296,7 @@ namespace System.Windows.Forms.Design
/// </summary>
public static void DrawNoResizeHandle(Graphics graphics, Rectangle bounds, bool isPrimary, Glyph glyph)
{
using var hDC = new DeviceContextHdcScope(graphics);
using var hDC = new DeviceContextHdcScope(graphics, applyGraphicsState: false);
// Set our pen and brush based on primary selection
using var brushSelection = new Gdi32.SelectObjectScope(hDC, isPrimary ? s_grabHandleFillBrushPrimary : s_grabHandleFillBrush);
@ -311,7 +311,7 @@ namespace System.Windows.Forms.Design
/// </summary>
public static void DrawLockedHandle(Graphics graphics, Rectangle bounds, bool isPrimary, Glyph glyph)
{
using var hDC = new DeviceContextHdcScope(graphics);
using var hDC = new DeviceContextHdcScope(graphics, applyGraphicsState: false);
using var penSelection = new Gdi32.SelectObjectScope(hDC, s_grabHandlePenPrimary);
@ -440,7 +440,7 @@ namespace System.Windows.Forms.Design
gDest.Clear(SystemColors.Control);
}
using var destDC = new DeviceContextHdcScope(gDest);
using var destDC = new DeviceContextHdcScope(gDest, applyGraphicsState: false);
// Perform our bitblit operation to push the image into the dest bitmap
Gdi32.BitBlt(
@ -580,7 +580,7 @@ namespace System.Windows.Forms.Design
int fontHeight = 0;
using Graphics g = ctrl.CreateGraphics();
using var dc = new DeviceContextHdcScope(g);
using var dc = new DeviceContextHdcScope(g, applyGraphicsState: false);
using var hFont = new Gdi32.ObjectScope(ctrl.Font.ToHFONT());
using var hFontOld = new Gdi32.SelectObjectScope(dc, hFont);

Просмотреть файл

@ -10,11 +10,11 @@ internal static partial class Interop
internal static partial class Gdi32
{
[DllImport(Libraries.Gdi32, ExactSpelling = true)]
public static extern BOOL LineTo(IntPtr hdc, int x, int y);
public static extern BOOL LineTo(HDC hdc, int x, int y);
public static BOOL LineTo(IHandle hdc, int x, int y)
{
BOOL result = LineTo(hdc.Handle, x, y);
BOOL result = LineTo((HDC)hdc.Handle, x, y);
GC.KeepAlive(hdc);
return result;
}

Просмотреть файл

@ -11,11 +11,11 @@ internal static partial class Interop
internal static partial class Gdi32
{
[DllImport(Libraries.Gdi32, ExactSpelling = true)]
public unsafe static extern BOOL MoveToEx(IntPtr hdc, int x, int y, Point* lppt);
public unsafe static extern BOOL MoveToEx(HDC hdc, int x, int y, Point* lppt);
public unsafe static BOOL MoveToEx(IHandle hdc, int x, int y, Point* lppt)
{
BOOL result = MoveToEx(hdc.Handle, x, y, lppt);
BOOL result = MoveToEx((HDC)hdc.Handle, x, y, lppt);
GC.KeepAlive(hdc);
return result;
}

Просмотреть файл

@ -0,0 +1,44 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
internal static partial class Interop
{
internal static partial class Gdi32
{
/// <summary>
/// Helper to scope selecting a given background mix mode into a HDC. Restores the original
/// mix mode into the HDC when disposed.
/// </summary>
/// <remarks>
/// Use in a <see langword="using" /> statement. If you must pass this around, always pass by
/// <see langword="ref" /> to avoid duplicating the handle and resetting multiple times.
/// </remarks>
internal ref struct SetBkModeScope
{
private readonly BKMODE _previousMode;
private readonly HDC _hdc;
/// <summary>
/// Selects <paramref name="bkmode"/> into the given <paramref name="hdc"/>.
/// </summary>
public SetBkModeScope(HDC hdc, BKMODE bkmode)
{
_previousMode = SetBkMode(hdc, bkmode);
// If we didn't actually change the mode, don't keep the HDC so we skip putting back the same state.
_hdc = _previousMode == bkmode ? default : hdc;
}
public void Dispose()
{
if (!_hdc.IsNull)
{
SetBkMode(_hdc, _previousMode);
}
}
}
}
}

Просмотреть файл

@ -26,13 +26,18 @@ internal static partial class Interop
/// </summary>
public SetRop2Scope(HDC hdc, R2 rop2)
{
_hdc = hdc;
_previousRop = SetROP2(hdc, rop2);
// If we didn't actually change the ROP, don't keep the HDC so we skip putting back the same state.
_hdc = _previousRop == rop2 ? default : hdc;
}
public void Dispose()
{
SetROP2(_hdc, _previousRop);
if (!_hdc.IsNull)
{
SetROP2(_hdc, _previousRop);
}
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
internal static partial class Interop
{
internal static partial class User32
{
// This is only available on Windows 1607 and later. Avoids needing a DC to get the DPI.
[DllImport(Libraries.User32, ExactSpelling = true)]
public static extern uint GetDpiForSystem();
}
}

Просмотреть файл

@ -10,13 +10,24 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public static extern unsafe HRESULT DrawThemeBackground(IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, ref RECT pRect, RECT* pClipRect);
public static extern unsafe HRESULT DrawThemeBackground(
IntPtr hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pRect,
RECT* pClipRect);
public static unsafe HRESULT DrawThemeBackground(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, ref RECT pRect, RECT* pClipRect)
public static unsafe HRESULT DrawThemeBackground(
IHandle hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pRect,
RECT* pClipRect)
{
HRESULT hr = DrawThemeBackground(hTheme.Handle, (Gdi32.HDC)hdc.Handle, iPartId, iStateId, ref pRect, pClipRect);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -12,7 +12,7 @@ internal static partial class Interop
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public static extern HRESULT DrawThemeEdge(
IntPtr hTheme,
IntPtr hdc,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pDestRect,
@ -22,7 +22,7 @@ internal static partial class Interop
public static HRESULT DrawThemeEdge(
IHandle hTheme,
IHandle hdc,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pDestRect,
@ -30,9 +30,8 @@ internal static partial class Interop
User32.BF uFlags,
ref RECT pContentRect)
{
HRESULT hr = DrawThemeEdge(hTheme.Handle, hdc.Handle, iPartId, iStateId, ref pDestRect, uEdge, uFlags, ref pContentRect);
HRESULT hr = DrawThemeEdge(hTheme.Handle, hdc, iPartId, iStateId, ref pDestRect, uEdge, uFlags, ref pContentRect);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -10,13 +10,12 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public static extern HRESULT DrawThemeParentBackground(IntPtr hwnd, IntPtr hdc, ref RECT prc);
public static extern HRESULT DrawThemeParentBackground(IntPtr hwnd, Gdi32.HDC hdc, ref RECT prc);
public static HRESULT DrawThemeParentBackground(IHandle hwnd, IHandle hdc, ref RECT prc)
public static HRESULT DrawThemeParentBackground(IHandle hwnd, Gdi32.HDC hdc, ref RECT prc)
{
HRESULT hr = DrawThemeParentBackground(hwnd.Handle, hdc.Handle, ref prc);
HRESULT hr = DrawThemeParentBackground(hwnd.Handle, hdc, ref prc);
GC.KeepAlive(hwnd);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -12,7 +12,7 @@ internal static partial class Interop
[DllImport(Libraries.UxTheme, ExactSpelling = true, CharSet = CharSet.Unicode)]
public static extern HRESULT DrawThemeText(
IntPtr hTheme,
IntPtr hdc,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
string pszText,
@ -23,7 +23,7 @@ internal static partial class Interop
public static HRESULT DrawThemeText(
IHandle hTheme,
IHandle hdc,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
string pszText,
@ -32,9 +32,8 @@ internal static partial class Interop
uint dwTextFlags2,
ref RECT pRect)
{
HRESULT hr = DrawThemeText(hTheme.Handle, hdc.Handle, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, ref pRect);
HRESULT hr = DrawThemeText(hTheme.Handle, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, ref pRect);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -10,13 +10,24 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public static extern HRESULT GetThemeBackgroundContentRect(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref RECT pBoundingRect, out RECT pContentRect);
public static extern HRESULT GetThemeBackgroundContentRect(
IntPtr hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pBoundingRect,
out RECT pContentRect);
public static HRESULT GetThemeBackgroundContentRect(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, ref RECT pBoundingRect, out RECT pContentRect)
public static HRESULT GetThemeBackgroundContentRect(
IHandle hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pBoundingRect,
out RECT pContentRect)
{
HRESULT hr = GetThemeBackgroundContentRect(hTheme.Handle, hdc.Handle, iPartId, iStateId, ref pBoundingRect, out pContentRect);
HRESULT hr = GetThemeBackgroundContentRect(hTheme.Handle, hdc, iPartId, iStateId, ref pBoundingRect, out pContentRect);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -10,13 +10,12 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public static extern HRESULT GetThemeBackgroundExtent(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref RECT pContentRect, out RECT pExtentRect);
public static extern HRESULT GetThemeBackgroundExtent(IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, ref RECT pContentRect, out RECT pExtentRect);
public static HRESULT GetThemeBackgroundExtent(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, ref RECT pContentRect, out RECT pExtentRect)
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.Handle, iPartId, iStateId, ref pContentRect, out pExtentRect);
HRESULT hr = GetThemeBackgroundExtent(hTheme.Handle, hdc, iPartId, iStateId, ref pContentRect, out pExtentRect);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -10,13 +10,24 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public static extern HRESULT GetThemeBackgroundRegion(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref RECT pRect, out IntPtr pRegion);
public static extern HRESULT GetThemeBackgroundRegion(
IntPtr hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pRect,
out Gdi32.HRGN pRegion);
public static HRESULT GetThemeBackgroundRegion(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, ref RECT pRect, out IntPtr pRegion)
public static HRESULT GetThemeBackgroundRegion(
IHandle hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
ref RECT pRect,
out Gdi32.HRGN pRegion)
{
HRESULT hr = GetThemeBackgroundRegion(hTheme.Handle, hdc.Handle, iPartId, iStateId, ref pRect, out pRegion);
HRESULT hr = GetThemeBackgroundRegion(hTheme.Handle, hdc, iPartId, iStateId, ref pRect, out pRegion);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -10,13 +10,12 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public static extern HRESULT GetThemeFont(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, int iPropId, out User32.LOGFONTW pFont);
public static extern HRESULT GetThemeFont(IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, int iPropId, out User32.LOGFONTW pFont);
public static HRESULT GetThemeFont(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, int iPropId, out User32.LOGFONTW pFont)
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.Handle, iPartId, iStateId, iPropId, out pFont);
HRESULT result = GetThemeFont(hTheme.Handle, hdc, iPartId, iStateId, iPropId, out pFont);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return result;
}
}

Просмотреть файл

@ -10,13 +10,26 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public unsafe static extern HRESULT GetThemeMargins(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, int iPropId, RECT* prc, out MARGINS pMargins);
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 HRESULT GetThemeMargins(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, int iPropId, RECT* prc, out MARGINS pMargins)
public unsafe static HRESULT GetThemeMargins(
IHandle hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
int iPropId,
RECT* prc,
out MARGINS pMargins)
{
HRESULT hr = GetThemeMargins(hTheme.Handle, hdc.Handle, iPartId, iStateId, iPropId, prc, out pMargins);
HRESULT hr = GetThemeMargins(hTheme.Handle, hdc, iPartId, iStateId, iPropId, prc, out pMargins);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -12,13 +12,26 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public unsafe static extern HRESULT GetThemePartSize(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, RECT* prc, ThemeSizeType eSize, out Size psz);
public unsafe static extern HRESULT GetThemePartSize(
IntPtr hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
RECT* prc,
ThemeSizeType eSize,
out Size psz);
public unsafe static HRESULT GetThemePartSize(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, RECT* prc, ThemeSizeType eSize, out Size psz)
public unsafe static HRESULT GetThemePartSize(
IHandle hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
RECT* prc,
ThemeSizeType eSize,
out Size psz)
{
HRESULT hr = GetThemePartSize(hTheme.Handle, hdc.Handle, iPartId, iStateId, prc, eSize, out psz);
HRESULT hr = GetThemePartSize(hTheme.Handle, hdc, iPartId, iStateId, prc, eSize, out psz);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -10,13 +10,40 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, CharSet = CharSet.Unicode, ExactSpelling = true)]
public unsafe static extern HRESULT GetThemeTextExtent(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, string pszText, int cchCharCount, uint dwTextFlags, RECT* pBoundingRect, out RECT pExtentRect);
public unsafe static extern HRESULT GetThemeTextExtent(
IntPtr hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
string pszText,
int cchCharCount,
uint dwTextFlags,
RECT* pBoundingRect,
out RECT pExtentRect);
public unsafe static HRESULT GetThemeTextExtent(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, string pszText, int cchCharCount, uint dwTextFlags, RECT* pBoundingRect, out RECT pExtentRect)
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.Handle, iPartId, iStateId, pszText, cchCharCount, dwTextFlags, pBoundingRect, out pExtentRect);
HRESULT hr = GetThemeTextExtent(
hTheme.Handle,
hdc,
iPartId,
iStateId,
pszText,
cchCharCount,
dwTextFlags,
pBoundingRect,
out pExtentRect);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -11,13 +11,12 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public unsafe static extern HRESULT GetThemeTextMetrics(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, out TextMetrics ptm);
public unsafe static extern HRESULT GetThemeTextMetrics(IntPtr hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, out TextMetrics ptm);
public unsafe static HRESULT GetThemeTextMetrics(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, out TextMetrics ptm)
public unsafe static HRESULT GetThemeTextMetrics(IHandle hTheme, Gdi32.HDC hdc, int iPartId, int iStateId, out TextMetrics ptm)
{
HRESULT hr = GetThemeTextMetrics(hTheme.Handle, hdc.Handle, iPartId, iStateId, out ptm);
HRESULT hr = GetThemeTextMetrics(hTheme.Handle, hdc, iPartId, iStateId, out ptm);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -11,13 +11,30 @@ internal static partial class Interop
public static partial class UxTheme
{
[DllImport(Libraries.UxTheme, ExactSpelling = true)]
public unsafe static extern HRESULT HitTestThemeBackground(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, uint dwOptions, ref RECT pRect, IntPtr hrgn, Point ptTest, out ushort pwHitTestCode);
public unsafe static extern HRESULT HitTestThemeBackground(
IntPtr hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
uint dwOptions,
ref RECT pRect,
IntPtr hrgn,
Point ptTest,
out ushort pwHitTestCode);
public unsafe static HRESULT HitTestThemeBackground(IHandle hTheme, IHandle hdc, int iPartId, int iStateId, uint dwOptions, ref RECT pRect, IntPtr hrgn, Point ptTest, out ushort pwHitTestCode)
public unsafe static HRESULT HitTestThemeBackground(
IHandle hTheme,
Gdi32.HDC hdc,
int iPartId,
int iStateId,
uint dwOptions,
ref RECT pRect,
IntPtr hrgn,
Point ptTest,
out ushort pwHitTestCode)
{
HRESULT hr = HitTestThemeBackground(hTheme.Handle, hdc.Handle, iPartId, iStateId, dwOptions, ref pRect, hrgn, ptTest, out pwHitTestCode);
HRESULT hr = HitTestThemeBackground(hTheme.Handle, hdc, iPartId, iStateId, dwOptions, ref pRect, hrgn, ptTest, out pwHitTestCode);
GC.KeepAlive(hTheme);
GC.KeepAlive(hdc);
return hr;
}
}

Просмотреть файл

@ -11,21 +11,21 @@ namespace System.Windows.Forms
[Flags]
internal enum ApplyGraphicsProperties
{
None = 0x00000000,
None = 0x0000_0000,
/// <summary>
/// Apply clipping region.
/// </summary>
Clipping = 0x00000001,
Clipping = 0x0000_0001,
/// <summary>
/// Apply coordinate transformation.
/// </summary>
TranslateTransform = 0x00000002,
TranslateTransform = 0x0000_0002,
/// <summary>
/// Apply all supported Graphics properties.
/// </summary>
All = Clipping | TranslateTransform
All = Clipping | TranslateTransform
}
}

Просмотреть файл

@ -48,6 +48,27 @@ namespace System.Windows.Forms
hbrush);
}
internal static void DrawLine(this DeviceContextHdcScope hdc, Gdi32.HPEN pen, int x1, int y1, int x2, int y2)
=> DrawLine(hdc.HDC, pen, x1, y1, x2, y2);
internal static void DrawLine(this Gdi32.CreateDcScope hdc, Gdi32.HPEN pen, int x1, int y1, int x2, int y2)
=> DrawLine(hdc.HDC, pen, x1, y1, x2, y2);
internal static void DrawLine(this User32.GetDcScope hdc, Gdi32.HPEN pen, int x1, int y1, int x2, int y2)
=> DrawLine(hdc.HDC, pen, x1, y1, x2, y2);
internal unsafe static void DrawLine(this Gdi32.HDC hdc, Gdi32.HPEN pen, int x1, int y1, int x2, int y2)
{
using var ropScope = new Gdi32.SetRop2Scope(hdc, Gdi32.R2.COPYPEN);
using var bkScope = new Gdi32.SetBkModeScope(hdc, Gdi32.BKMODE.TRANSPARENT);
using var selection = new Gdi32.SelectObjectScope(hdc, pen);
Point oldPoint = new Point();
Gdi32.MoveToEx(hdc, x1, y1, &oldPoint);
Gdi32.LineTo(hdc, x2, y2);
Gdi32.MoveToEx(hdc, oldPoint.X, oldPoint.Y, &oldPoint);
}
internal static Color GetNearestColor(this DeviceContextHdcScope hdc, Color color)
=> GetNearestColor(hdc.HDC, color);
@ -63,5 +84,17 @@ namespace System.Windows.Forms
internal static Graphics CreateGraphics(this Gdi32.HDC hdc) => Graphics.FromHdcInternal(hdc.Handle);
internal static Graphics CreateGraphics(this Gdi32.CreateDcScope hdc) => Graphics.FromHdcInternal(hdc.HDC.Handle);
internal static Graphics CreateGraphics(this User32.GetDcScope hdc) => Graphics.FromHdcInternal(hdc.HDC.Handle);
/// <summary>
/// Get the number of pixels per logical inch along the device width. In a system with multiple display
/// monitors, this value is always from the primary display.
/// </summary>
internal static int GetDpiX(this Gdi32.HDC hdc) => Gdi32.GetDeviceCaps(hdc, Gdi32.DeviceCapability.LOGPIXELSX);
/// <summary>
/// Get the number of pixels per logical inch along the device (screen) height. In a system with multiple
/// display monitors, this value is always from the primary display.
/// </summary>
internal static int GetDpiY(this Gdi32.HDC hdc) => Gdi32.GetDeviceCaps(hdc, Gdi32.DeviceCapability.LOGPIXELSY);
}
}

Просмотреть файл

@ -19,59 +19,52 @@ namespace System.Windows.Forms
/// Use in a <see langword="using" /> statement. If you must pass this around, always pass by+
/// <see langword="ref" /> to avoid duplicating the handle and risking a double release.
/// </remarks>
internal ref struct DeviceContextHdcScope
internal readonly ref struct DeviceContextHdcScope
{
public readonly Gdi32.HDC HDC { get; }
public IDeviceContext DeviceContext { get; }
public int _savedState;
public Gdi32.HDC HDC { get; }
private readonly int _savedHdcState;
/// <summary>
/// Gets the <see cref="Gdi32.HDC"/> from the the given <paramref name="deviceContext"/>.
/// </summary>
/// <param name="saveState">When true, saves the state.</param>
public DeviceContextHdcScope(IDeviceContext deviceContext, bool saveState = true)
{
DeviceContext = deviceContext;
HDC = (Gdi32.HDC)deviceContext.GetHdc();
_savedState = saveState ? Gdi32.SaveDC(HDC) : 0;
}
/// <summary>
/// Gets the <see cref="Gdi32.HDC"/> from the the given <paramref name="graphics"/>. Applies <paramref name="apply"/>
/// properties as specified.
/// </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. We provide
/// the capacity to do the same to the retrieved HDC with <see cref="ApplyGraphicsProperties.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 it's original or returned state after <see cref="Graphics.ReleaseHdc()"/>.
///
/// Outside of munging the DC with <paramref name="apply"/> we should consider adding an option to skip saving
/// the state here when we know we aren't changing the DC state without restoring it (e.g. selecting a pen into
/// the HDC without selecting the original pen back.
/// maintain the DC in its original or returned state after <see cref="Graphics.ReleaseHdc()"/>.
/// </remarks>
/// <param name="saveState">
/// When true, always saves the state. Otherwise only saves the state if the HDC is modified due
/// to <paramref name="apply" />.
/// <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>
public DeviceContextHdcScope(Graphics graphics, ApplyGraphicsProperties apply, bool saveState = true)
/// <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 = graphics;
_savedState = 0;
DeviceContext = deviceContext ?? throw new ArgumentNullException(nameof(deviceContext));
ApplyGraphicsProperties apply = applyGraphicsState ? ApplyGraphicsProperties.All : ApplyGraphicsProperties.None;
_savedHdcState = 0;
if (apply == ApplyGraphicsProperties.None)
if (apply == ApplyGraphicsProperties.None || !(DeviceContext is Graphics graphics))
{
// GetHdc() locks the Graphics object, it cannot be used until ReleaseHdc() is called
HDC = (Gdi32.HDC)graphics.GetHdc();
_savedState = saveState ? Gdi32.SaveDC(HDC) : 0;
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];
@ -88,9 +81,9 @@ namespace System.Windows.Forms
HDC = (Gdi32.HDC)graphics.GetHdc();
if (saveState || applyClipping || applyTransform)
if (saveHdcState || applyClipping || applyTransform)
{
_savedState = Gdi32.SaveDC(HDC);
_savedHdcState = Gdi32.SaveDC(HDC);
}
if (applyClipping)
@ -125,24 +118,18 @@ namespace System.Windows.Forms
}
}
public static implicit operator Gdi32.HDC(DeviceContextHdcScope scope) => scope.HDC;
public static explicit operator IntPtr(DeviceContextHdcScope scope) => scope.HDC.Handle;
public static implicit operator Gdi32.HDC(in DeviceContextHdcScope scope) => scope.HDC;
public static explicit operator IntPtr(in DeviceContextHdcScope scope) => scope.HDC.Handle;
public void Dispose()
{
if (_savedState != 0)
if (_savedHdcState != 0)
{
Gdi32.RestoreDC(HDC, _savedState);
Gdi32.RestoreDC(HDC, _savedHdcState);
}
if (DeviceContext is Graphics graphics)
{
graphics.ReleaseHdc((IntPtr)HDC);
}
else
{
DeviceContext.ReleaseHdc();
}
// Note that Graphics keeps track of the HDC it passes back, so we don't need to pass it back in
DeviceContext?.ReleaseHdc();
}
}
}

Просмотреть файл

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Drawing2D;
@ -15,70 +16,50 @@ namespace System.Windows.Forms
internal static partial class DpiHelper
{
internal const double LogicalDpi = 96.0;
private static bool s_isInitialized = false;
private static bool s_isInitializeDpiHelperForWinforms = false;
/// <summary>
/// The primary screen's (device) current DPI
/// </summary>
private static double s_deviceDpi = LogicalDpi;
private static double s_logicalToDeviceUnitsScalingFactor = 0.0;
private static InterpolationMode s_interpolationMode = InterpolationMode.Invalid;
// Backing field, indicating that we will need to send a PerMonitorV2 query in due course.
private static bool s_doesNeedQueryForPerMonitorV2Awareness = false;
private static readonly bool s_perMonitorAware = GetPerMonitorAware();
// Backing field, indicating that either DPI is <> 96 or we are in some PerMonitor HighDpi mode.
private static bool s_isScalingRequirementMet = false;
internal static int DeviceDpi { get; } = GetDeviceDPI();
private static void Initialize()
private static int GetDeviceDPI()
{
if (s_isInitialized)
return;
// This never changes for the process. Depending on what the DPI awareness settings are we'll get
// either the actual DPI of the primary display at process startup or the default LogicalDpi;
using var dc = User32.GetDcScope.ScreenDC;
s_deviceDpi = Gdi32.GetDeviceCaps(dc, Gdi32.DeviceCapability.LOGPIXELSX);
s_isInitialized = true;
if (!OsVersion.IsWindows10_1607OrGreater)
{
using var dc = User32.GetDcScope.ScreenDC;
return Gdi32.GetDeviceCaps(dc, Gdi32.DeviceCapability.LOGPIXELSX);
}
// This avoids needing to create a DC
return (int)User32.GetDpiForSystem();
}
internal static void InitializeDpiHelperForWinforms()
private static bool GetPerMonitorAware()
{
if (s_isInitializeDpiHelperForWinforms)
if (!OsVersion.IsWindows10_1607OrGreater)
{
return;
return false;
}
// initialize shared fields
Initialize();
HRESULT result = SHCore.GetProcessDpiAwareness(
IntPtr.Zero,
out SHCore.PROCESS_DPI_AWARENESS processDpiAwareness);
if (OsVersion.IsWindows10_1607OrGreater)
Debug.Assert(result.Succeeded(), $"Failed to get ProcessDpi HRESULT: {result}");
Debug.Assert(Enum.IsDefined(typeof(SHCore.PROCESS_DPI_AWARENESS), processDpiAwareness));
return result.Succeeded() && processDpiAwareness switch
{
// We are on Windows 10/1603 or greater, but we could still be DpiUnaware or SystemAware, so let's find that out...
IntPtr hProcess = Kernel32.OpenProcess(
Kernel32.ProcessAccessOptions.QUERY_INFORMATION,
BOOL.FALSE,
Kernel32.GetCurrentProcessId());
SHCore.GetProcessDpiAwareness(hProcess, out SHCore.PROCESS_DPI_AWARENESS processDpiAwareness);
// Only if we're not, it makes sense to query for PerMonitorV2 awareness from now on, if needed.
if (!(processDpiAwareness == SHCore.PROCESS_DPI_AWARENESS.UNAWARE ||
processDpiAwareness == SHCore.PROCESS_DPI_AWARENESS.SYSTEM_AWARE))
{
s_doesNeedQueryForPerMonitorV2Awareness = true;
}
}
if (IsScalingRequired || s_doesNeedQueryForPerMonitorV2Awareness)
{
s_isScalingRequirementMet = true;
}
s_isInitializeDpiHelperForWinforms = true;
SHCore.PROCESS_DPI_AWARENESS.UNAWARE => false,
SHCore.PROCESS_DPI_AWARENESS.SYSTEM_AWARE => false,
SHCore.PROCESS_DPI_AWARENESS.PER_MONITOR_AWARE => true,
_ => true
};
}
internal static bool DoesCurrentContextRequireScaling
=> true;
/// <summary>
/// Returns a boolean to specify if we should enable processing of WM_DPICHANGED and related messages
/// </summary>
@ -86,8 +67,7 @@ namespace System.Windows.Forms
{
get
{
InitializeDpiHelperForWinforms();
if (s_doesNeedQueryForPerMonitorV2Awareness)
if (s_perMonitorAware)
{
// We can't cache this value because different top level windows can have different DPI awareness context
// for mixed mode applications.
@ -104,36 +84,12 @@ namespace System.Windows.Forms
/// <summary>
/// Indicates, if rescaling becomes necessary, either because we are not 96 DPI or we're PerMonitorV2Aware.
/// </summary>
internal static bool IsScalingRequirementMet
{
get
{
InitializeDpiHelperForWinforms();
return s_isScalingRequirementMet;
}
}
internal static bool IsScalingRequirementMet => IsScalingRequired || s_perMonitorAware;
internal static int DeviceDpi
{
get
{
Initialize();
return (int)s_deviceDpi;
}
}
private static double LogicalToDeviceUnitsScalingFactor
{
get
{
if (s_logicalToDeviceUnitsScalingFactor == 0.0)
{
Initialize();
s_logicalToDeviceUnitsScalingFactor = s_deviceDpi / LogicalDpi;
}
return s_logicalToDeviceUnitsScalingFactor;
}
}
/// <summary>
/// Returns the ratio of <see cref="DeviceDpi"/> to <see cref="LogicalDpi"/>.
/// </summary>
internal static double LogicalToDeviceUnitsScalingFactor => DeviceDpi / LogicalDpi;
private static InterpolationMode InterpolationMode
{
@ -201,14 +157,7 @@ namespace System.Windows.Forms
/// Returns whether scaling is required when converting between logical-device units,
/// if the application opted in the automatic scaling in the .config file.
/// </summary>
public static bool IsScalingRequired
{
get
{
Initialize();
return s_deviceDpi != LogicalDpi;
}
}
public static bool IsScalingRequired => DeviceDpi != LogicalDpi;
/// <summary>
/// scale logical pixel to the factor
@ -221,7 +170,7 @@ namespace System.Windows.Forms
/// <summary>
/// Transforms a horizontal or vertical integer coordinate from logical to device units
/// by scaling it up for current DPI and rounding to nearest integer value
/// by scaling it up for current DPI and rounding to nearest integer value
/// </summary>
/// <param name="value">value in logical units</param>
/// <returns>value in device units</returns>
@ -229,10 +178,11 @@ namespace System.Windows.Forms
{
if (devicePixels == 0)
{
return (int)Math.Round(LogicalToDeviceUnitsScalingFactor * (double)value);
return (int)Math.Round(LogicalToDeviceUnitsScalingFactor * value);
}
double scalingFactor = devicePixels / LogicalDpi;
return (int)Math.Round(scalingFactor * (double)value);
return (int)Math.Round(scalingFactor * value);
}
/// <summary>
@ -243,10 +193,11 @@ namespace System.Windows.Forms
/// <returns>Padding in device units</returns>
public static Padding LogicalToDeviceUnits(Padding logicalPadding, int deviceDpi = 0)
{
return new Padding(LogicalToDeviceUnits(logicalPadding.Left, deviceDpi),
LogicalToDeviceUnits(logicalPadding.Top, deviceDpi),
LogicalToDeviceUnits(logicalPadding.Right, deviceDpi),
LogicalToDeviceUnits(logicalPadding.Bottom, deviceDpi));
return new Padding(
LogicalToDeviceUnits(logicalPadding.Left, deviceDpi),
LogicalToDeviceUnits(logicalPadding.Top, deviceDpi),
LogicalToDeviceUnits(logicalPadding.Right, deviceDpi),
LogicalToDeviceUnits(logicalPadding.Bottom, deviceDpi));
}
/// <summary>

Просмотреть файл

@ -45,7 +45,7 @@ namespace System.Windows.Forms.Tests
graphics.Clip = region;
graphics.Transform = new Matrix(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f);
using (var hdcScope = new DeviceContextHdcScope(graphics, ApplyGraphicsProperties.All))
using (var hdcScope = new DeviceContextHdcScope(graphics))
{
using var regionScope = new Gdi32.RegionScope(hdcScope);
Assert.False(regionScope.IsNull);

Просмотреть файл

@ -1040,8 +1040,6 @@ namespace System.Windows.Forms
{
ApplicationContext.MainForm.Visible = true;
}
DpiHelper.InitializeDpiHelperForWinforms();
}
Form oldForm = _currentForm;

Просмотреть файл

@ -776,12 +776,6 @@ namespace System.Windows.Forms.ButtonInternal
#region Draw Content Helpers
// the DataGridViewButtonCell uses this method
internal static void PaintButtonBackground(WindowsGraphics wg, Rectangle bounds, WindowsBrush background)
{
wg.FillRectangle(background, bounds);
}
internal void PaintButtonBackground(PaintEventArgs e, Rectangle bounds, Brush background)
{
if (background == null)
@ -906,16 +900,6 @@ namespace System.Windows.Forms.ButtonInternal
colors.windowFrame = foreColor;
/* debug * /
colors.buttonFace = Color.Yellow;
colors.buttonShadow = Color.Blue;
colors.highlight = Color.Brown;
colors.lowButtonFace = Color.Beige;
colors.lowHighlight = Color.Cyan;
colors.windowFrame = Color.Red;
colors.windowText = Color.Green;
/ * debug */
if (colors.buttonFace.GetBrightness() < .5)
{
colors.constrastButtonShadow = colors.lowHighlight;
@ -939,7 +923,7 @@ namespace System.Windows.Forms.ButtonInternal
colors.windowText = colors.windowFrame;
}
using var hdc = new DeviceContextHdcScope(graphics, saveState: false);
using var hdc = new DeviceContextHdcScope(graphics, applyGraphicsState: false);
colors.buttonFace = hdc.GetNearestColor(colors.buttonFace);
colors.buttonShadow = hdc.GetNearestColor(colors.buttonShadow);
@ -1620,12 +1604,13 @@ namespace System.Windows.Forms.ButtonInternal
protected virtual Size GetTextSize(Size proposedSize)
{
//set the Prefix field of TextFormatFlags
// Set the Prefix field of TextFormatFlags
proposedSize = LayoutUtils.FlipSizeIf(verticalText, proposedSize);
Size textSize = Size.Empty;
if (useCompatibleTextRendering)
{ // GDI+ text rendering.
{
// GDI+ text rendering.
using (Graphics g = WindowsFormsUtils.CreateMeasurementGraphics())
{
using (StringFormat gdipStringFormat = StringFormat)
@ -1635,10 +1620,12 @@ namespace System.Windows.Forms.ButtonInternal
}
}
else if (!string.IsNullOrEmpty(text))
{ // GDI text rendering (Whidbey feature).
{
// GDI text rendering (Whidbey feature).
textSize = TextRenderer.MeasureText(text, font, proposedSize, TextFormatFlags);
}
//else skip calling MeasureText, it should return 0,0
// Else skip calling MeasureText, it should return 0,0
return LayoutUtils.FlipSizeIf(verticalText, textSize);
}

Просмотреть файл

@ -95,7 +95,7 @@ namespace System.Windows.Forms.ButtonInternal
// Note: PaintEvent.HDC == 0 if GDI+ has used the HDC -- it wouldn't be safe for us
// to use it without enough bookkeeping to negate any performance gain of using GDI.
if (color.A == 255 && e.HDC != IntPtr.Zero)
if (color.A == 255 && !e.HDC.IsNull)
{
if (DisplayInformation.BitsPerPixel > 8)
{

Просмотреть файл

@ -7,7 +7,6 @@
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms.Internal;
using static Interop;
namespace System.Windows.Forms.ButtonInternal
@ -38,7 +37,13 @@ namespace System.Windows.Forms.ButtonInternal
#region Drawing Helpers
protected void DrawCheckFlat(PaintEventArgs e, LayoutData layout, Color checkColor, Color checkBackground, Color checkBorder, ColorData colors)
protected void DrawCheckFlat(
PaintEventArgs e,
LayoutData layout,
Color checkColor,
Color checkBackground,
Color checkBorder,
ColorData colors)
{
Rectangle bounds = layout.checkBounds;
@ -52,10 +57,10 @@ namespace System.Windows.Forms.ButtonInternal
bounds.Height--;
}
using (var hdc = new DeviceContextHdcScope(e.Graphics, ApplyGraphicsProperties.All, saveState: false))
using (var scope = new PaintEventHdcScope(e))
{
using var hpen = new Gdi32.CreatePenScope(checkBorder);
hdc.DrawRectangle(bounds, hpen);
scope.HDC.DrawRectangle(bounds, hpen);
// Now subtract, since the rest of the code is like Everett.
if (layout.options.everettButtonCompat)
@ -74,21 +79,26 @@ namespace System.Windows.Forms.ButtonInternal
}
else
{
using var hdc = new DeviceContextHdcScope(e.Graphics, ApplyGraphicsProperties.All, saveState: false);
using var scope = new PaintEventHdcScope(e);
using var hbrush = new Gdi32.CreateBrushScope(checkBackground);
// Even though we are using GDI here as opposed to GDI+ in Everett, we still need to add 1.
bounds.Width++;
bounds.Height++;
RECT rect = bounds;
User32.FillRect(hdc, ref rect, hbrush);
scope.HDC.FillRectangle(bounds, hbrush);
}
DrawCheckOnly(e, layout, colors, checkColor, checkBackground);
}
// used by DataGridViewCheckBoxCell
internal static void DrawCheckBackground(bool controlEnabled, CheckState controlCheckState, Graphics g, Rectangle bounds, Color checkColor, Color checkBackground, bool disabledColors, ColorData colors)
internal static void DrawCheckBackground(
bool controlEnabled,
CheckState controlCheckState,
Graphics g,
Rectangle bounds,
Color checkBackground,
bool disabledColors)
{
using var hdc = new DeviceContextHdcScope(g);
@ -117,7 +127,13 @@ namespace System.Windows.Forms.ButtonInternal
User32.FillRect(hdc, ref rect, hbrush);
}
protected void DrawCheckBackground(PaintEventArgs e, Rectangle bounds, Color checkColor, Color checkBackground, bool disabledColors, ColorData colors)
protected void DrawCheckBackground(
PaintEventArgs e,
Rectangle bounds,
Color checkColor,
Color checkBackground,
bool disabledColors,
ColorData colors)
{
// Area behind check
@ -127,7 +143,7 @@ namespace System.Windows.Forms.ButtonInternal
}
else
{
DrawCheckBackground(Control.Enabled, Control.CheckState, e.Graphics, bounds, checkColor, checkBackground, disabledColors, colors);
DrawCheckBackground(Control.Enabled, Control.CheckState, e.Graphics, bounds, checkBackground, disabledColors);
}
}
@ -189,22 +205,31 @@ namespace System.Windows.Forms.ButtonInternal
internal static Rectangle DrawPopupBorder(Graphics g, Rectangle r, ColorData colors)
{
using (WindowsGraphics wg = WindowsGraphics.FromGraphics(g))
{
using (WindowsPen high = new WindowsPen(wg.DeviceContext, colors.highlight),
shadow = new WindowsPen(wg.DeviceContext, colors.buttonShadow),
face = new WindowsPen(wg.DeviceContext, colors.buttonFace))
{
wg.DrawLine(high, r.Right - 1, r.Top, r.Right - 1, r.Bottom);
wg.DrawLine(high, r.Left, r.Bottom - 1, r.Right, r.Bottom - 1);
using var hdc = new DeviceContextHdcScope(g);
return DrawPopupBorder(hdc, r, colors);
}
wg.DrawLine(shadow, r.Left, r.Top, r.Left, r.Bottom);
wg.DrawLine(shadow, r.Left, r.Top, r.Right - 1, r.Top);
internal static Rectangle DrawPopupBorder(PaintEventArgs e, Rectangle r, ColorData colors)
{
using var hdc = new PaintEventHdcScope(e);
return DrawPopupBorder(hdc, r, colors);
}
internal static Rectangle DrawPopupBorder(Gdi32.HDC hdc, Rectangle r, ColorData colors)
{
using var high = new Gdi32.CreatePenScope(colors.highlight);
using var shadow = new Gdi32.CreatePenScope(colors.buttonShadow);
using var face = new Gdi32.CreatePenScope(colors.buttonFace);
hdc.DrawLine(high, r.Right - 1, r.Top, r.Right - 1, r.Bottom);
hdc.DrawLine(high, r.Left, r.Bottom - 1, r.Right, r.Bottom - 1);
hdc.DrawLine(shadow, r.Left, r.Top, r.Left, r.Bottom);
hdc.DrawLine(shadow, r.Left, r.Top, r.Right - 1, r.Top);
hdc.DrawLine(face, r.Right - 2, r.Top + 1, r.Right - 2, r.Bottom - 1);
hdc.DrawLine(face, r.Left + 1, r.Bottom - 2, r.Right - 1, r.Bottom - 2);
wg.DrawLine(face, r.Right - 2, r.Top + 1, r.Right - 2, r.Bottom - 1);
wg.DrawLine(face, r.Left + 1, r.Bottom - 2, r.Right - 1, r.Bottom - 2);
}
}
r.Inflate(-1, -1);
return r;
}
@ -237,30 +262,36 @@ namespace System.Windows.Forms.ButtonInternal
protected void DrawCheckBox(PaintEventArgs e, LayoutData layout)
{
Graphics g = e.Graphics;
ButtonState style = GetState();
if (Control.CheckState == CheckState.Indeterminate)
{
if (Application.RenderWithVisualStyles)
{
CheckBoxRenderer.DrawCheckBox(g, new Point(layout.checkBounds.Left, layout.checkBounds.Top), CheckBoxRenderer.ConvertFromButtonState(style, true, Control.MouseIsOver), Control.HandleInternal);
CheckBoxRenderer.DrawCheckBox(
e.Graphics,
new Point(layout.checkBounds.Left, layout.checkBounds.Top),
CheckBoxRenderer.ConvertFromButtonState(style, true, Control.MouseIsOver),
Control.HandleInternal);
}
else
{
ControlPaint.DrawMixedCheckBox(g, layout.checkBounds, style);
ControlPaint.DrawMixedCheckBox(e.Graphics, layout.checkBounds, style);
}
}
else
{
if (Application.RenderWithVisualStyles)
{
CheckBoxRenderer.DrawCheckBox(g, new Point(layout.checkBounds.Left, layout.checkBounds.Top), CheckBoxRenderer.ConvertFromButtonState(style, false, Control.MouseIsOver), Control.HandleInternal);
CheckBoxRenderer.DrawCheckBox(
e.Graphics,
new Point(layout.checkBounds.Left, layout.checkBounds.Top),
CheckBoxRenderer.ConvertFromButtonState(style, false, Control.MouseIsOver),
Control.HandleInternal);
}
else
{
ControlPaint.DrawCheckBox(g, layout.checkBounds, style);
ControlPaint.DrawCheckBox(e.Graphics, layout.checkBounds, style);
}
}
}

Просмотреть файл

@ -99,7 +99,7 @@ namespace System.Windows.Forms.ButtonInternal
protected override LayoutOptions Layout(PaintEventArgs e)
{
LayoutOptions layout = CommonLayout();
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio(e.Graphics));
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio());
layout.shadowedText = false;
return layout;

Просмотреть файл

@ -25,7 +25,7 @@ namespace System.Windows.Forms.ButtonInternal
{
Graphics g = e.Graphics;
ColorData colors = PaintPopupRender(e.Graphics).Calculate();
LayoutData layout = PaintPopupLayout(e, false).Layout();
LayoutData layout = PaintPopupLayout(show3D: false).Layout();
Region original = e.Graphics.Clip;
PaintButtonBackground(e, Control.ClientRectangle, null);
@ -44,7 +44,6 @@ namespace System.Windows.Forms.ButtonInternal
internal override void PaintOver(PaintEventArgs e, CheckState state)
{
Graphics g = e.Graphics;
if (Control.Appearance == Appearance.Button)
{
ButtonPopupAdapter adapter = new ButtonPopupAdapter(Control);
@ -53,15 +52,22 @@ namespace System.Windows.Forms.ButtonInternal
else
{
ColorData colors = PaintPopupRender(e.Graphics).Calculate();
LayoutData layout = PaintPopupLayout(e, true).Layout();
LayoutData layout = PaintPopupLayout(show3D: true).Layout();
Region original = e.Graphics.Clip;
PaintButtonBackground(e, Control.ClientRectangle, null);
PaintImage(e, layout);
DrawCheckBackground(e, layout.checkBounds, colors.windowText, colors.options.highContrast ? colors.buttonFace : colors.highlight, true, colors);
DrawPopupBorder(g, layout.checkBounds, colors);
DrawCheckBackground(
e,
layout.checkBounds,
colors.windowText,
colors.options.highContrast ? colors.buttonFace : colors.highlight,
disabledColors: true,
colors);
DrawPopupBorder(e, layout.checkBounds, colors);
DrawCheckOnly(e, layout, colors, colors.windowText, colors.highlight);
if (!string.IsNullOrEmpty(Control.Text))
@ -86,7 +92,7 @@ namespace System.Windows.Forms.ButtonInternal
{
Graphics g = e.Graphics;
ColorData colors = PaintPopupRender(e.Graphics).Calculate();
LayoutData layout = PaintPopupLayout(e, true).Layout();
LayoutData layout = PaintPopupLayout(show3D: true).Layout();
Region original = e.Graphics.Clip;
PaintButtonBackground(e, Control.ClientRectangle, null);
@ -94,7 +100,7 @@ namespace System.Windows.Forms.ButtonInternal
PaintImage(e, layout);
DrawCheckBackground(e, layout.checkBounds, colors.windowText, colors.buttonFace, true, colors);
DrawPopupBorder(g, layout.checkBounds, colors);
DrawPopupBorder(e, layout.checkBounds, colors);
DrawCheckOnly(e, layout, colors, colors.windowText, colors.buttonFace);
AdjustFocusRectangle(layout);
@ -111,42 +117,51 @@ namespace System.Windows.Forms.ButtonInternal
protected override LayoutOptions Layout(PaintEventArgs e)
{
LayoutOptions layout = PaintPopupLayout(e, /* up = */ true);
LayoutOptions layout = PaintPopupLayout(show3D: true);
Debug.Assert(layout.GetPreferredSizeCore(LayoutUtils.MaxSize)
== PaintPopupLayout(e, /* up = */ false).GetPreferredSizeCore(LayoutUtils.MaxSize),
== PaintPopupLayout(show3D: false).GetPreferredSizeCore(LayoutUtils.MaxSize),
"The state of show3D should not effect PreferredSize");
return layout;
}
internal static LayoutOptions PaintPopupLayout(Graphics g, bool show3D, int checkSize, Rectangle clientRectangle, Padding padding,
bool isDefault, Font font, string text, bool enabled, ContentAlignment textAlign, RightToLeft rtl,
Control control = null)
internal static LayoutOptions PaintPopupLayout(
bool show3D,
int checkSize,
Rectangle clientRectangle,
Padding padding,
bool isDefault,
Font font,
string text,
bool enabled,
ContentAlignment textAlign,
RightToLeft rtl,
Control control = null)
{
LayoutOptions layout = CommonLayout(clientRectangle, padding, isDefault, font, text, enabled, textAlign, rtl);
layout.shadowedText = false;
if (show3D)
{
layout.checkSize = (int)(checkSize * GetDpiScaleRatio(g, control) + 1);
layout.checkSize = (int)(checkSize * GetDpiScaleRatio(control) + 1);
}
else
{
layout.checkSize = (int)(checkSize * GetDpiScaleRatio(g, control));
layout.checkSize = (int)(checkSize * GetDpiScaleRatio(control));
layout.checkPaddingSize = 1;
}
return layout;
}
private LayoutOptions PaintPopupLayout(PaintEventArgs e, bool show3D)
private LayoutOptions PaintPopupLayout(bool show3D)
{
LayoutOptions layout = CommonLayout();
layout.shadowedText = false;
if (show3D)
{
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio(e.Graphics) + 1);
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio() + 1);
}
else
{
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio(e.Graphics));
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio());
layout.checkPaddingSize = 1;
}
return layout;

Просмотреть файл

@ -126,10 +126,13 @@ namespace System.Windows.Forms.ButtonInternal
if (Application.RenderWithVisualStyles)
{
using (Graphics g = WindowsFormsUtils.CreateMeasurementGraphics())
{
layout.checkSize = CheckBoxRenderer.GetGlyphSize(g, CheckBoxRenderer.ConvertFromButtonState(GetState(), true, Control.MouseIsOver), Control.HandleInternal).Width;
}
layout.checkSize = CheckBoxRenderer.GetGlyphSize(
WindowsFormsUtils.GetMeasurementDeviceContext(),
CheckBoxRenderer.ConvertFromButtonState(
GetState(),
true,
Control.MouseIsOver),
Control.HandleInternal).Width;
}
else
{
@ -139,7 +142,7 @@ namespace System.Windows.Forms.ButtonInternal
}
else
{
layout.checkSize = (int)(layout.checkSize * GetDpiScaleRatio(e.Graphics));
layout.checkSize = (int)(layout.checkSize * GetDpiScaleRatio());
}
}

Просмотреть файл

@ -81,12 +81,12 @@ namespace System.Windows.Forms.ButtonInternal
return layout;
}
internal double GetDpiScaleRatio(Graphics g)
internal double GetDpiScaleRatio()
{
return GetDpiScaleRatio(g, Control);
return GetDpiScaleRatio(Control);
}
internal static double GetDpiScaleRatio(Graphics g, Control control)
internal static double GetDpiScaleRatio(Control control)
{
if (DpiHelper.IsPerMonitorV2Awareness
&& control != null && control.IsHandleCreated)
@ -94,12 +94,7 @@ namespace System.Windows.Forms.ButtonInternal
return control._deviceDpi / DpiHelper.LogicalDpi;
}
if (g == null)
{
return 1.0F;
}
return g.DpiX / 96;
return DpiHelper.LogicalToDeviceUnitsScalingFactor;
}
}
}

Просмотреть файл

@ -7,6 +7,7 @@
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms.Internal;
using static Interop;
namespace System.Windows.Forms.ButtonInternal
{
@ -75,7 +76,7 @@ namespace System.Windows.Forms.ButtonInternal
field = SystemColors.Control;
}
double scale = GetDpiScaleRatio(e.Graphics);
double scale = GetDpiScaleRatio();
using (WindowsGraphics wg = WindowsGraphics.FromGraphics(e.Graphics))
{
@ -140,29 +141,36 @@ namespace System.Windows.Forms.ButtonInternal
protected void DrawCheckOnly(PaintEventArgs e, LayoutData layout, Color checkColor, Color checkBackground, bool disabledColors)
{
// check
//
if (Control.Checked)
if (!Control.Checked)
{
if (!Control.Enabled && disabledColors)
{
checkColor = SystemColors.ControlDark;
}
double scale = GetDpiScaleRatio(e.Graphics);
using (WindowsGraphics wg = WindowsGraphics.FromGraphics(e.Graphics))
{
using (WindowsBrush brush = new WindowsSolidBrush(wg.DeviceContext, checkColor))
{
// circle drawing doesn't work at this size
int offset = 5;
Rectangle vCross = new Rectangle(layout.checkBounds.X + GetScaledNumber(offset, scale), layout.checkBounds.Y + GetScaledNumber(offset - 1, scale), GetScaledNumber(2, scale), GetScaledNumber(4, scale));
wg.FillRectangle(brush, vCross);
Rectangle hCross = new Rectangle(layout.checkBounds.X + GetScaledNumber(offset - 1, scale), layout.checkBounds.Y + GetScaledNumber(offset, scale), GetScaledNumber(4, scale), GetScaledNumber(2, scale));
wg.FillRectangle(brush, hCross);
}
}
return;
}
if (!Control.Enabled && disabledColors)
{
checkColor = SystemColors.ControlDark;
}
double scale = GetDpiScaleRatio();
using var paintScope = new PaintEventHdcScope(e);
Gdi32.HDC hdc = paintScope.HDC;
using var brush = new Gdi32.CreateBrushScope(checkColor);
// Circle drawing doesn't work at this size
int offset = 5;
Rectangle vCross = new Rectangle(
layout.checkBounds.X + GetScaledNumber(offset, scale),
layout.checkBounds.Y + GetScaledNumber(offset - 1, scale),
GetScaledNumber(2, scale),
GetScaledNumber(4, scale));
hdc.FillRectangle(vCross, brush);
Rectangle hCross = new Rectangle(
layout.checkBounds.X + GetScaledNumber(offset - 1, scale),
layout.checkBounds.Y + GetScaledNumber(offset, scale),
GetScaledNumber(4, scale), GetScaledNumber(2, scale));
hdc.FillRectangle(hCross, brush);
}
protected ButtonState GetState()
@ -193,8 +201,6 @@ namespace System.Windows.Forms.ButtonInternal
protected void DrawCheckBox(PaintEventArgs e, LayoutData layout)
{
Graphics g = e.Graphics;
Rectangle check = layout.checkBounds;
if (!Application.RenderWithVisualStyles)
{
@ -205,11 +211,15 @@ namespace System.Windows.Forms.ButtonInternal
if (Application.RenderWithVisualStyles)
{
RadioButtonRenderer.DrawRadioButton(g, new Point(check.Left, check.Top), RadioButtonRenderer.ConvertFromButtonState(style, Control.MouseIsOver), Control.HandleInternal);
RadioButtonRenderer.DrawRadioButton(
e.Graphics,
new Point(check.Left, check.Top),
RadioButtonRenderer.ConvertFromButtonState(style, Control.MouseIsOver),
Control.HandleInternal);
}
else
{
ControlPaint.DrawRadioButton(g, check, style);
ControlPaint.DrawRadioButton(e.Graphics, check, style);
}
}

Просмотреть файл

@ -97,7 +97,7 @@ namespace System.Windows.Forms.ButtonInternal
protected override LayoutOptions Layout(PaintEventArgs e)
{
LayoutOptions layout = CommonLayout();
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio(e.Graphics));
layout.checkSize = (int)(flatCheckSize * GetDpiScaleRatio());
layout.shadowedText = false;
return layout;

Просмотреть файл

@ -68,8 +68,6 @@ namespace System.Windows.Forms.ButtonInternal
return new ButtonStandardAdapter(Control);
}
#region Temp
protected override LayoutOptions Layout(PaintEventArgs e)
{
LayoutOptions layout = CommonLayout();
@ -79,19 +77,17 @@ namespace System.Windows.Forms.ButtonInternal
if (Application.RenderWithVisualStyles)
{
ButtonBase b = Control;
using (Graphics g = WindowsFormsUtils.CreateMeasurementGraphics())
{
layout.checkSize = RadioButtonRenderer.GetGlyphSize(g, RadioButtonRenderer.ConvertFromButtonState(GetState(), b.MouseIsOver), b.HandleInternal).Width;
}
layout.checkSize = RadioButtonRenderer.GetGlyphSize(
WindowsFormsUtils.GetMeasurementDeviceContext(),
RadioButtonRenderer.ConvertFromButtonState(GetState(), b.MouseIsOver),
b.HandleInternal).Width;
}
else
{
layout.checkSize = (int)(layout.checkSize * GetDpiScaleRatio(e.Graphics));
layout.checkSize = (int)(layout.checkSize * GetDpiScaleRatio());
}
return layout;
}
#endregion
}
}

Просмотреть файл

@ -109,8 +109,9 @@ namespace System.Windows.Forms
{
InitializeRenderer((int)state);
visualStyleRenderer.DrawBackground(g, bounds, handle);
contentBounds = visualStyleRenderer.GetBackgroundContentRectangle(g, bounds);
using var hdc = new DeviceContextHdcScope(g);
visualStyleRenderer.DrawBackground(hdc, bounds, handle);
contentBounds = visualStyleRenderer.GetBackgroundContentRectangle(hdc, bounds);
}
else
{
@ -137,9 +138,14 @@ namespace System.Windows.Forms
/// </summary>
public static void DrawButton(Graphics g, Rectangle bounds, string buttonText, Font font, bool focused, PushButtonState state)
{
DrawButton(g, bounds, buttonText, font,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine,
focused, state);
DrawButton(
g,
bounds,
buttonText,
font,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine,
focused,
state);
}
/// <summary>

Просмотреть файл

@ -6,6 +6,7 @@
using System.Drawing;
using System.Windows.Forms.VisualStyles;
using static Interop;
namespace System.Windows.Forms
{
@ -93,7 +94,8 @@ namespace System.Windows.Forms
{
InitializeRenderer((int)state);
visualStyleRenderer.DrawBackground(g, glyphBounds, hWnd);
using var hdc = new DeviceContextHdcScope(g);
visualStyleRenderer.DrawBackground(hdc, glyphBounds, hWnd);
}
else
{
@ -173,7 +175,17 @@ namespace System.Windows.Forms
/// <summary>
/// Renders a CheckBox control.
/// </summary>
public static void DrawCheckBox(Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, CheckBoxState state)
public static void DrawCheckBox(
Graphics g,
Point glyphLocation,
Rectangle textBounds,
string checkBoxText,
Font font,
TextFormatFlags flags,
Image image,
Rectangle imageBounds,
bool focused,
CheckBoxState state)
{
Rectangle glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(g, state));
Color textColor;
@ -214,17 +226,26 @@ namespace System.Windows.Forms
/// Returns the size of the CheckBox glyph.
/// </summary>
public static Size GetGlyphSize(Graphics g, CheckBoxState state)
{
return GetGlyphSize(g, state, IntPtr.Zero);
}
=> GetGlyphSize(g, state, default);
internal static Size GetGlyphSize(Graphics g, CheckBoxState state, IntPtr hWnd)
{
if (!RenderWithVisualStyles)
{
return new Size(13, 13);
}
using var hdc = new DeviceContextHdcScope(g);
return GetGlyphSize(hdc, state, IntPtr.Zero);
}
internal static Size GetGlyphSize(Gdi32.HDC hdc, CheckBoxState state, IntPtr hWnd)
{
if (RenderWithVisualStyles)
{
InitializeRenderer((int)state);
return visualStyleRenderer.GetPartSize(g, ThemeSizeType.Draw, hWnd);
return visualStyleRenderer.GetPartSize(hdc, ThemeSizeType.Draw, hWnd);
}
return new Size(13, 13);

Просмотреть файл

@ -594,12 +594,15 @@ namespace System.Windows.Forms
// the Renderer might return a different size in different DPI modes..
if (Application.RenderWithVisualStyles)
{
VisualStyles.CheckBoxState cbState = CheckBoxRenderer.ConvertFromButtonState(state, false, ((e.State & DrawItemState.HotLight) == DrawItemState.HotLight));
idealCheckSize = (int)(CheckBoxRenderer.GetGlyphSize(e.Graphics, cbState, HandleInternal)).Width;
VisualStyles.CheckBoxState cbState = CheckBoxRenderer.ConvertFromButtonState(
state,
isMixed: false,
(e.State & DrawItemState.HotLight) == DrawItemState.HotLight);
idealCheckSize = CheckBoxRenderer.GetGlyphSize(e.Graphics, cbState, HandleInternal).Width;
}
// Determine bounds for the checkbox
//
int centeringFactor = Math.Max((height - idealCheckSize) / 2, 0);
// Keep the checkbox within the item's upper and lower bounds

Просмотреть файл

@ -6,6 +6,7 @@
using System.Drawing;
using System.Windows.Forms.VisualStyles;
using static Interop;
namespace System.Windows.Forms
{
@ -120,17 +121,18 @@ namespace System.Windows.Forms
/// </summary>
public static void DrawDropDownButton(Graphics g, Rectangle bounds, ComboBoxState state)
{
DrawDropDownButtonForHandle(g, bounds, state, IntPtr.Zero);
using var hdc = new DeviceContextHdcScope(g);
DrawDropDownButtonForHandle(hdc, bounds, state, IntPtr.Zero);
}
/// <summary>
/// Renders a ComboBox drop-down button in per-monitor scenario.
/// </summary>
/// <param name="g">graphics object</param>
/// <param name="hdc">device context</param>
/// <param name="bounds">dropdown button bounds</param>
/// <param name="state"> state</param>
/// <param name="handle"> handle of the control</param>
internal static void DrawDropDownButtonForHandle(Graphics g, Rectangle bounds, ComboBoxState state, IntPtr handle)
internal static void DrawDropDownButtonForHandle(Gdi32.HDC hdc, Rectangle bounds, ComboBoxState state, IntPtr handle)
{
if (visualStyleRenderer == null)
{
@ -141,7 +143,7 @@ namespace System.Windows.Forms
visualStyleRenderer.SetParameters(ComboBoxElement.ClassName, ComboBoxElement.Part, (int)state);
}
visualStyleRenderer.DrawBackground(g, bounds, handle);
visualStyleRenderer.DrawBackground(hdc, bounds, handle);
}
}
}

Просмотреть файл

@ -320,12 +320,12 @@ namespace System.Windows.Forms
// Screen Dpi
if (DpiHelper.IsPerMonitorV2Awareness)
{
_currentAutoScaleDimensions = new SizeF((float)_deviceDpi, (float)_deviceDpi);
_currentAutoScaleDimensions = new SizeF(_deviceDpi, _deviceDpi);
}
else
{
// this DPI value comes from the primary monitor.
_currentAutoScaleDimensions = WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.Dpi;
_currentAutoScaleDimensions = new SizeF(DpiHelper.DeviceDpi, DpiHelper.DeviceDpi);
}
break;

Просмотреть файл

@ -355,7 +355,6 @@ namespace System.Windows.Forms
#endif
Properties = new PropertyStore();
DpiHelper.InitializeDpiHelperForWinforms();
// Initialize DPI to the value on the primary screen, we will have the correct value when the Handle is created.
_deviceDpi = DpiHelper.DeviceDpi;
@ -5277,7 +5276,7 @@ namespace System.Windows.Forms
using Bitmap image = new Bitmap(width, height, bitmap.PixelFormat);
using Graphics g = Graphics.FromImage(image);
using var hDc = new DeviceContextHdcScope(g, saveState: false);
using var hDc = new DeviceContextHdcScope(g, applyGraphicsState: false);
// Send the WM_PRINT message.
User32.SendMessageW(
@ -5288,7 +5287,7 @@ namespace System.Windows.Forms
// Now BLT the result to the destination bitmap.
using Graphics destGraphics = Graphics.FromImage(bitmap);
using var desthDC = new DeviceContextHdcScope(destGraphics, saveState: false);
using var desthDC = new DeviceContextHdcScope(destGraphics, applyGraphicsState: false);
Gdi32.BitBlt(
desthDC,
targetBounds.X,
@ -7497,39 +7496,19 @@ namespace System.Windows.Forms
}
else
{
Message m;
bool releaseDC = false;
IntPtr hdc = IntPtr.Zero;
if (!(e is PrintPaintEventArgs ppev))
{
IntPtr flags = (IntPtr)(User32.PRF.CHILDREN | User32.PRF.CLIENT | User32.PRF.ERASEBKGND | User32.PRF.NONCLIENT);
hdc = e.HDC;
if (hdc == IntPtr.Zero)
{
// a manually created paintevent args
hdc = e.Graphics.GetHdc();
releaseDC = true;
}
m = Message.Create(Handle, User32.WM.PRINTCLIENT, hdc, flags);
using var scope = new PaintEventHdcScope(e);
Message m = Message.Create(Handle, User32.WM.PRINTCLIENT, (IntPtr)scope.HDC, flags);
DefWndProc(ref m);
}
else
{
m = ppev.Message;
}
try
{
Message m = ppev.Message;
DefWndProc(ref m);
}
finally
{
if (releaseDC)
{
e.Graphics.ReleaseHdcInternal(hdc);
}
}
}
}
@ -8488,7 +8467,7 @@ namespace System.Windows.Forms
Point scrollLocation = scrollOffset;
if (this is ScrollableControl scrollControl && scrollLocation != Point.Empty)
{
scrollLocation = ((ScrollableControl)this).AutoScrollPosition;
scrollLocation = scrollControl.AutoScrollPosition;
}
if (ControlPaint.IsImageTransparent(BackgroundImage))
@ -8510,38 +8489,23 @@ namespace System.Windows.Forms
// use GDI because it is faster for simple things than creating
// a graphics object, brush, etc. Also, we may be able to
// use a system brush, avoiding the brush create altogether.
//
Color color = backColor;
// Note: PaintEvent.HDC == 0 if GDI+ has used the HDC -- it wouldn't be safe for us
// to use it without enough bookkeeping to negate any performance gain of using GDI.
if (color.A == 255)
{
if (e.HDC != IntPtr.Zero && DisplayInformation.BitsPerPixel > 8)
{
Gdi32.HDC hdc = (Gdi32.HDC)e.HDC;
using var hbrush = new Gdi32.CreateBrushScope(hdc.GetNearestColor(color));
hdc.FillRectangle(rectangle, hbrush);
}
else
{
using var hdc = new DeviceContextHdcScope(e.Graphics, ApplyGraphicsProperties.All, saveState: false);
using var hbrush = new Gdi32.CreateBrushScope(hdc.GetNearestColor(color));
hdc.FillRectangle(rectangle, hbrush);
}
using var scope = new PaintEventHdcScope(e);
Gdi32.HDC hdc = scope.HDC;
using var hbrush = new Gdi32.CreateBrushScope(hdc.GetNearestColor(color));
hdc.FillRectangle(rectangle, hbrush);
}
else
else if (color.A > 0)
{
// don't paint anything from 100% transparent background
if (color.A > 0)
{
// Color has some transparency or we have no HDC, so we must
// fall back to using GDI+.
using (Brush brush = new SolidBrush(color))
{
e.Graphics.FillRectangle(brush, rectangle);
}
}
// Color has some transparency (but not completely transparent) use GDI+.
using Brush brush = new SolidBrush(color);
e.Graphics.FillRectangle(brush, rectangle);
}
}
@ -11689,6 +11653,7 @@ namespace System.Windows.Forms
private void WmDisplayChange(ref Message m)
{
BufferedGraphicsManager.Current.Invalidate();
DefWndProc(ref m);
}

Просмотреть файл

@ -355,33 +355,6 @@ namespace System.Windows.Forms
return Gdi32.CreateBrushIndirect(ref lb);
}
// roughly the same code as in Graphics.cs
internal static void CopyPixels(IntPtr sourceHwnd, IDeviceContext targetDC, Point sourceLocation, Point destinationLocation, Size blockRegionSize, CopyPixelOperation copyPixelOperation)
{
int destWidth = blockRegionSize.Width;
int destHeight = blockRegionSize.Height;
using var dc = new User32.GetDcScope(sourceHwnd);
using var targetHDC = new DeviceContextHdcScope(targetDC, saveState: false);
BOOL result = Gdi32.BitBlt(
targetHDC,
destinationLocation.X,
destinationLocation.Y,
destWidth,
destHeight,
dc,
sourceLocation.X,
sourceLocation.Y,
(Gdi32.ROP)copyPixelOperation);
// Zero result indicates a win32 exception has been thrown
if (!result.IsTrue())
{
throw new Win32Exception();
}
}
/// <summary>
/// Draws a border of the specified style and color to the given graphics.
/// </summary>
@ -1092,7 +1065,7 @@ namespace System.Windows.Forms
}
// Get Win32 dc with Graphics properties applied to it.
using var hdc = new DeviceContextHdcScope(graphics, ApplyGraphicsProperties.All, saveState: false);
using var hdc = new DeviceContextHdcScope(graphics);
User32.DrawEdge(hdc, ref rc, edge, flags);
}
@ -1424,7 +1397,7 @@ namespace System.Windows.Forms
using (Graphics g2 = Graphics.FromImage(bitmap))
{
g2.Clear(Color.Transparent);
using var dc = new DeviceContextHdcScope(g2, saveState: false);
using var dc = new DeviceContextHdcScope(g2, applyGraphicsState: false);
User32.DrawFrameControl(dc, ref rcCheck, User32.DFC.MENU, User32.DFCS.MENUCHECK);
}
@ -1511,40 +1484,36 @@ namespace System.Windows.Forms
}
RECT rcFrame = new RECT(0, 0, width, height);
using (Bitmap bitmap = new Bitmap(width, height))
using Bitmap bitmap = new Bitmap(width, height);
using Graphics g2 = Graphics.FromImage(bitmap);
g2.Clear(Color.Transparent);
using (var hdc = new DeviceContextHdcScope(g2, applyGraphicsState: false))
{
using (Graphics g2 = Graphics.FromImage(bitmap))
// Get Win32 dc with Graphics properties applied to it.
User32.DrawFrameControl(hdc, ref rcFrame, kind, state);
}
if (foreColor == Color.Empty || backColor == Color.Empty)
{
graphics.DrawImage(bitmap, x, y);
}
else
{
// Replace black/white with foreColor/backColor.
ImageAttributes attrs = new ImageAttributes();
ColorMap cm1 = new ColorMap
{
g2.Clear(Color.Transparent);
using (var hdc = new DeviceContextHdcScope(g2, saveState: false))
{
// Get Win32 dc with Graphics properties applied to it.
User32.DrawFrameControl(hdc, ref rcFrame, kind, state);
}
if (foreColor == Color.Empty || backColor == Color.Empty)
{
graphics.DrawImage(bitmap, x, y);
}
else
{
// Replace black/white with foreColor/backColor.
ImageAttributes attrs = new ImageAttributes();
ColorMap cm1 = new ColorMap
{
OldColor = Color.Black,
NewColor = foreColor
};
ColorMap cm2 = new ColorMap
{
OldColor = Color.White,
NewColor = backColor
};
attrs.SetRemapTable(new ColorMap[2] { cm1, cm2 }, ColorAdjustType.Bitmap);
graphics.DrawImage(bitmap, new Rectangle(x, y, width, height), 0, 0, width, height, GraphicsUnit.Pixel, attrs, null, IntPtr.Zero);
}
}
OldColor = Color.Black,
NewColor = foreColor
};
ColorMap cm2 = new ColorMap
{
OldColor = Color.White,
NewColor = backColor
};
attrs.SetRemapTable(new ColorMap[2] { cm1, cm2 }, ColorAdjustType.Bitmap);
graphics.DrawImage(bitmap, new Rectangle(x, y, width, height), 0, 0, width, height, GraphicsUnit.Pixel, attrs, null, IntPtr.Zero);
}
}

Просмотреть файл

@ -780,40 +780,17 @@ namespace System.Windows.Forms
DataGridView.Enabled).Calculate();
using var hdc = new DeviceContextHdcScope(g);
using (WindowsGraphics wg = WindowsGraphics.FromHdc(hdc))
{
WindowsBrush windowsBrush;
if (colors.options.highContrast)
{
windowsBrush = new WindowsSolidBrush(wg.DeviceContext, colors.buttonShadow);
}
else
{
windowsBrush = new WindowsSolidBrush(wg.DeviceContext, colors.lowHighlight);
}
try
{
ButtonBaseAdapter.PaintButtonBackground(wg, valBounds, windowsBrush);
}
finally
{
windowsBrush.Dispose();
}
}
using var hbrush = new Gdi32.CreateBrushScope(
colors.options.highContrast ? colors.buttonShadow : colors.lowHighlight);
hdc.FillRectangle(valBounds, hbrush);
}
else if (DataGridView.MouseEnteredCellAddress.Y == rowIndex &&
DataGridView.MouseEnteredCellAddress.X == ColumnIndex &&
mouseInContentBounds)
{
using var hdc = new DeviceContextHdcScope(g);
using (WindowsGraphics wg = WindowsGraphics.FromHdc(hdc))
{
Color mouseOverBackColor = SystemColors.ControlDark;
using (WindowsBrush windowBrush = new WindowsSolidBrush(wg.DeviceContext, mouseOverBackColor))
{
ButtonBaseAdapter.PaintButtonBackground(wg, valBounds, windowBrush);
}
}
using var hbrush = new Gdi32.CreateBrushScope(SystemColors.ControlDark);
hdc.FillRectangle(valBounds, hbrush);
}
}
}

Просмотреть файл

@ -718,6 +718,7 @@ namespace System.Windows.Forms
checkBoxSize.Height -= 2;
break;
}
switch (freeDimension)
{
case DataGridViewFreeDimension.Width:
@ -753,6 +754,7 @@ namespace System.Windows.Forms
checkBoxSize = SystemInformation.Border3DSize.Width * 2 + 9 + 2 * DATAGRIDVIEWCHECKBOXCELL_margin;
break;
}
switch (freeDimension)
{
case DataGridViewFreeDimension.Width:
@ -1390,21 +1392,22 @@ namespace System.Windows.Forms
if ((ButtonState & (ButtonState.Pushed | ButtonState.Checked)) != 0)
{
// paint down
ButtonBaseAdapter.LayoutOptions options = ButtonInternal.CheckBoxPopupAdapter.PaintPopupLayout(g,
true /*show3D*/,
checkBoxSize.Width,
checkBounds,
Padding.Empty,
false,
cellStyle.Font,
string.Empty,
DataGridView.Enabled,
DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
DataGridView.RightToLeft);
ButtonBaseAdapter.LayoutOptions options = CheckBoxPopupAdapter.PaintPopupLayout(
show3D: true,
checkBoxSize.Width,
checkBounds,
Padding.Empty,
isDefault: false,
cellStyle.Font,
string.Empty,
DataGridView.Enabled,
DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
DataGridView.RightToLeft);
options.everettButtonCompat = false;
ButtonBaseAdapter.LayoutData layout = options.Layout();
if (paint && DataGridViewCell.PaintContentForeground(paintParts))
if (paint && PaintContentForeground(paintParts))
{
ButtonBaseAdapter.ColorData colors = ButtonBaseAdapter.PaintPopupRender(g,
cellStyle.ForeColor,
@ -1414,10 +1417,8 @@ namespace System.Windows.Forms
checkState,
g,
layout.checkBounds,
colors.windowText,
colors.buttonFace,
true /*disabledColors*/,
colors);
disabledColors: true);
CheckBoxBaseAdapter.DrawPopupBorder(g, layout.checkBounds, colors);
CheckBoxBaseAdapter.DrawCheckOnly(checkBoxSize.Width,
checkState == CheckState.Checked || checkState == CheckState.Indeterminate,
@ -1437,34 +1438,35 @@ namespace System.Windows.Forms
{
// paint over
ButtonBaseAdapter.LayoutOptions options = ButtonInternal.CheckBoxPopupAdapter.PaintPopupLayout(g,
true /*show3D*/,
checkBoxSize.Width,
checkBounds,
Padding.Empty,
false,
cellStyle.Font,
string.Empty,
DataGridView.Enabled,
DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
DataGridView.RightToLeft);
ButtonBaseAdapter.LayoutOptions options = CheckBoxPopupAdapter.PaintPopupLayout(
show3D: true,
checkBoxSize.Width,
checkBounds,
Padding.Empty,
isDefault: false,
cellStyle.Font,
string.Empty,
DataGridView.Enabled,
DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
DataGridView.RightToLeft);
options.everettButtonCompat = false;
ButtonBaseAdapter.LayoutData layout = options.Layout();
if (paint && DataGridViewCell.PaintContentForeground(paintParts))
if (paint && PaintContentForeground(paintParts))
{
ButtonBaseAdapter.ColorData colors = ButtonBaseAdapter.PaintPopupRender(g,
cellStyle.ForeColor,
cellStyle.BackColor,
DataGridView.Enabled).Calculate();
CheckBoxBaseAdapter.DrawCheckBackground(DataGridView.Enabled,
checkState,
g,
layout.checkBounds,
colors.windowText,
colors.options.highContrast ? colors.buttonFace : colors.highlight,
true /*disabledColors*/,
colors);
CheckBoxBaseAdapter.DrawCheckBackground(
DataGridView.Enabled,
checkState,
g,
layout.checkBounds,
colors.options.highContrast ? colors.buttonFace : colors.highlight,
disabledColors: true);
CheckBoxBaseAdapter.DrawPopupBorder(g, layout.checkBounds, colors);
CheckBoxBaseAdapter.DrawCheckOnly(checkBoxSize.Width,
checkState == CheckState.Checked || checkState == CheckState.Indeterminate,
@ -1481,17 +1483,17 @@ namespace System.Windows.Forms
else
{
// paint up
ButtonBaseAdapter.LayoutOptions options = ButtonInternal.CheckBoxPopupAdapter.PaintPopupLayout(g,
false /*show3D*/,
checkBoxSize.Width,
checkBounds,
Padding.Empty,
false,
cellStyle.Font,
string.Empty,
DataGridView.Enabled,
DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
DataGridView.RightToLeft);
ButtonBaseAdapter.LayoutOptions options = CheckBoxPopupAdapter.PaintPopupLayout(
show3D: false,
checkBoxSize.Width,
checkBounds,
Padding.Empty,
false,
cellStyle.Font,
string.Empty,
DataGridView.Enabled,
DataGridViewUtilities.ComputeDrawingContentAlignmentForCellStyleAlignment(cellStyle.Alignment),
DataGridView.RightToLeft);
options.everettButtonCompat = false;
ButtonBaseAdapter.LayoutData layout = options.Layout();
@ -1502,14 +1504,14 @@ namespace System.Windows.Forms
cellStyle.ForeColor,
cellStyle.BackColor,
DataGridView.Enabled).Calculate();
CheckBoxBaseAdapter.DrawCheckBackground(DataGridView.Enabled,
checkState,
g,
layout.checkBounds,
colors.windowText,
colors.options.highContrast ? colors.buttonFace : colors.highlight,
true /*disabledColors*/,
colors);
CheckBoxBaseAdapter.DrawCheckBackground(
DataGridView.Enabled,
checkState,
g,
layout.checkBounds,
colors.options.highContrast ? colors.buttonFace : colors.highlight,
disabledColors: true);
ButtonBaseAdapter.DrawFlatBorder(g, layout.checkBounds, colors.buttonShadow);
CheckBoxBaseAdapter.DrawCheckOnly(checkBoxSize.Width,
checkState == CheckState.Checked || checkState == CheckState.Indeterminate,

Просмотреть файл

@ -1426,8 +1426,8 @@ namespace System.Windows.Forms
}
else
{
using var hdc = new DeviceContextHdcScope(e.Graphics, saveState: false);
color = hdc.GetNearestColor(Enabled ? ForeColor : DisabledColor);
using var scope = new PaintEventHdcScope(e);
color = scope.HDC.GetNearestColor(Enabled ? ForeColor : DisabledColor);
}
// Do actual drawing

Просмотреть файл

@ -1309,9 +1309,11 @@ namespace System.Windows.Forms
}
else
{
using var hdc = new DeviceContextHdcScope(e.Graphics, saveState: false);
foreColor = ColorTranslator.FromWin32(
Gdi32.GetNearestColor(hdc, ColorTranslator.ToWin32(DisabledColor)));
using (var scope = new PaintEventHdcScope(e))
{
foreColor = ColorTranslator.FromWin32(
Gdi32.GetNearestColor(scope.HDC, ColorTranslator.ToWin32(DisabledColor)));
}
Rectangle clientRectWidthPadding = ClientRectWithPadding;
@ -1501,9 +1503,11 @@ namespace System.Windows.Forms
brushColor = linkBrush.Color;
}
using var hdc = new DeviceContextHdcScope(g, saveState: false);
brushColor = ColorTranslator.FromWin32(
Gdi32.GetNearestColor(hdc, ColorTranslator.ToWin32(brushColor)));
using (var hdc = new DeviceContextHdcScope(g))
{
brushColor = ColorTranslator.FromWin32(
Gdi32.GetNearestColor(hdc, ColorTranslator.ToWin32(brushColor)));
}
Rectangle clientRectWithPadding = ClientRectWithPadding;
TextRenderer.DrawText(
@ -1562,9 +1566,12 @@ namespace System.Windows.Forms
}
else
{
using var hdc = new DeviceContextHdcScope(g, saveState: false);
Color color = ColorTranslator.FromWin32(
Gdi32.GetNearestColor(hdc, ColorTranslator.ToWin32(foreBrush.Color)));
Color color;
using (var hdc = new DeviceContextHdcScope(g, applyGraphicsState: false))
{
color = ColorTranslator.FromWin32(
Gdi32.GetNearestColor(hdc, ColorTranslator.ToWin32(foreBrush.Color)));
}
Rectangle clientRectWithPadding = ClientRectWithPadding;
TextRenderer.DrawText(

Просмотреть файл

@ -7,8 +7,6 @@
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using static Interop;
namespace System.Windows.Forms
@ -70,7 +68,9 @@ namespace System.Windows.Forms
/// HDC, or the GDI+ Graphics object has been created (meaning GDI+ now owns the
/// HDC), 0 is returned.
/// </summary>
internal IntPtr HDC => _graphics == null ? (IntPtr)_dc : IntPtr.Zero;
internal Gdi32.HDC HDC => _graphics == null ? _dc : default;
internal bool IsGraphicsCreated => _graphics != null;
/// <summary>
/// Gets the <see cref='Drawing.Graphics'/> object used to paint.

Просмотреть файл

@ -340,16 +340,16 @@ namespace System.Windows.Forms
{
using (Graphics g = WindowsFormsUtils.CreateMeasurementGraphics())
{
rgbTable[ProfessionalColorTable.KnownColors.ButtonPressedHighlight] = GetAlphaBlendedColor(g, SystemColors.Window, GetAlphaBlendedColor(g, SystemColors.Highlight, SystemColors.Window, 160), 50);
rgbTable[ProfessionalColorTable.KnownColors.ButtonCheckedHighlight] = GetAlphaBlendedColor(g, SystemColors.Window, GetAlphaBlendedColor(g, SystemColors.Highlight, SystemColors.Window, 80), 20);
rgbTable[ProfessionalColorTable.KnownColors.ButtonSelectedHighlight] = rgbTable[ProfessionalColorTable.KnownColors.ButtonCheckedHighlight];
rgbTable[KnownColors.ButtonPressedHighlight] = GetAlphaBlendedColor(g, SystemColors.Window, GetAlphaBlendedColor(g, SystemColors.Highlight, SystemColors.Window, 160), 50);
rgbTable[KnownColors.ButtonCheckedHighlight] = GetAlphaBlendedColor(g, SystemColors.Window, GetAlphaBlendedColor(g, SystemColors.Highlight, SystemColors.Window, 80), 20);
rgbTable[KnownColors.ButtonSelectedHighlight] = rgbTable[KnownColors.ButtonCheckedHighlight];
}
}
else
{
rgbTable[ProfessionalColorTable.KnownColors.ButtonPressedHighlight] = SystemColors.Highlight;
rgbTable[ProfessionalColorTable.KnownColors.ButtonCheckedHighlight] = SystemColors.ControlLight;
rgbTable[ProfessionalColorTable.KnownColors.ButtonSelectedHighlight] = SystemColors.ControlLight;
rgbTable[KnownColors.ButtonPressedHighlight] = SystemColors.Highlight;
rgbTable[KnownColors.ButtonCheckedHighlight] = SystemColors.ControlLight;
rgbTable[KnownColors.ButtonSelectedHighlight] = SystemColors.ControlLight;
}
}

Просмотреть файл

@ -103,13 +103,14 @@ namespace System.Windows.Forms.PropertyGridInternal
{
pevent.Graphics.FillRectangle(SystemBrushes.Window, dropDownButtonRect);
}
if (!DpiHelper.IsScalingRequirementMet)
using (var scope = new PaintEventHdcScope(pevent))
{
ComboBoxRenderer.DrawDropDownButton(pevent.Graphics, dropDownButtonRect, cbState);
}
else
{
ComboBoxRenderer.DrawDropDownButtonForHandle(pevent.Graphics, dropDownButtonRect, cbState, HandleInternal);
ComboBoxRenderer.DrawDropDownButtonForHandle(
scope.HDC,
dropDownButtonRect,
cbState,
DpiHelper.IsScalingRequirementMet ? HandleInternal : IntPtr.Zero);
}
// Redraw focus cues

Просмотреть файл

@ -2205,15 +2205,9 @@ namespace System.Windows.Forms.PropertyGridInternal
return;
}
VisualStyleElement element = null;
if (fExpanded)
{
element = VisualStyleElement.ExplorerTreeView.Glyph.Opened;
}
else
{
element = VisualStyleElement.ExplorerTreeView.Glyph.Closed;
}
VisualStyleElement element = fExpanded
? VisualStyleElement.ExplorerTreeView.Glyph.Opened
: VisualStyleElement.ExplorerTreeView.Glyph.Closed;
// Invert color if it is not overriden by developer.
if (colorInversionNeededInHC)
@ -2228,7 +2222,9 @@ namespace System.Windows.Forms.PropertyGridInternal
}
VisualStyleRenderer explorerTreeRenderer = new VisualStyleRenderer(element);
explorerTreeRenderer.DrawBackground(g, outline, handle);
using var hdc = new DeviceContextHdcScope(g);
explorerTreeRenderer.DrawBackground(hdc, outline, handle);
}
}
@ -2390,8 +2386,7 @@ namespace System.Windows.Forms.PropertyGridInternal
int textWidth = GetValueTextWidth(strValue, g, f);
bool doToolTip = false;
// To check if text contains multiple lines
//
// Check if text contains multiple lines
if (textWidth >= rect.Width || GetMultipleLines(strValue))
{
doToolTip = true;
@ -2404,8 +2399,6 @@ namespace System.Windows.Forms.PropertyGridInternal
// Do actual drawing
//strValue = ReplaceCRLF(strValue);
// bump the text down 2 pixels and over 1 pixel.
if ((paintFlags & PaintValueFlags.PaintInPlace) != PaintValueFlags.None)
{
@ -2419,7 +2412,7 @@ namespace System.Windows.Forms.PropertyGridInternal
Matrix m = g.Transform;
using var hdc = new DeviceContextHdcScope(g, saveState: false);
using var hdc = new DeviceContextHdcScope(g);
RECT lpRect = new Rectangle(rect.X + (int)m.OffsetX + 2, rect.Y + (int)m.OffsetY - 1, rect.Width - 4, rect.Height);
Gdi32.HGDIOBJ hfont = (Gdi32.HGDIOBJ)GetHfont(valueModified);
@ -2432,7 +2425,7 @@ namespace System.Windows.Forms.PropertyGridInternal
{
oldTextColor = Gdi32.SetTextColor(hdc, COLORREF.RgbToCOLORREF(textColor.ToArgb()));
oldBkColor = Gdi32.SetBkColor(hdc, COLORREF.RgbToCOLORREF(bkColor.ToArgb()));
hfont = Gdi32.SelectObject(hdc, hfont);
using var fontSelection = new Gdi32.SelectObjectScope(hdc, hfont);
User32.DT format = User32.DT.EDITCONTROL | User32.DT.EXPANDTABS | User32.DT.NOCLIP | User32.DT.SINGLELINE | User32.DT.NOPREFIX;
if (gridHost.DrawValuesRightToLeft)
{
@ -2457,7 +2450,6 @@ namespace System.Windows.Forms.PropertyGridInternal
{
Gdi32.SetTextColor(hdc, oldTextColor);
Gdi32.SetBkColor(hdc, oldBkColor);
Gdi32.SelectObject(hdc, hfont);
}
if (doToolTip)

Просмотреть файл

@ -6,6 +6,7 @@
using System.Drawing;
using System.Windows.Forms.VisualStyles;
using static Interop;
namespace System.Windows.Forms
{
@ -15,34 +16,24 @@ namespace System.Windows.Forms
/// </summary>
public static class RadioButtonRenderer
{
//Make this per-thread, so that different threads can safely use these methods.
// Make this per-thread, so that different threads can safely use these methods.
[ThreadStatic]
private static VisualStyleRenderer visualStyleRenderer = null;
private static readonly VisualStyleElement RadioElement = VisualStyleElement.Button.RadioButton.UncheckedNormal;
private static bool renderMatchingApplicationState = true;
private static VisualStyleRenderer t_visualStyleRenderer = null;
private static readonly VisualStyleElement s_radioElement = VisualStyleElement.Button.RadioButton.UncheckedNormal;
/// <summary>
/// If this property is true, then the renderer will use the setting from Application.RenderWithVisualStyles to
/// determine how to render.
/// If this property is false, the renderer will always render with visualstyles.
/// </summary>
public static bool RenderMatchingApplicationState
{
get
{
return renderMatchingApplicationState;
}
set
{
renderMatchingApplicationState = value;
}
}
public static bool RenderMatchingApplicationState { get; set; } = true;
private static bool RenderWithVisualStyles
{
get
{
return (!renderMatchingApplicationState || Application.RenderWithVisualStyles);
return (!RenderMatchingApplicationState || Application.RenderWithVisualStyles);
}
}
@ -55,7 +46,7 @@ namespace System.Windows.Forms
{
InitializeRenderer((int)state);
return visualStyleRenderer.IsBackgroundPartiallyTransparent();
return t_visualStyleRenderer.IsBackgroundPartiallyTransparent();
}
else
{
@ -73,7 +64,7 @@ namespace System.Windows.Forms
{
InitializeRenderer(0);
visualStyleRenderer.DrawParentBackground(g, bounds, childControl);
t_visualStyleRenderer.DrawParentBackground(g, bounds, childControl);
}
}
@ -87,16 +78,20 @@ namespace System.Windows.Forms
internal static void DrawRadioButton(Graphics g, Point glyphLocation, RadioButtonState state, IntPtr hWnd)
{
Rectangle glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(g, state, hWnd));
Rectangle glyphBounds;
if (RenderWithVisualStyles)
{
InitializeRenderer((int)state);
visualStyleRenderer.DrawBackground(g, glyphBounds, hWnd);
using var hdc = new DeviceContextHdcScope(g);
glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(hdc, state, hWnd));
t_visualStyleRenderer.DrawBackground(hdc, glyphBounds, hWnd);
}
else
{
using (var hdc = new DeviceContextHdcScope(g))
{
glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(hdc, state, hWnd));
}
ControlPaint.DrawRadioButton(g, glyphBounds, ConvertToButtonState(state));
}
}
@ -121,15 +116,19 @@ namespace System.Windows.Forms
internal static void DrawRadioButton(Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, TextFormatFlags flags, bool focused, RadioButtonState state, IntPtr hWnd)
{
Rectangle glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(g, state, hWnd));
Rectangle glyphBounds;
using (var hdc = new DeviceContextHdcScope(g))
{
glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(hdc, state, hWnd));
}
Color textColor;
if (RenderWithVisualStyles)
{
InitializeRenderer((int)state);
visualStyleRenderer.DrawBackground(g, glyphBounds);
textColor = visualStyleRenderer.GetColor(ColorProperty.TextColor);
t_visualStyleRenderer.DrawBackground(g, glyphBounds);
textColor = t_visualStyleRenderer.GetColor(ColorProperty.TextColor);
}
else
{
@ -165,17 +164,21 @@ namespace System.Windows.Forms
internal static void DrawRadioButton(Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, RadioButtonState state, IntPtr hWnd)
{
Rectangle glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(g, state, hWnd));
Rectangle glyphBounds;
using (var hdc = new DeviceContextHdcScope(g))
{
glyphBounds = new Rectangle(glyphLocation, GetGlyphSize(hdc, state, hWnd));
}
Color textColor;
if (RenderWithVisualStyles)
{
InitializeRenderer((int)state);
//Keep this drawing order! It matches default drawing order.
visualStyleRenderer.DrawImage(g, imageBounds, image);
visualStyleRenderer.DrawBackground(g, glyphBounds);
textColor = visualStyleRenderer.GetColor(ColorProperty.TextColor);
// Keep this drawing order! It matches default drawing order.
t_visualStyleRenderer.DrawImage(g, imageBounds, image);
t_visualStyleRenderer.DrawBackground(g, glyphBounds);
textColor = t_visualStyleRenderer.GetColor(ColorProperty.TextColor);
}
else
{
@ -197,16 +200,17 @@ namespace System.Windows.Forms
/// </summary>
public static Size GetGlyphSize(Graphics g, RadioButtonState state)
{
return GetGlyphSize(g, state, IntPtr.Zero);
using var hdc = new DeviceContextHdcScope(g);
return GetGlyphSize(hdc, state, IntPtr.Zero);
}
internal static Size GetGlyphSize(Graphics g, RadioButtonState state, IntPtr hWnd)
internal static Size GetGlyphSize(Gdi32.HDC hdc, RadioButtonState state, IntPtr hWnd)
{
if (RenderWithVisualStyles)
{
InitializeRenderer((int)state);
return visualStyleRenderer.GetPartSize(g, ThemeSizeType.Draw, hWnd);
return t_visualStyleRenderer.GetPartSize(hdc, ThemeSizeType.Draw, hWnd);
}
return new Size(13, 13);
@ -275,21 +279,21 @@ namespace System.Windows.Forms
private static void InitializeRenderer(int state)
{
RadioButtonState radioButtonState = (RadioButtonState)state;
int part = RadioElement.Part;
int part = s_radioElement.Part;
if (SystemInformation.HighContrast
&& (radioButtonState == RadioButtonState.CheckedDisabled || radioButtonState == RadioButtonState.UncheckedDisabled)
&& VisualStyleRenderer.IsCombinationDefined(RadioElement.ClassName, VisualStyleElement.Button.RadioButton.HighContrastDisabledPart))
&& VisualStyleRenderer.IsCombinationDefined(s_radioElement.ClassName, VisualStyleElement.Button.RadioButton.HighContrastDisabledPart))
{
part = VisualStyleElement.Button.RadioButton.HighContrastDisabledPart;
}
if (visualStyleRenderer == null)
if (t_visualStyleRenderer == null)
{
visualStyleRenderer = new VisualStyleRenderer(RadioElement.ClassName, part, state);
t_visualStyleRenderer = new VisualStyleRenderer(s_radioElement.ClassName, part, state);
}
else
{
visualStyleRenderer.SetParameters(RadioElement.ClassName, part, state);
t_visualStyleRenderer.SetParameters(s_radioElement.ClassName, part, state);
}
}
}

Просмотреть файл

@ -22,7 +22,7 @@ namespace System.Windows.Forms
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
using var hdc = new DeviceContextHdcScope(dc, saveState: false);
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
wg.DrawText(text, wf, pt, foreColor);
@ -37,7 +37,7 @@ namespace System.Windows.Forms
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
using var hdc = new DeviceContextHdcScope(dc);
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
wg.DrawText(text, wf, pt, foreColor, backColor);
@ -80,7 +80,7 @@ namespace System.Windows.Forms
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
using var hdc = new DeviceContextHdcScope(dc, saveState: false);
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
wg.DrawText(text, wf, bounds, foreColor);
@ -95,7 +95,7 @@ namespace System.Windows.Forms
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
using var hdc = new DeviceContextHdcScope(dc, saveState: false);
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
wg.DrawText(text, wf, bounds, foreColor, backColor);
@ -188,7 +188,7 @@ namespace System.Windows.Forms
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
using var hdc = new DeviceContextHdcScope(dc, saveState: false);
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
return wg.MeasureText(text, wf);
@ -207,7 +207,7 @@ namespace System.Windows.Forms
Gdi32.QUALITY fontQuality = WindowsFont.WindowsFontQualityFromTextRenderingHint(dc as Graphics);
using var hdc = new DeviceContextHdcScope(dc, saveState: false);
using var hdc = new DeviceContextHdcScope(dc, applyGraphicsState: false);
using WindowsGraphics wg = WindowsGraphics.FromHdc(hdc);
using WindowsFont? wf = WindowsGraphicsCacheManager.GetWindowsFont(font, fontQuality);
return wg.MeasureText(text, wf, proposedSize);

Просмотреть файл

@ -2632,11 +2632,6 @@ namespace System.Windows.Forms
}
#endregion
internal static Graphics GetMeasurementGraphics()
{
return WindowsFormsUtils.CreateMeasurementGraphics();
}
internal ToolStripItem GetSelectedItem()
{
ToolStripItem selectedItem = null;
@ -2909,7 +2904,7 @@ namespace System.Windows.Forms
{
using Bitmap image = new Bitmap(bounds.Width, bounds.Height);
using Graphics g = Graphics.FromImage(image);
using var imageHdc = new DeviceContextHdcScope(g, saveState: false);
using var imageHdc = new DeviceContextHdcScope(g, applyGraphicsState: false);
// Send the actual wm_print message
User32.SendMessageW(

Просмотреть файл

@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@ -276,7 +276,11 @@ namespace System.Windows.Forms
vsr.SetParameters(VisualStyleElement.Spin.Up.Pressed);
}
vsr.DrawBackground(e.Graphics, new Rectangle(0, 0, _parent._defaultButtonsWidth, half_height), HandleInternal);
using var paintScope = new PaintEventHdcScope(e);
vsr.DrawBackground(
paintScope,
new Rectangle(0, 0, _parent._defaultButtonsWidth, half_height),
HandleInternal);
if (!Enabled)
{
@ -291,19 +295,24 @@ namespace System.Windows.Forms
vsr.SetParameters(_mouseOver == ButtonID.Down ? VisualStyleElement.Spin.Down.Hot : VisualStyleElement.Spin.Down.Normal);
}
vsr.DrawBackground(e.Graphics, new Rectangle(0, half_height, _parent._defaultButtonsWidth, half_height), HandleInternal);
vsr.DrawBackground(
paintScope,
new Rectangle(0, half_height, _parent._defaultButtonsWidth, half_height),
HandleInternal);
}
else
{
ControlPaint.DrawScrollButton(e.Graphics,
new Rectangle(0, 0, _parent._defaultButtonsWidth, half_height),
ScrollButton.Up,
_pushed == ButtonID.Up ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive));
ControlPaint.DrawScrollButton(
e.Graphics,
new Rectangle(0, 0, _parent._defaultButtonsWidth, half_height),
ScrollButton.Up,
_pushed == ButtonID.Up ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive));
ControlPaint.DrawScrollButton(e.Graphics,
new Rectangle(0, half_height, _parent._defaultButtonsWidth, half_height),
ScrollButton.Down,
_pushed == ButtonID.Down ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive));
ControlPaint.DrawScrollButton(
e.Graphics,
new Rectangle(0, half_height, _parent._defaultButtonsWidth, half_height),
ScrollButton.Down,
_pushed == ButtonID.Down ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive));
}
if (half_height != (ClientSize.Height + 1) / 2)

Просмотреть файл

@ -545,10 +545,15 @@ namespace System.Windows.Forms
clipTop.Intersect(clipBounds);
clipRight.Intersect(clipBounds);
clipBottom.Intersect(clipBounds);
vsr.DrawBackground(e.Graphics, bounds, clipLeft, HandleInternal);
vsr.DrawBackground(e.Graphics, bounds, clipTop, HandleInternal);
vsr.DrawBackground(e.Graphics, bounds, clipRight, HandleInternal);
vsr.DrawBackground(e.Graphics, bounds, clipBottom, HandleInternal);
using (var scope = new PaintEventHdcScope(e))
{
vsr.DrawBackground(scope, bounds, clipLeft, HandleInternal);
vsr.DrawBackground(scope, bounds, clipTop, HandleInternal);
vsr.DrawBackground(scope, bounds, clipRight, HandleInternal);
vsr.DrawBackground(scope, bounds, clipBottom, HandleInternal);
}
// Draw rectangle around edit control with background color
using (Pen pen = new Pen(BackColor))
{

Просмотреть файл

@ -16,21 +16,16 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public sealed class VisualStyleRenderer : IHandle
{
private const TextFormatFlags AllGraphicsProperties = TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.PreserveGraphicsTranslateTransform;
private string _class;
private int part;
private int state;
private HRESULT lastHResult = 0;
private static readonly int numberOfPossibleClasses = VisualStyleElement.Count; //used as size for themeHandles
private HRESULT _lastHResult = 0;
private static readonly int s_numberOfPossibleClasses = VisualStyleElement.Count; //used as size for themeHandles
[ThreadStatic]
private static Hashtable? themeHandles; // per-thread cache of ThemeHandle objects.
private static Hashtable? t_themeHandles; // per-thread cache of ThemeHandle objects.
[ThreadStatic]
private static long threadCacheVersion = 0;
private static long t_threadCacheVersion = 0;
private static long globalCacheVersion = 0;
private static long s_globalCacheVersion = 0;
static VisualStyleRenderer()
{
@ -66,7 +61,7 @@ namespace System.Windows.Forms.VisualStyles
// In some cases, this check isn't enough, since the theme handle creation
// could fail for some other reason. Try creating a theme handle here - if successful, return true,
// else return false.
IntPtr hTheme = GetHandle("BUTTON", false); //Button is an arbitrary choice.
IntPtr hTheme = GetHandle("BUTTON", false); // Button is an arbitrary choice.
supported = (hTheme != IntPtr.Zero);
}
@ -85,9 +80,7 @@ namespace System.Windows.Forms.VisualStyles
public static bool IsElementDefined(VisualStyleElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return IsCombinationDefined(element.ClassName, element.Part);
}
@ -98,14 +91,9 @@ namespace System.Windows.Forms.VisualStyles
if (!IsSupported)
{
if (!VisualStyleInformation.IsEnabledByUser)
{
throw new InvalidOperationException(SR.VisualStyleNotActive);
}
else
{
throw new InvalidOperationException(SR.VisualStylesDisabledInClientArea);
}
throw new InvalidOperationException(VisualStyleInformation.IsEnabledByUser
? SR.VisualStylesDisabledInClientArea
: SR.VisualStyleNotActive);
}
IntPtr hTheme = GetHandle(className, false);
@ -124,7 +112,7 @@ namespace System.Windows.Forms.VisualStyles
}
}
//if the combo isn't defined, check the validity of our theme handle cache
// If the combo isn't defined, check the validity of our theme handle cache
if (!returnVal)
{
using (ThemeHandle? tHandle = ThemeHandle.Create(className, false))
@ -134,7 +122,7 @@ namespace System.Windows.Forms.VisualStyles
returnVal = IsThemePartDefined(tHandle, part, 0).IsTrue();
}
//if we did, in fact get a new correct theme handle, our cache is out of date -- update it now.
// If we did, in fact get a new correct theme handle, our cache is out of date -- update it now.
if (returnVal)
{
RefreshCache();
@ -159,51 +147,30 @@ namespace System.Windows.Forms.VisualStyles
public VisualStyleRenderer(string className, int part, int state)
{
if (className == null)
{
throw new ArgumentNullException(nameof(className));
}
if (!IsCombinationDefined(className, part))
{
throw new ArgumentException(SR.VisualStylesInvalidCombination);
}
_class = className;
this.part = part;
this.state = state;
if (!IsCombinationDefined(className, part))
throw new ArgumentException(SR.VisualStylesInvalidCombination);
Class = className;
Part = part;
State = state;
}
/// <summary>
/// Returns the current _class. Use SetParameters to set.
/// </summary>
public string Class
{
get
{
return _class;
}
}
public string Class { get; private set; }
/// <summary>
/// Returns the current part. Use SetParameters to set.
/// </summary>
public int Part
{
get
{
return part;
}
}
public int Part { get; private set; }
/// <summary>
/// Returns the current state. Use SetParameters to set.
/// </summary>
public int State
{
get
{
return state;
}
}
public int State { get; private set; }
/// <summary>
/// Returns the underlying HTheme handle.
@ -218,17 +185,12 @@ namespace System.Windows.Forms.VisualStyles
{
if (!IsSupported)
{
if (!VisualStyleInformation.IsEnabledByUser)
{
throw new InvalidOperationException(SR.VisualStyleNotActive);
}
else
{
throw new InvalidOperationException(SR.VisualStylesDisabledInClientArea);
}
throw new InvalidOperationException(VisualStyleInformation.IsEnabledByUser
? SR.VisualStylesDisabledInClientArea
: SR.VisualStyleNotActive);
}
return GetHandle(_class);
return GetHandle(Class);
}
}
@ -237,10 +199,8 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public void SetParameters(VisualStyleElement element)
{
if (element == null)
{
if (element is null)
throw new ArgumentNullException(nameof(element));
}
SetParameters(element.ClassName, element.Part, element.State);
}
@ -253,13 +213,11 @@ namespace System.Windows.Forms.VisualStyles
public void SetParameters(string className, int part, int state)
{
if (!IsCombinationDefined(className, part))
{
throw new ArgumentException(SR.VisualStylesInvalidCombination);
}
_class = className;
this.part = part;
this.state = state;
Class = className;
Part = part;
State = state;
}
/// <summary>
@ -267,35 +225,28 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public void DrawBackground(IDeviceContext dc, Rectangle bounds)
{
DrawBackground(dc, bounds, IntPtr.Zero);
if (dc is null)
throw new ArgumentNullException(nameof(dc));
using var hdc = new DeviceContextHdcScope(dc);
DrawBackground(hdc, bounds, IntPtr.Zero);
}
internal unsafe void DrawBackground(IDeviceContext dc, Rectangle bounds, IntPtr hWnd)
internal unsafe void DrawBackground(Gdi32.HDC dc, Rectangle bounds, IntPtr hWnd)
{
if (dc == null)
{
throw new ArgumentNullException(nameof(dc));
}
if (bounds.Width < 0 || bounds.Height < 0)
{
return;
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
if (IntPtr.Zero != hWnd)
{
if (IntPtr.Zero != hWnd)
{
using (ThemeHandle hTheme = ThemeHandle.Create(_class, true, hWnd)!)
{
RECT rect = bounds;
lastHResult = DrawThemeBackground(hTheme, wgr, part, state, ref rect, null);
}
}
else
{
RECT rect = bounds;
lastHResult = DrawThemeBackground(this, wgr, part, state, ref rect, null);
}
using ThemeHandle hTheme = ThemeHandle.Create(Class, true, hWnd)!;
RECT rect = bounds;
_lastHResult = DrawThemeBackground(hTheme, dc, Part, State, ref rect, null);
}
else
{
RECT rect = bounds;
_lastHResult = DrawThemeBackground(this, dc, Part, State, ref rect, null);
}
}
@ -304,41 +255,30 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public void DrawBackground(IDeviceContext dc, Rectangle bounds, Rectangle clipRectangle)
{
DrawBackground(dc, bounds, clipRectangle, IntPtr.Zero);
if (dc is null)
throw new ArgumentNullException(nameof(dc));
using var hdc = new DeviceContextHdcScope(dc);
DrawBackground(hdc, bounds, clipRectangle, IntPtr.Zero);
}
internal unsafe void DrawBackground(IDeviceContext dc, Rectangle bounds, Rectangle clipRectangle, IntPtr hWnd)
internal unsafe void DrawBackground(Gdi32.HDC dc, Rectangle bounds, Rectangle clipRectangle, IntPtr hWnd)
{
if (dc == null)
{
throw new ArgumentNullException(nameof(dc));
}
if (bounds.Width < 0 || bounds.Height < 0)
{
if (bounds.Width < 0 || bounds.Height < 0 || clipRectangle.Width < 0 || clipRectangle.Height < 0)
return;
}
if (clipRectangle.Width < 0 || clipRectangle.Height < 0)
{
return;
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
if (IntPtr.Zero != hWnd)
{
if (IntPtr.Zero != hWnd)
{
using (ThemeHandle hTheme = ThemeHandle.Create(_class, true, hWnd)!)
{
RECT rect = bounds;
RECT clipRect = clipRectangle;
lastHResult = DrawThemeBackground(hTheme, wgr, part, state, ref rect, &clipRect);
}
}
else
{
RECT rect = bounds;
RECT clipRect = clipRectangle;
lastHResult = DrawThemeBackground(this, wgr, part, state, ref rect, &clipRect);
}
using ThemeHandle hTheme = ThemeHandle.Create(Class, true, hWnd)!;
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);
}
}
@ -347,30 +287,36 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public Rectangle DrawEdge(IDeviceContext dc, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
using var hdc = new DeviceContextHdcScope(dc);
return DrawEdge(hdc, bounds, edges, style, effects);
}
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));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
RECT destRect = bounds;
var contentRect = new RECT();
lastHResult = DrawThemeEdge(this, wgr, part, state, ref destRect, (User32.EDGE)style, (User32.BF)edges | (User32.BF)effects | User32.BF.ADJUST, ref contentRect);
_lastHResult = DrawThemeEdge(
this,
dc,
Part,
State,
ref destRect,
(User32.EDGE)style,
(User32.BF)edges | (User32.BF)effects | User32.BF.ADJUST,
ref contentRect);
return contentRect;
}
@ -381,19 +327,13 @@ namespace System.Windows.Forms.VisualStyles
public void DrawImage(Graphics g, Rectangle bounds, Image image)
{
if (g == null)
{
throw new ArgumentNullException(nameof(g));
}
if (image == null)
{
throw new ArgumentNullException(nameof(image));
}
if (bounds.Width < 0 || bounds.Height < 0)
{
return;
}
g.DrawImage(image, bounds);
}
@ -405,24 +345,16 @@ namespace System.Windows.Forms.VisualStyles
public void DrawImage(Graphics g, Rectangle bounds, ImageList imageList, int imageIndex)
{
if (g == null)
{
throw new ArgumentNullException(nameof(g));
}
if (imageList == null)
{
throw new ArgumentNullException(nameof(imageList));
}
if (imageIndex < 0 || imageIndex >= imageList.Images.Count)
{
throw new ArgumentOutOfRangeException(nameof(imageIndex), imageIndex, string.Format(SR.InvalidArgument, nameof(imageIndex), imageIndex));
}
if (bounds.Width < 0 || bounds.Height < 0)
{
return;
}
// DrawThemeIcon currently seems to do nothing, but still return S_OK. As a workaround,
// we call DrawImage on the graphics object itself for now.
@ -436,25 +368,20 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public void DrawParentBackground(IDeviceContext dc, Rectangle bounds, Control childControl)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
if (childControl == null)
{
throw new ArgumentNullException(nameof(childControl));
}
if (bounds.Width < 0 || bounds.Height < 0)
{
return;
}
if (childControl.IsHandleCreated)
{
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
using var hdc = new DeviceContextHdcScope(dc);
RECT rc = bounds;
lastHResult = DrawThemeParentBackground(childControl, wgr, ref rc);
_lastHResult = DrawThemeParentBackground(childControl, hdc, ref rc);
}
}
@ -479,22 +406,23 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public void DrawText(IDeviceContext dc, Rectangle bounds, string? textToDraw, bool drawDisabled, TextFormatFlags flags)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
using var hdc = new DeviceContextHdcScope(dc);
DrawText(hdc, bounds, textToDraw, drawDisabled, flags);
}
internal void DrawText(Gdi32.HDC dc, Rectangle bounds, string? textToDraw, bool drawDisabled, TextFormatFlags flags)
{
if (bounds.Width < 0 || bounds.Height < 0)
{
return;
}
if (!string.IsNullOrEmpty(textToDraw))
{
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
uint disableFlag = drawDisabled ? 0x1u : 0u;
RECT rect = bounds;
lastHResult = DrawThemeText(this, wgr, part, state, textToDraw, textToDraw.Length, (User32.DT)flags, disableFlag, ref rect);
_lastHResult = DrawThemeText(this, dc, Part, State, textToDraw, textToDraw.Length, (User32.DT)flags, disableFlag, ref rect);
}
}
@ -503,18 +431,20 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public Rectangle GetBackgroundContentRectangle(IDeviceContext dc, Rectangle bounds)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
if (bounds.Width < 0 || bounds.Height < 0)
{
return Rectangle.Empty;
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
using var hdc = new DeviceContextHdcScope(dc);
return GetBackgroundContentRectangle(hdc, bounds);
}
internal Rectangle GetBackgroundContentRectangle(Gdi32.HDC dc, Rectangle bounds)
{
if (bounds.Width < 0 || bounds.Height < 0)
return Rectangle.Empty;
RECT boundsRect = bounds;
lastHResult = GetThemeBackgroundContentRect(this, wgr, part, state, ref boundsRect, out RECT rect);
_lastHResult = GetThemeBackgroundContentRect(this, dc, Part, State, ref boundsRect, out RECT rect);
return rect;
}
@ -523,18 +453,15 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public Rectangle GetBackgroundExtent(IDeviceContext dc, Rectangle contentBounds)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
if (contentBounds.Width < 0 || contentBounds.Height < 0)
{
return Rectangle.Empty;
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
if (contentBounds.Width < 0 || contentBounds.Height < 0)
return Rectangle.Empty;
using var hdc = new DeviceContextHdcScope(dc);
RECT contentBoundsRect = contentBounds;
lastHResult = GetThemeBackgroundExtent(this, wgr, part, state, ref contentBoundsRect, out RECT extentRect);
_lastHResult = GetThemeBackgroundExtent(this, hdc, Part, State, ref contentBoundsRect, out RECT extentRect);
return extentRect;
}
@ -545,30 +472,27 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public Region? GetBackgroundRegion(IDeviceContext dc, Rectangle bounds)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
if (bounds.Width < 0 || bounds.Height < 0)
{
return null;
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
if (bounds.Width < 0 || bounds.Height < 0)
return null;
using var hdc = new DeviceContextHdcScope(dc);
RECT boundsRect = bounds;
lastHResult = GetThemeBackgroundRegion(this, wgr, part, state, ref boundsRect, out IntPtr hRegion);
_lastHResult = GetThemeBackgroundRegion(this, hdc, Part, State, ref boundsRect, out Gdi32.HRGN hRegion);
// GetThemeBackgroundRegion returns a null hRegion if it fails to create one, it could be because the bounding
// box is too big. For more info see code in %xpsrc%\shell\themes\uxtheme\imagefile.cpp if you have an enlistment to it.
if (hRegion == IntPtr.Zero)
if (hRegion.IsNull)
{
return null;
}
// From the GDI+ sources it doesn't appear as if they take ownership of the hRegion, so this is safe to do.
// We need to DeleteObject in order to not leak.
Region region = Region.FromHrgn(hRegion);
Region region = Region.FromHrgn(hRegion.Handle);
Gdi32.DeleteObject(hRegion);
return region;
}
@ -579,12 +503,10 @@ namespace System.Windows.Forms.VisualStyles
public bool GetBoolean(BooleanProperty prop)
{
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)BooleanProperty.Transparent, (int)BooleanProperty.SourceShrink))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(BooleanProperty));
}
BOOL val = BOOL.FALSE;
lastHResult = GetThemeBool(this, part, state, (int)prop, ref val);
_lastHResult = GetThemeBool(this, Part, State, (int)prop, ref val);
return val.IsTrue();
}
@ -593,14 +515,12 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public Color GetColor(ColorProperty prop)
{
//valid values are 0xed9 to 0xeef
// Valid values are 0xed9 to 0xeef
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)ColorProperty.BorderColor, (int)ColorProperty.AccentColorHint))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(ColorProperty));
}
int color = 0;
lastHResult = GetThemeColor(this, part, state, (int)prop, ref color);
_lastHResult = GetThemeColor(this, Part, State, (int)prop, ref color);
return ColorTranslator.FromWin32(color);
}
@ -609,14 +529,12 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public int GetEnumValue(EnumProperty prop)
{
//valid values are 0xfa1 to 0xfaf
// Valid values are 0xfa1 to 0xfaf
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)EnumProperty.BackgroundType, (int)EnumProperty.TrueSizeScalingType))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(EnumProperty));
}
int val = 0;
lastHResult = GetThemeEnumValue(this, part, state, (int)prop, ref val);
_lastHResult = GetThemeEnumValue(this, Part, State, (int)prop, ref val);
return val;
}
@ -625,16 +543,14 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public unsafe string GetFilename(FilenameProperty prop)
{
//valid values are 0xbb9 to 0xbc0
// Valid values are 0xbb9 to 0xbc0
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)FilenameProperty.ImageFile, (int)FilenameProperty.GlyphImageFile))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(FilenameProperty));
}
Span<char> filename = stackalloc char[512];
fixed (char* pFilename = filename)
{
lastHResult = GetThemeFilename(this, part, state, (int)prop, pFilename, filename.Length);
_lastHResult = GetThemeFilename(this, Part, State, (int)prop, pFilename, filename.Length);
}
return filename.SliceAtFirstNull().ToString();
}
@ -645,21 +561,17 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public Font? GetFont(IDeviceContext dc, FontProperty prop)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
if (!ClientUtils.IsEnumValid_NotSequential(prop, (int)prop, (int)FontProperty.TextFont, (int)FontProperty.GlyphFont))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(FontProperty));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
lastHResult = GetThemeFont(this, wgr, part, state, (int)prop, out User32.LOGFONTW logfont);
using var hdc = new DeviceContextHdcScope(dc);
_lastHResult = GetThemeFont(this, hdc, Part, State, (int)prop, out User32.LOGFONTW logfont);
// Check for a failed HR.
if (!lastHResult.Succeeded())
if (!_lastHResult.Succeeded())
{
return null;
}
@ -685,14 +597,12 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public int GetInteger(IntegerProperty prop)
{
//valid values are 0x961 to 0x978
// Valid values are 0x961 to 0x978
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)IntegerProperty.ImageCount, (int)IntegerProperty.MinDpi5))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(IntegerProperty));
}
int val = 0;
lastHResult = GetThemeInt(this, part, state, (int)prop, ref val);
_lastHResult = GetThemeInt(this, Part, State, (int)prop, ref val);
return val;
}
@ -701,33 +611,27 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public Size GetPartSize(IDeviceContext dc, ThemeSizeType type)
{
return GetPartSize(dc, type, IntPtr.Zero);
if (dc is null)
throw new ArgumentNullException(nameof(dc));
using var hdc = new DeviceContextHdcScope(dc);
return GetPartSize(hdc, type, IntPtr.Zero);
}
internal unsafe Size GetPartSize(IDeviceContext dc, ThemeSizeType type, IntPtr hWnd)
internal unsafe Size GetPartSize(Gdi32.HDC dc, ThemeSizeType type, IntPtr hWnd = default)
{
if (dc == null)
{
throw new ArgumentNullException(nameof(dc));
}
// valid values are 0x0 to 0x2
// Valid values are 0x0 to 0x2
if (!ClientUtils.IsEnumValid(type, (int)type, (int)ThemeSizeType.Minimum, (int)ThemeSizeType.Draw))
{
throw new InvalidEnumArgumentException(nameof(type), (int)type, typeof(ThemeSizeType));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
if (DpiHelper.IsPerMonitorV2Awareness && hWnd != IntPtr.Zero)
{
using (ThemeHandle hTheme = ThemeHandle.Create(_class, true, hWnd)!)
{
lastHResult = GetThemePartSize(hTheme, wgr, part, state, null, type, out Size dpiSize);
return dpiSize;
}
using ThemeHandle hTheme = ThemeHandle.Create(Class, true, hWnd)!;
_lastHResult = GetThemePartSize(hTheme, dc, Part, State, null, type, out Size dpiSize);
return dpiSize;
}
lastHResult = GetThemePartSize(this, wgr, part, state, null, type, out Size size);
_lastHResult = GetThemePartSize(this, dc, Part, State, null, type, out Size size);
return size;
}
@ -736,20 +640,16 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public unsafe Size GetPartSize(IDeviceContext dc, Rectangle bounds, ThemeSizeType type)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
//valid values are 0x0 to 0x2
// Valid values are 0x0 to 0x2
if (!ClientUtils.IsEnumValid(type, (int)type, (int)ThemeSizeType.Minimum, (int)ThemeSizeType.Draw))
{
throw new InvalidEnumArgumentException(nameof(type), (int)type, typeof(ThemeSizeType));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
using var hdc = new DeviceContextHdcScope(dc);
RECT boundsRect = bounds;
lastHResult = GetThemePartSize(this, wgr, part, state, &boundsRect, type, out Size size);
_lastHResult = GetThemePartSize(this, hdc, Part, State, &boundsRect, type, out Size size);
return size;
}
@ -760,11 +660,9 @@ namespace System.Windows.Forms.VisualStyles
{
//valid values are 0xd49 to 0xd50
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)PointProperty.Offset, (int)PointProperty.MinSize5))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(PointProperty));
}
lastHResult = GetThemePosition(this, part, state, (int)prop, out Point point);
_lastHResult = GetThemePosition(this, Part, State, (int)prop, out Point point);
return point;
}
@ -773,19 +671,15 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public unsafe Padding GetMargins(IDeviceContext dc, MarginProperty prop)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
//valid values are 0xe11 to 0xe13
// Valid values are 0xe11 to 0xe13
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)MarginProperty.SizingMargins, (int)MarginProperty.CaptionMargins))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(MarginProperty));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
lastHResult = GetThemeMargins(this, wgr, part, state, (int)prop, null, out MARGINS margins);
using var hdc = new DeviceContextHdcScope(dc);
_lastHResult = GetThemeMargins(this, hdc, Part, State, (int)prop, null, out MARGINS margins);
return new Padding(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
}
@ -795,16 +689,14 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public unsafe string GetString(StringProperty prop)
{
//valid values are 0xc81 to 0xc81
// Valid values are 0xc81 to 0xc81
if (!ClientUtils.IsEnumValid(prop, (int)prop, (int)StringProperty.Text, (int)StringProperty.Text))
{
throw new InvalidEnumArgumentException(nameof(prop), (int)prop, typeof(StringProperty));
}
Span<char> aString = stackalloc char[512];
fixed (char* pString = aString)
{
lastHResult = GetThemeString(this, part, state, (int)prop, pString, aString.Length);
_lastHResult = GetThemeString(this, Part, State, (int)prop, pString, aString.Length);
}
return aString.SliceAtFirstNull().ToString();
}
@ -814,18 +706,14 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public unsafe Rectangle GetTextExtent(IDeviceContext dc, string textToDraw, TextFormatFlags flags)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
if (string.IsNullOrEmpty(textToDraw))
{
throw new ArgumentNullException(nameof(textToDraw));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
lastHResult = GetThemeTextExtent(this, wgr, part, state, textToDraw, textToDraw.Length, (uint)flags, null, out RECT rect);
using var hdc = new DeviceContextHdcScope(dc);
_lastHResult = GetThemeTextExtent(this, hdc, Part, State, textToDraw, textToDraw.Length, (uint)flags, null, out RECT rect);
return rect;
}
@ -834,19 +722,15 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public unsafe Rectangle GetTextExtent(IDeviceContext dc, Rectangle bounds, string textToDraw, TextFormatFlags flags)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
if (string.IsNullOrEmpty(textToDraw))
{
throw new ArgumentNullException(nameof(textToDraw));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
using var hdc = new DeviceContextHdcScope(dc);
RECT boundsRect = bounds;
lastHResult = GetThemeTextExtent(this, wgr, part, state, textToDraw, textToDraw.Length, (uint)flags, &boundsRect, out RECT rect);
_lastHResult = GetThemeTextExtent(this, hdc, Part, State, textToDraw, textToDraw.Length, (uint)flags, &boundsRect, out RECT rect);
return rect;
}
@ -855,13 +739,11 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public TextMetrics GetTextMetrics(IDeviceContext dc)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
lastHResult = GetThemeTextMetrics(this, wgr, part, state, out TextMetrics tm);
using var hdc = new DeviceContextHdcScope(dc);
_lastHResult = GetThemeTextMetrics(this, hdc, Part, State, out TextMetrics tm);
return tm;
}
@ -870,14 +752,12 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public HitTestCode HitTestBackground(IDeviceContext dc, Rectangle backgroundRectangle, Point pt, HitTestOptions options)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
using var hdc = new DeviceContextHdcScope(dc);
RECT backgroundRect = backgroundRectangle;
lastHResult = HitTestThemeBackground(this, wgr, part, state, (uint)options, ref backgroundRect, IntPtr.Zero, pt, out ushort htCode);
_lastHResult = HitTestThemeBackground(this, hdc, Part, State, (uint)options, ref backgroundRect, IntPtr.Zero, pt, out ushort htCode);
return (HitTestCode)htCode;
}
@ -887,13 +767,10 @@ namespace System.Windows.Forms.VisualStyles
public HitTestCode HitTestBackground(Graphics g, Rectangle backgroundRectangle, Region region, Point pt, HitTestOptions options)
{
if (g == null)
{
throw new ArgumentNullException(nameof(g));
}
if (region == null)
{
throw new ArgumentNullException(nameof(region));
}
IntPtr hRgn = region.GetHrgn(g);
return HitTestBackground(g, backgroundRectangle, hRgn, pt, options);
@ -904,14 +781,12 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public HitTestCode HitTestBackground(IDeviceContext dc, Rectangle backgroundRectangle, IntPtr hRgn, Point pt, HitTestOptions options)
{
if (dc == null)
{
if (dc is null)
throw new ArgumentNullException(nameof(dc));
}
using var wgr = new WindowsGraphicsWrapper(dc, AllGraphicsProperties);
using var hdc = new DeviceContextHdcScope(dc);
RECT backgroundRect = backgroundRectangle;
lastHResult = HitTestThemeBackground(this, wgr, part, state, (uint)options, ref backgroundRect, hRgn, pt, out ushort htCode);
_lastHResult = HitTestThemeBackground(this, hdc, Part, State, (uint)options, ref backgroundRect, hRgn, pt, out ushort htCode);
return (HitTestCode)htCode;
}
@ -920,27 +795,21 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
public bool IsBackgroundPartiallyTransparent()
{
return IsThemeBackgroundPartiallyTransparent(this, part, state).IsTrue();
return IsThemeBackgroundPartiallyTransparent(this, Part, State).IsTrue();
}
/// <summary>
/// This is similar to GetLastError in Win32. It returns the last HRESULT returned from a native call
/// into theme apis. We eat the errors and let the user handle any errors that occurred.
/// </summary>
public int LastHResult
{
get
{
return (int)lastHResult;
}
}
public int LastHResult => (int)_lastHResult;
/// <summary>
/// Instantiates the ThemeHandle cache hashtable.
/// </summary>
private static void CreateThemeHandleHashtable()
{
themeHandles = new Hashtable(numberOfPossibleClasses);
t_themeHandles = new Hashtable(s_numberOfPossibleClasses);
}
/// <summary>
@ -957,7 +826,7 @@ namespace System.Windows.Forms.VisualStyles
// its handle, this whole version check won't work, but it is unlikely to happen.
// this is not ideal.
globalCacheVersion++;
s_globalCacheVersion++;
}
}
@ -968,14 +837,14 @@ namespace System.Windows.Forms.VisualStyles
{
ThemeHandle? tHandle = null;
if (themeHandles != null)
if (t_themeHandles != null)
{
string[] classNames = new string[themeHandles.Keys.Count];
themeHandles.Keys.CopyTo(classNames, 0);
string[] classNames = new string[t_themeHandles.Keys.Count];
t_themeHandles.Keys.CopyTo(classNames, 0);
foreach (string className in classNames)
{
tHandle = (ThemeHandle?)themeHandles[className];
tHandle = (ThemeHandle?)t_themeHandles[className];
if (tHandle != null)
{
tHandle.Dispose();
@ -988,7 +857,7 @@ namespace System.Windows.Forms.VisualStyles
tHandle = ThemeHandle.Create(className, false);
if (tHandle != null)
{
themeHandles[className] = tHandle;
t_themeHandles[className] = tHandle;
}
}
}
@ -1006,18 +875,18 @@ namespace System.Windows.Forms.VisualStyles
/// </summary>
private static IntPtr GetHandle(string className, bool throwExceptionOnFail)
{
if (themeHandles == null)
if (t_themeHandles == null)
{
CreateThemeHandleHashtable();
}
if (threadCacheVersion != globalCacheVersion)
if (t_threadCacheVersion != s_globalCacheVersion)
{
RefreshCache();
threadCacheVersion = globalCacheVersion;
t_threadCacheVersion = s_globalCacheVersion;
}
if (!themeHandles!.Contains(className))
if (!t_themeHandles!.Contains(className))
{
// See if it is already in cache
ThemeHandle? tHandle = ThemeHandle.Create(className, throwExceptionOnFail);
@ -1026,11 +895,11 @@ namespace System.Windows.Forms.VisualStyles
return IntPtr.Zero;
}
themeHandles.Add(className, tHandle);
t_themeHandles.Add(className, tHandle);
return tHandle.Handle;
}
return ((ThemeHandle)themeHandles[className]!).Handle;
return ((ThemeHandle)t_themeHandles[className]!).Handle;
}
// This wrapper class is needed for safely cleaning up TLS cache of handles.

Просмотреть файл

@ -42,7 +42,10 @@ namespace System.Windows.Forms
/// This <see cref="Graphics"/> requires disposal.
/// </remarks>
public static Graphics CreateMeasurementGraphics()
=> WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.Hdc.CreateGraphics();
=> GetMeasurementDeviceContext().CreateGraphics();
public static Gdi32.HDC GetMeasurementDeviceContext()
=> WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.Hdc;
/// <summary>
/// If you want to know if a piece of text contains one and only one &amp;

Просмотреть файл

@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using static Interop;
namespace System.Windows.Forms
{
/// <summary>
/// Scope for <see cref="PaintEventArgs"/> that prefers to avoid creating <see cref="System.Drawing.Graphics"/> if
/// possible to get HDC.
/// </summary>
internal readonly ref struct PaintEventHdcScope
{
internal Gdi32.HDC HDC { get; }
private readonly DeviceContextHdcScope _scope;
public PaintEventHdcScope(PaintEventArgs args)
{
if (!args.IsGraphicsCreated)
{
HDC = args.HDC;
_scope = default;
}
else
{
_scope = new DeviceContextHdcScope(args.Graphics);
HDC = _scope.HDC;
}
}
public static implicit operator Gdi32.HDC(in PaintEventHdcScope scope) => scope.HDC;
public void Dispose()
{
_scope.Dispose();
}
}
}

Просмотреть файл

@ -196,9 +196,12 @@ namespace System.Windows.Forms.Internal
/// <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)
{
// If hdc is null, the function creates a memory DC compatible with the application's current screen.
// 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.

Просмотреть файл

@ -89,7 +89,7 @@ namespace System.Windows.Forms.Internal
// Get the font height from the specified size. size is in point units and height in logical
// units (pixels when using MM_TEXT) so we need to make the conversion using the number of
// pixels per logical inch along the screen height. (1 point = 1/72 inch.)
int pixelsY = (int)Math.Ceiling(WindowsGraphicsCacheManager.MeasurementGraphics.DeviceContext.DpiY * font.SizeInPoints / 72);
int pixelsY = (int)Math.Ceiling(DpiHelper.DeviceDpi * font.SizeInPoints / 72);
// The lfHeight represents the font cell height (line spacing) which includes the internal
// leading; we specify a negative size value (in pixels) for the height so the font mapper

Просмотреть файл

@ -12893,7 +12893,7 @@ namespace System.Windows.Forms.Tests
}
[WinFormsFact]
public void Control_WndProc_InvokePrintClientWithoutHandleWithoutWParamUserPaint_ThrowsNullReferenceException()
public void Control_WndProc_InvokePrintClientWithoutHandleWithoutWParamUserPaint_DoesNotThrow()
{
using (new NoAssertContext())
{
@ -12908,10 +12908,10 @@ namespace System.Windows.Forms.Tests
Msg = (int)User32.WM.PRINTCLIENT,
Result = (IntPtr)250
};
Assert.Throws<NullReferenceException>(() => control.WndProc(ref m));
control.WndProc(ref m);
Assert.Equal((IntPtr)250, m.Result);
Assert.False(control.IsHandleCreated);
Assert.Equal(0, paintCallCount);
Assert.Equal(1, paintCallCount);
}
}
@ -12997,7 +12997,7 @@ namespace System.Windows.Forms.Tests
}
[WinFormsFact]
public void Control_WndProc_InvokePrintClientWithHandleWithoutWParamUserPaint_ThrowsNullReferenceException()
public void Control_WndProc_InvokePrintClientWithHandleWithoutWParamUserPaint_DoesNotThrow()
{
using var control = new SubControl();
control.SetStyle(ControlStyles.UserPaint, true);
@ -13017,13 +13017,14 @@ namespace System.Windows.Forms.Tests
Msg = (int)User32.WM.PRINTCLIENT,
Result = (IntPtr)250
};
Assert.Throws<NullReferenceException>(() => control.WndProc(ref m));
control.WndProc(ref m);
Assert.Equal((IntPtr)250, m.Result);
Assert.True(control.IsHandleCreated);
Assert.Equal(1, invalidatedCallCount);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
Assert.Equal(0, paintCallCount);
Assert.Equal(1, paintCallCount);
}
public static IEnumerable<object[]> WndProc_PrintClientWithHandleWithWParam_TestData()