From f22357da17f1861014d850847ae5296c56a36590 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Sun, 11 May 2025 08:58:24 +0300 Subject: [PATCH 1/5] Add MessageBox API Suggestion --- .../Analyzers/Diagnostics/DiagnosticIDs.cs | 1 + .../src/NativeMethods.txt | 2 + .../PublicAPI.Unshipped.txt | 20 + .../Windows/Forms/Dialogs/MessageBox.cs | 546 +++++++++++++++++- .../WinformsControlsTest/Program.cs | 4 + start-vs.cmd | 2 + 6 files changed, 569 insertions(+), 6 deletions(-) diff --git a/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs b/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs index 7d8ad147fb6..2d5429a00ac 100644 --- a/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs +++ b/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs @@ -22,4 +22,5 @@ internal static class DiagnosticIDs // Experimental, number group 5000+ public const string ExperimentalDarkMode = "WFO5001"; public const string ExperimentalAsync = "WFO5002"; + public const string ExperimentalMessageBox = "WFO5003"; } diff --git a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt index 3980fbc2d4e..96217baa334 100644 --- a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt +++ b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt @@ -58,6 +58,7 @@ CreateStdAccessibleObject CreateWindowEx CSIDL_* CW_USEDEFAULT +CWPSTRUCT DATETIMEPICK_CLASS DeactivateActCtx DefFrameProc @@ -149,6 +150,7 @@ GetCurrentThread GetCursor GetCursorPos GetDIBits +GetDlgCtrlID GetDlgItem GetDlgItemInt GetDoubleClickTime diff --git a/src/System.Windows.Forms/PublicAPI.Unshipped.txt b/src/System.Windows.Forms/PublicAPI.Unshipped.txt index e69de29bb2d..b62305537bc 100644 --- a/src/System.Windows.Forms/PublicAPI.Unshipped.txt +++ b/src/System.Windows.Forms/PublicAPI.Unshipped.txt @@ -0,0 +1,20 @@ +static System.Windows.Forms.MessageBox.BackColor.get -> System.Drawing.Color +static System.Windows.Forms.MessageBox.BackColor.set -> void +static System.Windows.Forms.MessageBox.FooterBackColor.get -> System.Drawing.Color +static System.Windows.Forms.MessageBox.FooterBackColor.set -> void +static System.Windows.Forms.MessageBox.ForeColor.get -> System.Drawing.Color +static System.Windows.Forms.MessageBox.ForeColor.set -> void +static System.Windows.Forms.MessageBox.ResourceType.get -> System.Type? +static System.Windows.Forms.MessageBox.ResourceType.set -> void +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, bool displayHelpButton) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, string! keyword) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator, object? param) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, string! keyword) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator) -> System.Windows.Forms.DialogResult +[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator, object? param) -> System.Windows.Forms.DialogResult \ No newline at end of file diff --git a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs index 5f75aff0f30..2ae0c1acd01 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs @@ -2,8 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; +using System.Drawing; +using System.Globalization; +using System.Resources; using System.Runtime.InteropServices; - +using System.Windows.Forms.Analyzers.Diagnostics; +using System.Windows.Forms.Primitives; +using Windows.Win32.Graphics.Dwm; namespace System.Windows.Forms; /// @@ -13,12 +18,321 @@ public class MessageBox { [ThreadStatic] private static HelpInfo[]? t_helpInfoTable; + private const int MBOKId = 1; + private const int MBCancelId = 2; + private const int MBAbortId = 3; + private const int MBRetryId = 4; + private const int MBIgnoreId = 5; + private const int MBYesId = 6; + private const int MBNoId = 7; + private const int MBHelpId = 9; + // see + // https://devblogs.microsoft.com/oldnewthing/20140224-00/?p=1683 + // and https://learn.microsoft.com/archive/msdn-magazine/2002/november/cutting-edge-using-windows-hooks-to-enhance-messagebox-in-net + // Unique ID for static Edit in MessageBox, This ID has not changed since Windows 95 and will remain so. + private const int MBTextId = ushort.MaxValue; // 0xFFFF + private const int MBIconId = 20; // 0X0014 + private const int STM_SETICON = 0x00000170; + private static HHOOK s_messageBoxHook; + private static bool s_isMessageBoxHooked; + private static readonly HOOKPROC s_hookCallBack = HookProc; + private static readonly Lock s_lock = new(); + private static readonly nint s_hookPointer = Marshal.GetFunctionPointerForDelegate(s_hookCallBack); + private static HWND s_hWndInternal; + private static nint s_priorDlgProc; + private static readonly PInvokeCore.EnumChildWindowsCallback s_childWindowsCallback = new PInvokeCore.EnumChildWindowsCallback(EnumChildProc); + +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + private static ResourceManager? s_resourceManager => ResourceType is null ? null : new ResourceManager(ResourceType); +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + private static string? OK { get; set; } + [Localizable(true)] + private static string? Cancel { get; set; } + [Localizable(true)] + private static string? Abort { get; set; } + [Localizable(true)] + private static string? Retry { get; set; } + [Localizable(true)] + private static string? Ignore { get; set; } + [Localizable(true)] + private static string? Yes { get; set; } + [Localizable(true)] + private static string? No { get; set; } + [Localizable(true)] + private static string? Help { get; set; } + + /// + /// Type of that used to localize Buttons in . + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static Type? ResourceType { get; set; } + /// + /// The foreground color of the . + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static Color ForeColor { get; set; } = SystemColors.ControlText; + /// + /// The background color of the . + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static Color BackColor { get; set; } = SystemColors.Window; + /// + /// The background color of the Footer in . + /// + + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static Color FooterBackColor { get; set; } = SystemColors.Control; + private static LRESULT DlgProcInternal(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam) + => DlgProc(hWnd, (int)msg, (nint)wParam, lParam); + private static Icon? s_customIcon; // This is meant to be a static class, but predates that feature. private MessageBox() { } + private static LRESULT OnWmCtlColor(uint msg, IntPtr wParam) + { + switch (msg) + { + case PInvokeCore.WM_CTLCOLORBTN: + return new LRESULT(PInvokeCore.CreateSolidBrush(SystemColors.ButtonFace)); + case PInvokeCore.WM_CTLCOLORDLG: + case PInvokeCore.WM_CTLCOLORSTATIC: + HDC hdc = new HDC(wParam); + PInvokeCore.SetBkMode(hdc, BACKGROUND_MODE.TRANSPARENT); +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + PInvokeCore.SetTextColor(hdc, ForeColor); + return new LRESULT(PInvokeCore.CreateSolidBrush(BackColor)); +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + } + + return new LRESULT(0); + } + + private static LRESULT OnWmPaint(HWND hWnd, IntPtr wParam) + { + HDC hdc = (HDC)wParam; + bool usingBeginPaint = hdc.IsNull; + using var paintScope = usingBeginPaint ? new BeginPaintScope(hWnd) : default; + + RECT clipRect; + if (usingBeginPaint) + { + hdc = paintScope!.HDC; + clipRect = paintScope.PaintRectangle; + } + else + { + PInvokeCore.GetClientRect(hWnd, out clipRect); + } + +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + using CreateBrushScope backGroundBrushScope = new CreateBrushScope(BackColor); +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + hdc.FillRectangle(clipRect, backGroundBrushScope); + RECT FooterRect = clipRect; + FooterRect.top = clipRect.Height - SystemInformation.CaptionHeight * 2; +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + using CreateBrushScope FooterBrushScope = new CreateBrushScope(FooterBackColor); +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + hdc.FillRectangle(FooterRect, FooterBrushScope); + return new LRESULT(0); + } + + private static unsafe BOOL EnumChildProc(HWND handle) + { + string className = string.Empty; + Span buffer = stackalloc char[PInvokeCore.MaxClassName]; + int length = 0; + fixed (char* lpClassName = buffer) + { + length = PInvoke.GetClassName(handle, lpClassName, buffer.Length); + } + + className = buffer.ToString()[..length]; + switch (className) + { + case PInvoke.WC_BUTTON: +#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. + + PInvoke.SetWindowTheme(handle, Application.IsDarkModeEnabled ? "DarkMode_Explorer" : className, null); + +#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. + if (s_resourceManager is null) + { + return true; + } + + int dlgCtrlID = PInvoke.GetDlgCtrlID(s_hWndInternal); + switch (dlgCtrlID) + { + case MBOKId: + OK = s_resourceManager.GetString("OK", CultureInfo.CurrentCulture) ?? "&OK"; + PInvoke.SetWindowText(s_hWndInternal, OK); + break; + case MBCancelId: + OK = s_resourceManager.GetString("OK", CultureInfo.CurrentCulture); + Cancel = s_resourceManager.GetString("Cancel", CultureInfo.CurrentCulture) ?? "&Cancel"; + PInvoke.SetWindowText(s_hWndInternal, Cancel); + break; + case MBAbortId: + Abort = s_resourceManager.GetString("Abort", CultureInfo.CurrentCulture) ?? "&Abort"; + PInvoke.SetWindowText(s_hWndInternal, Abort); + break; + case MBRetryId: + Retry = s_resourceManager.GetString("Retry", CultureInfo.CurrentCulture) ?? "&Retry"; + PInvoke.SetWindowText(s_hWndInternal, Retry); + break; + case MBIgnoreId: + Ignore = s_resourceManager.GetString("Ignore", CultureInfo.CurrentCulture) ?? "&Ignore"; + PInvoke.SetWindowText(s_hWndInternal, Ignore); + break; + case MBYesId: + Yes = s_resourceManager.GetString("Yes", CultureInfo.CurrentCulture) ?? "&Yes"; + PInvoke.SetWindowText(s_hWndInternal, Yes); + break; + case MBNoId: + No = s_resourceManager.GetString("No", CultureInfo.CurrentCulture) ?? "&No"; + PInvoke.SetWindowText(s_hWndInternal, No); + break; + case MBHelpId: + Help = s_resourceManager.GetString("Help", CultureInfo.CurrentCulture) ?? "&Help"; + PInvoke.SetWindowText(s_hWndInternal, Help); + break; + } + + break; + } + + return true; + } + + private static unsafe void AllowDarkNonClientArea(HWND hWnd, bool allow) + { + BOOL currentValue; + HRESULT result = PInvoke.DwmGetWindowAttribute( + hWnd, + DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, + ¤tValue, + (uint)sizeof(BOOL)); + if (result.Succeeded) + { + if (currentValue == allow) + { + // no need for using DwmSetWindowAttribute + return; + } + + PInvoke.DwmSetWindowAttribute( + hWnd, + DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, + &allow, + (uint)sizeof(BOOL)).AssertSuccess(); + } + } + + private static unsafe LRESULT DlgProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) + { + s_hWndInternal = (HWND)hWnd; + switch ((uint)msg) + { + case PInvokeCore.WM_INITDIALOG: +#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. + AllowDarkNonClientArea(s_hWndInternal, Application.IsDarkModeEnabled); + if (s_customIcon is not null && s_customIcon.Handle != IntPtr.Zero) + { + HWND hwndIcon = PInvoke.GetDlgItem(s_hWndInternal, MBIconId); + if (!hwndIcon.IsNull) + { + PInvokeCore.SendMessage(hwndIcon, STM_SETICON, (WPARAM)s_customIcon.Handle, 0); + } + } +#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. + PInvokeCore.EnumChildWindows(s_hWndInternal, s_childWindowsCallback); + return PInvokeCore.CallWindowProc((void*)s_priorDlgProc, s_hWndInternal, (uint)msg, (nuint)wparam, lparam); + case PInvokeCore.WM_PAINT: + return OnWmPaint(s_hWndInternal, wparam); + case PInvokeCore.WM_CTLCOLORBTN: + case PInvokeCore.WM_CTLCOLORDLG: + case PInvokeCore.WM_CTLCOLORSTATIC: + return OnWmCtlColor((uint)msg, wparam); + default: + return PInvokeCore.CallWindowProc((void*)s_priorDlgProc, s_hWndInternal, (uint)msg, (nuint)wparam, lparam); + } + } + + private static unsafe void InstallHook() + { + lock (s_lock) + { + if (s_messageBoxHook != 0) + { + return; + } + + s_messageBoxHook = PInvoke.SetWindowsHookEx( + WINDOWS_HOOK_ID.WH_CALLWNDPROC, + (delegate* unmanaged[Stdcall])s_hookPointer, + HINSTANCE.Null, + PInvokeCore.GetCurrentThreadId()); + + s_isMessageBoxHooked = s_messageBoxHook != 0; + + Debug.Assert(s_isMessageBoxHooked, "Failed to install MessageBox hook."); + } + } + + private static void UnInstallHook() + { + lock (s_lock) + { + if (s_messageBoxHook != 0) + { + if (!PInvoke.UnhookWindowsHookEx(s_messageBoxHook)) + { + Debug.Fail("Failed to remove MessageBox hook."); + } + + s_messageBoxHook = default; + s_isMessageBoxHooked = false; + } + + if (s_priorDlgProc != 0) + { + PInvokeCore.SetWindowLong(s_hWndInternal, (WINDOW_LONG_PTR_INDEX)IntPtr.Size, s_priorDlgProc); + } + + s_priorDlgProc = 0; + } + } + + private static unsafe LRESULT HookProc(int nCode, WPARAM wParam, LPARAM lParam) + { + if (s_isMessageBoxHooked && nCode == PInvoke.HC_ACTION && lParam != 0) + { + CWPSTRUCT msg = Marshal.PtrToStructure(lParam); + if (msg.message == PInvokeCore.WM_INITDIALOG) + { + HWND hwndText = PInvoke.GetDlgItem(msg.hwnd, MBTextId); + if (!hwndText.IsNull) + { + WNDPROC ownerWindowProcedure = DlgProcInternal; + nint newDlgProcPointer = Marshal.GetFunctionPointerForDelegate(ownerWindowProcedure); + Debug.Assert(s_priorDlgProc == 0, "The previous subclass wasn't properly cleaned up"); + s_priorDlgProc = PInvokeCore.SetWindowLong( + msg.hwnd, + (WINDOW_LONG_PTR_INDEX)IntPtr.Size, + newDlgProcPointer); + } + + } + } + + return PInvoke.CallNextHookEx(s_messageBoxHook, nCode, wParam, lParam); + } + internal static HelpInfo? HelpInfo { get @@ -73,7 +387,7 @@ private static MESSAGEBOX_STYLE GetMessageBoxStyle( private static void PopHelpInfo() { // we roll our own stack here because we want a pretty lightweight implementation. - // usually there's only going to be one message box shown at a time. But if + // usually there's only going to be one message box shown at a time. But if // someone shows two message boxes (say by launching them via a WM_TIMER message) // we've got to gracefully handle the current help info. if (t_helpInfoTable is null) @@ -99,7 +413,7 @@ private static void PopHelpInfo() private static void PushHelpInfo(HelpInfo hpi) { // we roll our own stack here because we want a pretty lightweight implementation. - // usually there's only going to be one message box shown at a time. But if + // usually there's only going to be one message box shown at a time. But if // someone shows two message boxes (say by launching them via a WM_TIMER message) // we've got to gracefully handle the current help info. @@ -319,7 +633,225 @@ public static DialogResult Show( } /// - /// Displays a message box with specified text, caption, and style. + /// Displays a message box with specified text, caption, and style with Help Button. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + bool displayHelpButton) + { + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, displayHelpButton); + } + + /// + /// Displays a message box with specified text, caption, style and Help file Path . + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath) + { + HelpInfo hpi = new(helpFilePath); + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style and Help file Path for a IWin32Window. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + IWin32Window? owner, + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath) + { + HelpInfo hpi = new(helpFilePath); + s_customIcon = icon; + return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style, Help file Path, keyword and custom Icon. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath, + string keyword) + { + HelpInfo hpi = new(helpFilePath, keyword); + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style, Help file Path, keyword and custom Icon for a IWin32Window. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + IWin32Window? owner, + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath, + string keyword) + { + HelpInfo hpi = new(helpFilePath, keyword); + s_customIcon = icon; + return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style, Help file Path HelpNavigator, and custom Icon. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath, + HelpNavigator navigator) + { + HelpInfo hpi = new(helpFilePath, navigator); + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style, Help file Path HelpNavigator, and custom Icon for IWin32Window. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + IWin32Window? owner, + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath, + HelpNavigator navigator) + { + HelpInfo hpi = new(helpFilePath, navigator); + s_customIcon = icon; + return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style, Help file Path ,HelpNavigator,object and custom Icon. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath, + HelpNavigator navigator, + object? param) + { + HelpInfo hpi = new(helpFilePath, navigator, param); + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style, Help file Path ,HelpNavigator, object and custom Icon for a IWin32Window. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + IWin32Window? owner, + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + string helpFilePath, + HelpNavigator navigator, + object? param) + { + HelpInfo hpi = new(helpFilePath, navigator, param); + s_customIcon = icon; + return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); + } + + /// + /// Displays a message box with specified text, caption, style, and custom Icon. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options) + { + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, false); + } + + /// + /// Displays a message box with specified text, caption, style, and custom Icon. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon, + MessageBoxDefaultButton defaultButton) + { + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, 0, false); + } + + /// + /// Displays a message box with specified text, caption, style, and custom Icon. + /// + [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] + public static DialogResult Show( + string? text, + string? caption, + MessageBoxButtons buttons, + Icon icon) + { + s_customIcon = icon; + return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, 0, false); + } + + /// + /// Displays a message box with specified text, caption, style . /// public static DialogResult Show(string? text, string? caption, MessageBoxButtons buttons) { @@ -446,7 +978,7 @@ private static DialogResult ShowCore( MessageBoxOptions options, bool showHelp) { - if (AppContextSwitches.NoClientNotifications) + if (LocalAppContextSwitches.NoClientNotifications) { return DialogResult.None; } @@ -475,14 +1007,16 @@ private static DialogResult ShowCore( // Activate theming scope to get theming for controls at design time and when hosted in browser. // NOTE: If a theming context is already active, this call is very fast, so shouldn't be a perf issue. using ThemingScope scope = new(Application.UseVisualStyles); - Application.BeginModalMessageLoop(); + try { + InstallHook(); return (DialogResult)PInvoke.MessageBox(handle.Handle, text, caption, style); } finally { + UnInstallHook(); Application.EndModalMessageLoop(); // Right after the dialog box is closed, Windows sends WM_SETFOCUS back to the previously active control diff --git a/src/test/integration/WinformsControlsTest/Program.cs b/src/test/integration/WinformsControlsTest/Program.cs index ff4e7e9e8bb..ac06b660073 100644 --- a/src/test/integration/WinformsControlsTest/Program.cs +++ b/src/test/integration/WinformsControlsTest/Program.cs @@ -16,6 +16,10 @@ Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; +#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +Application.SetColorMode(SystemColorMode.Dark); +#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + try { MainForm form = new() diff --git a/start-vs.cmd b/start-vs.cmd index 00d7fab77eb..089808790e8 100644 --- a/start-vs.cmd +++ b/start-vs.cmd @@ -1,6 +1,8 @@ @echo off setlocal enabledelayedexpansion +:: Allow this script to run as administrator by right-clicking. +cd /d %~dp0 :: This command launches a Visual Studio solution with environment variables required to use a local version of the .NET Core SDK. :: This tells .NET Core to use the same dotnet.exe that build scripts use From dc9b4a9160784d9e6047d1ce05e4a61b7d7df791 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Sun, 11 May 2025 18:47:26 +0300 Subject: [PATCH 2/5] Complete MessageBox API Suggestion --- .../src/NativeMethods.txt | 1 + .../Windows/Forms/Dialogs/MessageBox.cs | 51 +++++-- .../MessageBoxes.ar-EG.resx | 144 ++++++++++++++++++ .../WinformsControlsTest/MessageBoxes.cs | 65 +++++++- .../WinformsControlsTest/Program.cs | 4 - 5 files changed, 241 insertions(+), 24 deletions(-) create mode 100644 src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx diff --git a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt index 96217baa334..0471243cb2c 100644 --- a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt +++ b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt @@ -225,6 +225,7 @@ GetViewportExtEx GetWindow GetWindowDpiAwarenessContext GetWindowPlacement +GetWindowTheme GetWorldTransform GMR_* HC_* diff --git a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs index 2ae0c1acd01..cce7190b408 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs @@ -7,7 +7,6 @@ using System.Resources; using System.Runtime.InteropServices; using System.Windows.Forms.Analyzers.Diagnostics; -using System.Windows.Forms.Primitives; using Windows.Win32.Graphics.Dwm; namespace System.Windows.Forms; @@ -96,7 +95,9 @@ private static LRESULT OnWmCtlColor(uint msg, IntPtr wParam) switch (msg) { case PInvokeCore.WM_CTLCOLORBTN: - return new LRESULT(PInvokeCore.CreateSolidBrush(SystemColors.ButtonFace)); +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + return new LRESULT(PInvokeCore.CreateSolidBrush(FooterBackColor)); +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. case PInvokeCore.WM_CTLCOLORDLG: case PInvokeCore.WM_CTLCOLORSTATIC: HDC hdc = new HDC(wParam); @@ -156,8 +157,13 @@ private static unsafe BOOL EnumChildProc(HWND handle) { case PInvoke.WC_BUTTON: #pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. + // Make sure that Uxtheme Visual Style is applied at this time to the Buttons + HTHEME buttonTheme = PInvoke.GetWindowTheme(handle); - PInvoke.SetWindowTheme(handle, Application.IsDarkModeEnabled ? "DarkMode_Explorer" : className, null); + if (!buttonTheme.IsNull) + { + PInvoke.SetWindowTheme(handle, Application.IsDarkModeEnabled ? "DarkMode_Explorer" : className, null); + } #pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. if (s_resourceManager is null) @@ -165,41 +171,41 @@ private static unsafe BOOL EnumChildProc(HWND handle) return true; } - int dlgCtrlID = PInvoke.GetDlgCtrlID(s_hWndInternal); + int dlgCtrlID = PInvoke.GetDlgCtrlID(handle); switch (dlgCtrlID) { case MBOKId: OK = s_resourceManager.GetString("OK", CultureInfo.CurrentCulture) ?? "&OK"; - PInvoke.SetWindowText(s_hWndInternal, OK); + PInvoke.SetWindowText(handle, OK); break; case MBCancelId: OK = s_resourceManager.GetString("OK", CultureInfo.CurrentCulture); Cancel = s_resourceManager.GetString("Cancel", CultureInfo.CurrentCulture) ?? "&Cancel"; - PInvoke.SetWindowText(s_hWndInternal, Cancel); + PInvoke.SetWindowText(handle, Cancel); break; case MBAbortId: Abort = s_resourceManager.GetString("Abort", CultureInfo.CurrentCulture) ?? "&Abort"; - PInvoke.SetWindowText(s_hWndInternal, Abort); + PInvoke.SetWindowText(handle, Abort); break; case MBRetryId: Retry = s_resourceManager.GetString("Retry", CultureInfo.CurrentCulture) ?? "&Retry"; - PInvoke.SetWindowText(s_hWndInternal, Retry); + PInvoke.SetWindowText(handle, Retry); break; case MBIgnoreId: Ignore = s_resourceManager.GetString("Ignore", CultureInfo.CurrentCulture) ?? "&Ignore"; - PInvoke.SetWindowText(s_hWndInternal, Ignore); + PInvoke.SetWindowText(handle, Ignore); break; case MBYesId: Yes = s_resourceManager.GetString("Yes", CultureInfo.CurrentCulture) ?? "&Yes"; - PInvoke.SetWindowText(s_hWndInternal, Yes); + PInvoke.SetWindowText(handle, Yes); break; case MBNoId: No = s_resourceManager.GetString("No", CultureInfo.CurrentCulture) ?? "&No"; - PInvoke.SetWindowText(s_hWndInternal, No); + PInvoke.SetWindowText(handle, No); break; case MBHelpId: Help = s_resourceManager.GetString("Help", CultureInfo.CurrentCulture) ?? "&Help"; - PInvoke.SetWindowText(s_hWndInternal, Help); + PInvoke.SetWindowText(handle, Help); break; } @@ -272,6 +278,10 @@ private static unsafe void InstallHook() return; } + // see https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-setwindowshookexw + // Installs a hook procedure that monitors messages before the system sends them to the destination. + + // Handling messages from WH_CALLWNDPROC or WH_CALLWNDPROCRET does not give good results so we chose to use WH_CALLWNDPROC and support subclassing by using Setwindowlong. s_messageBoxHook = PInvoke.SetWindowsHookEx( WINDOWS_HOOK_ID.WH_CALLWNDPROC, (delegate* unmanaged[Stdcall])s_hookPointer, @@ -318,6 +328,8 @@ private static unsafe LRESULT HookProc(int nCode, WPARAM wParam, LPARAM lParam) HWND hwndText = PInvoke.GetDlgItem(msg.hwnd, MBTextId); if (!hwndText.IsNull) { + // subclassing the DLGPROC instead of WNDPROC. + // DWL_DLGPROC and DWLP_DLGPROC have the exact value of IntPtr.Size. WNDPROC ownerWindowProcedure = DlgProcInternal; nint newDlgProcPointer = Marshal.GetFunctionPointerForDelegate(ownerWindowProcedure); Debug.Assert(s_priorDlgProc == 0, "The previous subclass wasn't properly cleaned up"); @@ -326,7 +338,6 @@ private static unsafe LRESULT HookProc(int nCode, WPARAM wParam, LPARAM lParam) (WINDOW_LONG_PTR_INDEX)IntPtr.Size, newDlgProcPointer); } - } } @@ -668,7 +679,8 @@ public static DialogResult Show( } /// - /// Displays a message box with specified text, caption, style and Help file Path for a IWin32Window. + /// Displays a message box with specified text, caption, style and Help file Path for a IWin32Window with custom Icon. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -688,6 +700,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, Help file Path, keyword and custom Icon. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -707,6 +720,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, Help file Path, keyword and custom Icon for a IWin32Window. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -727,6 +741,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, Help file Path HelpNavigator, and custom Icon. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -746,6 +761,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, Help file Path HelpNavigator, and custom Icon for IWin32Window. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -766,6 +782,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, Help file Path ,HelpNavigator,object and custom Icon. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -786,6 +803,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, Help file Path ,HelpNavigator, object and custom Icon for a IWin32Window. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -807,6 +825,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, and custom Icon. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -823,6 +842,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, and custom Icon. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -838,6 +858,7 @@ public static DialogResult Show( /// /// Displays a message box with specified text, caption, style, and custom Icon. + /// Rcomnded size of the custom icon is 32x32. /// [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] public static DialogResult Show( @@ -978,7 +999,7 @@ private static DialogResult ShowCore( MessageBoxOptions options, bool showHelp) { - if (LocalAppContextSwitches.NoClientNotifications) + if (AppContextSwitches.NoClientNotifications) { return DialogResult.None; } diff --git a/src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx b/src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx new file mode 100644 index 00000000000..ee42832f6c2 --- /dev/null +++ b/src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + إحباط + + + إلغاء + + + مساعدة + + + تجاهل + + + لا + + + موافق + + + إعادة المحاولة + + + نعم + + \ No newline at end of file diff --git a/src/test/integration/WinformsControlsTest/MessageBoxes.cs b/src/test/integration/WinformsControlsTest/MessageBoxes.cs index 66f14b7474f..5867198b4fa 100644 --- a/src/test/integration/WinformsControlsTest/MessageBoxes.cs +++ b/src/test/integration/WinformsControlsTest/MessageBoxes.cs @@ -3,6 +3,8 @@ #nullable enable +using System.Drawing; + namespace WinFormsControlsTest; [DesignerCategory("Default")] @@ -17,7 +19,7 @@ public MessageBoxes() _btnOpen = new("Show MessageBox") { - Image = (System.Drawing.Bitmap?)(resources.GetObject("OpenDialog")), + Image = (Bitmap?)(resources.GetObject("OpenDialog")), Enabled = false }; @@ -25,11 +27,25 @@ public MessageBoxes() { if ((_messgageBoxProxy.Options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) == 0) { - MessageBox.Show(this, _messgageBoxProxy.Text, _messgageBoxProxy.Caption, - _messgageBoxProxy.Buttons, _messgageBoxProxy.Icon, - _messgageBoxProxy.DefaultButton, _messgageBoxProxy.Options, - "mmc.chm", HelpNavigator.KeywordIndex, "ovals"); + PreparOpthions(); + if (_messgageBoxProxy.CustomIcon is not null) + { +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + MessageBox.Show(this, _messgageBoxProxy.Text, _messgageBoxProxy.Caption, + _messgageBoxProxy.Buttons, _messgageBoxProxy.CustomIcon, + _messgageBoxProxy.DefaultButton, _messgageBoxProxy.Options, + "mmc.chm", HelpNavigator.KeywordIndex, "ovals"); +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + } + else + { + MessageBox.Show(this, _messgageBoxProxy.Text, _messgageBoxProxy.Caption, + _messgageBoxProxy.Buttons, _messgageBoxProxy.Icon, + _messgageBoxProxy.DefaultButton, _messgageBoxProxy.Options, + "mmc.chm", HelpNavigator.KeywordIndex, "ovals"); + } } + else { MessageBox.Show(_messgageBoxProxy.Text, _messgageBoxProxy.Caption, @@ -45,6 +61,34 @@ public MessageBoxes() propertyGrid1.SelectedObject = _messgageBoxProxy; } + private void PreparOpthions() + { + if (_messgageBoxProxy.Localized) + { + Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("ar-EG"); +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + MessageBox.ResourceType = typeof(MessageBoxes); +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + } + else + { +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + MessageBox.ResourceType = null; +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; + } + +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + MessageBox.ForeColor = _messgageBoxProxy.ForColor; +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + MessageBox.BackColor = _messgageBoxProxy.BackColor; +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + MessageBox.FooterBackColor = _messgageBoxProxy.FooterBackColor; +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + } + private ToolStrip GetToolbar() { foreach (Control control in propertyGrid1.Controls) @@ -72,5 +116,16 @@ private class MessageBoxProxy public MessageBoxIcon Icon { get; set; } public MessageBoxDefaultButton DefaultButton { get; set; } public MessageBoxOptions Options { get; set; } + public Icon? CustomIcon { get; set; } +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public Color ForColor { get; set; } = MessageBox.ForeColor; +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public Color BackColor { get; set; } = MessageBox.BackColor; +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public Color FooterBackColor { get; set; } = MessageBox.FooterBackColor; +#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public bool Localized { get; set; } } } diff --git a/src/test/integration/WinformsControlsTest/Program.cs b/src/test/integration/WinformsControlsTest/Program.cs index ac06b660073..ff4e7e9e8bb 100644 --- a/src/test/integration/WinformsControlsTest/Program.cs +++ b/src/test/integration/WinformsControlsTest/Program.cs @@ -16,10 +16,6 @@ Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; -#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -Application.SetColorMode(SystemColorMode.Dark); -#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - try { MainForm form = new() From eabcaeee4b2b5873d6ce044c0d08a89a8f4b11e9 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Mon, 12 May 2025 16:47:34 +0300 Subject: [PATCH 3/5] Remove all MessageBox improvment and add only dark MessageBox style when DarkMode is enabeld --- .../Analyzers/Diagnostics/DiagnosticIDs.cs | 1 - .../Windows/Forms/Dialogs/MessageBox.cs | 385 ++---------------- .../MessageBoxes.ar-EG.resx | 144 ------- .../WinformsControlsTest/MessageBoxes.cs | 65 +-- 4 files changed, 32 insertions(+), 563 deletions(-) delete mode 100644 src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx diff --git a/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs b/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs index 2d5429a00ac..7d8ad147fb6 100644 --- a/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs +++ b/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs @@ -22,5 +22,4 @@ internal static class DiagnosticIDs // Experimental, number group 5000+ public const string ExperimentalDarkMode = "WFO5001"; public const string ExperimentalAsync = "WFO5002"; - public const string ExperimentalMessageBox = "WFO5003"; } diff --git a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs index cce7190b408..1942512abd6 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs @@ -3,10 +3,7 @@ using System.ComponentModel; using System.Drawing; -using System.Globalization; -using System.Resources; using System.Runtime.InteropServices; -using System.Windows.Forms.Analyzers.Diagnostics; using Windows.Win32.Graphics.Dwm; namespace System.Windows.Forms; @@ -17,21 +14,11 @@ public class MessageBox { [ThreadStatic] private static HelpInfo[]? t_helpInfoTable; - private const int MBOKId = 1; - private const int MBCancelId = 2; - private const int MBAbortId = 3; - private const int MBRetryId = 4; - private const int MBIgnoreId = 5; - private const int MBYesId = 6; - private const int MBNoId = 7; - private const int MBHelpId = 9; // see // https://devblogs.microsoft.com/oldnewthing/20140224-00/?p=1683 // and https://learn.microsoft.com/archive/msdn-magazine/2002/november/cutting-edge-using-windows-hooks-to-enhance-messagebox-in-net // Unique ID for static Edit in MessageBox, This ID has not changed since Windows 95 and will remain so. private const int MBTextId = ushort.MaxValue; // 0xFFFF - private const int MBIconId = 20; // 0X0014 - private const int STM_SETICON = 0x00000170; private static HHOOK s_messageBoxHook; private static bool s_isMessageBoxHooked; private static readonly HOOKPROC s_hookCallBack = HookProc; @@ -40,51 +27,8 @@ public class MessageBox private static HWND s_hWndInternal; private static nint s_priorDlgProc; private static readonly PInvokeCore.EnumChildWindowsCallback s_childWindowsCallback = new PInvokeCore.EnumChildWindowsCallback(EnumChildProc); - -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - private static ResourceManager? s_resourceManager => ResourceType is null ? null : new ResourceManager(ResourceType); -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - private static string? OK { get; set; } - [Localizable(true)] - private static string? Cancel { get; set; } - [Localizable(true)] - private static string? Abort { get; set; } - [Localizable(true)] - private static string? Retry { get; set; } - [Localizable(true)] - private static string? Ignore { get; set; } - [Localizable(true)] - private static string? Yes { get; set; } - [Localizable(true)] - private static string? No { get; set; } - [Localizable(true)] - private static string? Help { get; set; } - - /// - /// Type of that used to localize Buttons in . - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static Type? ResourceType { get; set; } - /// - /// The foreground color of the . - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static Color ForeColor { get; set; } = SystemColors.ControlText; - /// - /// The background color of the . - /// - - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static Color BackColor { get; set; } = SystemColors.Window; - /// - /// The background color of the Footer in . - /// - - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static Color FooterBackColor { get; set; } = SystemColors.Control; private static LRESULT DlgProcInternal(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam) => DlgProc(hWnd, (int)msg, (nint)wParam, lParam); - private static Icon? s_customIcon; // This is meant to be a static class, but predates that feature. private MessageBox() { @@ -95,17 +39,13 @@ private static LRESULT OnWmCtlColor(uint msg, IntPtr wParam) switch (msg) { case PInvokeCore.WM_CTLCOLORBTN: -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - return new LRESULT(PInvokeCore.CreateSolidBrush(FooterBackColor)); -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + return new LRESULT(PInvokeCore.CreateSolidBrush(SystemColors.Control)); case PInvokeCore.WM_CTLCOLORDLG: case PInvokeCore.WM_CTLCOLORSTATIC: HDC hdc = new HDC(wParam); PInvokeCore.SetBkMode(hdc, BACKGROUND_MODE.TRANSPARENT); -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - PInvokeCore.SetTextColor(hdc, ForeColor); - return new LRESULT(PInvokeCore.CreateSolidBrush(BackColor)); -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + PInvokeCore.SetTextColor(hdc, SystemColors.ControlText); + return new LRESULT(PInvokeCore.CreateSolidBrush(SystemColors.Window)); } @@ -117,27 +57,20 @@ private static LRESULT OnWmPaint(HWND hWnd, IntPtr wParam) HDC hdc = (HDC)wParam; bool usingBeginPaint = hdc.IsNull; using var paintScope = usingBeginPaint ? new BeginPaintScope(hWnd) : default; - RECT clipRect; + PInvokeCore.GetClientRect(hWnd, out clipRect); if (usingBeginPaint) { hdc = paintScope!.HDC; - clipRect = paintScope.PaintRectangle; - } - else - { - PInvokeCore.GetClientRect(hWnd, out clipRect); } -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using CreateBrushScope backGroundBrushScope = new CreateBrushScope(BackColor); -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + // Fill the background with the BackColor + using CreateBrushScope backGroundBrushScope = new CreateBrushScope(SystemColors.Window); hdc.FillRectangle(clipRect, backGroundBrushScope); RECT FooterRect = clipRect; FooterRect.top = clipRect.Height - SystemInformation.CaptionHeight * 2; -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - using CreateBrushScope FooterBrushScope = new CreateBrushScope(FooterBackColor); -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + // Fill the footer with the FooterBackColor + using CreateBrushScope FooterBrushScope = new CreateBrushScope(SystemColors.Control); hdc.FillRectangle(FooterRect, FooterBrushScope); return new LRESULT(0); } @@ -162,53 +95,15 @@ private static unsafe BOOL EnumChildProc(HWND handle) if (!buttonTheme.IsNull) { - PInvoke.SetWindowTheme(handle, Application.IsDarkModeEnabled ? "DarkMode_Explorer" : className, null); + const string DarkModeThemeIdentifier + = $"{Control.DarkModeIdentifier}_{Control.ExplorerThemeIdentifier}"; + PInvoke.SetWindowTheme(handle, + Application.IsDarkModeEnabled + ? $"{DarkModeThemeIdentifier}" + : PInvoke.WC_BUTTON, null); } #pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. - if (s_resourceManager is null) - { - return true; - } - - int dlgCtrlID = PInvoke.GetDlgCtrlID(handle); - switch (dlgCtrlID) - { - case MBOKId: - OK = s_resourceManager.GetString("OK", CultureInfo.CurrentCulture) ?? "&OK"; - PInvoke.SetWindowText(handle, OK); - break; - case MBCancelId: - OK = s_resourceManager.GetString("OK", CultureInfo.CurrentCulture); - Cancel = s_resourceManager.GetString("Cancel", CultureInfo.CurrentCulture) ?? "&Cancel"; - PInvoke.SetWindowText(handle, Cancel); - break; - case MBAbortId: - Abort = s_resourceManager.GetString("Abort", CultureInfo.CurrentCulture) ?? "&Abort"; - PInvoke.SetWindowText(handle, Abort); - break; - case MBRetryId: - Retry = s_resourceManager.GetString("Retry", CultureInfo.CurrentCulture) ?? "&Retry"; - PInvoke.SetWindowText(handle, Retry); - break; - case MBIgnoreId: - Ignore = s_resourceManager.GetString("Ignore", CultureInfo.CurrentCulture) ?? "&Ignore"; - PInvoke.SetWindowText(handle, Ignore); - break; - case MBYesId: - Yes = s_resourceManager.GetString("Yes", CultureInfo.CurrentCulture) ?? "&Yes"; - PInvoke.SetWindowText(handle, Yes); - break; - case MBNoId: - No = s_resourceManager.GetString("No", CultureInfo.CurrentCulture) ?? "&No"; - PInvoke.SetWindowText(handle, No); - break; - case MBHelpId: - Help = s_resourceManager.GetString("Help", CultureInfo.CurrentCulture) ?? "&Help"; - PInvoke.SetWindowText(handle, Help); - break; - } - break; } @@ -247,14 +142,6 @@ private static unsafe LRESULT DlgProc(IntPtr hWnd, int msg, IntPtr wparam, IntPt case PInvokeCore.WM_INITDIALOG: #pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. AllowDarkNonClientArea(s_hWndInternal, Application.IsDarkModeEnabled); - if (s_customIcon is not null && s_customIcon.Handle != IntPtr.Zero) - { - HWND hwndIcon = PInvoke.GetDlgItem(s_hWndInternal, MBIconId); - if (!hwndIcon.IsNull) - { - PInvokeCore.SendMessage(hwndIcon, STM_SETICON, (WPARAM)s_customIcon.Handle, 0); - } - } #pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. PInvokeCore.EnumChildWindows(s_hWndInternal, s_childWindowsCallback); return PInvokeCore.CallWindowProc((void*)s_priorDlgProc, s_hWndInternal, (uint)msg, (nuint)wparam, lparam); @@ -294,7 +181,7 @@ private static unsafe void InstallHook() } } - private static void UnInstallHook() + private static void UninstallHook() { lock (s_lock) { @@ -643,234 +530,6 @@ public static DialogResult Show( return ShowCore(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1, 0, false); } - /// - /// Displays a message box with specified text, caption, and style with Help Button. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - bool displayHelpButton) - { - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, displayHelpButton); - } - - /// - /// Displays a message box with specified text, caption, style and Help file Path . - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath) - { - HelpInfo hpi = new(helpFilePath); - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style and Help file Path for a IWin32Window with custom Icon. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - IWin32Window? owner, - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath) - { - HelpInfo hpi = new(helpFilePath); - s_customIcon = icon; - return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style, Help file Path, keyword and custom Icon. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath, - string keyword) - { - HelpInfo hpi = new(helpFilePath, keyword); - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style, Help file Path, keyword and custom Icon for a IWin32Window. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - IWin32Window? owner, - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath, - string keyword) - { - HelpInfo hpi = new(helpFilePath, keyword); - s_customIcon = icon; - return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style, Help file Path HelpNavigator, and custom Icon. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath, - HelpNavigator navigator) - { - HelpInfo hpi = new(helpFilePath, navigator); - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style, Help file Path HelpNavigator, and custom Icon for IWin32Window. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - IWin32Window? owner, - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath, - HelpNavigator navigator) - { - HelpInfo hpi = new(helpFilePath, navigator); - s_customIcon = icon; - return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style, Help file Path ,HelpNavigator,object and custom Icon. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath, - HelpNavigator navigator, - object? param) - { - HelpInfo hpi = new(helpFilePath, navigator, param); - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style, Help file Path ,HelpNavigator, object and custom Icon for a IWin32Window. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - IWin32Window? owner, - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options, - string helpFilePath, - HelpNavigator navigator, - object? param) - { - HelpInfo hpi = new(helpFilePath, navigator, param); - s_customIcon = icon; - return ShowCore(owner, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, hpi); - } - - /// - /// Displays a message box with specified text, caption, style, and custom Icon. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton, - MessageBoxOptions options) - { - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, options, false); - } - - /// - /// Displays a message box with specified text, caption, style, and custom Icon. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon, - MessageBoxDefaultButton defaultButton) - { - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, defaultButton, 0, false); - } - - /// - /// Displays a message box with specified text, caption, style, and custom Icon. - /// Rcomnded size of the custom icon is 32x32. - /// - [Experimental(DiagnosticIDs.ExperimentalMessageBox, UrlFormat = DiagnosticIDs.UrlFormat)] - public static DialogResult Show( - string? text, - string? caption, - MessageBoxButtons buttons, - Icon icon) - { - s_customIcon = icon; - return ShowCore(null, text, caption, buttons, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, 0, false); - } - /// /// Displays a message box with specified text, caption, style . /// @@ -1032,12 +691,22 @@ private static DialogResult ShowCore( try { - InstallHook(); +#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + if (Application.IsDarkModeEnabled) + { + InstallHook(); + } +#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. return (DialogResult)PInvoke.MessageBox(handle.Handle, text, caption, style); } finally { - UnInstallHook(); +#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + if (Application.IsDarkModeEnabled) + { + UninstallHook(); + } +#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. Application.EndModalMessageLoop(); // Right after the dialog box is closed, Windows sends WM_SETFOCUS back to the previously active control diff --git a/src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx b/src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx deleted file mode 100644 index ee42832f6c2..00000000000 --- a/src/test/integration/WinformsControlsTest/MessageBoxes.ar-EG.resx +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - إحباط - - - إلغاء - - - مساعدة - - - تجاهل - - - لا - - - موافق - - - إعادة المحاولة - - - نعم - - \ No newline at end of file diff --git a/src/test/integration/WinformsControlsTest/MessageBoxes.cs b/src/test/integration/WinformsControlsTest/MessageBoxes.cs index 5867198b4fa..66f14b7474f 100644 --- a/src/test/integration/WinformsControlsTest/MessageBoxes.cs +++ b/src/test/integration/WinformsControlsTest/MessageBoxes.cs @@ -3,8 +3,6 @@ #nullable enable -using System.Drawing; - namespace WinFormsControlsTest; [DesignerCategory("Default")] @@ -19,7 +17,7 @@ public MessageBoxes() _btnOpen = new("Show MessageBox") { - Image = (Bitmap?)(resources.GetObject("OpenDialog")), + Image = (System.Drawing.Bitmap?)(resources.GetObject("OpenDialog")), Enabled = false }; @@ -27,25 +25,11 @@ public MessageBoxes() { if ((_messgageBoxProxy.Options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) == 0) { - PreparOpthions(); - if (_messgageBoxProxy.CustomIcon is not null) - { -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - MessageBox.Show(this, _messgageBoxProxy.Text, _messgageBoxProxy.Caption, - _messgageBoxProxy.Buttons, _messgageBoxProxy.CustomIcon, - _messgageBoxProxy.DefaultButton, _messgageBoxProxy.Options, - "mmc.chm", HelpNavigator.KeywordIndex, "ovals"); -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - } - else - { - MessageBox.Show(this, _messgageBoxProxy.Text, _messgageBoxProxy.Caption, - _messgageBoxProxy.Buttons, _messgageBoxProxy.Icon, - _messgageBoxProxy.DefaultButton, _messgageBoxProxy.Options, - "mmc.chm", HelpNavigator.KeywordIndex, "ovals"); - } + MessageBox.Show(this, _messgageBoxProxy.Text, _messgageBoxProxy.Caption, + _messgageBoxProxy.Buttons, _messgageBoxProxy.Icon, + _messgageBoxProxy.DefaultButton, _messgageBoxProxy.Options, + "mmc.chm", HelpNavigator.KeywordIndex, "ovals"); } - else { MessageBox.Show(_messgageBoxProxy.Text, _messgageBoxProxy.Caption, @@ -61,34 +45,6 @@ public MessageBoxes() propertyGrid1.SelectedObject = _messgageBoxProxy; } - private void PreparOpthions() - { - if (_messgageBoxProxy.Localized) - { - Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("ar-EG"); -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - MessageBox.ResourceType = typeof(MessageBoxes); -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - } - else - { -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - MessageBox.ResourceType = null; -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; - } - -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - MessageBox.ForeColor = _messgageBoxProxy.ForColor; -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - MessageBox.BackColor = _messgageBoxProxy.BackColor; -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - MessageBox.FooterBackColor = _messgageBoxProxy.FooterBackColor; -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - } - private ToolStrip GetToolbar() { foreach (Control control in propertyGrid1.Controls) @@ -116,16 +72,5 @@ private class MessageBoxProxy public MessageBoxIcon Icon { get; set; } public MessageBoxDefaultButton DefaultButton { get; set; } public MessageBoxOptions Options { get; set; } - public Icon? CustomIcon { get; set; } -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public Color ForColor { get; set; } = MessageBox.ForeColor; -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public Color BackColor { get; set; } = MessageBox.BackColor; -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -#pragma warning disable WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public Color FooterBackColor { get; set; } = MessageBox.FooterBackColor; -#pragma warning restore WFO5003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public bool Localized { get; set; } } } From 81b583d2d26a35d6bcd77bab774ffd6daebadd92 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Mon, 12 May 2025 17:14:03 +0300 Subject: [PATCH 4/5] remove PublicAPI.Unshipped and fix build error --- src/test/integration/WinformsControlsTest/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/integration/WinformsControlsTest/Program.cs b/src/test/integration/WinformsControlsTest/Program.cs index ff4e7e9e8bb..f02faea745b 100644 --- a/src/test/integration/WinformsControlsTest/Program.cs +++ b/src/test/integration/WinformsControlsTest/Program.cs @@ -10,7 +10,7 @@ ApplicationConfiguration.Initialize(); #pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -Application.SetColorMode(SystemColorMode.Classic); +Application.SetColorMode(SystemColorMode.System); #pragma warning restore WFO5001 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); From 925fc08d4e84cd975d0b0ccb6caef4c1db399e10 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Mon, 12 May 2025 17:16:23 +0300 Subject: [PATCH 5/5] remove PublicAPI.Unshipped and fix build error --- .../PublicAPI.Unshipped.txt | 20 ------------------- .../Windows/Forms/Dialogs/MessageBox.cs | 1 - .../WinformsControlsTest/Program.cs | 2 +- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/System.Windows.Forms/PublicAPI.Unshipped.txt b/src/System.Windows.Forms/PublicAPI.Unshipped.txt index b62305537bc..e69de29bb2d 100644 --- a/src/System.Windows.Forms/PublicAPI.Unshipped.txt +++ b/src/System.Windows.Forms/PublicAPI.Unshipped.txt @@ -1,20 +0,0 @@ -static System.Windows.Forms.MessageBox.BackColor.get -> System.Drawing.Color -static System.Windows.Forms.MessageBox.BackColor.set -> void -static System.Windows.Forms.MessageBox.FooterBackColor.get -> System.Drawing.Color -static System.Windows.Forms.MessageBox.FooterBackColor.set -> void -static System.Windows.Forms.MessageBox.ForeColor.get -> System.Drawing.Color -static System.Windows.Forms.MessageBox.ForeColor.set -> void -static System.Windows.Forms.MessageBox.ResourceType.get -> System.Type? -static System.Windows.Forms.MessageBox.ResourceType.set -> void -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, bool displayHelpButton) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, string! keyword) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator, object? param) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, string! keyword) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator) -> System.Windows.Forms.DialogResult -[WFO5003]static System.Windows.Forms.MessageBox.Show(System.Windows.Forms.IWin32Window? owner, string? text, string? caption, System.Windows.Forms.MessageBoxButtons buttons, System.Drawing.Icon! icon, System.Windows.Forms.MessageBoxDefaultButton defaultButton, System.Windows.Forms.MessageBoxOptions options, string! helpFilePath, System.Windows.Forms.HelpNavigator navigator, object? param) -> System.Windows.Forms.DialogResult \ No newline at end of file diff --git a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs index 1942512abd6..67f8ad99d49 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Dialogs/MessageBox.cs @@ -46,7 +46,6 @@ private static LRESULT OnWmCtlColor(uint msg, IntPtr wParam) PInvokeCore.SetBkMode(hdc, BACKGROUND_MODE.TRANSPARENT); PInvokeCore.SetTextColor(hdc, SystemColors.ControlText); return new LRESULT(PInvokeCore.CreateSolidBrush(SystemColors.Window)); - } return new LRESULT(0); diff --git a/src/test/integration/WinformsControlsTest/Program.cs b/src/test/integration/WinformsControlsTest/Program.cs index f02faea745b..ff4e7e9e8bb 100644 --- a/src/test/integration/WinformsControlsTest/Program.cs +++ b/src/test/integration/WinformsControlsTest/Program.cs @@ -10,7 +10,7 @@ ApplicationConfiguration.Initialize(); #pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -Application.SetColorMode(SystemColorMode.System); +Application.SetColorMode(SystemColorMode.Classic); #pragma warning restore WFO5001 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);