// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms.Layout;
using System.Windows.Forms.VisualStyles;
using Windows.Win32.Graphics.Dwm;
using Windows.Win32.System.Threading;
using Windows.Win32.UI.Accessibility;

namespace System.Windows.Forms;

/// <summary>
///  Represents a window or dialog box that makes up an application's user interface.
/// </summary>
[ToolboxItemFilter("System.Windows.Forms.Control.TopLevel")]
[ToolboxItem(false)]
[DesignTimeVisible(false)]
[Designer($"System.Windows.Forms.Design.FormDocumentDesigner, {Assemblies.SystemDesign}", typeof(IRootDesigner))]
[DefaultEvent(nameof(Load))]
[InitializationEvent(nameof(Load))]
[DesignerCategory("Form")]
public partial class Form : ContainerControl
{
    private static readonly object s_activatedEvent = new();
    private static readonly object s_closingEvent = new();
    private static readonly object s_closedEvent = new();
    private static readonly object s_formClosingEvent = new();
    private static readonly object s_formClosedEvent = new();
    private static readonly object s_deactivateEvent = new();
    private static readonly object s_loadEvent = new();
    private static readonly object s_mdiChildActivateEvent = new();
    private static readonly object s_inputLanguageChangeEvent = new();
    private static readonly object s_inputLanguageChangeRequestEvent = new();
    private static readonly object s_menuStartEvent = new();
    private static readonly object s_menuCompleteEvent = new();
    private static readonly object s_maximumSizeChangedEvent = new();
    private static readonly object s_minimumSizeChangedEvent = new();
    private static readonly object s_helpButtonChangedEvent = new();
    private static readonly object s_shownEvent = new();
    private static readonly object s_resizeBeginEvent = new();
    private static readonly object s_resizeEndEvent = new();
    private static readonly object s_rightToLeftLayoutChangedEvent = new();
    private static readonly object s_dpiChangedEvent = new();
    private static readonly object s_formBorderColorChanged = new();
    private static readonly object s_formCaptionBackColorChanged = new();
    private static readonly object s_formCaptionTextColorChanged = new();
    private static readonly object s_formCornerPreferenceChanged = new();

    //
    // The following flags should be used with formState[..] not formStateEx[..]
    // Don't add any more sections to this vector, it is already full.
    //
    private static readonly BitVector32.Section s_formStateAllowTransparency = BitVector32.CreateSection(1);
    private static readonly BitVector32.Section s_formStateBorderStyle = BitVector32.CreateSection(6, s_formStateAllowTransparency);
    private static readonly BitVector32.Section s_formStateTaskBar = BitVector32.CreateSection(1, s_formStateBorderStyle);
    private static readonly BitVector32.Section s_formStateControlBox = BitVector32.CreateSection(1, s_formStateTaskBar);
    private static readonly BitVector32.Section s_formStateKeyPreview = BitVector32.CreateSection(1, s_formStateControlBox);
    private static readonly BitVector32.Section s_formStateLayered = BitVector32.CreateSection(1, s_formStateKeyPreview);
    private static readonly BitVector32.Section s_formStateMaximizeBox = BitVector32.CreateSection(1, s_formStateLayered);
    private static readonly BitVector32.Section s_formStateMinimizeBox = BitVector32.CreateSection(1, s_formStateMaximizeBox);
    private static readonly BitVector32.Section s_formStateHelpButton = BitVector32.CreateSection(1, s_formStateMinimizeBox);
    private static readonly BitVector32.Section s_formStateStartPos = BitVector32.CreateSection(4, s_formStateHelpButton);
    private static readonly BitVector32.Section s_formStateWindowState = BitVector32.CreateSection(2, s_formStateStartPos);
    private static readonly BitVector32.Section s_formStateShowWindowOnCreate = BitVector32.CreateSection(1, s_formStateWindowState);
    private static readonly BitVector32.Section s_formStateAutoScaling = BitVector32.CreateSection(1, s_formStateShowWindowOnCreate);
    private static readonly BitVector32.Section s_formStateSetClientSize = BitVector32.CreateSection(1, s_formStateAutoScaling);
    private static readonly BitVector32.Section s_formStateTopMost = BitVector32.CreateSection(1, s_formStateSetClientSize);
    private static readonly BitVector32.Section s_formStateSWCalled = BitVector32.CreateSection(1, s_formStateTopMost);
    private static readonly BitVector32.Section s_formStateMdiChildMax = BitVector32.CreateSection(1, s_formStateSWCalled);
    private static readonly BitVector32.Section s_formStateRenderSizeGrip = BitVector32.CreateSection(1, s_formStateMdiChildMax);
    private static readonly BitVector32.Section s_formStateSizeGripStyle = BitVector32.CreateSection(2, s_formStateRenderSizeGrip);
    private static readonly BitVector32.Section s_formStateIsWindowActivated = BitVector32.CreateSection(1, s_formStateSizeGripStyle);
    private static readonly BitVector32.Section s_formStateIsTextEmpty = BitVector32.CreateSection(1, s_formStateIsWindowActivated);
    private static readonly BitVector32.Section s_formStateIsActive = BitVector32.CreateSection(1, s_formStateIsTextEmpty);
    private static readonly BitVector32.Section s_formStateIconSet = BitVector32.CreateSection(1, s_formStateIsActive);

    // The following flags should be used with formStateEx[...] not formState[..]
    private static readonly BitVector32.Section s_formStateExCalledClosing = BitVector32.CreateSection(1);
    private static readonly BitVector32.Section s_formStateExUpdateMenuHandlesSuspendCount = BitVector32.CreateSection(8, s_formStateExCalledClosing);
    private static readonly BitVector32.Section s_formStateExUpdateMenuHandlesDeferred = BitVector32.CreateSection(1, s_formStateExUpdateMenuHandlesSuspendCount);
    private static readonly BitVector32.Section s_formStateExUseMdiChildProc = BitVector32.CreateSection(1, s_formStateExUpdateMenuHandlesDeferred);
    private static readonly BitVector32.Section s_formStateExCalledOnLoad = BitVector32.CreateSection(1, s_formStateExUseMdiChildProc);
    private static readonly BitVector32.Section s_formStateExCalledMakeVisible = BitVector32.CreateSection(1, s_formStateExCalledOnLoad);
    private static readonly BitVector32.Section s_formStateExCalledCreateControl = BitVector32.CreateSection(1, s_formStateExCalledMakeVisible);
    private static readonly BitVector32.Section s_formStateExAutoSize = BitVector32.CreateSection(1, s_formStateExCalledCreateControl);
    private static readonly BitVector32.Section s_formStateExInUpdateMdiControlStrip = BitVector32.CreateSection(1, s_formStateExAutoSize);
    private static readonly BitVector32.Section s_formStateExShowIcon = BitVector32.CreateSection(1, s_formStateExInUpdateMdiControlStrip);
    private static readonly BitVector32.Section s_formStateExMnemonicProcessed = BitVector32.CreateSection(1, s_formStateExShowIcon);
    private static readonly BitVector32.Section s_formStateExInScale = BitVector32.CreateSection(1, s_formStateExMnemonicProcessed);
    private static readonly BitVector32.Section s_formStateExInModalSizingLoop = BitVector32.CreateSection(1, s_formStateExInScale);
    private static readonly BitVector32.Section s_formStateExSettingAutoScale = BitVector32.CreateSection(1, s_formStateExInModalSizingLoop);
    private static readonly BitVector32.Section s_formStateExWindowBoundsWidthIsClientSize = BitVector32.CreateSection(1, s_formStateExSettingAutoScale);
    private static readonly BitVector32.Section s_formStateExWindowBoundsHeightIsClientSize = BitVector32.CreateSection(1, s_formStateExWindowBoundsWidthIsClientSize);
    private static readonly BitVector32.Section s_formStateExWindowClosing = BitVector32.CreateSection(1, s_formStateExWindowBoundsHeightIsClientSize);

    private const int SizeGripSize = 16;

    private static Icon? s_defaultIcon;
    private static readonly Lock s_internalSyncObject = new();

    // Property store keys for properties. The property store allocates most efficiently
    // in groups of four, so we try to lump properties in groups of four based on how
    // likely they are going to be used in a group.

    private static readonly int s_propAcceptButton = PropertyStore.CreateKey();
    private static readonly int s_propCancelButton = PropertyStore.CreateKey();
    private static readonly int s_propDefaultButton = PropertyStore.CreateKey();
    private static readonly int s_propDialogOwner = PropertyStore.CreateKey();

    private static readonly int s_propOwner = PropertyStore.CreateKey();
    private static readonly int s_propOwnedForms = PropertyStore.CreateKey();
    private static readonly int s_propMaximizedBounds = PropertyStore.CreateKey();

    private static readonly int s_propMinTrackSize = PropertyStore.CreateKey();
    private static readonly int s_propMaxTrackSize = PropertyStore.CreateKey();

    private static readonly int s_propFormMdiParent = PropertyStore.CreateKey();
    private static readonly int s_propActiveMdiChild = PropertyStore.CreateKey();
    private static readonly int s_propFormerlyActiveMdiChild = PropertyStore.CreateKey();
    private static readonly int s_propMdiChildFocusable = PropertyStore.CreateKey();

    private static readonly int s_propDummyMdiMenu = PropertyStore.CreateKey();
    private static readonly int s_propMainMenuStrip = PropertyStore.CreateKey();
    private static readonly int s_propMdiWindowListStrip = PropertyStore.CreateKey();
    private static readonly int s_propMdiControlStrip = PropertyStore.CreateKey();

    private static readonly int s_propOpacity = PropertyStore.CreateKey();
    private static readonly int s_propTransparencyKey = PropertyStore.CreateKey();
    private static readonly int s_propFormCornerPreference = PropertyStore.CreateKey();
    private static readonly int s_propFormBorderColor = PropertyStore.CreateKey();

    private static readonly int s_propFormCaptionTextColor = PropertyStore.CreateKey();
    private static readonly int s_propFormCaptionBackColor = PropertyStore.CreateKey();
    private static readonly int s_propFormScreenCaptureMode = PropertyStore.CreateKey();
#if NET11_0_OR_GREATER
    private static readonly int s_propFormAppearanceCloaked = PropertyStore.CreateKey();
#endif

    // Form per instance members
    // Note: Do not add anything to this list unless absolutely necessary.

    private BitVector32 _formState = new(0x21338);   // magic value... all the defaults... see the ctor for details...
    private BitVector32 _formStateEx;

    private Icon? _icon;
    private Icon? _smallIcon;
    private Size _autoScaleBaseSize = Size.Empty;
    private Size _minAutoSize = Size.Empty;
    private Rectangle _restoredWindowBounds = new(-1, -1, -1, -1);
    private BoundsSpecified _restoredWindowBoundsSpecified;
    private DialogResult _dialogResult;
    private MdiClient? _ctlClient;
    private NativeWindow? _ownerWindow;
    private bool _rightToLeftLayout;

    private Rectangle _restoreBounds = new(-1, -1, -1, -1);
    private CloseReason _closeReason = CloseReason.None;

    private VisualStyleRenderer? _sizeGripRenderer;

    // Cache Form's size for the DPI. When Form is moved between the monitors with different DPI settings, we use
    // cached values to set the size matching the DPI on the Form instead of recalculating the size again. This help
    // preventing rounding error in size calculations with float DPI factor and rounding it to nearest integer.
    private Dictionary<int, Size>? _dpiFormSizes;
    private bool _processingDpiChanged;
    private bool _inRecreateHandle;

    private TaskCompletionSource? _nonModalFormCompletion;
    private TaskCompletionSource<DialogResult>? _modalFormCompletion;
    private readonly Lock _lock = new();

    /// <summary>
    ///  Initializes a new instance of the <see cref="Form"/> class.
    /// </summary>
    public Form() : base()
    {
        // Assert section.
        Debug.Assert(_formState[s_formStateAllowTransparency] == 0, "Failed to set formState[FormStateAllowTransparency]");
        Debug.Assert(_formState[s_formStateBorderStyle] == (int)FormBorderStyle.Sizable, "Failed to set formState[FormStateBorderStyle]");
        Debug.Assert(_formState[s_formStateTaskBar] == 1, "Failed to set formState[FormStateTaskBar]");
        Debug.Assert(_formState[s_formStateControlBox] == 1, "Failed to set formState[FormStateControlBox]");
        Debug.Assert(_formState[s_formStateKeyPreview] == 0, "Failed to set formState[FormStateKeyPreview]");
        Debug.Assert(_formState[s_formStateLayered] == 0, "Failed to set formState[FormStateLayered]");
        Debug.Assert(_formState[s_formStateMaximizeBox] == 1, "Failed to set formState[FormStateMaximizeBox]");
        Debug.Assert(_formState[s_formStateMinimizeBox] == 1, "Failed to set formState[FormStateMinimizeBox]");
        Debug.Assert(_formState[s_formStateHelpButton] == 0, "Failed to set formState[FormStateHelpButton]");
        Debug.Assert(_formState[s_formStateStartPos] == (int)FormStartPosition.WindowsDefaultLocation, "Failed to set formState[FormStateStartPos]");
        Debug.Assert(_formState[s_formStateWindowState] == (int)FormWindowState.Normal, "Failed to set formState[FormStateWindowState]");
        Debug.Assert(_formState[s_formStateShowWindowOnCreate] == 0, "Failed to set formState[FormStateShowWindowOnCreate]");
        Debug.Assert(_formState[s_formStateAutoScaling] == 1, "Failed to set formState[FormStateAutoScaling]");
        Debug.Assert(_formState[s_formStateSetClientSize] == 0, "Failed to set formState[FormStateSetClientSize]");
        Debug.Assert(_formState[s_formStateTopMost] == 0, "Failed to set formState[FormStateTopMost]");
        Debug.Assert(_formState[s_formStateSWCalled] == 0, "Failed to set formState[FormStateSWCalled]");
        Debug.Assert(_formState[s_formStateMdiChildMax] == 0, "Failed to set formState[FormStateMdiChildMax]");
        Debug.Assert(_formState[s_formStateRenderSizeGrip] == 0, "Failed to set formState[FormStateRenderSizeGrip]");
        Debug.Assert(_formState[s_formStateSizeGripStyle] == 0, "Failed to set formState[FormStateSizeGripStyle]");
        Debug.Assert(_formState[s_formStateIsWindowActivated] == 0, "Failed to set formState[FormStateIsWindowActivated]");
        Debug.Assert(_formState[s_formStateIsTextEmpty] == 0, "Failed to set formState[FormStateIsTextEmpty]");
        Debug.Assert(_formState[s_formStateIsActive] == 0, "Failed to set formState[FormStateIsActive]");
        Debug.Assert(_formState[s_formStateIconSet] == 0, "Failed to set formState[FormStateIconSet]");

        _formStateEx[s_formStateExShowIcon] = 1;

        SetState(States.Visible, false);
        SetState(States.TopLevel, true);
    }

    /// <summary>
    ///  Indicates the <see cref="Button"/> control on the form that is clicked when
    ///  the user presses the ENTER key.
    /// </summary>
    [DefaultValue(null)]
    [SRDescription(nameof(SR.FormAcceptButtonDescr))]
    public IButtonControl? AcceptButton
    {
        get => Properties.GetValueOrDefault<IButtonControl?>(s_propAcceptButton);
        set
        {
            if (Properties.AddOrRemoveValue(s_propAcceptButton, value) != value)
            {
                UpdateDefaultButton();
            }
        }
    }

    /// <summary>
    ///  Retrieves true if this form is currently active.
    /// </summary>
    internal bool Active
    {
        get
        {
            Form? parentForm = ParentForm;
            if (parentForm is null)
            {
                return _formState[s_formStateIsActive] != 0;
            }

            return parentForm.ActiveControl == this && parentForm.Active;
        }
        set
        {
            if (_formState[s_formStateIsActive] != 0 == value)
            {
                return;
            }

            if (value && !CanRecreateHandle())
            {
                return;
            }

            _formState[s_formStateIsActive] = value ? 1 : 0;

            if (value)
            {
                _formState[s_formStateIsWindowActivated] = 1;

                // Check if validation has been canceled to avoid raising Validation event multiple times.
                if (!ValidationCancelled)
                {
                    if (ActiveControl is null)
                    {
                        // If no control is selected focus will go to form
                        SelectNextControl(null, true, true, true, false);
                    }

                    InnerMostActiveContainerControl.FocusActiveControlInternal();
                }

                OnActivated(EventArgs.Empty);
            }
            else
            {
                _formState[s_formStateIsWindowActivated] = 0;
                OnDeactivate(EventArgs.Empty);
            }
        }
    }

    /// <summary>
    ///  Gets the currently active form for this application.
    /// </summary>
    public static Form? ActiveForm => FromHandle(PInvokeCore.GetForegroundWindow()) as Form;

    /// <summary>
    ///
    ///  Gets the currently active multiple document interface (MDI) child window.
    ///  Note: Don't use this property internally, use ActiveMdiChildInternal instead (see comments below).
    /// </summary>
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormActiveMDIChildDescr))]
    public Form? ActiveMdiChild
    {
        get
        {
            Form? mdiChild = ActiveMdiChildInternal;

            // We keep the active mdi child in the cached in the property store; when changing its value
            // (due to a change to one of the following properties/methods: Visible, Enabled, Active, Show/Hide,
            // Focus() or as the  result of WM_SETFOCUS/WM_ACTIVATE/WM_MDIACTIVATE) we temporarily set it to null
            // (to properly handle menu merging among other things) rendering the cache out-of-date; the problem
            // arises when the user has an event handler that is raised during this process; in that case we ask
            // Windows for it (see ActiveMdiChildFromWindows).

            if (mdiChild is null)
            {
                // If this.MdiClient is not null it means this.IsMdiContainer == true.
                if (_ctlClient is not null && _ctlClient.IsHandleCreated)
                {
                    IntPtr hwnd = PInvokeCore.SendMessage(_ctlClient, PInvokeCore.WM_MDIGETACTIVE);
                    mdiChild = FromHandle(hwnd) as Form;
                }
            }

            if (mdiChild is not null && mdiChild.Visible && mdiChild.Enabled)
            {
                return mdiChild;
            }

            return null;
        }
    }

    /// <summary>
    ///  Property to be used internally. See comments a on ActiveMdiChild property.
    /// </summary>
    internal Form? ActiveMdiChildInternal
    {
        get => Properties.GetValueOrDefault<Form>(s_propActiveMdiChild);
        set => Properties.AddOrRemoveValue(s_propActiveMdiChild, value);
    }

    // we don't repaint the mdi child that used to be active any more. We used to do this in Activated, but no
    // longer do because of added event Deactivate.
    private Form? FormerlyActiveMdiChild
    {
        get => Properties.GetValueOrDefault<Form>(s_propFormerlyActiveMdiChild);
        set => Properties.AddOrRemoveValue(s_propFormerlyActiveMdiChild, value);
    }

    /// <summary>
    ///  Gets or sets a value indicating whether the opacity of the form can be adjusted.
    /// </summary>
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.ControlAllowTransparencyDescr))]
    public bool AllowTransparency
    {
        get => _formState[s_formStateAllowTransparency] != 0;
        set
        {
            if (value == (_formState[s_formStateAllowTransparency] != 0))
            {
                return;
            }

            _formState[s_formStateAllowTransparency] = value ? 1 : 0;

            _formState[s_formStateLayered] = _formState[s_formStateAllowTransparency];

            UpdateStyles();

            if (!value)
            {
                Properties.RemoveValue(s_propOpacity);

                if (Properties.ContainsKey(s_propTransparencyKey))
                {
                    Properties.AddValue(s_propTransparencyKey, Color.Empty);
                }

                UpdateLayered();
            }
        }
    }

    /// <summary>
    ///  Gets or sets a value indicating whether the form will adjust its size
    ///  to fit the height of the font used on the form and scale
    ///  its controls.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [SRDescription(nameof(SR.FormAutoScaleDescr))]
    [Obsolete("This property has been deprecated. Use the AutoScaleMode property instead.  https://go.microsoft.com/fwlink/?linkid=14202")]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool AutoScale
    {
        get
        {
            return _formState[s_formStateAutoScaling] != 0;
        }
        set
        {
            _formStateEx[s_formStateExSettingAutoScale] = 1;
            try
            {
                if (value)
                {
                    _formState[s_formStateAutoScaling] = 1;

                    // if someone insists on auto scaling,
                    // force the new property back to none so they
                    // don't compete.
                    AutoScaleMode = AutoScaleMode.None;
                }
                else
                {
                    _formState[s_formStateAutoScaling] = 0;
                }
            }
            finally
            {
                _formStateEx[s_formStateExSettingAutoScale] = 0;
            }
        }
    }

    // Our STRONG recommendation to customers is to upgrade to AutoScaleDimensions
    // however, since this is generated by default in Everett, and there's not a 1:1 mapping of
    // the old to the new, we are un-obsoleting the setter for AutoScaleBaseSize only.

    /// <summary>
    ///  The base size used for autoscaling. The AutoScaleBaseSize is used internally to determine how much to scale
    ///  the form when AutoScaling is used.
    /// </summary>
    [Localizable(true)]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual Size AutoScaleBaseSize
    {
        get
        {
            if (_autoScaleBaseSize.IsEmpty)
            {
#pragma warning disable CS0618 // Type or member is obsolete - compat
                SizeF real = GetAutoScaleSize(Font);
#pragma warning restore CS0618
                return new Size((int)Math.Round(real.Width), (int)Math.Round(real.Height));
            }

            return _autoScaleBaseSize;
        }

        set
        {
            // Only allow the set when not in DesignMode, this prevents us from
            // preserving an old value. The form design should prevent this for
            // us by shadowing this property, so we just assert that the designer
            // is doing its job.
            //
            Debug.Assert(!DesignMode, "Form designer should not allow base size set in design mode.");
            _autoScaleBaseSize = value;
        }
    }

    /// <summary>
    ///  Gets or sets a value indicating whether the form implements
    ///  autoscrolling.
    /// </summary>
    [Localizable(true)]
    public override bool AutoScroll
    {
        get => base.AutoScroll;

        set
        {
            if (value)
            {
                IsMdiContainer = false;
            }

            base.AutoScroll = value;
        }
    }

    // Forms implement their own AutoSize in OnLayout so we shadow this property
    // just in case someone parents a Form to a container control.
    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public override bool AutoSize
    {
        get { return _formStateEx[s_formStateExAutoSize] != 0; }
        set
        {
            if (value != AutoSize)
            {
                _formStateEx[s_formStateExAutoSize] = value ? 1 : 0;
                if (!AutoSize)
                {
                    _minAutoSize = Size.Empty;
                    // If we just disabled AutoSize, restore the original size.
                    Size = CommonProperties.GetSpecifiedBounds(this).Size;
                }

                LayoutTransaction.DoLayout(this, this, PropertyNames.AutoSize);
                OnAutoSizeChanged(EventArgs.Empty);
            }

            Debug.Assert(AutoSize == value, "Error detected setting Form.AutoSize.");
        }
    }

    [SRCategory(nameof(SR.CatPropertyChanged))]
    [SRDescription(nameof(SR.ControlOnAutoSizeChangedDescr))]
    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public new event EventHandler? AutoSizeChanged
    {
        add => base.AutoSizeChanged += value;
        remove => base.AutoSizeChanged -= value;
    }

    /// <summary>
    ///  Allows the control to optionally shrink when AutoSize is true.
    /// </summary>
    [SRDescription(nameof(SR.ControlAutoSizeModeDescr))]
    [SRCategory(nameof(SR.CatLayout))]
    [Browsable(true)]
    [DefaultValue(AutoSizeMode.GrowOnly)]
    [Localizable(true)]
    public AutoSizeMode AutoSizeMode
    {
        get
        {
            return GetAutoSizeMode();
        }
        set
        {
            SourceGenerated.EnumValidator.Validate(value);

            if (GetAutoSizeMode() != value)
            {
                SetAutoSizeMode(value);
                Control toLayout = DesignMode || ParentInternal is null ? this : ParentInternal;

                if (toLayout is not null)
                {
                    // DefaultLayout does not keep anchor information until it needs to. When
                    // AutoSize became a common property, we could no longer blindly call into
                    // DefaultLayout, so now we do a special InitLayout just for DefaultLayout.
                    if (toLayout.LayoutEngine == DefaultLayout.Instance)
                    {
                        toLayout.LayoutEngine.InitLayout(this, BoundsSpecified.Size);
                    }

                    LayoutTransaction.DoLayout(toLayout, this, PropertyNames.AutoSize);
                }
            }
        }
    }

    /// <summary>
    ///  Indicates whether controls in this container will be automatically validated when the focus changes.
    /// </summary>
    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public override AutoValidate AutoValidate
    {
        get => base.AutoValidate;
        set => base.AutoValidate = value;
    }

    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public new event EventHandler? AutoValidateChanged
    {
        add => base.AutoValidateChanged += value;
        remove => base.AutoValidateChanged -= value;
    }

    /// <summary>
    ///  The background color of this control. This is an ambient property and
    ///  will always return a non-null value.
    /// </summary>
    public override Color BackColor
    {
        get
        {
            // Forms should not inherit BackColor from their parent,
            // particularly if the parent is an MDIClient.
            Color c = RawBackColor; // inheritedProperties.BackColor
            if (!c.IsEmpty)
            {
                return c;
            }

            return DefaultBackColor;
        }
        set => base.BackColor = value;
    }

    private bool CalledClosing
    {
        get
        {
            return _formStateEx[s_formStateExCalledClosing] != 0;
        }
        set
        {
            _formStateEx[s_formStateExCalledClosing] = (value ? 1 : 0);
        }
    }

    private bool CalledCreateControl
    {
        get
        {
            return _formStateEx[s_formStateExCalledCreateControl] != 0;
        }
        set
        {
            _formStateEx[s_formStateExCalledCreateControl] = (value ? 1 : 0);
        }
    }

    private bool CalledMakeVisible
    {
        get
        {
            return _formStateEx[s_formStateExCalledMakeVisible] != 0;
        }
        set
        {
            _formStateEx[s_formStateExCalledMakeVisible] = (value ? 1 : 0);
        }
    }

    private bool CalledOnLoad
    {
        get
        {
            return _formStateEx[s_formStateExCalledOnLoad] != 0;
        }
        set
        {
            _formStateEx[s_formStateExCalledOnLoad] = (value ? 1 : 0);
        }
    }

    /// <summary>
    ///  Gets or sets the border style of the form.
    /// </summary>
    [SRCategory(nameof(SR.CatAppearance))]
    [DefaultValue(FormBorderStyle.Sizable)]
    [DispId(PInvokeCore.DISPID_BORDERSTYLE)]
    [SRDescription(nameof(SR.FormBorderStyleDescr))]
    public FormBorderStyle FormBorderStyle
    {
        get => (FormBorderStyle)_formState[s_formStateBorderStyle];
        set
        {
            SourceGenerated.EnumValidator.Validate(value);

            _formState[s_formStateBorderStyle] = (int)value;
            if (_formState[s_formStateSetClientSize] == 1 && !IsHandleCreated)
            {
                Size size = ClientSize;
                ClientSize = size;
            }

            // Since setting the border style induces a call to SetBoundsCore, which,
            // when the WindowState is not Normal, will cause the values stored in the field restoredWindowBounds
            // to be replaced. The side-effect of this, of course, is that when the form window is restored,
            // the Form's size is restored to the size it was when in a non-Normal state.
            // So, we need to cache these values now before the call to UpdateFormStyles() to prevent
            // these existing values from being lost. Then, if the WindowState is something other than
            // FormWindowState.Normal after the call to UpdateFormStyles(), restore these cached values to
            // the restoredWindowBounds field.
            Rectangle preClientUpdateRestoredWindowBounds = _restoredWindowBounds;
            BoundsSpecified preClientUpdateRestoredWindowBoundsSpecified = _restoredWindowBoundsSpecified;
            int preWindowBoundsWidthIsClientSize = _formStateEx[s_formStateExWindowBoundsWidthIsClientSize];
            int preWindowBoundsHeightIsClientSize = _formStateEx[s_formStateExWindowBoundsHeightIsClientSize];

            UpdateFormStyles();

            // In Windows Theme, the FixedDialog tend to have a small Icon.
            // So to make this behave uniformly with other styles, we need to make
            // the call to UpdateIcon after the form styles have been updated.
            if (_formState[s_formStateIconSet] == 0)
            {
                UpdateWindowIcon(false);
            }

            // Now restore the values cached above.
            if (WindowState != FormWindowState.Normal)
            {
                _restoredWindowBounds = preClientUpdateRestoredWindowBounds;
                _restoredWindowBoundsSpecified = preClientUpdateRestoredWindowBoundsSpecified;
                _formStateEx[s_formStateExWindowBoundsWidthIsClientSize] = preWindowBoundsWidthIsClientSize;
                _formStateEx[s_formStateExWindowBoundsHeightIsClientSize] = preWindowBoundsHeightIsClientSize;
            }
        }
    }

    /// <summary>
    ///  Gets or sets the button control that will be clicked when the user presses the ESC key.
    /// </summary>
    [DefaultValue(null)]
    [SRDescription(nameof(SR.FormCancelButtonDescr))]
    public IButtonControl? CancelButton
    {
        get => Properties.GetValueOrDefault<IButtonControl>(s_propCancelButton);
        set
        {
            Properties.AddOrRemoveValue(s_propCancelButton, value);

            if (value is not null && value.DialogResult == DialogResult.None)
            {
                value.DialogResult = DialogResult.Cancel;
            }
        }
    }

    /// <summary>
    ///  Gets or sets the size of the client area of the form.
    /// </summary>
    [Localizable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public new Size ClientSize
    {
        get => base.ClientSize;
        set => base.ClientSize = value;
    }

    /// <summary>
    ///  Gets or sets a value indicating whether a control box is displayed in the
    ///  caption bar of the form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(true)]
    [SRDescription(nameof(SR.FormControlBoxDescr))]
    public bool ControlBox
    {
        get => _formState[s_formStateControlBox] != 0;
        set
        {
            _formState[s_formStateControlBox] = value ? 1 : 0;
            UpdateFormStyles();
        }
    }

    /// <summary>
    ///  Retrieves the CreateParams used to create the window.
    ///  If a subclass overrides this function, it must call the base implementation.
    /// </summary>
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;

            if (IsHandleCreated && WindowStyle.HasFlag(WINDOW_STYLE.WS_DISABLED))
            {
                // Forms that are parent of a modal dialog must keep their WS_DISABLED style
                cp.Style |= (int)WINDOW_STYLE.WS_DISABLED;
            }
            else if (TopLevel)
            {
                // It doesn't seem to make sense to allow a top-level form to be disabled
                cp.Style &= ~(int)WINDOW_STYLE.WS_DISABLED;
            }

            if (TopLevel && (_formState[s_formStateLayered] != 0))
            {
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_LAYERED;
            }

            if (Properties.TryGetValue(s_propDialogOwner, out IWin32Window? dialogOwner))
            {
                cp.Parent = GetSafeHandle(dialogOwner).Handle;
            }

            FillInCreateParamsBorderStyles(cp);
            FillInCreateParamsWindowState(cp);
            FillInCreateParamsBorderIcons(cp);

            if (_formState[s_formStateTaskBar] != 0)
            {
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
            }

            FormBorderStyle borderStyle = FormBorderStyle;
            if (!ShowIcon && (borderStyle is FormBorderStyle.Sizable or FormBorderStyle.Fixed3D or FormBorderStyle.FixedSingle))
            {
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_DLGMODALFRAME;
            }

            if (IsMdiChild)
            {
                if (Visible && (WindowState is FormWindowState.Maximized or FormWindowState.Normal))
                {
                    Form? formMdiParent = Properties.GetValueOrDefault<Form>(s_propFormMdiParent);
                    Form? form = formMdiParent?.ActiveMdiChildInternal;

                    if (form is not null && form.WindowState == FormWindowState.Maximized)
                    {
                        cp.Style |= (int)WINDOW_STYLE.WS_MAXIMIZE;
                        _formState[s_formStateWindowState] = (int)FormWindowState.Maximized;
                        SetState(States.SizeLockedByOS, true);
                    }
                }

                if (_formState[s_formStateMdiChildMax] != 0)
                {
                    cp.Style |= (int)WINDOW_STYLE.WS_MAXIMIZE;
                }

                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_MDICHILD;
            }

            if (TopLevel || IsMdiChild)
            {
                FillInCreateParamsStartPosition(cp);
                // Delay setting to visible until after the handle gets created
                // to allow applyClientSize to adjust the size before displaying
                // the form.
                //
                if ((cp.Style & (int)WINDOW_STYLE.WS_VISIBLE) != 0)
                {
                    _formState[s_formStateShowWindowOnCreate] = 1;
                    cp.Style &= ~(int)WINDOW_STYLE.WS_VISIBLE;
                }
                else
                {
                    _formState[s_formStateShowWindowOnCreate] = 0;
                }
            }

            if (RightToLeft == RightToLeft.Yes && RightToLeftLayout)
            {
                // We want to turn on mirroring for Form explicitly.
                cp.ExStyle |= (int)(WINDOW_EX_STYLE.WS_EX_LAYOUTRTL | WINDOW_EX_STYLE.WS_EX_NOINHERITLAYOUT);
                // Don't need these styles when mirroring is turned on.
                cp.ExStyle &= ~(int)(WINDOW_EX_STYLE.WS_EX_RTLREADING | WINDOW_EX_STYLE.WS_EX_RIGHT | WINDOW_EX_STYLE.WS_EX_LEFTSCROLLBAR);
            }

            return cp;
        }
    }

    internal CloseReason CloseReason
    {
        get { return _closeReason; }
        set { _closeReason = value; }
    }

    /// <summary>
    ///  The default icon used by the Form. This is the standard "windows forms" icon.
    /// </summary>
    internal static Icon DefaultIcon
    {
        get
        {
            // Avoid locking if the value is filled in.
            if (s_defaultIcon is null)
            {
                lock (s_internalSyncObject)
                {
                    // Once we grab the lock, we re-check the value to avoid a race condition.
                    s_defaultIcon ??= new Icon(typeof(Form), "wfc");
                }
            }

            return s_defaultIcon;
        }
    }

    protected override ImeMode DefaultImeMode => ImeMode.NoControl;

    /// <summary>
    ///  Deriving classes can override this to configure a default size for their control.
    ///  This is more efficient than setting the size in the control's constructor.
    /// </summary>
    protected override Size DefaultSize => new Size(300, 300);

    /// <summary>
    ///  Gets or sets the size and location of the form on the Windows desktop.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormDesktopBoundsDescr))]
    public Rectangle DesktopBounds
    {
        get
        {
            Rectangle screen = SystemInformation.WorkingArea;
            Rectangle bounds = Bounds;
            bounds.X -= screen.X;
            bounds.Y -= screen.Y;
            return bounds;
        }
        set
        {
            SetDesktopBounds(value.X, value.Y, value.Width, value.Height);
        }
    }

    /// <summary>
    ///  Gets or sets the location of the form on the Windows desktop.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormDesktopLocationDescr))]
    public Point DesktopLocation
    {
        get
        {
            Rectangle screen = SystemInformation.WorkingArea;
            Point loc = Location;
            loc.X -= screen.X;
            loc.Y -= screen.Y;
            return loc;
        }
        set
        {
            SetDesktopLocation(value.X, value.Y);
        }
    }

    /// <summary>
    ///  Gets or sets the dialog result for the form.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormDialogResultDescr))]
    public DialogResult DialogResult
    {
        get
        {
            return _dialogResult;
        }

        set
        {
            // valid values are 0x0 to 0x7
            SourceGenerated.EnumValidator.Validate(value);

            _dialogResult = value;
        }
    }

    /// <summary>
    ///  Gets or sets a value indicating whether a
    ///  help button should be displayed in the caption box of the form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(false)]
    [SRDescription(nameof(SR.FormHelpButtonDescr))]
    public bool HelpButton
    {
        get
        {
            return _formState[s_formStateHelpButton] != 0;
        }

        set
        {
            if (value)
            {
                _formState[s_formStateHelpButton] = 1;
            }
            else
            {
                _formState[s_formStateHelpButton] = 0;
            }

            UpdateFormStyles();
        }
    }

    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormHelpButtonClickedDescr))]
    public event CancelEventHandler? HelpButtonClicked
    {
        add => Events.AddHandler(s_helpButtonChangedEvent, value);
        remove => Events.RemoveHandler(s_helpButtonChangedEvent, value);
    }

    /// <summary>
    ///  Gets or sets the icon for the form.
    /// </summary>
    [AmbientValue(null)]
    [Localizable(true)]
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormIconDescr))]
    public Icon? Icon
    {
        get
        {
            if (_formState[s_formStateIconSet] == 0)
            {
                return DefaultIcon;
            }

            return _icon;
        }
        set
        {
            if (_icon != value)
            {
                // If the user is setting the default back in, treat this
                // as a reset.
                if (value == s_defaultIcon)
                {
                    value = null;
                }

                // If null is passed, reset the icon.
                _formState[s_formStateIconSet] = value is null ? 0 : 1;
                _icon = value;

                _smallIcon?.Dispose();
                _smallIcon = null;

                UpdateWindowIcon(true);
            }
        }
    }

    /// <summary>
    ///  Determines whether the window is closing.
    /// </summary>
    private bool IsClosing
    {
        get
        {
            return _formStateEx[s_formStateExWindowClosing] == 1;
        }
        set
        {
            _formStateEx[s_formStateExWindowClosing] = value ? 1 : 0;
        }
    }

    // Returns a more accurate statement of whether or not the form is maximized.
    // during handle creation, an MDIChild is created as not maximized.
    private bool IsMaximized
    {
        get
        {
            return (WindowState == FormWindowState.Maximized || (IsMdiChild && (_formState[s_formStateMdiChildMax] == 1)));
        }
    }

    /// <summary>
    ///  Gets a value indicating whether the form is a multiple document
    ///  interface (MDI) child form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormIsMDIChildDescr))]
    [MemberNotNullWhen(true, nameof(MdiParentInternal))]
    public bool IsMdiChild => Properties.ContainsKey(s_propFormMdiParent);

    // Deactivates active MDI child and temporarily marks it as unfocusable,
    // so that WM_SETFOCUS sent to MDIClient does not activate that child. (See MdiClient.WndProc).
    internal bool IsMdiChildFocusable
    {
        get => Properties.GetValueOrDefault<bool>(s_propMdiChildFocusable);
        set => Properties.AddOrRemoveValue(s_propMdiChildFocusable, value);
    }

    /// <summary>
    ///  Gets or sets a value indicating whether the form is a container for multiple document interface
    ///  (MDI) child forms.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(false)]
    [SRDescription(nameof(SR.FormIsMDIContainerDescr))]
    [MemberNotNullWhen(true, nameof(MdiClient))]
    public bool IsMdiContainer
    {
        get
        {
            return _ctlClient is not null;
        }

        set
        {
            if (value == IsMdiContainer)
            {
                return;
            }

            if (value)
            {
                Debug.Assert(_ctlClient is null, "why isn't ctlClient null");
                AllowTransparency = false;
                Controls.Add(new MdiClient());
            }
            else
            {
                Debug.Assert(_ctlClient is not null, "why is ctlClient null");
                ActiveMdiChildInternal = null;
                _ctlClient.Dispose();
            }

            // since we paint the background when mdi is true, we need
            // to invalidate here
            //
            Invalidate();
        }
    }

    /// <summary>
    ///  Determines if this form should display a warning banner when the form is
    ///  displayed in an unsecure mode.
    /// </summary>
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public bool IsRestrictedWindow => false;

    /// <summary>
    ///  Gets or sets a value
    ///  indicating whether the form will receive key events
    ///  before the event is passed to the control that has focus.
    /// </summary>
    [DefaultValue(false)]
    [SRDescription(nameof(SR.FormKeyPreviewDescr))]
    public bool KeyPreview
    {
        get => _formState[s_formStateKeyPreview] != 0;
        set => _formState[s_formStateKeyPreview] = value ? 1 : 0;
    }

    /// <summary>
    ///  Gets or sets the location of the form.
    /// </summary>
    [SettingsBindable(true)]
    public new Point Location
    {
        get => base.Location;
        set => base.Location = value;
    }

    /// <summary>
    ///  Gets the size of the form when it is maximized.
    /// </summary>
    protected Rectangle MaximizedBounds
    {
        get => Properties.GetValueOrDefault<Rectangle>(s_propMaximizedBounds);
        set
        {
            if (!value.Equals(MaximizedBounds))
            {
                Properties.AddValue(s_propMaximizedBounds, value);
                OnMaximizedBoundsChanged(EventArgs.Empty);
            }
        }
    }

    private static readonly object s_maximizeBoundsChangedEvent = new();

    [SRCategory(nameof(SR.CatPropertyChanged))]
    [SRDescription(nameof(SR.FormOnMaximizedBoundsChangedDescr))]
    public event EventHandler? MaximizedBoundsChanged
    {
        add => Events.AddHandler(s_maximizeBoundsChangedEvent, value);
        remove => Events.RemoveHandler(s_maximizeBoundsChangedEvent, value);
    }

    /// <summary>
    ///  Gets the maximum size the form can be resized to.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [Localizable(true)]
    [SRDescription(nameof(SR.FormMaximumSizeDescr))]
    [RefreshProperties(RefreshProperties.Repaint)]
    [DefaultValue(typeof(Size), "0, 0")]
    public override Size MaximumSize
    {
        get => Properties.TryGetValue(s_propMaxTrackSize, out Size maximumSize) ? maximumSize : Size.Empty;
        set
        {
            if (!value.Equals(MaximumSize))
            {
                if (value.Width < 0 || value.Height < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(MaximumSize));
                }

                UpdateMaximumSize(value);
            }
        }
    }

    private void UpdateMaximumSize(Size value, bool updateFormSize = true)
    {
        Properties.AddValue(s_propMaxTrackSize, value);

        // Bump minimum size if necessary
        if (!MinimumSize.IsEmpty && !value.IsEmpty)
        {
            Size minimumSize = MinimumSize;
            bool sizeUpdated = false;
            if (minimumSize.Width > value.Width)
            {
                minimumSize.Width = value.Width;
                sizeUpdated = true;
            }

            if (minimumSize.Height > value.Height)
            {
                minimumSize.Height = value.Height;
                sizeUpdated = true;
            }

            if (sizeUpdated)
            {
                Properties.AddValue(s_propMinTrackSize, minimumSize);
            }
        }

        // UpdateFormSize=false when Minimum/Maximum sizes get updated as a result of DPI_CHANGED message.
        // DPI_CHANGED message updates the Form size with the SuggestedRectangle provided by Windows.
        if (updateFormSize)
        {
            // Keep form size within new limits
            Size size = Size;
            if (!value.IsEmpty && (size.Width > value.Width || size.Height > value.Height))
            {
                Size = new Size(Math.Min(size.Width, value.Width), Math.Min(size.Height, value.Height));
            }
        }

        OnMaximumSizeChanged(EventArgs.Empty);
    }

    [SRCategory(nameof(SR.CatPropertyChanged))]
    [SRDescription(nameof(SR.FormOnMaximumSizeChangedDescr))]
    public event EventHandler? MaximumSizeChanged
    {
        add => Events.AddHandler(s_maximumSizeChangedEvent, value);
        remove => Events.RemoveHandler(s_maximumSizeChangedEvent, value);
    }

    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(null)]
    [SRDescription(nameof(SR.FormMenuStripDescr))]
    [TypeConverter(typeof(ReferenceConverter))]
    public MenuStrip? MainMenuStrip
    {
        get => Properties.GetValueOrDefault<MenuStrip>(s_propMainMenuStrip);
        set
        {
            Properties.AddOrRemoveValue(s_propMainMenuStrip, value);
            if (IsHandleCreated)
            {
                UpdateMenuHandles(recreateMenu: true);
            }
        }
    }

    /// <summary>
    ///  Hide Margin/MarginChanged
    /// </summary>
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public new Padding Margin
    {
        get => base.Margin;
        set => base.Margin = value;
    }

    /// <summary>
    ///  Hide Margin/MarginChanged
    /// </summary>
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public new event EventHandler? MarginChanged
    {
        add => base.MarginChanged += value;
        remove => base.MarginChanged -= value;
    }

    /// <summary>
    ///  Gets the minimum size the form can be resized to.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [Localizable(true)]
    [SRDescription(nameof(SR.FormMinimumSizeDescr))]
    [RefreshProperties(RefreshProperties.Repaint)]
    public override Size MinimumSize
    {
        get => Properties.TryGetValue(s_propMinTrackSize, out Size minimumSize) ? minimumSize : DefaultMinimumSize;
        set
        {
            if (!value.Equals(MinimumSize))
            {
                if (value.Width < 0 || value.Height < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(MinimumSize));
                }

                Rectangle bounds = Bounds;
                bounds.Size = value;
                value = WindowsFormsUtils.ConstrainToScreenWorkingAreaBounds(bounds).Size;

                UpdateMinimumSize(value);
            }
        }
    }

    private void UpdateMinimumSize(Size value, bool updateFormSize = true)
    {
        Properties.AddValue(s_propMinTrackSize, value);

        // Bump maximum size if necessary
        if (!MaximumSize.IsEmpty && !value.IsEmpty)
        {
            Size maximumSize = MaximumSize;
            bool sizeUpdated = false;
            if (maximumSize.Width < value.Width)
            {
                maximumSize.Width = value.Width;
                sizeUpdated = true;
            }

            if (maximumSize.Height < value.Height)
            {
                maximumSize.Height = value.Height;
                sizeUpdated = true;
            }

            if (sizeUpdated)
            {
                Properties.AddValue(s_propMaxTrackSize, maximumSize);
            }
        }

        // UpdateFormSize=false when Minimum/Maximum sizes get updated as a result of DPI_CHANGED message.
        // DPI_CHANGED message updates the Form size with the SuggestedRectangle provided by Windows.
        if (updateFormSize)
        {
            // Keep form size within new limits
            Size size = Size;
            if (size.Width < value.Width || size.Height < value.Height)
            {
                Size = new Size(Math.Max(size.Width, value.Width), Math.Max(size.Height, value.Height));
            }

            if (IsHandleCreated)
            {
                // "Move" the form to the same size and position to prevent windows from moving it
                // when the user tries to grab a resizing border.
                PInvoke.SetWindowPos(
                    this,
                    HWND.HWND_TOP,
                    Location.X,
                    Location.Y,
                    Size.Width,
                    Size.Height,
                    SET_WINDOW_POS_FLAGS.SWP_NOZORDER | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
            }
        }

        OnMinimumSizeChanged(EventArgs.Empty);
    }

    [SRCategory(nameof(SR.CatPropertyChanged))]
    [SRDescription(nameof(SR.FormOnMinimumSizeChangedDescr))]
    public event EventHandler? MinimumSizeChanged
    {
        add => Events.AddHandler(s_minimumSizeChangedEvent, value);
        remove => Events.RemoveHandler(s_minimumSizeChangedEvent, value);
    }

    /// <summary>
    ///  Gets or sets a value indicating whether the maximize button is
    ///  displayed in the caption bar of the form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(true)]
    [SRDescription(nameof(SR.FormMaximizeBoxDescr))]
    public bool MaximizeBox
    {
        get => _formState[s_formStateMaximizeBox] != 0;
        set
        {
            _formState[s_formStateMaximizeBox] = value ? 1 : 0;
            UpdateFormStyles();
        }
    }

    /// <summary>
    ///  Gets an array of forms that represent the multiple document interface (MDI) child forms
    ///  that are parented to this form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormMDIChildrenDescr))]
    public Form[] MdiChildren => _ctlClient is not null ? _ctlClient.MdiChildren : ([]);

    /// <summary>
    ///  Gets or sets the anchoring for minimized MDI children.
    /// </summary>
    /// <value>
    ///  <see langword="true" /> to anchor minimized MDI children to the bottom left of the parent form;
    ///  <see langword="false" /> to anchor to the top left of the parent form.
    /// </value>
    /// <remarks>
    ///  <para>
    ///   By default Windows Forms anchors MDI children to the bottom left of the parent form, whilst the Windows default is top left.
    ///  </para>
    /// </remarks>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(true)]
    [SRDescription(nameof(SR.FormMdiChildrenMinimizedAnchorBottomDescr))]
    public bool MdiChildrenMinimizedAnchorBottom { get; set; } = true;

    /// <summary>
    ///  Gets the MDIClient that the MDI container form is using to contain Multiple Document Interface (MDI) child forms,
    ///  if this is an MDI container form.
    ///  Represents the client area of a Multiple Document Interface (MDI) Form window, also known as the MDI child window.
    /// </summary>
    internal MdiClient? MdiClient => _ctlClient;

    /// <summary>
    ///  Indicates the current multiple document
    ///  interface (MDI) parent form of this form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormMDIParentDescr))]
    public Form? MdiParent
    {
        get => MdiParentInternal;
        set => MdiParentInternal = value;
    }

    private Form? MdiParentInternal
    {
        get => Properties.GetValueOrDefault<Form>(s_propFormMdiParent);
        set
        {
            Form? formMdiParent = Properties.GetValueOrDefault<Form>(s_propFormMdiParent);
            if (value == formMdiParent && (value is not null || ParentInternal is null))
            {
                return;
            }

            if (value is not null && CreateThreadId != value.CreateThreadId)
            {
                throw new ArgumentException(SR.AddDifferentThreads, nameof(value));
            }

            bool oldVisibleBit = GetState(States.Visible);
            Visible = false;

            try
            {
                if (value is null)
                {
                    ParentInternal = null;
                    SetTopLevel(true);
                }
                else
                {
                    if (IsMdiContainer)
                    {
                        throw new ArgumentException(SR.FormMDIParentAndChild, nameof(value));
                    }

                    if (!value.IsMdiContainer)
                    {
                        throw new ArgumentException(SR.MDIParentNotContainer, nameof(value));
                    }

                    // Setting TopLevel forces a handle recreate before Parent is set,
                    // which causes problems because we try to assign an MDI child to the
                    // parking window, which can't take MDI children. We explicitly destroy
                    // and create the handle here.

                    Dock = DockStyle.None;
                    Properties.AddOrRemoveValue(s_propFormMdiParent, value);

                    SetState(States.TopLevel, false);
                    ParentInternal = value.MdiClient;

                    // If it is an MDIChild, and it is not yet visible, we'll
                    // hold off on recreating the window handle. We'll do that
                    // when MdiChild's visibility is set to true (see

                    // But if the handle has already been created, we need to destroy it
                    // so the form gets MDI-parented properly.
                    if (ParentInternal.IsHandleCreated && IsMdiChild && IsHandleCreated)
                    {
                        DestroyHandle();
                    }
                }

                InvalidateMergedMenu();
                UpdateMenuHandles();
            }
            finally
            {
                UpdateStyles();
                Visible = oldVisibleBit;
            }
        }
    }

    private MdiWindowListStrip? MdiWindowListStrip
    {
        get => Properties.GetValueOrDefault<MdiWindowListStrip>(s_propMdiWindowListStrip);
        set => Properties.AddOrRemoveValue(s_propMdiWindowListStrip, value);
    }

    private MdiControlStrip? MdiControlStrip
    {
        get => Properties.GetValueOrDefault<MdiControlStrip>(s_propMdiControlStrip);
        set => Properties.AddOrRemoveValue(s_propMdiControlStrip, value);
    }

    /// <summary>
    ///  Gets or sets a value indicating whether the minimize button is displayed in the caption bar of the form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(true)]
    [SRDescription(nameof(SR.FormMinimizeBoxDescr))]
    public bool MinimizeBox
    {
        get => _formState[s_formStateMinimizeBox] != 0;
        set
        {
            _formState[s_formStateMinimizeBox] = value ? 1 : 0;
            UpdateFormStyles();
        }
    }

    /// <summary>
    ///  Gets a value indicating whether this form is displayed modally.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormModalDescr))]
    public bool Modal => GetState(States.Modal);

    /// <summary>
    ///  Determines the opacity of the form. This can only be set on top level controls.
    ///  Opacity requires Windows 2000 or later, and is ignored on earlier operating systems.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [TypeConverter(typeof(OpacityConverter))]
    [SRDescription(nameof(SR.FormOpacityDescr))]
    [DefaultValue(1.0)]
    public double Opacity
    {
        get => Properties.GetValueOrDefault(s_propOpacity, 1.0d);
        set
        {
            value = Math.Clamp(value, 0.0d, 1.0d);

            Properties.AddOrRemoveValue(s_propOpacity, value, defaultValue: 1.0d);

            bool oldLayered = _formState[s_formStateLayered] != 0;

            if (OpacityAsByte < 255)
            {
                AllowTransparency = true;
                if (_formState[s_formStateLayered] != 1)
                {
                    _formState[s_formStateLayered] = 1;
                    if (!oldLayered)
                    {
                        UpdateStyles();
                    }
                }
            }
            else
            {
                _formState[s_formStateLayered] = (TransparencyKey != Color.Empty) ? 1 : 0;
                if (oldLayered != (_formState[s_formStateLayered] != 0))
                {
                    CreateParams cp = CreateParams;
                    if ((int)ExtendedWindowStyle != cp.ExStyle)
                    {
                        PInvokeCore.SetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, cp.ExStyle);
                    }
                }
            }

            UpdateLayered();
        }
    }

    private byte OpacityAsByte => (byte)(Opacity * 255.0f);

    /// <summary>
    ///  Gets an array of <see cref="Form"/> objects that represent all forms that are owned by this form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormOwnedFormsDescr))]
    public Form[] OwnedForms => Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms) ? ([.. ownedForms]) : ([]);

    /// <summary>
    ///  Gets or sets the form that owns this form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [SRDescription(nameof(SR.FormOwnerDescr))]
    public Form? Owner
    {
        get => OwnerInternal;
        set
        {
            Form? ownerOld = OwnerInternal;
            if (ownerOld == value)
            {
                return;
            }

            if (value is not null && !TopLevel)
            {
                throw new ArgumentException(SR.NonTopLevelCantHaveOwner, nameof(value));
            }

            CheckParentingCycle(this, value);
            CheckParentingCycle(value, this);

            Properties.RemoveValue(s_propOwner);

            ownerOld?.RemoveOwnedForm(this);

            Properties.AddOrRemoveValue(s_propOwner, value);

            value?.AddOwnedForm(this);

            UpdateHandleWithOwner();
        }
    }

    internal Form? OwnerInternal => Properties.GetValueOrDefault<Form?>(s_propOwner);

    /// <summary>
    ///  Gets or sets the restored bounds of the Form.
    /// </summary>
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    public Rectangle RestoreBounds
    {
        get
        {
            if (_restoreBounds.Width == -1
                && _restoreBounds.Height == -1
                && _restoreBounds.X == -1
                && _restoreBounds.Y == -1)
            {
                // Form scaling depends on this property being
                // set correctly. In some cases (where the size has not yet been set or
                // has only been set to the default, restoreBounds will remain uninitialized until the
                // handle has been created. In this case, return the current Bounds.
                return Bounds;
            }

            return _restoreBounds;
        }
    }

    /// <summary>
    ///  This is used for international applications where the language is written from RightToLeft.
    ///  When this property is true, and the RightToLeft is true, mirroring will be turned on on
    ///  the form, and control placement and text will be from right to left.
    /// </summary>
    [SRCategory(nameof(SR.CatAppearance))]
    [Localizable(true)]
    [DefaultValue(false)]
    [SRDescription(nameof(SR.ControlRightToLeftLayoutDescr))]
    public virtual bool RightToLeftLayout
    {
        get => _rightToLeftLayout;
        set
        {
            if (value != _rightToLeftLayout)
            {
                _rightToLeftLayout = value;
                using (new LayoutTransaction(this, this, PropertyNames.RightToLeftLayout))
                {
                    OnRightToLeftLayoutChanged(EventArgs.Empty);
                }
            }
        }
    }

    internal override Control? ParentInternal
    {
        get => base.ParentInternal;
        set
        {
            if (value is not null)
            {
                Owner = null;
            }

            base.ParentInternal = value;
        }
    }

    /// <summary>
    ///  Gets or sets how the form’s content is protected from screen capture or video recording
    ///  using Windows-based screen capture APIs.
    /// </summary>
    /// <remarks>
    ///  <para>
    ///   This property controls how the form’s content is handled when a screen capture or screenshot
    ///   is attempted. Each capture mode offers different levels of protection for sensitive information.
    ///  </para>
    ///  <para>
    ///   By default, forms permit their content to be captured. Choosing a more restrictive mode
    ///   can block screenshots or recordings that include confidential data.
    ///  </para>
    ///  <para>
    ///   Changes to this property take effect immediately for any form that is already visible. For
    ///   forms not yet displayed, the selected mode is applied as soon as the form appears.
    ///  </para>
    ///  <para>
    ///   Note that this setting applies only to the form itself. Any additional top-level windows—such
    ///   as pop-ups, message boxes, context menus, or dropdown menus—are not affected and can still be
    ///   captured. Similarly, other application windows remain unaffected by this property.
    ///  </para>
    ///  <para>
    ///   This also influences video-streaming or conferencing applications that rely on the same
    ///   Windows capture APIs. However, it cannot prevent tools that bypass these APIs or use
    ///   hardware-level capture methods from recording the screen.
    ///   See the remarks for the Windows API <a href="https://aka.ms/AAwi872">SetWindowDisplayAffinity</a>
    ///   for more details.
    ///  </para>
    /// </remarks>
    /// <value>
    ///  A <see cref="ScreenCaptureMode"/> enumeration value indicating the desired capture restriction.
    ///  The default is <see cref="ScreenCaptureMode.Allow"/>.
    /// </value>

    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormScreenCaptureModeDescr))]
    public ScreenCaptureMode FormScreenCaptureMode
    {
        get => Properties.GetValueOrDefault(s_propFormScreenCaptureMode, ScreenCaptureMode.Allow);
        set
        {
            if (FormScreenCaptureMode == value)
            {
                return;
            }

            if (!TopLevel && !DesignMode)
            {
                throw new InvalidOperationException(SR.FormScreenCaptureModeRequiresTopLevel);
            }

            SourceGenerated.EnumValidator.Validate(value);
            Properties.AddOrRemoveValue(s_propFormScreenCaptureMode, value);

            if (IsHandleCreated)
            {
                SetScreenCaptureModeInternal(value);
            }
        }
    }

    private bool ShouldSerializeFormScreenCaptureMode() =>
        FormScreenCaptureMode != ScreenCaptureMode.Allow;

    private void ResetFormScreenCaptureMode() =>
        FormScreenCaptureMode = ScreenCaptureMode.Allow;

    private void SetScreenCaptureModeInternal(ScreenCaptureMode value)
    {
        // Always reset to NONE before setting new affinity.
        PInvoke.SetWindowDisplayAffinity(HWND, WINDOW_DISPLAY_AFFINITY.WDA_NONE);

        WINDOW_DISPLAY_AFFINITY affinity = value switch
        {
            ScreenCaptureMode.Allow => WINDOW_DISPLAY_AFFINITY.WDA_NONE,
            ScreenCaptureMode.HideWindow => WINDOW_DISPLAY_AFFINITY.WDA_EXCLUDEFROMCAPTURE,
            ScreenCaptureMode.HideContent => WINDOW_DISPLAY_AFFINITY.WDA_MONITOR,
            _ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
        };

        PInvoke.SetWindowDisplayAffinity(HWND, affinity);
    }

    /// <summary>
    ///  If ShowInTaskbar is true then the form will be displayed in the Windows Taskbar.
    /// </summary>
    [DefaultValue(true)]
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormShowInTaskbarDescr))]
    public bool ShowInTaskbar
    {
        get => _formState[s_formStateTaskBar] != 0;
        set
        {
            if (ShowInTaskbar != value)
            {
                _formState[s_formStateTaskBar] = value ? 1 : 0;
                if (IsHandleCreated)
                {
                    RecreateHandle();
                }
            }
        }
    }

    /// <summary>
    ///  Gets or sets a value indicating whether an icon is displayed in the
    ///  caption bar of the form.
    ///  If ControlBox == false, then the icon won't be shown no matter what
    ///  the value of ShowIcon is
    /// </summary>
    [DefaultValue(true)]
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormShowIconDescr))]
    public bool ShowIcon
    {
        get => _formStateEx[s_formStateExShowIcon] != 0;
        set
        {
            _formStateEx[s_formStateExShowIcon] = value ? 1 : 0;
            if (!value)
            {
                UpdateStyles();
            }

            UpdateWindowIcon(true);
        }
    }

    internal override SHOW_WINDOW_CMD ShowParams
    {
        get
        {
            // From MSDN:
            //
            //  The first time an application calls ShowWindow, it should use the WinMain function's nCmdShow parameter
            //  as its nCmdShow parameter. Subsequent calls to ShowWindow must use one of the values in the given list,
            //  instead of the one specified by the WinMain function's nCmdShow parameter.

            // As noted in the discussion of the nCmdShow parameter, the nCmdShow value is ignored in the first call
            //  to ShowWindow if the program that launched the application specifies startup information in the
            //  STARTUPINFO structure. In this case, ShowWindow uses the information specified in the STARTUPINFO
            //  structure to show the window. On subsequent calls, the application must call ShowWindow with nCmdShow
            //  set to SW_SHOWDEFAULT to use the startup information provided by the program that launched the
            //  application. This behavior is designed for the following situations:
            //
            //    Applications create their main window by calling CreateWindow with the WS_VISIBLE flag set.
            //
            //    Applications create their main window by calling CreateWindow with the WS_VISIBLE flag cleared, and
            //    later call ShowWindow with the SW_SHOW flag set to make it visible.

            switch (WindowState)
            {
                case FormWindowState.Maximized:
                    return SHOW_WINDOW_CMD.SW_SHOWMAXIMIZED;
                case FormWindowState.Minimized:
                    return SHOW_WINDOW_CMD.SW_SHOWMINIMIZED;
            }

            if (ShowWithoutActivation)
            {
                return SHOW_WINDOW_CMD.SW_SHOWNOACTIVATE;
            }

            return SHOW_WINDOW_CMD.SW_SHOW;
        }
    }

    /// <summary>
    ///  When this property returns true, the internal ShowParams property will return User32.ShowWindowCommand.SHOWNOACTIVATE.
    /// </summary>
    [Browsable(false)]
    protected virtual bool ShowWithoutActivation
    {
        get
        {
            return false;
        }
    }

    /// <summary>
    ///  Gets or sets the size of the form.
    /// </summary>
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Localizable(false)]
    public new Size Size
    {
        get => base.Size;
        set => base.Size = value;
    }

    /// <summary>
    ///  Gets or sets the style of size grip to display in the lower-left corner of the form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [DefaultValue(SizeGripStyle.Auto)]
    [SRDescription(nameof(SR.FormSizeGripStyleDescr))]
    public SizeGripStyle SizeGripStyle
    {
        get
        {
            return (SizeGripStyle)_formState[s_formStateSizeGripStyle];
        }
        set
        {
            if (SizeGripStyle != value)
            {
                // do some bounds checking here
                //
                // valid values are 0x0 to 0x2
                SourceGenerated.EnumValidator.Validate(value);

                _formState[s_formStateSizeGripStyle] = (int)value;
                UpdateRenderSizeGrip();
            }
        }
    }

    /// <summary>
    ///  Gets or sets the
    ///  starting position of the form at run time.
    /// </summary>
    [Localizable(true)]
    [SRCategory(nameof(SR.CatLayout))]
    [DefaultValue(FormStartPosition.WindowsDefaultLocation)]
    [SRDescription(nameof(SR.FormStartPositionDescr))]
    public FormStartPosition StartPosition
    {
        get
        {
            return (FormStartPosition)_formState[s_formStateStartPos];
        }
        set
        {
            // valid values are 0x0 to 0x4
            SourceGenerated.EnumValidator.Validate(value);
            _formState[s_formStateStartPos] = (int)value;
        }
    }

    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new int TabIndex
    {
        get => base.TabIndex;
        set => base.TabIndex = value;
    }

    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public new event EventHandler? TabIndexChanged
    {
        add => base.TabIndexChanged += value;
        remove => base.TabIndexChanged -= value;
    }

    /// <summary>
    ///  This property has no effect on Form, we need to hide it from browsers.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [DefaultValue(true)]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [DispId(PInvokeCore.DISPID_TABSTOP)]
    [SRDescription(nameof(SR.ControlTabStopDescr))]
    public new bool TabStop
    {
        get => base.TabStop;
        set => base.TabStop = value;
    }

    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public new event EventHandler? TabStopChanged
    {
        add => base.TabStopChanged += value;
        remove => base.TabStopChanged -= value;
    }

    /// <summary>
    ///  For forms that are show in task bar false, this returns a HWND they must be parented to in order for it to work.
    /// </summary>
    private IHandle<HWND> TaskbarOwner
    {
        get
        {
            _ownerWindow ??= new NativeWindow();

            if (_ownerWindow.Handle == IntPtr.Zero)
            {
                CreateParams cp = new CreateParams
                {
                    ExStyle = (int)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW
                };

                _ownerWindow.CreateHandle(cp);
            }

            return _ownerWindow;
        }
    }

    [SettingsBindable(true)]
    [AllowNull]
    public override string Text
    {
        get => base.Text;
        set => base.Text = value;
    }

    /// <summary>
    ///  Gets or sets a value indicating whether to display the form as a top-level window.
    /// </summary>
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool TopLevel
    {
        get => GetTopLevel();
        set
        {
            if (!value && IsMdiContainer && !DesignMode)
            {
                throw new ArgumentException(SR.MDIContainerMustBeTopLevel, nameof(value));
            }

            SetTopLevel(value);
        }
    }

    /// <summary>
    ///  Gets or sets a value indicating whether the form should be displayed as the
    ///  top-most form of the application.
    /// </summary>
    [DefaultValue(false)]
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormTopMostDescr))]
    public bool TopMost
    {
        get => _formState[s_formStateTopMost] != 0;
        set
        {
            if (IsHandleCreated && TopLevel)
            {
                PInvoke.SetWindowPos(
                    this,
                    value ? HWND.HWND_TOPMOST : HWND.HWND_NOTOPMOST,
                    0, 0, 0, 0,
                    SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE);
            }

            _formState[s_formStateTopMost] = value ? 1 : 0;
        }
    }

    /// <summary>
    ///  Gets or sets the color that will represent transparent areas of the form.
    /// </summary>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormTransparencyKeyDescr))]
    public Color TransparencyKey
    {
        get => Properties.GetValueOrDefault(s_propTransparencyKey, Color.Empty);
        set
        {
            Properties.AddOrRemoveValue(s_propTransparencyKey, value, defaultValue: Color.Empty);
            if (!IsMdiContainer)
            {
                bool oldLayered = (_formState[s_formStateLayered] == 1);
                if (value != Color.Empty)
                {
                    AllowTransparency = true;
                    _formState[s_formStateLayered] = 1;
                }
                else
                {
                    _formState[s_formStateLayered] = (OpacityAsByte < 255) ? 1 : 0;
                }

                if (oldLayered != (_formState[s_formStateLayered] != 0))
                {
                    UpdateStyles();
                }

                UpdateLayered();
            }
        }
    }

    /// <summary>
    ///  Adjusts form location based on <see cref="FormStartPosition"/>
    /// </summary>
    internal void AdjustFormPosition()
    {
        FormStartPosition startPos = (FormStartPosition)_formState[s_formStateStartPos];
        if (startPos == FormStartPosition.CenterParent)
        {
            CenterToParent();
        }
        else if (startPos == FormStartPosition.CenterScreen)
        {
            CenterToScreen();
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void SetVisibleCore(bool value)
    {
        // If DialogResult.OK and the value == Visible then this code has been called either through
        // ShowDialog( ) or explicit Hide( ) by the user. So don't go through this function again.
        // This will avoid flashing during closing the dialog;
        if (value == Visible && _dialogResult == DialogResult.OK)
        {
            return;
        }

        // (!value || calledMakeVisible) is to make sure that we fall
        // through and execute the code below atleast once.
        if (value == Visible && (!value || CalledMakeVisible))
        {
            base.SetVisibleCore(value);
            return;
        }

        if (value)
        {
            CalledMakeVisible = true;
            if (CalledCreateControl)
            {
                if (CalledOnLoad)
                {
                    // Make sure the form is in the Application.OpenForms collection
                    if (!Application.OpenForms.Contains(this))
                    {
                        Application.OpenForms.Add(this);
                    }
                }
                else
                {
                    CalledOnLoad = true;
                    OnLoad(EventArgs.Empty);
                    if (_dialogResult != DialogResult.None)
                    {
                        // Don't show the dialog if the dialog result was set
                        // in the OnLoad event.
                        //
                        value = false;
                    }
                }
            }
        }

        if (!IsMdiChild)
        {
            base.SetVisibleCore(value);

            // We need to force this call if we were created
            // with a STARTUPINFO structure (e.g. launched from explorer), since
            // it won't send a WM_SHOWWINDOW the first time it's called.
            // when WM_SHOWWINDOW gets called, we'll flip this bit to true
            //
            if (_formState[s_formStateSWCalled] == 0)
            {
                PInvokeCore.SendMessage(this, PInvokeCore.WM_SHOWWINDOW, (WPARAM)(BOOL)value);
            }
        }
        else
        {
            // Throw away any existing handle.
            if (IsHandleCreated)
            {
                // Everett/RTM used to wrap this in an assert for AWP.
                DestroyHandle();
            }

            if (!value)
            {
                InvalidateMergedMenu();
                SetState(States.Visible, false);
            }
            else
            {
                // The ordering is important here... Force handle creation
                // (getHandle) then show the window (ShowWindow) then finish
                // creating children using createControl...
                SetState(States.Visible, true);

                // Ask the mdiClient to re-layout the controls so that any docking or
                // anchor settings for this mdi child window will be honored.
                MdiParentInternal.MdiClient?.PerformLayout();

                if (ParentInternal is not null && ParentInternal.Visible)
                {
                    using SuspendLayoutScope scope = new(this);
                    PInvoke.ShowWindow(this, SHOW_WINDOW_CMD.SW_SHOW);
                    CreateControl();

                    // If this form is mdichild and maximized, we need to redraw the MdiParent non-client area to
                    // update the menu bar because we always create the window as if it were not maximized.
                    // See comment on CreateHandle about this.
                    if (WindowState == FormWindowState.Maximized)
                    {
                        MdiParentInternal.UpdateWindowIcon(true);
                    }
                }
            }

            OnVisibleChanged(EventArgs.Empty);
        }

        if (value && !IsMdiChild && (WindowState == FormWindowState.Maximized || TopMost))
        {
            if (ActiveControl is null)
            {
                SelectNextControl(null, true, true, true, false);
            }

            FocusActiveControlInternal();
        }
    }

    /// <summary>
    ///  Sets or gets the rounding style of the Form's corners using the <see cref="FormCornerPreference"/> enum.
    /// </summary>
    /// <remarks>
    ///  <para>
    ///   Note: Reading this property is only for tracking purposes. If the Form's corner preference is
    ///   changed through other external means (Win32 calls), reading this property will not reflect
    ///   those changes, as the Win32 API does not provide a mechanism to retrieve the current title
    ///   bar color.
    ///  </para>
    ///  <para>
    ///   The property only reflects the value that was previously set using this property. The
    ///   <see cref="FormCornerPreferenceChanged"/> event is raised accordingly when the value is
    ///   changed, which allows the property to be participating in binding scenarios.
    ///  </para>
    /// </remarks>
    [DefaultValue(FormCornerPreference.Default)]
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormCornerPreferenceDescr))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public FormCornerPreference FormCornerPreference
    {
        get => Properties.GetValueOrDefault(s_propFormCornerPreference, FormCornerPreference.Default);
        set
        {
            if (value == FormCornerPreference)
            {
                return;
            }

            _ = value switch
            {
                FormCornerPreference.Default => value,
                FormCornerPreference.DoNotRound => value,
                FormCornerPreference.Round => value,
                FormCornerPreference.RoundSmall => value,
                _ => throw new ArgumentOutOfRangeException(nameof(value))
            };

            Properties.AddOrRemoveValue(s_propFormCornerPreference, value, defaultValue: FormCornerPreference.Default);

            if (IsHandleCreated)
            {
                SetFormCornerPreferenceInternal(value);
            }

            OnFormCornerPreferenceChanged(EventArgs.Empty);
        }
    }

    /// <summary>
    ///  Raises the <see cref="FormCornerPreferenceChanged"/> event when the
    ///  <see cref="FormCornerPreference"/> property changes.
    /// </summary>
    /// <param name="e">
    ///  An <see cref="EventArgs"/> that contains the event data, in this case empty.
    /// </param>
    protected virtual void OnFormCornerPreferenceChanged(EventArgs e)
    {
        if (Events[s_formCornerPreferenceChanged] is EventHandler eventHandler)
        {
            eventHandler(this, e);
        }
    }

    private unsafe void SetFormCornerPreferenceInternal(FormCornerPreference cornerPreference)
    {
        DWM_WINDOW_CORNER_PREFERENCE dwmCornerPreference = cornerPreference switch
        {
            FormCornerPreference.Default => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DEFAULT,
            FormCornerPreference.DoNotRound => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DONOTROUND,
            FormCornerPreference.Round => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND,
            FormCornerPreference.RoundSmall => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUNDSMALL,
            _ => throw new ArgumentOutOfRangeException(nameof(cornerPreference))
        };

        PInvoke.DwmSetWindowAttribute(
            HWND,
            DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE,
            &dwmCornerPreference,
            sizeof(DWM_WINDOW_CORNER_PREFERENCE));
    }

    /// <summary>
    ///  Sets or gets the Form's border color.
    /// </summary>
    /// <returns>
    ///  The <see cref="Color"/> which has be previously set using this property or <see cref="Color.Empty"/>.
    ///  Note that the underlying Win32 API does not provide a reliable mechanism to retrieve the current
    ///  border color.
    /// </returns>
    /// <remarks>
    ///  <para>
    ///   Note: Reading this property is only for tracking purposes. If the Form's border color is
    ///   changed through other external means (Win32 calls), reading this property will not reflect
    ///   those changes, as the Win32 API does not provide a mechanism to retrieve the current title
    ///   bar color.
    ///  </para>
    ///  <para>
    ///   The property only reflects the value that was previously set using this property. The
    ///   <see cref="FormBorderColorChanged"/> event is raised accordingly when the value is
    ///   changed, which allows the property to be participating in binding scenarios.
    ///  </para>
    /// </remarks>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormBorderColorDescr))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public Color FormBorderColor
    {
        get => Properties.GetValueOrDefault(s_propFormBorderColor, Color.Empty);
        set
        {
            if (value == FormBorderColor)
            {
                return;
            }

            Properties.AddOrRemoveValue(s_propFormBorderColor, value, defaultValue: Color.Empty);

            if (IsHandleCreated)
            {
                SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, value);
            }

            OnFormBorderColorChanged(EventArgs.Empty);
        }
    }

    /// <summary>
    ///  Raises the <see cref="FormBorderColorChanged"/> event when the <see cref="FormBorderColor"/> property changes.
    /// </summary>
    /// <param name="e">
    ///  An <see cref="EventArgs"/> that contains the event data, in this case empty.
    /// </param>
    protected virtual void OnFormBorderColorChanged(EventArgs e)
    {
        if (Events[s_formBorderColorChanged] is EventHandler eventHandler)
        {
            eventHandler(this, e);
        }
    }

    /// <summary>
    ///  Sets or gets the Form's title bar back color (caption back color).
    /// </summary>
    /// <returns>
    ///  The <see cref="Color"/>, which has be previously set using this property or <see cref="Color.Empty"/>.
    ///  Note that the underlying Win32 API does not provide a reliable mechanism to retrieve the current title
    ///  bar color.
    /// </returns>
    /// <remarks>
    ///  <para>
    ///   Note: Reading this property is only for tracking purposes. If the window's title bar color is
    ///   changed through other external means (Win32 calls), reading this property will not reflect
    ///   those changes, as the Win32 API does not provide a mechanism to retrieve the current title
    ///   bar color.
    ///  </para>
    ///  <para>
    ///   The property only reflects the value that was previously set using this property. The
    ///   <see cref="FormCaptionBackColorChanged"/> event is raised accordingly when the value is
    ///   changed, which allows the property to be participating in binding scenarios.
    ///  </para>
    /// </remarks>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormCaptionBackColorDescr))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public Color FormCaptionBackColor
    {
        get => Properties.GetValueOrDefault(s_propFormCaptionBackColor, Color.Empty);
        set
        {
            if (value == FormCaptionBackColor)
            {
                return;
            }

            Properties.AddOrRemoveValue(s_propFormCaptionBackColor, value, defaultValue: Color.Empty);

            if (IsHandleCreated)
            {
                SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR, value);
            }

            OnFormCaptionBackColorChanged(EventArgs.Empty);
        }
    }

    /// <summary>
    ///  Raises the <see cref="FormCaptionBackColorChanged"/> event when the <see cref="FormCaptionBackColor"/>
    ///  property changes.
    /// </summary>
    /// <param name="e">
    ///  An <see cref="EventArgs"/> that contains the event data, in this case empty.
    /// </param>
    protected virtual void OnFormCaptionBackColorChanged(EventArgs e)
    {
        if (Events[s_formCaptionBackColorChanged] is EventHandler eventHandler)
        {
            eventHandler(this, e);
        }
    }

    /// <summary>
    ///  Sets or gets the Form's title bar text color (windows caption text color).
    /// </summary>
    /// <returns>
    ///  The <see cref="Color"/>, which has be previously set using this property or <see cref="Color.Empty"/>.
    ///  Note that the underlying Win32 API does not provide a reliable mechanism to retrieve the current title
    ///  bar text color.
    /// </returns>
    /// <remarks>
    ///  <para>
    ///   Note: Reading this property is only for tracking purposes. If the Form's title bar's text color
    ///   (window caption text) is changed through other external means (Win32 calls), reading this property
    ///   will not reflect those changes, as the Win32 API does not provide a mechanism to retrieve the
    ///   current title bar color.
    ///  </para>
    ///  <para>
    ///   The property only reflects the value that was previously set using this property. The
    ///   <see cref="FormCaptionTextColorChanged"/> event is raised accordingly when the value is
    ///   changed, which allows the property to be participating in binding scenarios.
    ///  </para>
    /// </remarks>
    [SRCategory(nameof(SR.CatWindowStyle))]
    [SRDescription(nameof(SR.FormCaptionTextColorDescr))]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public Color FormCaptionTextColor
    {
        get => Properties.GetValueOrDefault(s_propFormCaptionTextColor, Color.Empty);
        set
        {
            if (value == FormCaptionTextColor)
            {
                return;
            }

            Properties.AddOrRemoveValue(s_propFormCaptionTextColor, value, defaultValue: Color.Empty);

            if (IsHandleCreated)
            {
                SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_TEXT_COLOR, value);
            }

            OnFormCaptionTextColorChanged(EventArgs.Empty);
        }
    }

    /// <summary>
    ///  Raises the <see cref="FormCaptionTextColorChanged"/> event when the
    ///  <see cref="FormCaptionTextColor"/> property changes.
    /// </summary>
    /// <param name="e">
    ///  An <see cref="EventArgs"/> that contains the event data, in this case empty.
    /// </param>
    protected virtual void OnFormCaptionTextColorChanged(EventArgs e)
    {
        if (Events[s_formCaptionTextColorChanged] is EventHandler eventHandler)
        {
            eventHandler(this, e);
        }
    }

    private unsafe Color GetFormAttributeColorInternal(DWMWINDOWATTRIBUTE dmwWindowAttribute)
    {
        COLORREF colorRef;

        PInvoke.DwmGetWindowAttribute(
            HWND,
            dmwWindowAttribute,
            &colorRef,
            (uint)sizeof(COLORREF));

        return colorRef;
    }

    private unsafe void SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE dmwWindowAttribute, Color color)
    {
        COLORREF colorRef = color;

        PInvoke.DwmSetWindowAttribute(
            HWND,
            dmwWindowAttribute,
            &colorRef,
            (uint)sizeof(COLORREF));
    }

    /// <summary>
    ///  Gets or sets the form's window state.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [DefaultValue(FormWindowState.Normal)]
    [SRDescription(nameof(SR.FormWindowStateDescr))]
    public FormWindowState WindowState
    {
        get => (FormWindowState)_formState[s_formStateWindowState];
        set
        {
            SourceGenerated.EnumValidator.Validate(value);

            switch (value)
            {
                case FormWindowState.Normal:
                    SetState(States.SizeLockedByOS, false);
                    break;
                case FormWindowState.Maximized:
                case FormWindowState.Minimized:
                    SetState(States.SizeLockedByOS, true);
                    break;
            }

            if (IsHandleCreated && Visible)
            {
                switch (value)
                {
                    case FormWindowState.Normal:
                        PInvoke.ShowWindow(this, SHOW_WINDOW_CMD.SW_NORMAL);
                        break;
                    case FormWindowState.Maximized:
                        PInvoke.ShowWindow(this, SHOW_WINDOW_CMD.SW_MAXIMIZE);
                        break;
                    case FormWindowState.Minimized:
                        PInvoke.ShowWindow(this, SHOW_WINDOW_CMD.SW_MINIMIZE);
                        break;
                }
            }

            // Now set the local property to the passed in value so that
            // when UpdateWindowState is by the ShowWindow call above, the window state in effect when
            // this call was made will still be effective while processing that method.
            _formState[s_formStateWindowState] = (int)value;
        }
    }

    /// <summary>
    ///  Gets or sets the text to display in the caption bar of the form.
    /// </summary>
    internal override string WindowText
    {
        get => base.WindowText;
        set
        {
            string oldText = WindowText;
            base.WindowText = value;

            // For non-default FormBorderStyles, we do not set the WS_CAPTION style if
            // the Text property is null or "".
            // When we reload the form from code view, the text property is not set till
            // the very end, and so we do not end up updating the CreateParams with
            // WS_CAPTION. Fixed this by making sure we call UpdateStyles() when
            // we transition from a non-null value to a null value or vice versa in
            // Form.WindowText.
            if (string.IsNullOrEmpty(oldText) || string.IsNullOrEmpty(value))
            {
                UpdateFormStyles();
            }
        }
    }

    /// <summary>
    ///  Occurs when the form is activated in code or by the user.
    /// </summary>
    [SRCategory(nameof(SR.CatFocus))]
    [SRDescription(nameof(SR.FormOnActivateDescr))]
    public event EventHandler? Activated
    {
        add => Events.AddHandler(s_activatedEvent, value);
        remove => Events.RemoveHandler(s_activatedEvent, value);
    }

    /// <summary>
    ///  Occurs when the form is closing.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnClosingDescr))]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete(
        Obsoletions.FormOnClosingClosedMessage,
        error: false,
        DiagnosticId = Obsoletions.FormOnClosingClosedDiagnosticId,
        UrlFormat = Obsoletions.SharedUrlFormat)]
    public event CancelEventHandler? Closing
    {
        add => Events.AddHandler(s_closingEvent, value);
        remove => Events.RemoveHandler(s_closingEvent, value);
    }

    /// <summary>
    ///  Occurs when the form is closed.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnClosedDescr))]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete(
        Obsoletions.FormOnClosingClosedMessage,
        error: false,
        DiagnosticId = Obsoletions.FormOnClosingClosedDiagnosticId,
        UrlFormat = Obsoletions.SharedUrlFormat)]
    public event EventHandler? Closed
    {
        add => Events.AddHandler(s_closedEvent, value);
        remove => Events.RemoveHandler(s_closedEvent, value);
    }

    /// <summary>
    ///  Occurs when the form loses focus and is not the active form.
    /// </summary>
    [SRCategory(nameof(SR.CatFocus))]
    [SRDescription(nameof(SR.FormOnDeactivateDescr))]
    public event EventHandler? Deactivate
    {
        add => Events.AddHandler(s_deactivateEvent, value);
        remove => Events.RemoveHandler(s_deactivateEvent, value);
    }

    /// <summary>
    ///  Occurs when the form is closing.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnFormClosingDescr))]
    public event FormClosingEventHandler? FormClosing
    {
        add => Events.AddHandler(s_formClosingEvent, value);
        remove => Events.RemoveHandler(s_formClosingEvent, value);
    }

    /// <summary>
    ///  Occurs when the <see cref="FormBorderColor"/> property has changed.
    /// </summary>
    [SRCategory(nameof(SR.CatAppearance))]
    [SRDescription(nameof(SR.FormBorderColorChangedDescr))]
    public event EventHandler? FormBorderColorChanged
    {
        add => Events.AddHandler(s_formBorderColorChanged, value);
        remove => Events.RemoveHandler(s_formBorderColorChanged, value);
    }

    /// <summary>
    ///  Occurs when the <see cref="FormCaptionBackColor"/> property has changed.
    /// </summary>
    [SRCategory(nameof(SR.CatAppearance))]
    [SRDescription(nameof(SR.FormCaptionBackColorChangedDescr))]
    public event EventHandler? FormCaptionBackColorChanged
    {
        add => Events.AddHandler(s_formCaptionBackColorChanged, value);
        remove => Events.RemoveHandler(s_formCaptionBackColorChanged, value);
    }

    /// <summary>
    ///  Occurs when the <see cref="FormCaptionTextColor"/> property has changed.
    /// </summary>
    [SRCategory(nameof(SR.CatAppearance))]
    [SRDescription(nameof(SR.FormCaptionTextColorChangedDescr))]
    public event EventHandler? FormCaptionTextColorChanged
    {
        add => Events.AddHandler(s_formCaptionTextColorChanged, value);
        remove => Events.RemoveHandler(s_formCaptionTextColorChanged, value);
    }

    /// <summary>
    ///  Occurs when the <see cref="FormCornerPreference"/> property has changed.
    /// </summary>
    [SRCategory(nameof(SR.CatAppearance))]
    [SRDescription(nameof(SR.FormCornerPreferenceChangedDescr))]
    public event EventHandler? FormCornerPreferenceChanged
    {
        add => Events.AddHandler(s_formCornerPreferenceChanged, value);
        remove => Events.RemoveHandler(s_formCornerPreferenceChanged, value);
    }

    /// <summary>
    ///  Occurs when the form is closed.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnFormClosedDescr))]
    public event FormClosedEventHandler? FormClosed
    {
        add => Events.AddHandler(s_formClosedEvent, value);
        remove => Events.RemoveHandler(s_formClosedEvent, value);
    }

    /// <summary>
    ///  Occurs before the form becomes visible.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnLoadDescr))]
    public event EventHandler? Load
    {
        add => Events.AddHandler(s_loadEvent, value);
        remove => Events.RemoveHandler(s_loadEvent, value);
    }

    /// <summary>
    ///  Occurs when a Multiple Document Interface (MDI) child form is activated or closed
    ///  within an MDI application.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [SRDescription(nameof(SR.FormOnMDIChildActivateDescr))]
    public event EventHandler? MdiChildActivate
    {
        add => Events.AddHandler(s_mdiChildActivateEvent, value);
        remove => Events.RemoveHandler(s_mdiChildActivateEvent, value);
    }

    /// <summary>
    ///  Occurs when the menu of a form loses focus.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnMenuCompleteDescr))]
    [Browsable(false)]
    public event EventHandler? MenuComplete
    {
        add => Events.AddHandler(s_menuCompleteEvent, value);
        remove => Events.RemoveHandler(s_menuCompleteEvent, value);
    }

    /// <summary>
    ///  Occurs when the menu of a form receives focus.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnMenuStartDescr))]
    [Browsable(false)]
    public event EventHandler? MenuStart
    {
        add => Events.AddHandler(s_menuStartEvent, value);
        remove => Events.RemoveHandler(s_menuStartEvent, value);
    }

    /// <summary>
    ///  Occurs after the input language of the form has changed.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnInputLangChangeDescr))]
    public event InputLanguageChangedEventHandler? InputLanguageChanged
    {
        add => Events.AddHandler(s_inputLanguageChangeEvent, value);
        remove => Events.RemoveHandler(s_inputLanguageChangeEvent, value);
    }

    /// <summary>
    ///  Occurs when the user attempts to change the input language for the
    ///  form.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnInputLangChangeRequestDescr))]
    public event InputLanguageChangingEventHandler? InputLanguageChanging
    {
        add => Events.AddHandler(s_inputLanguageChangeRequestEvent, value);
        remove => Events.RemoveHandler(s_inputLanguageChangeRequestEvent, value);
    }

    [SRCategory(nameof(SR.CatPropertyChanged))]
    [SRDescription(nameof(SR.ControlOnRightToLeftLayoutChangedDescr))]
    public event EventHandler? RightToLeftLayoutChanged
    {
        add => Events.AddHandler(s_rightToLeftLayoutChangedEvent, value);
        remove => Events.RemoveHandler(s_rightToLeftLayoutChangedEvent, value);
    }

    /// <summary>
    ///  Occurs whenever the form is first shown.
    /// </summary>
    [SRCategory(nameof(SR.CatBehavior))]
    [SRDescription(nameof(SR.FormOnShownDescr))]
    public event EventHandler? Shown
    {
        add => Events.AddHandler(s_shownEvent, value);
        remove => Events.RemoveHandler(s_shownEvent, value);
    }

    /// <summary>
    ///  Activates the form and gives it focus.
    /// </summary>
    public void Activate()
    {
        if (Visible && IsHandleCreated)
        {
            if (IsMdiChild)
            {
                if (MdiParentInternal.MdiClient is not null)
                {
                    PInvokeCore.SendMessage(MdiParentInternal.MdiClient, PInvokeCore.WM_MDIACTIVATE, (WPARAM)HWND);
                }
            }
            else
            {
                PInvoke.SetForegroundWindow(this);
            }
        }
    }

    protected void ActivateMdiChild(Form? form)
    {
        if (FormerlyActiveMdiChild is not null && !FormerlyActiveMdiChild.IsClosing)
        {
            FormerlyActiveMdiChild.UpdateWindowIcon(true);
            FormerlyActiveMdiChild = null;
        }

        Form? activeMdiChild = ActiveMdiChildInternal;
        if (activeMdiChild == form)
        {
            return;
        }

        // Don't believe we ever hit this with non-null, but leaving it intact in
        // case removing it would cause a problem.
        activeMdiChild?.Active = false;

        activeMdiChild = form;
        ActiveMdiChildInternal = form;

        if (activeMdiChild is not null)
        {
            activeMdiChild.IsMdiChildFocusable = true;
            activeMdiChild.Active = true;
        }
        else if (Active)
        {
            ActivateControl(this);
        }

        // Note: It is possible that we are raising this event when the activeMdiChild is null,
        // this is the case when the only visible mdi child is being closed. See DeactivateMdiChild
        // for more info.
        OnMdiChildActivate(EventArgs.Empty);
    }

    /// <summary>
    ///  Adds an owned form to this form.
    /// </summary>
    public void AddOwnedForm(Form? ownedForm)
    {
        if (ownedForm is null)
        {
            return;
        }

        if (ownedForm.OwnerInternal != this)
        {
            ownedForm.Owner = this; // NOTE: this calls AddOwnedForm again with correct owner set.
            return;
        }

        if (!Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms))
        {
            ownedForms = [];
            Properties.AddValue(s_propOwnedForms, ownedForms);
        }

        // Make sure this isn't already in the list.
        if (ownedForms.Contains(ownedForm))
        {
            return;
        }

        ownedForms.Add(ownedForm);
    }

    // When shrinking the form (i.e. going from Large Fonts to Small
    // Fonts) we end up making everything too small due to roundoff,
    // etc... solution - just don't shrink as much.
    private static float AdjustScale(float scale)
    {
        // NOTE : This function is cloned in FormDocumentDesigner... remember to keep
        //      : them in sync
        //

        // Map 0.0 - .92... increment by 0.08
        //
        if (scale < .92f)
        {
            return scale + 0.08f;
        }

        // Map .92 - .99 to 1.0
        //
        else if (scale < 1.0f)
        {
            return 1.0f;
        }

        // Map 1.02... increment by 0.08
        //
        else if (scale > 1.01f)
        {
            return scale + 0.08f;
        }

        // Map 1.0 - 1.01... no change
        //
        else
        {
            return scale;
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void AdjustFormScrollbars(bool displayScrollbars)
    {
        if (WindowState != FormWindowState.Minimized)
        {
            base.AdjustFormScrollbars(displayScrollbars);
        }
    }

    private void AdjustSystemMenu(HMENU hmenu)
    {
        UpdateWindowState();
        FormWindowState winState = WindowState;
        FormBorderStyle borderStyle = FormBorderStyle;
        bool sizableBorder = (borderStyle is FormBorderStyle.SizableToolWindow
                              or FormBorderStyle.Sizable);

        bool showMin = MinimizeBox && winState != FormWindowState.Minimized;
        bool showMax = MaximizeBox && winState != FormWindowState.Maximized;
        bool showClose = ControlBox;
        bool showRestore = winState != FormWindowState.Normal;
        bool showSize = sizableBorder && winState != FormWindowState.Minimized
                        && winState != FormWindowState.Maximized;

        if (!showMin)
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_MINIMIZE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_GRAYED);
        }
        else
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_MINIMIZE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_ENABLED);
        }

        if (!showMax)
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_MAXIMIZE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_GRAYED);
        }
        else
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_MAXIMIZE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_ENABLED);
        }

        if (!showClose)
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_CLOSE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_GRAYED);
        }
        else
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_CLOSE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_ENABLED);
        }

        if (!showRestore)
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_RESTORE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_GRAYED);
        }
        else
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_RESTORE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_ENABLED);
        }

        if (!showSize)
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_SIZE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_GRAYED);
        }
        else
        {
            PInvoke.EnableMenuItem(hmenu, PInvoke.SC_SIZE, MENU_ITEM_FLAGS.MF_BYCOMMAND | MENU_ITEM_FLAGS.MF_ENABLED);
        }

        // Prevent the finalizer running to avoid closing the handle.
        GC.KeepAlive(this);
    }

    /// <summary>
    ///  This forces the SystemMenu to look like we want.
    /// </summary>
    private void AdjustSystemMenu()
    {
        if (IsHandleCreated)
        {
            HMENU hmenu = PInvoke.GetSystemMenu(this, bRevert: false);
            AdjustSystemMenu(hmenu);
        }
    }

    /// <summary>
    ///  This auto scales the form based on the AutoScaleBaseSize.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("This method has been deprecated. Use the ApplyAutoScaling method instead.  https://go.microsoft.com/fwlink/?linkid=14202")]
    protected void ApplyAutoScaling()
    {
        // NOTE : This function is cloned in FormDocumentDesigner, remember to keep them in sync.

        // We also don't do this if the property is empty. Otherwise we will perform two GetAutoScaleBaseSize
        // calls only to find that they returned the same value.
        if (!_autoScaleBaseSize.IsEmpty)
        {
            Size baseVar = AutoScaleBaseSize;
            SizeF newVarF = GetAutoScaleSize(Font);
            Size newVar = new((int)Math.Round(newVarF.Width), (int)Math.Round(newVarF.Height));

            // We save a significant amount of time by bailing early if there's no work to be done
            if (baseVar.Equals(newVar))
            {
                return;
            }

            float percY = AdjustScale(newVar.Height / ((float)baseVar.Height));
            float percX = AdjustScale(newVar.Width / ((float)baseVar.Width));
            Scale(percX, percY);

            // This would ensure that we use the new font information to calculate the AutoScaleBaseSize.
            AutoScaleBaseSize = newVar;
        }
    }

    /// <summary>
    ///  This adjusts the size of the windowRect so that the client rect is the
    ///  correct size.
    /// </summary>
    private void ApplyClientSize()
    {
        if ((FormWindowState)_formState[s_formStateWindowState] != FormWindowState.Normal
            || !IsHandleCreated)
        {
            return;
        }

        // Cache the clientSize, since calling setBounds will end up causing
        // clientSize to get reset to the actual clientRect size...
        //
        Size correctClientSize = ClientSize;
        bool hscr = HScroll;
        bool vscr = VScroll;

        // This logic assumes that the caller of setClientSize() knows if the scrollbars
        // are showing or not. Since the 90% case is that setClientSize() is the persisted
        // ClientSize, this is correct.
        // Without this logic persisted forms that were saved with the scrollbars showing,
        // don't get set to the correct size.
        //
        bool adjustScroll = false;
        if (_formState[s_formStateSetClientSize] != 0)
        {
            adjustScroll = true;
            _formState[s_formStateSetClientSize] = 0;
        }

        if (adjustScroll)
        {
            if (hscr)
            {
                correctClientSize.Height += SystemInformation.HorizontalScrollBarHeight;
            }

            if (vscr)
            {
                correctClientSize.Width += SystemInformation.VerticalScrollBarWidth;
            }
        }

        PInvokeCore.GetClientRect(this, out RECT currentClient);
        Rectangle bounds = Bounds;

        // If the width is incorrect, compute the correct size with
        // computeWindowSize. We only do this logic if the width needs to
        // be adjusted to avoid double adjusting the window.
        //
        if (correctClientSize.Width != currentClient.Width)
        {
            Size correct = ComputeWindowSize(correctClientSize);

            // Since computeWindowSize ignores scrollbars, we must tack these on to
            // assure the correct size.
            //
            if (vscr)
            {
                correct.Width += SystemInformation.VerticalScrollBarWidth;
            }

            if (hscr)
            {
                correct.Height += SystemInformation.HorizontalScrollBarHeight;
            }

            bounds.Width = correct.Width;
            bounds.Height = correct.Height;
            Bounds = bounds;
            PInvokeCore.GetClientRect(this, out currentClient);
        }

        // If it still isn't correct, then we assume that the problem is
        // menu wrapping (since computeWindowSize doesn't take that into
        // account), so we just need to adjust the height by the correct
        // amount.
        //
        if (correctClientSize.Height != currentClient.Height)
        {
            int delta = correctClientSize.Height - currentClient.Height;
            bounds.Height += delta;
            Bounds = bounds;
        }

        UpdateBounds();
    }

    /// <summary>
    ///  Assigns a new parent control. Sends out the appropriate property change
    ///  notifications for properties that are affected by the change of parent.
    /// </summary>
    internal override void AssignParent(Control? value)
    {
        // If we are being unparented from the MDI client control, remove formMDIParent as well.
        if (Properties.TryGetValue(s_propFormMdiParent, out Form? formMdiParent) && formMdiParent.MdiClient != value)
        {
            Properties.RemoveValue(s_propFormMdiParent);
        }

        base.AssignParent(value);
    }

    /// <summary>
    ///  Checks whether a modal dialog is ready to close. If the dialogResult
    ///  property is not DialogResult.None, the OnClosing and OnClosed events
    ///  are fired. A return value of true indicates that both events were
    ///  successfully dispatched and that event handlers did not cancel closing
    ///  of the dialog. User code should never have a reason to call this method.
    ///  It is internal only so that the Application class can call it from a
    ///  modal message loop.
    ///
    ///  closingOnly is set when this is called from WmClose so that we can do just the beginning portion
    ///  of this and then let the message loop finish it off with the actual close code.
    ///
    ///  Note we set a flag to determine if we've already called close or not.
    /// </summary>
    internal bool CheckCloseDialog(bool closingOnly)
    {
        if (_dialogResult == DialogResult.None && Visible)
        {
            return false;
        }

        try
        {
            FormClosingEventArgs e = new(_closeReason, false);

            if (!CalledClosing)
            {
#pragma warning disable WFDEV004 // Type or member is obsolete - compat
                OnClosing(e);
#pragma warning restore WFDEV004
                OnFormClosing(e);
                if (e.Cancel)
                {
                    _dialogResult = DialogResult.None;
                }
                else
                {
                    // we have called closing here, and it wasn't cancelled, so we're expecting a close
                    // call again soon.
                    CalledClosing = true;
                }
            }

            if (!closingOnly && _dialogResult != DialogResult.None)
            {
                FormClosedEventArgs fc = new(_closeReason);
#pragma warning disable WFDEV004 // Type or member is obsolete - compat
                OnClosed(fc);
#pragma warning restore WFDEV004
                OnFormClosed(fc);

                // reset called closing.
                //
                CalledClosing = false;
            }
        }
        catch (Exception e)
        {
            _dialogResult = DialogResult.None;
            if (NativeWindow.WndProcShouldBeDebuggable)
            {
                throw;
            }
            else
            {
                Application.OnThreadException(e);
            }
        }

        return _dialogResult != DialogResult.None || !Visible;
    }

    /// <summary>
    ///  Closes the form.
    /// </summary>
    public void Close()
    {
        if (GetState(States.CreatingHandle))
        {
            throw new InvalidOperationException(string.Format(SR.ClosingWhileCreatingHandle, "Close"));
        }

        if (IsHandleCreated)
        {
            _closeReason = CloseReason.UserClosing;
            PInvokeCore.SendMessage(this, PInvokeCore.WM_CLOSE);
        }
        else
        {
            // MSDN: When a form is closed, all resources created within the object are closed and the form is disposed.
            // For MDI child: MdiChildren collection gets updated
            Dispose();
        }
    }

    /// <summary>
    ///  Computes the window size from the clientSize based on the styles
    ///  returned from CreateParams.
    /// </summary>
    private Size ComputeWindowSize(Size clientSize)
    {
        CreateParams cp = CreateParams;
        return ComputeWindowSize(clientSize, (WINDOW_STYLE)cp.Style, (WINDOW_EX_STYLE)cp.ExStyle);
    }

    /// <summary>
    ///  Computes the window size from the clientSize base on the specified
    ///  window styles. This will not return the correct size if menus wrap.
    /// </summary>
    private Size ComputeWindowSize(Size clientSize, WINDOW_STYLE style, WINDOW_EX_STYLE exStyle)
    {
        RECT result = new(clientSize);
        AdjustWindowRectExForControlDpi(ref result, style, false, exStyle);
        return result.Size;
    }

    protected override AccessibleObject CreateAccessibilityInstance()
    {
        FormAccessibleObject accessibleObject = new(this);

        // Try to raise UIA focus event for the form, if it's focused.
        // Try it after the accessible object creation, because a screen reader
        // gets the accessible object after "OnGotFocus", "OnLoad", "OnShown" handlers,
        // and the object is not created yet, when these methods work, so we can't raise
        // the event while the object is not created. It's the Form control's feature only,
        // for the rest controls the accessibility tree will be built, when they get focus.
        // This case works for an empty form or a form with disabled or invisible controls
        // to have consistent behavior with .NET Framework.
        // If the form has any control (ActiveControl is true), a screen reader will focus on it instead.
        if (Focused && ActiveControl is null)
        {
            accessibleObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId);
        }

        return accessibleObject;
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override Control.ControlCollection CreateControlsInstance()
    {
        return new ControlCollection(this);
    }

    /// <summary>
    ///  Cleans up form state after a control has been removed.
    ///  Package scope for Control
    /// </summary>
    internal override void AfterControlRemoved(Control control, Control oldParent)
    {
        base.AfterControlRemoved(control, oldParent);

        if (control == AcceptButton)
        {
            AcceptButton = null;
        }

        if (control == CancelButton)
        {
            CancelButton = null;
        }

        if (control == _ctlClient)
        {
            _ctlClient = null;
            UpdateMenuHandles();
        }
    }

    /// <summary>
    ///  Creates the handle for the Form. If a subclass overrides this function,
    ///  it must call the base implementation.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void CreateHandle()
    {
        // In the windows MDI code we have to suspend menu
        // updates on the parent while creating the handle. Otherwise if the
        // child is created maximized, the menu ends up with two sets of
        // MDI child ornaments.
        Form? form = Properties.GetValueOrDefault<Form>(s_propFormMdiParent);
        form?.SuspendUpdateMenuHandles();

        try
        {
            // If the child is created before the MDI parent we can
            // get Win32 exceptions as the MDI child is parked to the parking window.
            if (IsMdiChild && MdiParentInternal.IsHandleCreated)
            {
                MdiClient? mdiClient = MdiParentInternal.MdiClient;
                if (mdiClient is not null && !mdiClient.IsHandleCreated)
                {
                    mdiClient.CreateControl();
                }
            }

            // If we think that we are maximized, then a duplicate set of mdi gadgets are created.
            // If we create the window maximized, BUT our internal form state thinks it
            // isn't... then everything is OK...
            //
            // We really should find out what causes this... but I can't find it...
            //
            if (IsMdiChild
                && (FormWindowState)_formState[s_formStateWindowState] == FormWindowState.Maximized)
            {
                // This is the reason why we see the blue borders
                // when creating a maximized mdi child, unfortunately we cannot fix this now...
                _formState[s_formStateWindowState] = (int)FormWindowState.Normal;
                _formState[s_formStateMdiChildMax] = 1;
                base.CreateHandle();
                _formState[s_formStateWindowState] = (int)FormWindowState.Maximized;
                _formState[s_formStateMdiChildMax] = 0;
            }
            else
            {
                base.CreateHandle();
            }

            UpdateHandleWithOwner();
            UpdateWindowIcon(false);

            AdjustSystemMenu();

            if ((FormStartPosition)_formState[s_formStateStartPos] != FormStartPosition.WindowsDefaultBounds)
            {
                ApplyClientSize();
            }

            if (_formState[s_formStateShowWindowOnCreate] == 1)
            {
                Visible = true;
            }

            // avoid extra SetMenu calls for perf
            if (!TopLevel || IsMdiContainer)
            {
                UpdateMenuHandles();
            }

            // In order for a window not to have a taskbar entry, it must be owned.
            if (!ShowInTaskbar && OwnerInternal is null && TopLevel)
            {
                PInvokeCore.SetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT, TaskbarOwner);

                // Make sure the large icon is set so the ALT+TAB icon
                // reflects the real icon of the application
                Icon? icon = Icon;
                if (icon is not null && !TaskbarOwner.Handle.IsNull)
                {
                    PInvokeCore.SendMessage(TaskbarOwner, PInvokeCore.WM_SETICON, (WPARAM)PInvoke.ICON_BIG, (LPARAM)icon.Handle);
                }
            }

            if (_formState[s_formStateTopMost] != 0)
            {
                TopMost = true;
            }
        }
        finally
        {
            form?.ResumeUpdateMenuHandles();

            // We need to reset the styles in case Windows tries to set us up
            // with "correct" styles
            //
            UpdateStyles();
        }
    }

    // Deactivates active MDI child and temporarily marks it as un-focusable,
    // so that WM_SETFOCUS sent to MDIClient does not activate that child.
    private void DeactivateMdiChild()
    {
        Form? activeMdiChild = ActiveMdiChildInternal;
        if (activeMdiChild is not null)
        {
            Form? mdiParent = activeMdiChild.MdiParentInternal;

            activeMdiChild.Active = false;
            activeMdiChild.IsMdiChildFocusable = false;
            if (!activeMdiChild.IsClosing)
            {
                FormerlyActiveMdiChild = activeMdiChild;
            }

            // Enter/Leave events on child controls are raised from the ActivateMdiChild method, usually when another
            // Mdi child is getting activated after deactivating this one; but if this is the only visible MDI child
            // we need to fake the activation call so MdiChildActivate and Leave events are raised properly. (We say
            // in the MSDN doc that the MdiChildActivate event is raised when an mdi child is activated or closed -
            // we actually meant the last mdi child is closed).
            if (mdiParent is not null)
            {
                bool fakeActivation = true;
                foreach (Form mdiChild in mdiParent.MdiChildren)
                {
                    if (mdiChild != this && mdiChild.Visible)
                    {
                        fakeActivation = false; // more than one mdi child visible.
                        break;
                    }
                }

                if (fakeActivation)
                {
                    mdiParent.ActivateMdiChild(null);
                }
            }

            ActiveMdiChildInternal = null;

            // Note: WM_MDIACTIVATE message is sent to the form being activated and to the form being deactivated, ideally
            // we would raise the MdiChildActivate event here accordingly but it would constitute a breaking change.

            // undo merge
            UpdateMenuHandles();
            UpdateToolStrip();
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void DefWndProc(ref Message m)
    {
        if (_ctlClient is not null && _ctlClient.IsHandleCreated && _ctlClient.ParentInternal == this)
        {
            m.ResultInternal = PInvoke.DefFrameProc(
                m.HWND,
                _ctlClient.HWND,
                (uint)m.Msg,
                m.WParamInternal,
                m.LParamInternal);

            GC.KeepAlive(_ctlClient);
        }
        else if (_formStateEx[s_formStateExUseMdiChildProc] != 0)
        {
            m.ResultInternal = PInvoke.DefMDIChildProc(m.HWND, (uint)m.Msg, m.WParamInternal, m.LParamInternal);
        }
        else
        {
            base.DefWndProc(ref m);
        }
    }

    /// <summary>
    ///  Releases all the system resources associated with the Form. If a subclass
    ///  overrides this function, it must call the base implementation.
    /// </summary>
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            CalledOnLoad = false;
            CalledMakeVisible = false;
            CalledCreateControl = false;

            Properties.RemoveValue(s_propAcceptButton);
            Properties.RemoveValue(s_propCancelButton);
            Properties.RemoveValue(s_propDefaultButton);
            Properties.RemoveValue(s_propActiveMdiChild);

            MdiWindowListStrip?.Dispose();
            MdiWindowListStrip = null;

            MdiControlStrip?.Dispose();
            MdiControlStrip = null;

            if (MainMenuStrip is not null)
            {
                // should NOT call dispose on MainMenuStrip - it's likely NOT to be in the form's control collection.
                MainMenuStrip = null;
            }

            if (Properties.TryGetValue(s_propOwner, out Form? owner))
            {
                owner.RemoveOwnedForm(this);
                Properties.RemoveValue(s_propOwner);
            }

            Properties.RemoveValue(s_propDialogOwner);

            if (Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms))
            {
                // It calls remove and removes itself.
                for (int i = ownedForms.Count - 1; i >= 0; i--)
                {
                    ownedForms[i].Dispose();
                }
            }

            _smallIcon?.Dispose();
            _smallIcon = null;

            base.Dispose(disposing);
            _ctlClient = null;

            if (Properties.TryGetValue(s_propDummyMdiMenu, out HMENU dummyMenu))
            {
                Properties.RemoveValue(s_propDummyMdiMenu);
                PInvoke.DestroyMenu(dummyMenu);
            }

            _nonModalFormCompletion?.TrySetResult();
        }
        else
        {
            base.Dispose(disposing);
        }
    }

    /// <summary>
    ///  Adjusts the window style of the CreateParams to reflect the bordericons.
    /// </summary>
    private void FillInCreateParamsBorderIcons(CreateParams cp)
    {
        if (FormBorderStyle != FormBorderStyle.None)
        {
            if (!string.IsNullOrEmpty(Text))
            {
                cp.Style |= (int)WINDOW_STYLE.WS_CAPTION;
            }

            if (ControlBox)
            {
                cp.Style |= (int)(WINDOW_STYLE.WS_SYSMENU | WINDOW_STYLE.WS_CAPTION);
            }
            else
            {
                cp.Style &= ~(int)WINDOW_STYLE.WS_SYSMENU;
            }

            if (MaximizeBox)
            {
                cp.Style |= (int)WINDOW_STYLE.WS_MAXIMIZEBOX;
            }
            else
            {
                cp.Style &= ~(int)WINDOW_STYLE.WS_MAXIMIZEBOX;
            }

            if (MinimizeBox)
            {
                cp.Style |= (int)WINDOW_STYLE.WS_MINIMIZEBOX;
            }
            else
            {
                cp.Style &= ~(int)WINDOW_STYLE.WS_MINIMIZEBOX;
            }

            if (HelpButton && !MaximizeBox && !MinimizeBox && ControlBox)
            {
                // Windows should ignore WS_EX_CONTEXTHELP unless all those conditions hold.
                // But someone must have failed the check, because Windows 2000
                // will show a help button if either the maximize or
                // minimize button is disabled.
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_CONTEXTHELP;
            }
            else
            {
                cp.ExStyle &= ~(int)WINDOW_EX_STYLE.WS_EX_CONTEXTHELP;
            }
        }
    }

    /// <summary>
    ///  Adjusts the window style of the CreateParams to reflect the borderstyle.
    /// </summary>
    private void FillInCreateParamsBorderStyles(CreateParams cp)
    {
        switch ((FormBorderStyle)_formState[s_formStateBorderStyle])
        {
            case FormBorderStyle.None:
                break;
            case FormBorderStyle.FixedSingle:
                cp.Style |= (int)WINDOW_STYLE.WS_BORDER;
                break;
            case FormBorderStyle.Sizable:
                cp.Style |= (int)(WINDOW_STYLE.WS_BORDER | WINDOW_STYLE.WS_THICKFRAME);
                break;
            case FormBorderStyle.Fixed3D:
                cp.Style |= (int)WINDOW_STYLE.WS_BORDER;
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_CLIENTEDGE;
                break;
            case FormBorderStyle.FixedDialog:
                cp.Style |= (int)WINDOW_STYLE.WS_BORDER;
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_DLGMODALFRAME;
                break;
            case FormBorderStyle.FixedToolWindow:
                cp.Style |= (int)WINDOW_STYLE.WS_BORDER;
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW;
                break;
            case FormBorderStyle.SizableToolWindow:
                cp.Style |= (int)(WINDOW_STYLE.WS_BORDER | WINDOW_STYLE.WS_THICKFRAME);
                cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW;
                break;
        }
    }

    /// <summary>
    ///  Adjusts the CreateParams to reflect the window bounds and start position.
    /// </summary>
    private void FillInCreateParamsStartPosition(CreateParams cp)
    {
        if (_formState[s_formStateSetClientSize] != 0)
        {
            // When computing the client window size, don't tell them that we are going to be maximized.
            int maskedStyle = cp.Style & ~(int)(WINDOW_STYLE.WS_MAXIMIZE | WINDOW_STYLE.WS_MINIMIZE);
            Size correct = ComputeWindowSize(ClientSize, (WINDOW_STYLE)maskedStyle, (WINDOW_EX_STYLE)cp.ExStyle);
            cp.Width = correct.Width;
            cp.Height = correct.Height;
        }

        switch ((FormStartPosition)_formState[s_formStateStartPos])
        {
            case FormStartPosition.WindowsDefaultBounds:
                cp.Width = PInvoke.CW_USEDEFAULT;
                cp.Height = PInvoke.CW_USEDEFAULT;
                // no break, fall through to set the location to default...
                goto case FormStartPosition.WindowsDefaultLocation;
            case FormStartPosition.WindowsDefaultLocation:
            case FormStartPosition.CenterParent:
                // Since FillInCreateParamsStartPosition() is called
                // several times when a window is shown, we'll need to force the location
                // each time for MdiChild windows that are docked so that the window will
                // be created in the correct location and scroll bars will not be displayed.
                if (IsMdiChild && Dock != DockStyle.None)
                {
                    break;
                }

                cp.X = PInvoke.CW_USEDEFAULT;
                cp.Y = PInvoke.CW_USEDEFAULT;
                break;
            case FormStartPosition.CenterScreen:
                if (IsMdiChild)
                {
                    Control? mdiclient = MdiParentInternal.MdiClient;
                    Rectangle clientRect = mdiclient is null ? Rectangle.Empty : mdiclient.ClientRectangle;

                    cp.X = Math.Max(clientRect.X, clientRect.X + (clientRect.Width - cp.Width) / 2);
                    cp.Y = Math.Max(clientRect.Y, clientRect.Y + (clientRect.Height - cp.Height) / 2);
                }
                else
                {
                    Screen desktop;
                    IWin32Window? dialogOwner = Properties.GetValueOrDefault<IWin32Window>(s_propDialogOwner);
                    if ((OwnerInternal is not null) || (dialogOwner is not null))
                    {
                        HandleRef<HWND> ownerHandle = dialogOwner is not null
                            ? GetSafeHandle(dialogOwner)
                            : new(OwnerInternal!);
                        desktop = Screen.FromHandle(ownerHandle.Handle);
                        GC.KeepAlive(ownerHandle.Wrapper);
                    }
                    else
                    {
                        desktop = Screen.FromPoint(MousePosition);
                    }

                    Rectangle screenRect = desktop.WorkingArea;

                    // If we're maximized then don't set the x & y coordinates (they're @(0,0))
                    if (WindowState != FormWindowState.Maximized)
                    {
                        cp.X = Math.Max(screenRect.X, screenRect.X + (screenRect.Width - cp.Width) / 2);
                        cp.Y = Math.Max(screenRect.Y, screenRect.Y + (screenRect.Height - cp.Height) / 2);
                    }
                }

                break;
        }
    }

    /// <summary>
    ///  Adjusts the CreateParams to reflect the window state.
    /// </summary>
    private void FillInCreateParamsWindowState(CreateParams cp)
    {
        switch ((FormWindowState)_formState[s_formStateWindowState])
        {
            case FormWindowState.Maximized:
                cp.Style |= (int)WINDOW_STYLE.WS_MAXIMIZE;
                break;
            case FormWindowState.Minimized:
                cp.Style |= (int)WINDOW_STYLE.WS_MINIMIZE;
                break;
        }
    }

    /// <summary>
    ///  Attempts to set focus to this Form.
    /// </summary>
    private protected override bool FocusInternal()
    {
        Debug.Assert(IsHandleCreated, "Attempt to set focus to a form that has not yet created its handle.");

        // If this form is a MdiChild, then we need to set the focus differently.
        if (IsMdiChild)
        {
            if (MdiParentInternal.MdiClient is not null)
            {
                PInvokeCore.SendMessage(MdiParentInternal.MdiClient, PInvokeCore.WM_MDIACTIVATE, this);
            }

            return Focused;
        }

        return base.FocusInternal();
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("This method has been deprecated. Use the AutoScaleDimensions property instead.  https://go.microsoft.com/fwlink/?linkid=14202")]
    public static SizeF GetAutoScaleSize(Font font)
    {
        float height = font.Height;
        float width = 9.0f;

        try
        {
            // Get the screen HDC
            using Graphics graphics = Graphics.FromHwndInternal(0);
            string magicString = "The quick brown fox jumped over the lazy dog.";
            double magicNumber = 44.549996948242189; // chosen for compatibility with older versions of windows forms, but approximately magicString.Length
            float stringWidth = graphics.MeasureString(magicString, font).Width;
            width = (float)(stringWidth / magicNumber);
        }
        catch
        {
            // We may get an bogus OutOfMemoryException
            // (which is a critical exception - according to ClientUtils.IsCriticalException())
            // from GDI+. So we can't use ClientUtils.IsCriticalException here and rethrow.
        }

        return new SizeF(width, height);
    }

    private void CallShownEvent()
    {
        OnShown(EventArgs.Empty);
#if NET11_0_OR_GREATER
        // Primary deferred-reveal trigger: OnShown is a guaranteed one-shot for a shown top-level
        // form and runs before the first natural WM_PAINT, so revealing here shows the fully painted
        // window tree at once rather than mid-paint.
        RevealDeferredAppearance();
#endif
    }

    /// <summary>
    ///  Override since CanProcessMnemonic is overridden too (base.CanSelectCore calls CanProcessMnemonic).
    /// </summary>
    internal override bool CanSelectCore()
    {
        if (!GetStyle(ControlStyles.Selectable) || !Enabled || !Visible)
        {
            return false;
        }

        return true;
    }

    /// <summary>
    ///  When an MDI form is hidden it means its handle has not yet been created or has been destroyed (see
    ///  SetVisibleCore). If the handle is recreated, the form will be made visible which should be avoided.
    /// </summary>
    internal bool CanRecreateHandle()
    {
        if (IsMdiChild)
        {
            // During changing visibility, it is possible that the style returns true for visible but the handle has
            // not yet been created, add a check for both.
            return GetState(States.Visible) && IsHandleCreated;
        }

        return true;
    }

    /// <summary>
    ///  Overridden to handle MDI mnemonic processing properly.
    /// </summary>
    internal override bool CanProcessMnemonic()
    {
        // If this is a Mdi child form, child controls should process mnemonics only if this is the active mdi child.
        if (IsMdiChild &&
            (_formStateEx[s_formStateExMnemonicProcessed] == 1
                || this != MdiParentInternal.ActiveMdiChildInternal
                || WindowState == FormWindowState.Minimized))
        {
            return false;
        }

        return base.CanProcessMnemonic();
    }

    /// <summary>
    ///  Overridden to handle MDI mnemonic processing properly.
    /// </summary>
    protected internal override bool ProcessMnemonic(char charCode)
    {
        // MDI container form has at least one control, the MDI client which contains the MDI children. We need
        // to allow the MDI children process the mnemonic before any other control in the MDI container (like
        // menu items or any other control).
        if (base.ProcessMnemonic(charCode))
        {
            return true;
        }

        if (IsMdiContainer)
        {
            // ContainerControl have already processed the active MDI child for us (if any) in the call above,
            // now process remaining controls (non-mdi children).
            if (Controls.Count > 1)
            { // Ignore the MdiClient control
                for (int index = 0; index < Controls.Count; index++)
                {
                    Control ctl = Controls[index];
                    if (ctl is MdiClient)
                    {
                        continue;
                    }

                    if (ctl.ProcessMnemonic(charCode))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        return false;
    }

    /// <summary>
    ///  Centers the dialog to its parent.
    /// </summary>
    protected void CenterToParent()
    {
        if (!TopLevel)
        {
            return;
        }

        Point p = default;
        Size s = Size;
        HWND ownerHandle = (HWND)PInvokeCore.GetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT);

        if (!ownerHandle.IsNull)
        {
            Screen desktop = Screen.FromHandle(ownerHandle);
            Rectangle screenRect = desktop.WorkingArea;
            PInvokeCore.GetWindowRect(ownerHandle, out var ownerRect);

            p.X = (ownerRect.left + ownerRect.right - s.Width) / 2;
            if (p.X < screenRect.X)
            {
                p.X = screenRect.X;
            }
            else if (p.X + s.Width > screenRect.X + screenRect.Width)
            {
                p.X = screenRect.X + screenRect.Width - s.Width;
            }

            p.Y = (ownerRect.top + ownerRect.bottom - s.Height) / 2;
            if (p.Y < screenRect.Y)
            {
                p.Y = screenRect.Y;
            }
            else if (p.Y + s.Height > screenRect.Y + screenRect.Height)
            {
                p.Y = screenRect.Y + screenRect.Height - s.Height;
            }

            Location = p;
        }
        else
        {
            CenterToScreen();
        }
    }

    /// <summary>
    ///  Centers the dialog to the screen. This will first attempt to use
    ///  the owner property to determine the correct screen, then
    ///  it will try the HWND owner of the form, and finally this will
    ///  center the form on the same monitor as the mouse cursor.
    /// </summary>
    protected void CenterToScreen()
    {
        Point p = default;
        Screen desktop;
        if (OwnerInternal is not null)
        {
            desktop = Screen.FromControl(OwnerInternal);
        }
        else
        {
            HWND hWndOwner = default;
            if (TopLevel)
            {
                hWndOwner = (HWND)PInvokeCore.GetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT);
            }

            desktop = !hWndOwner.IsNull ? Screen.FromHandle(hWndOwner) : Screen.FromPoint(MousePosition);
        }

        Rectangle screenRect = desktop.WorkingArea;
        p.X = Math.Max(screenRect.X, screenRect.X + (screenRect.Width - Width) / 2);
        p.Y = Math.Max(screenRect.Y, screenRect.Y + (screenRect.Height - Height) / 2);
        Location = p;
    }

    /// <summary>
    ///  Invalidates the merged menu, forcing the menu to be recreated if
    ///  needed again.
    /// </summary>
    private void InvalidateMergedMenu() => ParentForm?.UpdateMenuHandles();

    /// <summary>
    ///  Arranges the Multiple Document Interface
    ///  (MDI) child forms according to value.
    /// </summary>
    public void LayoutMdi(MdiLayout value)
    {
        _ctlClient?.LayoutMdi(value);
    }

    /// <summary>
    ///  The activate event is fired when the form is activated.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnActivated(EventArgs e)
    {
        ((EventHandler?)Events[s_activatedEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  Override of AutoScaleModeChange method from ContainerControl. We use this to keep our
    ///  own AutoScale property in sync.
    /// </summary>
    private protected override void OnAutoScaleModeChanged()
    {
        base.OnAutoScaleModeChanged();
        if (_formStateEx[s_formStateExSettingAutoScale] != 1)
        {
            // Obsolete code required here for backwards compat
#pragma warning disable CS0618 // Type or member is obsolete
            AutoScale = false;
#pragma warning restore CS0618
        }
    }

    protected override void OnBackgroundImageChanged(EventArgs e)
    {
        base.OnBackgroundImageChanged(e);
        if (IsMdiContainer)
        {
            MdiClient.BackgroundImage = BackgroundImage;
            // requires explicit invalidate to update the image.
            MdiClient.Invalidate();
        }
    }

    protected override void OnBackgroundImageLayoutChanged(EventArgs e)
    {
        base.OnBackgroundImageLayoutChanged(e);
        if (IsMdiContainer)
        {
            MdiClient.BackgroundImageLayout = BackgroundImageLayout;
            // requires explicit invalidate to update the imageLayout.
            MdiClient.Invalidate();
        }
    }

    /// <summary>
    ///  The Closing event is fired when the form is closed.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete(
        Obsoletions.FormOnClosingClosedMessage,
        error: false,
        DiagnosticId = Obsoletions.FormOnClosingClosedDiagnosticId,
        UrlFormat = Obsoletions.SharedUrlFormat)]
    protected virtual void OnClosing(CancelEventArgs e)
    {
        ((CancelEventHandler?)Events[s_closingEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  The Closed event is fired when the form is closed.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete(
        Obsoletions.FormOnClosingClosedMessage,
        error: false,
        DiagnosticId = Obsoletions.FormOnClosingClosedDiagnosticId,
        UrlFormat = Obsoletions.SharedUrlFormat)]
    protected virtual void OnClosed(EventArgs e)
    {
        ((EventHandler?)Events[s_closedEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  The Closing event is fired before the form is closed.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnFormClosing(FormClosingEventArgs e)
    {
        ((FormClosingEventHandler?)Events[s_formClosingEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  The Closed event is fired when the form is closed.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnFormClosed(FormClosedEventArgs e)
    {
        // Remove the form from Application.OpenForms (nothing happens if isn't present)
        Application.OpenForms.Remove(this);

        try
        {
            ((FormClosedEventHandler?)Events[s_formClosedEvent])?.Invoke(this, e);

            // This effectively ends an `await form.ShowAsync();` call.
            _nonModalFormCompletion?.TrySetResult();
        }
        catch (Exception ex)
        {
            if (_nonModalFormCompletion is not null)
            {
                _nonModalFormCompletion.TrySetException(ex);
            }
            else
            {
                throw;
            }
        }
    }

    /// <summary>
    ///  Raises the CreateControl event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnCreateControl()
    {
        CalledCreateControl = true;
        base.OnCreateControl();

        if (CalledMakeVisible && !CalledOnLoad)
        {
            CalledOnLoad = true;
            OnLoad(EventArgs.Empty);
        }
    }

    /// <summary>
    ///  Raises the Deactivate event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnDeactivate(EventArgs e)
    {
        ((EventHandler?)Events[s_deactivateEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  Raises the EnabledChanged event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnEnabledChanged(EventArgs e)
    {
        base.OnEnabledChanged(e);
        if (!DesignMode && Enabled && Active)
        {
            // Make sure we activate the active control.
            Control? activeControl = ActiveControl;

            if (activeControl is null)
            {
                SelectNextControl(this, true, true, true, true);
            }
            else
            {
                FocusActiveControlInternal();
            }
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected internal override void OnEnter(EventArgs e)
    {
        base.OnEnter(e);

        // Enter events are not raised on mdi child form controls on form Enabled.
        if (IsMdiChild)
        {
            UpdateFocusedControl();
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnFontChanged(EventArgs e)
    {
        if (DesignMode)
        {
            UpdateAutoScaleBaseSize();
        }

        base.OnFontChanged(e);
    }

    protected override void OnGotFocus(EventArgs e)
    {
        base.OnGotFocus(e);

        // Raise the UIA focus event for an empty form (form with no ActiveControl),
        // when it gets focus to a screen reader can focus on it and announce its title text.
        // If the form has any control, a screen reader will focus on it instead.
        if (Focused && IsAccessibilityObjectCreated && ActiveControl is null)
        {
            AccessibilityObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId);
        }
    }

    /// <summary>
    ///  Inheriting classes should override this method to find out when the
    ///  handle has been created.
    ///  Call base.OnHandleCreated first.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnHandleCreated(EventArgs e)
    {
        _formStateEx[s_formStateExUseMdiChildProc] = (IsMdiChild && Visible) ? 1 : 0;
        base.OnHandleCreated(e);

        UpdateLayered();

        // Normally, we update the form's title properties here after the handle is created.
        // However, during handle recreation (ReCreateHandle), this method is invoked as part
        // of the base class chain—before the new handle is fully established and before
        // other required updates are complete. In that scenario, SetFormTitleProperties
        // must be called *after* all recreation steps have finished, which is handled by a
        // dedicated call at the end of ReCreateHandle. Therefore, to avoid updating the
        // title properties too early or twice, we skip the call here if we are in the
        // middle of handle recreation.
        if (!_inRecreateHandle)
        {
            SetFormTitleProperties();
        }

        if (FormScreenCaptureMode != ScreenCaptureMode.Allow)
        {
            SetScreenCaptureModeInternal(FormScreenCaptureMode);
        }

#if NET11_0_OR_GREATER
        CloakForDeferredAppearanceIfNeeded();
#endif
    }

    /// <summary>
    ///  Inheriting classes should override this method to find out when the
    ///  handle is about to be destroyed.
    ///  Call base.OnHandleDestroyed last.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnHandleDestroyed(EventArgs e)
    {
#if NET11_0_OR_GREATER
        ClearDeferredAppearanceCloakState();
#endif
        base.OnHandleDestroyed(e);
        _formStateEx[s_formStateExUseMdiChildProc] = 0;

        // Remove the form from OpenForms collection only if we're not recreating the handle of this form
        // (e.g., when ShowInTaskbar or RightToLeft properties get changed).
        if (!_inRecreateHandle)
        {
            Application.OpenForms.Remove(this);
        }
    }

    /// <summary>
    ///  Handles the event that a helpButton is clicked
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnHelpButtonClicked(CancelEventArgs e)
    {
        ((CancelEventHandler?)Events[s_helpButtonChangedEvent])?.Invoke(this, e);
    }

    protected override void OnLayout(LayoutEventArgs levent)
    {
        // Typically forms are either top level or parented to an MDIClient area.
        // In either case, forms a responsible for managing their own size.
        if (AutoSize)
        {
            // If AutoSized, set the Form to the maximum of its preferredSize or the user
            // specified size.
            Size prefSize = PreferredSize;
            _minAutoSize = prefSize;

            // This used to use "GetSpecifiedBounds" - but it was not updated when we're in the middle of
            // a modal resizing loop (WM_WINDOWPOSCHANGED).
            Size adjustedSize = AutoSizeMode == AutoSizeMode.GrowAndShrink ? prefSize : LayoutUtils.UnionSizes(prefSize, Size);

            if (this is IArrangedElement form)
            {
                form.SetBounds(new Rectangle(Left, Top, adjustedSize.Width, adjustedSize.Height), BoundsSpecified.None);
            }
        }

        base.OnLayout(levent);
    }

    /// <summary>
    ///  The Load event is fired before the form becomes visible for the first time.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnLoad(EventArgs e)
    {
        // First - add the form to Application.OpenForms
        Application.OpenForms.Add(this);
        if (Application.UseWaitCursor)
        {
            UseWaitCursor = true;
        }

        // This will apply AutoScaling to the form just before the form becomes visible.
        if (_formState[s_formStateAutoScaling] == 1 && !DesignMode)
        {
            // Turn off autoscaling so we don't do this on every handle creation.
            _formState[s_formStateAutoScaling] = 0;

            // Obsolete code required here for backwards compat.
#pragma warning disable CS0618 // Type or member is obsolete
            ApplyAutoScaling();
#pragma warning restore CS0618
        }

        // Also, at this time we can now locate the form on the correct area of the screen.
        // We must do this after applying any autoscaling.
        if (GetState(States.Modal))
        {
            AdjustFormPosition();
        }

        // There is no good way to explain this event except to say
        // that it's just another name for OnControlCreated.
        EventHandler? handler = (EventHandler?)Events[s_loadEvent];
        if (handler is not null)
        {
            string text = Text;

            handler(this, e);

            // It seems that if you set a window style during the onload
            // event, we have a problem initially painting the window.
            // So in the event that the user has set the on load event
            // in their application, we should go ahead and invalidate
            // the controls in their collection so that we paint properly.
            // This seems to manifest itself in changes to the window caption,
            // and changes to the control box and help.

            foreach (Control c in Controls)
            {
                c.Invalidate();
            }
        }

        if (IsHandleCreated)
        {
            // Finally fire the new OnShown(unless the form has already been closed).
            BeginInvoke(new MethodInvoker(CallShownEvent));
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnMaximizedBoundsChanged(EventArgs e)
    {
        if (Events[s_maximizeBoundsChangedEvent] is EventHandler eh)
        {
            eh(this, e);
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnMaximumSizeChanged(EventArgs e)
    {
        if (Events[s_maximumSizeChangedEvent] is EventHandler eh)
        {
            eh(this, e);
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnMinimumSizeChanged(EventArgs e)
    {
        if (Events[s_minimumSizeChangedEvent] is EventHandler eh)
        {
            eh(this, e);
        }
    }

    /// <summary>
    ///  Raises the <see cref="InputLanguageChanged"/>
    ///  event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnInputLanguageChanged(InputLanguageChangedEventArgs e)
    {
        ((InputLanguageChangedEventHandler?)Events[s_inputLanguageChangeEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  Raises the <see cref="InputLanguageChanging"/>
    ///  event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnInputLanguageChanging(InputLanguageChangingEventArgs e)
    {
        ((InputLanguageChangingEventHandler?)Events[s_inputLanguageChangeRequestEvent])?.Invoke(this, e);
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnVisibleChanged(EventArgs e)
    {
        UpdateRenderSizeGrip();
        MdiParentInternal?.UpdateMdiWindowListStrip();

        base.OnVisibleChanged(e);

        // Windows forms have to behave like dialog boxes sometimes. If the
        // user has specified that the mouse should snap to the
        // Accept button using the Mouse applet in the control panel,
        // we have to respect that setting each time our form is made visible.
        bool data = false;
        if (IsHandleCreated
            && Visible
            && (AcceptButton is not null)
            && PInvokeCore.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETSNAPTODEFBUTTON, ref data)
            && data)
        {
            Control button = (Control)AcceptButton;
            Point pointToSnap = new(button.Left + button.Width / 2, button.Top + button.Height / 2);
            PInvoke.ClientToScreen(this, ref pointToSnap);
            if (!button.IsWindowObscured)
            {
                Cursor.Position = pointToSnap;
            }
        }
    }

    /// <summary>
    ///  Raises the <see cref="MdiChildActivate"/> event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnMdiChildActivate(EventArgs e)
    {
        UpdateMenuHandles();
        UpdateToolStrip();
        ((EventHandler?)Events[s_mdiChildActivateEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  Raises the <see cref="MenuStart"/> event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnMenuStart(EventArgs e)
    {
        EventHandler? handler = (EventHandler?)Events[s_menuStartEvent];
        handler?.Invoke(this, e);
    }

    /// <summary>
    ///  Raises the MenuComplete event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnMenuComplete(EventArgs e)
    {
        ((EventHandler?)Events[s_menuCompleteEvent])?.Invoke(this, e);
    }

    /// <summary>
    ///  Raises the Paint event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        if (_formState[s_formStateRenderSizeGrip] != 0)
        {
            Size size = ClientSize;
            if (Application.RenderWithVisualStyles)
            {
                _sizeGripRenderer ??= new VisualStyleRenderer(VisualStyleElement.Status.Gripper.Normal);

                using DeviceContextHdcScope hdc = new(e);
                _sizeGripRenderer.DrawBackground(
                    hdc,
                    new Rectangle(size.Width - SizeGripSize, size.Height - SizeGripSize, SizeGripSize, SizeGripSize));
            }
            else
            {
                ControlPaint.DrawSizeGrip(
                    e,
                    BackColor,
                    size.Width - SizeGripSize,
                    size.Height - SizeGripSize,
                    SizeGripSize,
                    SizeGripSize);
            }
        }

        if (IsMdiContainer)
        {
            e.GraphicsInternal.FillRectangle(SystemBrushes.AppWorkspace, ClientRectangle);
        }
    }

    /// <summary>
    ///  Raises the Resize event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnResize(EventArgs e)
    {
        if (!_processingDpiChanged)
        {
            _dpiFormSizes?.Clear();
        }

        base.OnResize(e);
        if (_formState[s_formStateRenderSizeGrip] != 0)
        {
            Invalidate();
        }
    }

    /// <summary>
    ///  Raises the DpiChanged event.
    /// </summary>
    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    protected virtual void OnDpiChanged(DpiChangedEventArgs e)
    {
        if (e.DeviceDpiNew != e.DeviceDpiOld)
        {
            CommonProperties.xClearAllPreferredSizeCaches(this);
            OriginalDeviceDpiInternal = e.DeviceDpiOld;

            // call any additional handlers
            ((DpiChangedEventHandler?)Events[s_dpiChangedEvent])?.Invoke(this, e);

            if (e.Cancel)
            {
                return;
            }

            try
            {
                // Cache Form's size for the current and new DPI if not already done. We do this only
                // for AutoScaleMode is Font. In other modes, Windows OS will compute Form's size.
                if (AutoScaleMode == AutoScaleMode.Font)
                {
                    _dpiFormSizes ??= [];

                    if (!_dpiFormSizes.ContainsKey(e.DeviceDpiNew))
                    {
                        _dpiFormSizes.Add(e.DeviceDpiNew, new Size(e.SuggestedRectangle.Width, e.SuggestedRectangle.Height));
                    }

                    // Store size of the Form for current DPI.
                    if (!_dpiFormSizes.ContainsKey(e.DeviceDpiOld))
                    {
                        _dpiFormSizes.Add(e.DeviceDpiOld, Size);
                    }

                    // Prevent clearing Form's size cache while applying bounds from DPI change.
                    // Any other events that cause Form's size change should clear the cache.
                    _processingDpiChanged = true;
                }

                UpdateWindowIcon(redrawFrame: true, dpi: e.DeviceDpiNew);
                ScaleContainerForDpi(e.DeviceDpiNew, e.DeviceDpiOld, e.SuggestedRectangle);
            }
            finally
            {
                _processingDpiChanged = false;
            }
        }
    }

    /// <summary>
    ///  Occurs when the Dpi resolution of the screen this top level window is displayed on changes,
    ///  either when the top level window is moved between monitors or when the OS settings are changed.
    /// </summary>
    [SRCategory(nameof(SR.CatLayout))]
    [SRDescription(nameof(SR.FormOnDpiChangedDescr))]
    public event DpiChangedEventHandler? DpiChanged
    {
        add => Events.AddHandler(s_dpiChangedEvent, value);
        remove => Events.RemoveHandler(s_dpiChangedEvent, value);
    }

    /// <summary>
    ///  Handles the WM_DPICHANGED message
    /// </summary>
    private void WmDpiChanged(ref Message m)
    {
        DefWndProc(ref m);

        DpiChangedEventArgs e = new(DeviceDpiInternal, m);
        DeviceDpiInternal = e.DeviceDpiNew;

        OnDpiChanged(e);
    }

    /// <summary>
    ///  Allows derived form to handle WM_GETDPISCALEDSIZE message.
    /// </summary>
    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual bool OnGetDpiScaledSize(int deviceDpiOld, int deviceDpiNew, ref Size desiredSize)
    {
        // Compute font for the current DPI and cache it. DPI specific fonts cache is available only in PermonitorV2 mode applications.
        Font fontForDpi = GetScaledFont(Font, deviceDpiNew, deviceDpiOld);

        // If AutoScaleMode=AutoScaleMode.Dpi then we continue with the linear size we get from Windows for the top-level window.
        if (AutoScaleMode == AutoScaleMode.Dpi)
        {
            return false;
        }

        // Calculate AutoscaleFactor for AutoScaleMode.Font. We will be using this factor to scale child controls
        // and use same factor to compute desired size for top-level windows for the current DPI.
        // This desired size is then used to notify Windows that we need non-linear size for top-level window.
        FontHandleWrapper fontwrapper = new(fontForDpi);
        SizeF currentAutoScaleDimensions = GetCurrentAutoScaleDimensions(fontwrapper.Handle);
        SizeF autoScaleFactor = GetCurrentAutoScaleFactor(currentAutoScaleDimensions, AutoScaleDimensions);

        desiredSize.Width = (int)(Size.Width * autoScaleFactor.Width);
        desiredSize.Height = (int)(Size.Height * autoScaleFactor.Height);
        Debug.WriteLine($"AutoScaleFactor computed for new DPI = {autoScaleFactor.Width} - {autoScaleFactor.Height}");

        // Notify Windows that the top-level window size should be based on AutoScaleMode value.
        return true;
    }

    /// <summary>
    ///  Handles the WM_GETDPISCALEDSIZE message, this is a chance for the application to
    ///  scale window size non-lineary. If this message is not processed, the size is scaled linearly by Windows.
    ///  This message is sent to top level windows before WM_DPICHANGED.
    ///  If the application responds to this message, the resulting size will be the candidate rectangle
    ///  sent to WM_DPICHANGED. The WPARAM contains a Dpi value. The size needs to be computed if
    ///  the window were to switch to this Dpi. LPARAM is used to store the Size desired for top-level window.
    ///  A return value of zero indicates that the app does not want any special behavior and the candidate rectangle
    ///  will be computed linearly.
    /// </summary>
    private unsafe void WmGetDpiScaledSize(ref Message m)
    {
        DefWndProc(ref m);

        Size desiredSize = default;
        if ((_dpiFormSizes is not null && _dpiFormSizes.TryGetValue(m.WParamInternal.LOWORD, out desiredSize))
            || OnGetDpiScaledSize(DeviceDpiInternal, m.WParamInternal.LOWORD, ref desiredSize))
        {
            SIZE* size = (SIZE*)m.LParamInternal;
            size->cx = desiredSize.Width;
            size->cy = desiredSize.Height;
            m.ResultInternal = (LRESULT)1;
            return;
        }

        m.ResultInternal = (LRESULT)0;
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnRightToLeftLayoutChanged(EventArgs e)
    {
        if (GetAnyDisposingInHierarchy())
        {
            return;
        }

        if (RightToLeft == RightToLeft.Yes)
        {
            RecreateHandle();
        }

        if (Events[s_rightToLeftLayoutChangedEvent] is EventHandler eh)
        {
            eh(this, e);
        }

        // Want to do this after we fire the event.
        if (RightToLeft == RightToLeft.Yes)
        {
            foreach (Control c in Controls)
            {
                c.RecreateHandleCore();
            }
        }
    }

    /// <summary>
    ///  This event fires whenever the form is first shown.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnShown(EventArgs e)
    {
        ((EventHandler?)Events[s_shownEvent])?.Invoke(this, e);
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);

        // If there is no control box, there should only be a title bar if text != "".
        int newTextEmpty = Text.Length == 0 ? 1 : 0;
        if (!ControlBox && _formState[s_formStateIsTextEmpty] != newTextEmpty)
        {
            RecreateHandle();
        }

        _formState[s_formStateIsTextEmpty] = newTextEmpty;
    }

    /// <summary>
    ///  Simulates a InputLanguageChanged event. Used by Control to forward events
    ///  to the parent form.
    /// </summary>
    internal void PerformOnInputLanguageChanged(InputLanguageChangedEventArgs iplevent)
    {
        OnInputLanguageChanged(iplevent);
    }

    /// <summary>
    ///  Simulates a InputLanguageChanging event. Used by Control to forward
    ///  events to the parent form.
    /// </summary>
    internal void PerformOnInputLanguageChanging(InputLanguageChangingEventArgs iplcevent)
    {
        OnInputLanguageChanging(iplcevent);
    }

    /// <summary>
    ///  Processes a command key. Overrides Control.processCmdKey() to provide
    ///  additional handling of main menu command keys and Mdi accelerators.
    /// </summary>
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (base.ProcessCmdKey(ref msg, keyData))
        {
            return true;
        }

        // Process MDI accelerator keys.
        bool retValue = false;
        MSG win32Message = msg.ToMSG();
        if (_ctlClient is not null && _ctlClient.Handle != IntPtr.Zero &&
            PInvoke.TranslateMDISysAccel(_ctlClient.HWND, win32Message))
        {
            retValue = true;
        }

        msg.MsgInternal = (MessageId)win32Message.message;
        msg.WParamInternal = win32Message.wParam;
        msg.LParamInternal = win32Message.lParam;
        msg.HWnd = win32Message.hwnd;

        return retValue;
    }

    /// <summary>
    ///  Processes a dialog key. Overrides Control.processDialogKey(). This
    ///  method implements handling of the RETURN, and ESCAPE keys in dialogs.
    ///  The method performs no processing on keys that include the ALT or
    ///  CONTROL modifiers.
    /// </summary>
    protected override bool ProcessDialogKey(Keys keyData)
    {
        if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None)
        {
            Keys keyCode = keyData & Keys.KeyCode;

            switch (keyCode)
            {
                case Keys.Return:
                    if (Properties.TryGetValue(s_propDefaultButton, out IButtonControl? button))
                    {
                        // PerformClick now checks for validationcancelled.
                        if (button is Control)
                        {
                            button.PerformClick();
                        }

                        return true;
                    }

                    break;
                case Keys.Escape:
                    if (Properties.TryGetValue(s_propCancelButton, out button))
                    {
                        // In order to keep the behavior in sync with native
                        // and MFC dialogs, we want to not give the cancel button
                        // the focus on Escape. If we do, we end up with giving it
                        // the focus when we reshow the dialog.
                        //
                        // if (button is Control) {
                        //    ((Control)button).Focus();
                        // }
                        button.PerformClick();
                        return true;
                    }

                    break;
            }
        }

        return base.ProcessDialogKey(keyData);
    }

    /// <summary>
    ///  Processes a dialog character For a MdiChild.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override bool ProcessDialogChar(char charCode)
    {
        // If we're the top-level form or control, we need to do the mnemonic handling.
        if (IsMdiChild && charCode != ' ')
        {
            if (ProcessMnemonic(charCode))
            {
                return true;
            }

            // ContainerControl calls ProcessMnemonic starting from the active MdiChild form (this)
            // so let's flag it as processed.
            _formStateEx[s_formStateExMnemonicProcessed] = 1;
            try
            {
                return base.ProcessDialogChar(charCode);
            }
            finally
            {
                _formStateEx[s_formStateExMnemonicProcessed] = 0;
            }
        }

        // Non-MdiChild form, just pass the call to ContainerControl.
        return base.ProcessDialogChar(charCode);
    }

    protected override bool ProcessKeyPreview(ref Message m)
    {
        if (_formState[s_formStateKeyPreview] != 0 && ProcessKeyEventArgs(ref m))
        {
            return true;
        }

        return base.ProcessKeyPreview(ref m);
    }

    protected override bool ProcessTabKey(bool forward)
    {
        if (SelectNextControl(ActiveControl, forward, true, true, true))
        {
            return true;
        }

        // I've added a special case for UserControls because they shouldn't cycle back to the
        // beginning if they don't have a parent form, such as when they're on an ActiveXBridge.
        if (IsMdiChild || ParentForm is null)
        {
            bool selected = SelectNextControl(null, forward, true, true, false);

            if (selected)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    ///  Raises the FormClosed event for this form when Application.Exit is called.
    /// </summary>
    internal void RaiseFormClosedOnAppExit()
    {
        if (!Modal)
        {
            // Fire FormClosed event on all the forms that this form owns and are not in the Application.OpenForms collection
            // This is to be consistent with what WmClose does.
            if (Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms))
            {
                FormClosedEventArgs fce = new(CloseReason.FormOwnerClosing);
                for (int i = ownedForms.Count - 1; i >= 0; i--)
                {
                    if (!Application.OpenForms.Contains(ownedForms[i]))
                    {
                        ownedForms[i].OnFormClosed(fce);
                    }
                }
            }
        }

        OnFormClosed(new FormClosedEventArgs(CloseReason.ApplicationExitCall));
    }

    /// <summary>
    ///  Raises the FormClosing event for this form when Application.Exit is called.
    ///  Returns e.Cancel returned by the event handler.
    /// </summary>
    internal bool RaiseFormClosingOnAppExit()
    {
        FormClosingEventArgs e = new(CloseReason.ApplicationExitCall, false);
        // e.Cancel = !Validate(true);    This would cause a breaking change between v2.0 and v1.0/v1.1 in case validation fails.
        if (!Modal)
        {
            // Fire FormClosing event on all the forms that this form owns and are not in the Application.OpenForms collection
            // This is to be consistent with what WmClose does.
            if (Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms))
            {
                FormClosingEventArgs fce = new(CloseReason.FormOwnerClosing, false);
                for (int i = ownedForms.Count - 1; i >= 0; i--)
                {
                    if (ownedForms[i] is not null && !Application.OpenForms.Contains(ownedForms[i]))
                    {
                        ownedForms[i].OnFormClosing(fce);
                        if (fce.Cancel)
                        {
                            e.Cancel = true;
                            break;
                        }
                    }
                }
            }
        }

        OnFormClosing(e);
        return e.Cancel;
    }

    internal override unsafe void RecreateHandleCore()
    {
        WINDOWPLACEMENT wp = default;

        FormStartPosition oldStartPosition = FormStartPosition.Manual;

        if (!IsMdiChild && (WindowState == FormWindowState.Minimized || WindowState == FormWindowState.Maximized))
        {
            wp.length = (uint)sizeof(WINDOWPLACEMENT);
            bool result = PInvoke.GetWindowPlacement(HWND, &wp);
            Debug.Assert(result);
        }

        if (StartPosition != FormStartPosition.Manual)
        {
            oldStartPosition = StartPosition;

            // Set the startup position to manual, to stop the form from
            // changing position each time RecreateHandle() is called.
            StartPosition = FormStartPosition.Manual;
        }

        EnumThreadWindowsCallback? callback = null;
        if (IsHandleCreated)
        {
            // First put all the owned windows into a list
            callback = new EnumThreadWindowsCallback(HWND);
            PInvokeCore.EnumCurrentThreadWindows(callback.Callback);

            // Reset the owner of the windows in the list
            callback.ResetOwners();
        }

        _inRecreateHandle = true;
        try
        {
            base.RecreateHandleCore();
        }
        finally
        {
            _inRecreateHandle = false;
        }

        // Set the owner of the windows in the list back to the new Form's handle
        callback?.SetOwners(Handle);

        if (oldStartPosition != FormStartPosition.Manual)
        {
            StartPosition = oldStartPosition;
        }

        if (wp.length > 0)
        {
            bool result = PInvoke.SetWindowPlacement(HWND, &wp);
            Debug.Assert(result);
        }

        SetFormTitleProperties();

        if (FormScreenCaptureMode != ScreenCaptureMode.Allow)
        {
            SetScreenCaptureModeInternal(FormScreenCaptureMode);
        }

        GC.KeepAlive(this);
    }

    private void SetFormTitleProperties()
    {
        if (TopLevel && IsHandleCreated)
        {
            if (Properties.TryGetValue(s_propFormBorderColor, out Color? formBorderColor))
            {
                SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, formBorderColor.Value);
            }

            if (Properties.TryGetValue(s_propFormCaptionBackColor, out Color? formCaptionBackColor))
            {
                SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR, formCaptionBackColor.Value);
            }

            if (Properties.TryGetValue(s_propFormCaptionTextColor, out Color? formCaptionTextColor))
            {
                SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_TEXT_COLOR, formCaptionTextColor.Value);
            }

            if (Properties.TryGetValue(s_propFormCornerPreference, out FormCornerPreference? cornerPreference))
            {
                SetFormCornerPreferenceInternal(cornerPreference.Value);
            }
        }
    }

    /// <summary>
    ///  Removes a form from the list of owned forms. Also sets the owner of the
    ///  removed form to null.
    /// </summary>
    public void RemoveOwnedForm(Form? ownedForm)
    {
        if (ownedForm is null)
        {
            return;
        }

        if (ownedForm.OwnerInternal is not null)
        {
            // NOTE: this will call RemoveOwnedForm again, bypassing if.
            ownedForm.Owner = null;
            return;
        }

        if (Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms))
        {
            ownedForms.Remove(ownedForm);
        }
    }

    /// <summary>
    ///  Resets the form's icon the default value.
    /// </summary>
    private void ResetIcon()
    {
        _icon = null;
        _smallIcon?.Dispose();
        _smallIcon = null;

        _formState[s_formStateIconSet] = 0;
        UpdateWindowIcon(true);
    }

    /// <summary>
    ///  Resets the TransparencyKey to Color.Empty.
    /// </summary>
    private void ResetTransparencyKey() => TransparencyKey = Color.Empty;

    /// <summary>
    ///  Occurs when the form enters the sizing modal loop
    /// </summary>
    [SRCategory(nameof(SR.CatAction))]
    [SRDescription(nameof(SR.FormOnResizeBeginDescr))]
    public event EventHandler? ResizeBegin
    {
        add => Events.AddHandler(s_resizeBeginEvent, value);
        remove => Events.RemoveHandler(s_resizeBeginEvent, value);
    }

    /// <summary>
    ///  Occurs when the control exits the sizing modal loop.
    /// </summary>
    [SRCategory(nameof(SR.CatAction))]
    [SRDescription(nameof(SR.FormOnResizeEndDescr))]
    public event EventHandler? ResizeEnd
    {
        add => Events.AddHandler(s_resizeEndEvent, value);
        remove => Events.RemoveHandler(s_resizeEndEvent, value);
    }

    /// <summary>
    ///  This is called when we have just been restored after being
    ///  minimized. At this point we resume our layout.
    /// </summary>
    private void ResumeLayoutFromMinimize()
    {
        // If we're currently minimized, resume our layout because we are
        // about to snap out of it.
        if (_formState[s_formStateWindowState] == (int)FormWindowState.Minimized)
        {
            ResumeLayout();
        }
    }

    // If someone set Location or Size while the form was maximized or minimized,
    // we had to cache the new value away until after the form was restored to normal size.
    // This function is called after WindowState changes, and handles the above logic.
    // In the normal case where no one sets Location or Size programmatically,
    // Windows does the restoring for us.
    //
    private void RestoreWindowBoundsIfNecessary()
    {
        if (WindowState == FormWindowState.Normal)
        {
            Size restoredSize = _restoredWindowBounds.Size;
            if ((_restoredWindowBoundsSpecified & BoundsSpecified.Size) != 0)
            {
                restoredSize = SizeFromClientSizeInternal(restoredSize);
            }

            SetBounds(_restoredWindowBounds.X, _restoredWindowBounds.Y,
                _formStateEx[s_formStateExWindowBoundsWidthIsClientSize] == 1 ? restoredSize.Width : _restoredWindowBounds.Width,
                _formStateEx[s_formStateExWindowBoundsHeightIsClientSize] == 1 ? restoredSize.Height : _restoredWindowBounds.Height,
                      _restoredWindowBoundsSpecified);
            _restoredWindowBoundsSpecified = 0;
            _restoredWindowBounds = new Rectangle(-1, -1, -1, -1);
            _formStateEx[s_formStateExWindowBoundsHeightIsClientSize] = 0;
            _formStateEx[s_formStateExWindowBoundsWidthIsClientSize] = 0;
        }
    }

    /// <summary>
    ///  Decrements updateMenuHandleSuspendCount. If updateMenuHandleSuspendCount
    ///  becomes zero and updateMenuHandlesDeferred is true, updateMenuHandles
    ///  is called.
    /// </summary>
    private void ResumeUpdateMenuHandles()
    {
        int suspendCount = _formStateEx[s_formStateExUpdateMenuHandlesSuspendCount];
        if (suspendCount <= 0)
        {
            throw new InvalidOperationException(SR.TooManyResumeUpdateMenuHandles);
        }

        _formStateEx[s_formStateExUpdateMenuHandlesSuspendCount] = --suspendCount;
        if (suspendCount == 0 && _formStateEx[s_formStateExUpdateMenuHandlesDeferred] != 0)
        {
            UpdateMenuHandles();
        }
    }

    /// <summary>
    ///  Selects this form, and optionally selects the next/previous control.
    /// </summary>
    protected override void Select(bool directed, bool forward)
    {
        if (directed)
        {
            SelectNextControl(null, forward, true, true, false);
        }

        if (TopLevel)
        {
            PInvoke.SetActiveWindow(this);
        }
        else if (IsMdiChild)
        {
            PInvoke.SetActiveWindow(MdiParentInternal);
            if (MdiParentInternal.MdiClient is not null)
            {
                PInvokeCore.SendMessage(MdiParentInternal.MdiClient, PInvokeCore.WM_MDIACTIVATE, (WPARAM)HWND);
            }
        }
        else
        {
            Form? form = ParentForm;
            form?.ActiveControl = this;
        }
    }

    /// <summary>
    ///  Base function that performs scaling of the form.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    protected override void ScaleCore(float x, float y)
    {
        using SuspendLayoutScope scope = new(this);

        // Get size values in advance to prevent one change from affecting another.
        Size clientSize = ClientSize;
        ScaleMinMaxSize(x, y);
        ScaleDockPadding(x, y);
        if (WindowState == FormWindowState.Normal)
        {
            ClientSize = ScaleSize(clientSize, x, y);
        }

        foreach (Control control in Controls)
        {
#pragma warning disable CS0618 // Type or member is obsolete - compat
            control?.Scale(x, y);
#pragma warning restore CS0618
        }
    }

    /// <summary>
    ///  Scales Form's properties Min and Max size with the scale factor provided.
    /// </summary>
    /// <param name="xScaleFactor">The scale factor to be applied on width of the property being scaled.</param>
    /// <param name="yScaleFactor">The scale factor to be applied on height of the property being scaled.</param>
    /// <param name="updateContainerSize">
    ///  <see langword="true"/> to resize of the Form along with properties being scaled;
    ///  otherwise, <see langword="false"/>.
    /// </param>
    protected override void ScaleMinMaxSize(float xScaleFactor, float yScaleFactor, bool updateContainerSize = true)
    {
        base.ScaleMinMaxSize(xScaleFactor, yScaleFactor, updateContainerSize);
        if (WindowState == FormWindowState.Normal)
        {
            Size minSize = MinimumSize;
            Size maxSize = MaximumSize;
            if (!minSize.IsEmpty)
            {
                UpdateMinimumSize(ScaleSize(minSize, xScaleFactor, yScaleFactor), updateContainerSize);
            }

            if (!maxSize.IsEmpty)
            {
                UpdateMaximumSize(ScaleSize(maxSize, xScaleFactor, yScaleFactor), updateContainerSize);
            }
        }
    }

    /// <summary>
    ///  For overrides this to calculate scaled bounds based on the restored rect
    ///  if it is maximized or minimized.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override Rectangle GetScaledBounds(Rectangle bounds, SizeF factor, BoundsSpecified specified)
    {
        // If we're maximized or minimized, scale using the restored bounds, not
        // the real bounds.
        if (WindowState != FormWindowState.Normal)
        {
            bounds = RestoreBounds;
        }

        return base.GetScaledBounds(bounds, factor, specified);
    }

    /// <summary>
    ///  Scale this form. Form overrides this to enforce a maximum / minimum size.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
    {
        _formStateEx[s_formStateExInScale] = 1;
        try
        {
            // don't scale the location of MDI child forms
            if (MdiParentInternal is not null)
            {
                specified &= ~BoundsSpecified.Location;
            }

            base.ScaleControl(factor, specified);
        }
        finally
        {
            _formStateEx[s_formStateExInScale] = 0;
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
    {
        if (WindowState != FormWindowState.Normal)
        {
            // See RestoreWindowBoundsIfNecessary for an explanation of this
            // Only restore position when x,y is not -1,-1
            if (x != -1 || y != -1)
            {
                _restoredWindowBoundsSpecified |= (specified & (BoundsSpecified.X | BoundsSpecified.Y));
            }

            _restoredWindowBoundsSpecified |= (specified & (BoundsSpecified.Width | BoundsSpecified.Height));

            if ((specified & BoundsSpecified.X) != 0)
            {
                _restoredWindowBounds.X = x;
            }

            if ((specified & BoundsSpecified.Y) != 0)
            {
                _restoredWindowBounds.Y = y;
            }

            if ((specified & BoundsSpecified.Width) != 0)
            {
                _restoredWindowBounds.Width = width;
                _formStateEx[s_formStateExWindowBoundsWidthIsClientSize] = 0;
            }

            if ((specified & BoundsSpecified.Height) != 0)
            {
                _restoredWindowBounds.Height = height;
                _formStateEx[s_formStateExWindowBoundsHeightIsClientSize] = 0;
            }
        }

        // Update RestoreBounds
        if ((specified & BoundsSpecified.X) != 0)
        {
            _restoreBounds.X = x;
        }

        if ((specified & BoundsSpecified.Y) != 0)
        {
            _restoreBounds.Y = y;
        }

        if ((specified & BoundsSpecified.Width) != 0 || _restoreBounds.Width == -1)
        {
            _restoreBounds.Width = width;
        }

        if ((specified & BoundsSpecified.Height) != 0 || _restoreBounds.Height == -1)
        {
            _restoreBounds.Height = height;
        }

        // Enforce maximum size...
        if (WindowState == FormWindowState.Normal && (Height != height || Width != width))
        {
            Size max = SystemInformation.MaxWindowTrackSize;
            if (height > max.Height)
            {
                height = max.Height;
            }

            if (width > max.Width)
            {
                width = max.Width;
            }
        }

        // Only enforce the minimum size if the form has a border and is a top
        // level form.
        FormBorderStyle borderStyle = FormBorderStyle;
        if (borderStyle != FormBorderStyle.None
            && borderStyle != FormBorderStyle.FixedToolWindow
            && borderStyle != FormBorderStyle.SizableToolWindow
            && ParentInternal is null)
        {
            Size min = SystemInformation.MinWindowTrackSize;
            if (height < min.Height)
            {
                height = min.Height;
            }

            if (width < min.Width)
            {
                width = min.Width;
            }
        }

        base.SetBoundsCore(x, y, width, height, specified);
    }

    /// <summary>
    ///  Sets the defaultButton for the form. The defaultButton is "clicked" when
    ///  the user presses Enter.
    /// </summary>
    private void SetDefaultButton(IButtonControl? button)
    {
        IButtonControl? existing = Properties.GetValueOrDefault<IButtonControl>(s_propDefaultButton);

        if (existing != button)
        {
            existing?.NotifyDefault(false);

            Properties.AddOrRemoveValue(s_propDefaultButton, button);
            button?.NotifyDefault(true);
        }
    }

    /// <summary>
    ///  Sets the clientSize of the form. This will adjust the bounds of the form
    ///  to make the clientSize the requested size.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void SetClientSizeCore(int x, int y)
    {
        bool hadHScroll = HScroll, hadVScroll = VScroll;
        base.SetClientSizeCore(x, y);

        if (IsHandleCreated)
        {
            // Adjust for the scrollbars, if they were introduced by
            // the call to base.SetClientSizeCore
            if (VScroll != hadVScroll)
            {
                if (VScroll)
                {
                    x += SystemInformation.VerticalScrollBarWidth;
                }
            }

            if (HScroll != hadHScroll)
            {
                if (HScroll)
                {
                    y += SystemInformation.HorizontalScrollBarHeight;
                }
            }

            if (x != ClientSize.Width || y != ClientSize.Height)
            {
                base.SetClientSizeCore(x, y);
            }
        }

        _formState[s_formStateSetClientSize] = 1;
    }

    /// <summary>
    ///  Sets the bounds of the form in desktop coordinates.
    /// </summary>
    public void SetDesktopBounds(int x, int y, int width, int height)
    {
        Rectangle workingArea = SystemInformation.WorkingArea;
        SetBounds(x + workingArea.X, y + workingArea.Y, width, height, BoundsSpecified.All);
    }

    /// <summary>
    ///  Sets the location of the form in desktop coordinates.
    /// </summary>
    public void SetDesktopLocation(int x, int y)
    {
        Rectangle workingArea = SystemInformation.WorkingArea;
        Location = new Point(workingArea.X + x, workingArea.Y + y);
    }

    /// <summary>
    ///  Displays the form by setting its <see cref="Control.Visible"/> property to <see langword="true"/>.
    /// </summary>
    /// <param name="owner">
    ///  The optional owner window that implements <see cref="IWin32Window"/>.
    /// </param>
    /// <exception cref="InvalidOperationException">
    ///  <para>Thrown if:</para>
    ///  <list type="bullet">
    ///   <item><description>The form is already visible.</description></item>
    ///   <item><description>The form is disabled.</description></item>
    ///   <item><description>The form is not a top-level form.</description></item>
    ///   <item><description>The form is trying to set itself as its own owner.</description></item>
    ///   <item><description>The operating system is in a non-interactive mode.</description></item>
    ///  </list>
    /// </exception>
    /// <exception cref="ArgumentException">
    ///  <para>Thrown if the owner window is trying to set itself as its own owner.</para>
    /// </exception>
    /// <remarks>
    ///  <para>
    ///   This method makes the form visible by setting the <see cref="Control.Visible"/> property to <see langword="true"/>.
    ///  </para>
    ///  <para>
    ///   If the owner window is provided, it ensures that the owner is topmost and sets the owner for the form.
    ///  </para>
    ///  <para>
    ///   This method also performs several checks to prevent invalid operations, such as trying to display a disabled form,
    ///   attempting to display the form when it is not a top-level window, or setting the form as its own owner.
    ///  </para>
    ///  <para>
    ///   If the operating system is in a non-interactive mode, this method will throw an <see cref="InvalidOperationException"/>.
    ///  </para>
    /// </remarks>
    public void Show(IWin32Window? owner)
    {
        if (owner == this)
        {
            throw new InvalidOperationException(string.Format(SR.OwnsSelfOrOwner, nameof(Show)));
        }

        if (Visible)
        {
            throw new InvalidOperationException(string.Format(SR.ShowDialogOnVisible, nameof(Show)));
        }

        if (!Enabled)
        {
            throw new InvalidOperationException(string.Format(SR.ShowDialogOnDisabled, nameof(Show)));
        }

        if (!TopLevel)
        {
            throw new InvalidOperationException(string.Format(SR.ShowDialogOnNonTopLevel, nameof(Show)));
        }

        if (!SystemInformation.UserInteractive)
        {
            throw new InvalidOperationException(SR.CantShowModalOnNonInteractive);
        }

        if ((owner is not null) && !owner.GetExtendedStyle().HasFlag(WINDOW_EX_STYLE.WS_EX_TOPMOST))
        {
            // It's not the top-most window
            if (owner is Control ownerControl)
            {
                owner = ownerControl.TopLevelControlInternal;
            }
        }

        HWND activeHwnd = PInvoke.GetActiveWindow();
        HandleRef<HWND> ownerHwnd = owner is null ? GetHandleRef(activeHwnd) : GetSafeHandle(owner);
        Properties.AddOrRemoveValue(s_propDialogOwner, owner);
        Form? oldOwner = OwnerInternal;
        if (owner is Form ownerForm && owner != oldOwner)
        {
            Owner = ownerForm;
        }

        if (!ownerHwnd.IsNull && ownerHwnd.Handle != HWND)
        {
            // Catch the case of a window trying to own its owner
            if (PInvokeCore.GetWindowLong(ownerHwnd, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT) == HWND)
            {
                throw new ArgumentException(string.Format(SR.OwnsSelfOrOwner, nameof(Show)), nameof(owner));
            }

            // Set the new owner.
            PInvokeCore.SetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT, ownerHwnd);
        }

        Visible = true;
    }

    /// <summary>
    ///  Displays the form asynchronously, by setting its <see cref="Control.Visible"/> property to <see langword="true"/>.
    /// </summary>
    /// <param name="owner">
    ///  The optional owner window that implements <see cref="IWin32Window"/>.
    /// </param>
    /// <returns>
    ///  A <see cref="Task"/> that completes when the form is closed or disposed.
    /// </returns>
    /// <remarks>
    ///  <para>
    ///   This method makes the form visible by setting the <see cref="Control.Visible"/> property to <see langword="true"/>.
    ///  </para>
    ///  <para>
    ///   This method immediately returns, even if the form is large and takes a long time to be set up.
    ///  </para>
    ///  <para>
    ///   The task will complete when the form is closed or disposed.
    ///  </para>
    ///  <para>
    ///   If the owner window is provided, it ensures that the owner is topmost and sets the owner for the form.
    ///  </para>
    ///  <para>
    ///   This method also performs several checks to prevent invalid operations, such as trying to display a disabled form,
    ///   attempting to display the form when it is not a top-level window, or setting the form as its own owner.
    ///  </para>
    ///  <para>
    ///   If the operating system is in a non-interactive mode, this method will throw an <see cref="InvalidOperationException"/>.
    ///  </para>
    ///  <para>
    ///   If the form is already displayed asynchronously, an <see cref="InvalidOperationException"/> will be thrown.
    ///  </para>
    ///  <para>
    ///   An <see cref="InvalidOperationException"/> will also occur if no
    ///   <see cref="WindowsFormsSynchronizationContext"/> could be retrieved or installed.
    ///  </para>
    ///  <para>
    ///   There is no need to marshal the call to the UI thread manually if the call
    ///   originates from a different thread than the UI-Thread. This is handled automatically.
    ///  </para>
    ///  <para>
    ///   The returned <see cref="Task"/> carries a <see cref="WeakReference{T}"/> to the <see cref="Form"/> in its
    ///   <see cref="Task.AsyncState"/> property. This is particularly useful when managing multiple forms (such as tool windows)
    ///   in a task-based window manager, as it eliminates the need for a separate lookup table to synchronize between tasks and forms.
    ///  </para>
    ///  <para>
    ///   The following example shows how to retrieve the form from a completed task when managing multiple forms:
    ///  </para>
    ///  <code>
    ///  // Wait for any of the forms to complete
    ///  Task completedShowAsyncTask = await Task
    ///      .WhenAny(formAsyncTasks)
    ///      .ConfigureAwait(false);
    ///
    ///  // Retrieve the form using an extension method
    ///  if (completedShowAsyncTask.ToForm() is Form form)
    ///  {
    ///      // Handle the completed form
    ///  }
    ///  </code>
    ///  <para>
    ///   Where the extension method can be implemented as:
    ///  </para>
    ///  <code>
    ///  public static Form? ToForm(this Task task)
    ///  {
    ///      ArgumentNullException.ThrowIfNull(task);
    ///
    ///      if (task.AsyncState is WeakReference&lt;Form&gt; weakRefToForm
    ///          &amp;&amp; weakRefToForm.TryGetTarget(out Form? form))
    ///      {
    ///          return form;
    ///      }
    ///
    ///      return null;
    ///  }
    ///  </code>
    /// </remarks>
    /// <exception cref="InvalidOperationException">
    ///  <para>Thrown if:</para>
    ///  <list type="bullet">
    ///   <item><description>The form is already visible.</description></item>
    ///   <item><description>The form is disabled.</description></item>
    ///   <item><description>The form is not a top-level form.</description></item>
    ///   <item><description>The form is trying to set itself as its own owner.</description></item>
    ///   <item><description>
    ///    Thrown if the form is already displayed asynchronously or if no
    ///    <see cref="WindowsFormsSynchronizationContext"/> could be retrieved or installed.
    ///   </description></item>
    ///   <item><description>The operating system is in a non-interactive mode.</description></item>
    ///  </list>
    /// </exception>
    /// <exception cref="ArgumentException">
    ///  <para>Thrown if the owner window is trying to set itself as its own owner.</para>
    /// </exception>
    public Task ShowAsync(IWin32Window? owner = null)
    {
        // We lock the access to the task completion source to prevent
        // multiple calls to ShowAsync from interfering with each other.
        lock (_lock)
        {
            if (_nonModalFormCompletion is not null
                || _modalFormCompletion is not null)
            {
                throw new InvalidOperationException(SR.Form_HasAlreadyBeenShownAsync);
            }

            _nonModalFormCompletion = new(
                new WeakReference<Form>(this),
                TaskCreationOptions.RunContinuationsAsynchronously);
        }

        if (SynchronizationContext.Current is null)
        {
            WindowsFormsSynchronizationContext.InstallIfNeeded();
        }

        var syncContext = SynchronizationContext.Current
            ?? throw new InvalidOperationException(SR.FormOrTaskDialog_NoSyncContextForShowAsync);

        syncContext.Post((state) => ShowFormInternally(owner), null);

        return _nonModalFormCompletion.Task;

        void ShowFormInternally(IWin32Window? owner)
        {
            try
            {
                // Show the form with an optional owner.
                Show(owner);
            }
            catch (Exception ex)
            {
                _nonModalFormCompletion.TrySetException(ex);
                _nonModalFormCompletion = null;
            }
        }
    }

    private protected override bool SuppressApplicationOnThreadException(Exception ex)
    {
        lock (_lock)
        {
            if (_nonModalFormCompletion is not TaskCompletionSource completion)
            {
                return false;
            }

            completion.TrySetException(ex);
            return true;
        }
    }

    /// <summary>
    ///  Displays this form as a modal dialog box with no owner window.
    /// </summary>
    public DialogResult ShowDialog() => ShowDialog(owner: null);

    /// <summary>
    ///  Shows this form as a modal dialog with the specified owner.
    /// </summary>
    public DialogResult ShowDialog(IWin32Window? owner)
    {
        if (owner == this)
        {
            throw new ArgumentException(string.Format(SR.OwnsSelfOrOwner, nameof(ShowDialog)), nameof(owner));
        }

        if (Visible)
        {
            throw new InvalidOperationException(string.Format(SR.ShowDialogOnVisible, nameof(ShowDialog)));
        }

        if (!Enabled)
        {
            throw new InvalidOperationException(string.Format(SR.ShowDialogOnDisabled, nameof(ShowDialog)));
        }

        if (!TopLevel)
        {
            throw new InvalidOperationException(string.Format(SR.ShowDialogOnNonTopLevel, nameof(ShowDialog)));
        }

        if (Modal)
        {
            throw new InvalidOperationException(string.Format(SR.ShowDialogOnModal, nameof(ShowDialog)));
        }

        if (!SystemInformation.UserInteractive)
        {
            throw new InvalidOperationException(SR.CantShowModalOnNonInteractive);
        }

        if ((owner is not null) && !owner.GetExtendedStyle().HasFlag(WINDOW_EX_STYLE.WS_EX_TOPMOST))
        {
            // It's not the top-most window
            if (owner is Control ownerControl)
            {
                owner = ownerControl.TopLevelControlInternal;
            }
        }

        CalledOnLoad = false;
        CalledMakeVisible = false;

        // for modal dialogs make sure we reset close reason.
        CloseReason = CloseReason.None;

        HWND captureHwnd = PInvoke.GetCapture();
        if (!captureHwnd.IsNull)
        {
            PInvokeCore.SendMessage(captureHwnd, PInvokeCore.WM_CANCELMODE);
            PInvoke.ReleaseCapture();
        }

        HWND activeHwnd = PInvoke.GetActiveWindow();
        HandleRef<HWND> ownerHwnd = owner is null ? GetHandleRef(activeHwnd) : GetSafeHandle(owner);

        Form? oldOwner = OwnerInternal;

        try
        {
            SetState(States.Modal, true);

            // It's possible that while in the process of creating the control,
            // (i.e. inside the CreateControl() call) the dialog can be closed.
            // e.g. A user might call Close() inside the OnLoad() event.
            // Calling Close() will set the DialogResult to some value, so that
            // we'll know to terminate the RunDialog loop immediately.
            // Thus we must initialize the DialogResult *before* the call
            // to CreateControl().
            _dialogResult = DialogResult.None;

            // If "this" is an MDI parent then the window gets activated,
            // causing GetActiveWindow to return "this.handle"... to prevent setting
            // the owner of this to this, we must create the control AFTER calling
            // GetActiveWindow.
            CreateControl();

            if (!ownerHwnd.IsNull && ownerHwnd.Handle != HWND)
            {
                // Catch the case of a window trying to own its owner
                if (PInvokeCore.GetWindowLong(ownerHwnd.Handle, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT) == Handle)
                {
                    throw new ArgumentException(string.Format(SR.OwnsSelfOrOwner, nameof(ShowDialog)), nameof(owner));
                }

                // In a multi Dpi environment and applications in PMV2 mode, Dpi changed events triggered
                // only when there is a Dpi change happened for the Handle directly or via its parent.
                // So, it is necessary to not set the owner before creating the handle. Otherwise,
                // the window may never receive Dpi changed event even if its parent has different Dpi.
                // Users at runtime, has to move the window between the screens to get the Dpi changed events triggered.

                Properties.AddOrRemoveValue(s_propDialogOwner, owner);
                if (owner is Form form && owner != oldOwner)
                {
                    Owner = form;
                }
                else
                {
                    // Set the new parent.
                    PInvokeCore.SetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT, ownerHwnd);
                }
            }

            try
            {
                // If the DialogResult was already set, then there's no need to actually display the dialog.
                if (_dialogResult == DialogResult.None)
                {
                    // Application.RunDialog sets this dialog to be visible.
                    Application.RunDialog(this);
                }
            }
            finally
            {
                // Call SetActiveWindow before setting Visible = false.

                if (!PInvoke.IsWindow(activeHwnd))
                {
                    activeHwnd = ownerHwnd.Handle;
                }

                if (PInvoke.IsWindow(activeHwnd) && PInvoke.IsWindowVisible(activeHwnd))
                {
                    PInvoke.SetActiveWindow(activeHwnd);
                }
                else if (PInvoke.IsWindow(ownerHwnd) && PInvoke.IsWindowVisible(ownerHwnd))
                {
                    PInvoke.SetActiveWindow(ownerHwnd);
                }

                SetVisibleCore(false);
                if (IsHandleCreated)
                {
                    // If this is a dialog opened from an MDI Container, then invalidate
                    // so that child windows will be properly updated.
                    if (OwnerInternal is not null &&
                        OwnerInternal.IsMdiContainer)
                    {
                        OwnerInternal.Invalidate(true);
                        OwnerInternal.Update();
                    }

                    // Everett/RTM used to wrap this in an assert for AWP.
                    DestroyHandle();
                }

                SetState(States.Modal, false);
            }
        }
        finally
        {
            Owner = oldOwner;
            Properties.RemoveValue(s_propDialogOwner);
            GC.KeepAlive(ownerHwnd.Wrapper);
        }

        return DialogResult;
    }

    /// <summary>
    ///  Shows the form as a modal dialog box asynchronously.
    /// </summary>
    /// <returns>
    ///  A <see cref="Task{DialogResult}"/> representing the outcome of the dialog. The task completes when the form is
    ///  closed or disposed.
    /// </returns>
    /// <remarks>
    ///  <para>
    ///   The task will complete when the form is closed or disposed.
    ///  </para>
    ///  <para>
    ///   This method immediately returns, even if the form is large and takes a long time to be set up.
    ///  </para>
    ///  <para>
    ///   If the form is already displayed asynchronously by <see cref="ShowAsync"/>,
    ///   an <see cref="InvalidOperationException"/> will be thrown.
    ///  </para>
    ///  <para>
    ///   An <see cref="InvalidOperationException"/> will also occur if no
    ///   <see cref="WindowsFormsSynchronizationContext"/> could be retrieved or installed.
    ///  </para>
    ///  <para>
    ///   There is no need to marshal the call to the UI thread manually if the call originates from a
    ///   different thread. This is handled automatically.
    ///  </para>
    ///  <para>
    ///   Any exceptions that occur will be automatically propagated to the calling thread.
    ///  </para>
    /// </remarks>
    /// <exception cref="InvalidOperationException">
    ///  Thrown if the form is already displayed asynchronously or if no
    ///  <see cref="WindowsFormsSynchronizationContext"/> could be retrieved or installed.
    /// </exception>
    public Task<DialogResult> ShowDialogAsync() => ShowDialogAsyncInternal(owner: null);

    /// <summary>
    ///  Shows the form as a modal dialog box with the specified owner asynchronously.
    /// </summary>
    /// <param name="owner">
    ///  Any object that implements <see cref="IWin32Window"/>
    ///  that represents the top-level window that will own the modal dialog box.
    /// </param>
    /// <returns>
    ///  A <see cref="Task{DialogResult}"/> representing the outcome of the dialog.
    ///  The task completes when the form is closed or disposed.
    /// </returns>
    /// <remarks>
    ///  <para>
    ///   The task will complete when the form is closed or disposed.
    ///  </para>
    ///  <para>
    ///   This method immediately returns, even if the form is large and takes a long time to be set up.
    ///  </para>
    ///  <para>
    ///   If the form is already displayed asynchronously by <see cref="ShowAsync"/>,
    ///   an <see cref="InvalidOperationException"/> will be thrown.
    ///  </para>
    ///  <para>
    ///   An <see cref="InvalidOperationException"/> will also occur if no
    ///   <see cref="WindowsFormsSynchronizationContext"/> could be retrieved or installed.
    ///  </para>
    ///  <para>
    ///   There is no need to marshal the call to the UI thread manually if the call originates from a different thread.
    ///   This is handled automatically.
    ///  </para>
    ///  <para>
    ///   Any exceptions that occur will be automatically propagated to the calling thread.
    ///  </para>
    /// </remarks>
    /// <exception cref="InvalidOperationException">
    ///  Thrown if the form is already displayed asynchronously or if
    ///  no <see cref="WindowsFormsSynchronizationContext"/> could be retrieved or installed.
    /// </exception>
    public Task<DialogResult> ShowDialogAsync(IWin32Window owner) => ShowDialogAsyncInternal(owner);

    private Task<DialogResult> ShowDialogAsyncInternal(IWin32Window? owner)
    {
        lock (_lock)
        {
            if (_nonModalFormCompletion is not null
                || _modalFormCompletion is not null)
            {
                throw new InvalidOperationException(SR.Form_HasAlreadyBeenShownAsync);
            }

            _modalFormCompletion = new TaskCompletionSource<DialogResult>(
                state: new WeakReference<Form>(this),
                creationOptions: TaskCreationOptions.RunContinuationsAsynchronously);
        }

        if (SynchronizationContext.Current is null)
        {
            WindowsFormsSynchronizationContext.InstallIfNeeded();
        }

        var syncContext = SynchronizationContext.Current
            ?? throw new InvalidOperationException(SR.FormOrTaskDialog_NoSyncContextForShowAsync);

        syncContext.Post((state) => ShowDialogProc(
            modalFormCompletion: ref _modalFormCompletion, owner: owner),
            state: null);

        return _modalFormCompletion.Task;

        void ShowDialogProc(ref TaskCompletionSource<DialogResult> modalFormCompletion, IWin32Window? owner = default)
        {
            try
            {
                DialogResult result = ShowDialog(owner);
                modalFormCompletion.TrySetResult(result);
            }
            catch (Exception ex)
            {
                modalFormCompletion.TrySetException(ex);
            }
            finally
            {
                modalFormCompletion = null!;
            }
        }
    }

    /// <summary>
    ///  Indicates whether the <see cref="AutoScaleBaseSize"/> property should be
    ///  persisted.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    internal virtual bool ShouldSerializeAutoScaleBaseSize()
    {
        return _formState[s_formStateAutoScaling] != 0;
    }

    private static bool ShouldSerializeClientSize()
    {
        return true;
    }

    /// <summary>
    ///  Indicates whether the <see cref="Icon"/> property should be persisted.
    /// </summary>
    private bool ShouldSerializeIcon()
    {
        return _formState[s_formStateIconSet] == 1;
    }

    /// <summary>
    ///  Determines if the Location property needs to be persisted.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    private bool ShouldSerializeLocation()
    {
        return Left != 0 || Top != 0;
    }

    /// <summary>
    ///  Indicates whether the <see cref="Size"/> property should be persisted.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    internal override bool ShouldSerializeSize()
    {
        return false;
    }

    /// <summary>
    ///  Indicates whether the <see cref="TransparencyKey"/> property should be
    ///  persisted.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    internal bool ShouldSerializeTransparencyKey()
    {
        return !TransparencyKey.Equals(Color.Empty);
    }

    internal override bool SupportsUiaProviders => true;

    /// <summary>
    ///  This is called when we are about to become minimized. Laying out
    ///  while minimized can be a problem because the physical dimensions
    ///  of the window are very small. So, we simply suspend.
    /// </summary>
    private void SuspendLayoutForMinimize()
    {
        // If we're not currently minimized, suspend our layout because we are
        // about to become minimized
        if (_formState[s_formStateWindowState] != (int)FormWindowState.Minimized)
        {
            SuspendLayout();
        }
    }

    /// <summary>
    ///  Increments updateMenuHandleSuspendCount.
    /// </summary>
    private void SuspendUpdateMenuHandles()
    {
        int suspendCount = _formStateEx[s_formStateExUpdateMenuHandlesSuspendCount];
        _formStateEx[s_formStateExUpdateMenuHandlesSuspendCount] = ++suspendCount;
    }

    /// <summary>
    ///  Returns a string representation for this control.
    /// </summary>
    public override string ToString() => $"{base.ToString()}, Text: {Text}";

    /// <summary>
    ///  Updates the autoscalebasesize based on the current font.
    /// </summary>
    private void UpdateAutoScaleBaseSize()
    {
        _autoScaleBaseSize = Size.Empty;
    }

    private void UpdateRenderSizeGrip()
    {
        int current = _formState[s_formStateRenderSizeGrip];
        switch (FormBorderStyle)
        {
            case FormBorderStyle.None:
            case FormBorderStyle.FixedSingle:
            case FormBorderStyle.Fixed3D:
            case FormBorderStyle.FixedDialog:
            case FormBorderStyle.FixedToolWindow:
                _formState[s_formStateRenderSizeGrip] = 0;
                break;
            case FormBorderStyle.Sizable:
            case FormBorderStyle.SizableToolWindow:
                switch (SizeGripStyle)
                {
                    case SizeGripStyle.Show:
                        _formState[s_formStateRenderSizeGrip] = 1;
                        break;
                    case SizeGripStyle.Hide:
                        _formState[s_formStateRenderSizeGrip] = 0;
                        break;
                    case SizeGripStyle.Auto:
                        if (GetState(States.Modal))
                        {
                            _formState[s_formStateRenderSizeGrip] = 1;
                        }
                        else
                        {
                            _formState[s_formStateRenderSizeGrip] = 0;
                        }

                        break;
                }

                break;
        }

        if (_formState[s_formStateRenderSizeGrip] != current)
        {
            Invalidate();
        }
    }

    protected override void UpdateDefaultButton()
    {
        ContainerControl? containerControl = this;

        while (containerControl.ActiveControl is ContainerControl)
        {
            containerControl = containerControl.ActiveControl as ContainerControl;
            Debug.Assert(containerControl is not null);

            if (containerControl is Form)
            {
                // Don't allow a parent form to get its default button from a child form,
                // otherwise the two forms will 'compete' for the Enter key and produce unpredictable results.
                // This is aimed primarily at fixing the behavior of MDI container forms.
                containerControl = this;
                break;
            }
        }

        if (containerControl.ActiveControl is IButtonControl control)
        {
            SetDefaultButton(control);
        }
        else
        {
            SetDefaultButton(AcceptButton);
        }
    }

    /// <summary>
    ///  Updates the underlying hWnd with the correct parent/owner of the form.
    /// </summary>
    private void UpdateHandleWithOwner()
    {
        if (IsHandleCreated && TopLevel)
        {
            IHandle<HWND> ownerHwnd = NullHandle<HWND>.Instance;
            if (Properties.TryGetValue(s_propOwner, out Form? owner))
            {
                ownerHwnd = owner;
            }
            else
            {
                if (!ShowInTaskbar)
                {
                    ownerHwnd = TaskbarOwner;
                }
            }

            PInvokeCore.SetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT, ownerHwnd);
            GC.KeepAlive(ownerHwnd);
        }
    }

    /// <summary>
    ///  Updates the layered window attributes if the control
    ///  is in layered mode.
    /// </summary>
    private void UpdateLayered()
    {
        if ((_formState[s_formStateLayered] != 0) && IsHandleCreated && TopLevel)
        {
            BOOL result;

            Color transparencyKey = TransparencyKey;

            if (transparencyKey.IsEmpty)
            {
                result = PInvoke.SetLayeredWindowAttributes(this, (COLORREF)0, OpacityAsByte, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_ALPHA);
            }
            else if (OpacityAsByte == 255)
            {
                // Windows doesn't do so well setting colorkey and alpha, so avoid it if we can
                result = PInvoke.SetLayeredWindowAttributes(this, (COLORREF)transparencyKey, 0, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_COLORKEY);
            }
            else
            {
                result = PInvoke.SetLayeredWindowAttributes(this, (COLORREF)transparencyKey, OpacityAsByte, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_ALPHA | LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_COLORKEY);
            }

            if (!result)
            {
                throw new Win32Exception();
            }
        }
    }

    private unsafe void UpdateMenuHandles(bool recreateMenu = false)
    {
        if (!IsHandleCreated)
        {
            return;
        }

        if (_ctlClient is null || !_ctlClient.IsHandleCreated)
        {
            PInvoke.SetMenu(this, HMENU.Null);
        }
        else
        {
            Debug.Assert(IsMdiContainer, "Not an MDI container!");
            // when both MainMenuStrip and Menu are set, we honor the win32 menu over
            // the MainMenuStrip as the place to store the system menu controls for the maximized MDI child.

            MenuStrip? mainMenuStrip = MainMenuStrip;
            if (mainMenuStrip is null)
            {
                // We are dealing with a Win32 Menu; MenuStrip doesn't have control buttons.

                // We need to set the "dummy" menu even when a menu is being removed
                // (set to null) so that duplicate control buttons are not placed on the menu bar when
                // an ole menu is being removed.
                // Make MDI forget the mdi item position.
                if (!Properties.TryGetValue(s_propDummyMdiMenu, out HMENU dummyMenu) || recreateMenu)
                {
                    dummyMenu = PInvoke.CreateMenu();
                    if (!dummyMenu.IsNull)
                    {
                        Properties.AddValue(s_propDummyMdiMenu, dummyMenu);
                    }
                }

                PInvokeCore.SendMessage(_ctlClient, PInvokeCore.WM_MDISETMENU, (WPARAM)dummyMenu.Value);
            }

            // (New fix: Only destroy Win32 Menu if using a MenuStrip)
            if (mainMenuStrip is not null)
            {
                // If MainMenuStrip, we need to remove any Win32 Menu to make room for it.
                HMENU hMenu = PInvoke.GetMenu(this);
                if (!hMenu.IsNull)
                {
                    // Remove the current menu.
                    PInvoke.SetMenu(this, HMENU.Null);

                    // because we have messed with the child's system menu by shoving in our own dummy menu,
                    // once we clear the main menu we're in trouble - this eats the close, minimize, maximize gadgets
                    // of the child form. (See WM_MDISETMENU in MSDN)
                    Form? activeMdiChild = ActiveMdiChildInternal;
                    if (activeMdiChild is not null && activeMdiChild.WindowState == FormWindowState.Maximized)
                    {
                        activeMdiChild.RecreateHandle();
                    }

                    // Since we're removing a menu but we possibly had a menu previously,
                    // we need to clear the cached size so that new size calculations will be performed correctly.
                    CommonProperties.xClearPreferredSizeCache(this);
                }
            }
        }

        PInvoke.DrawMenuBar(this);
        _formStateEx[s_formStateExUpdateMenuHandlesDeferred] = 0;
    }

    // Call this function instead of UpdateStyles() when the form's client-size must
    // be preserved e.g. when changing the border style.
    //
    internal void UpdateFormStyles()
    {
        Size previousClientSize = ClientSize;
        UpdateStyles();
        if (!ClientSize.Equals(previousClientSize))
        {
            ClientSize = previousClientSize;
        }
    }

    private static Type? FindClosestStockType(Type type)
    {
        Type[] stockTypes = [typeof(MenuStrip)];

        // Add other types here from most specific to most generic if we want to merge other types of toolstrips.

        foreach (Type t in stockTypes)
        {
            if (t.IsAssignableFrom(type))
            {
                return t;
            }
        }

        return null;
    }

    /// <summary> ToolStrip MDI Merging support </summary>
    private void UpdateToolStrip()
    {
        // try to merge each one of the MDI Child toolstrip with the first toolstrip
        // in the parent form that has the same type NOTE: THESE LISTS ARE ORDERED (See ToolstripManager)
        ToolStrip? thisToolstrip = MainMenuStrip;
        List<ToolStrip> childrenToolStrips = ToolStripManager.FindMergeableToolStrips(ActiveMdiChildInternal);

        // revert any previous merge
        if (thisToolstrip is not null)
        {
            ToolStripManager.RevertMerge(thisToolstrip);
        }

        // if someone has a MdiWindowListItem specified we should merge in the
        // names of all the MDI child forms.
        UpdateMdiWindowListStrip();

        if (ActiveMdiChildInternal is not null)
        {
            // do the new merging
            foreach (ToolStrip sourceToolStrip in childrenToolStrips)
            {
                Type? closestMatchingSourceType = FindClosestStockType(sourceToolStrip.GetType());
                if (thisToolstrip is not null)
                {
                    Type? closestMatchingTargetType = FindClosestStockType(thisToolstrip.GetType());
                    if (closestMatchingTargetType is not null && closestMatchingSourceType is not null &&
                        closestMatchingSourceType == closestMatchingTargetType &&
                        thisToolstrip.GetType().IsAssignableFrom(sourceToolStrip.GetType()))
                    {
                        ToolStripManager.Merge(sourceToolStrip, thisToolstrip);
                        break;
                    }
                }
            }
        }

        // add in the control gadgets for the mdi child form to the first menu strip
        Form? activeMdiForm = ActiveMdiChildInternal;
        UpdateMdiControlStrip(activeMdiForm is not null && activeMdiForm.IsMaximized);
    }

    private void UpdateMdiControlStrip(bool maximized)
    {
        if (_formStateEx[s_formStateExInUpdateMdiControlStrip] != 0)
        {
            return;
        }

        // we don't want to be redundantly called as we could merge in two control menus.
        _formStateEx[s_formStateExInUpdateMdiControlStrip] = 1;

        try
        {
            MdiControlStrip? mdiControlStrip = MdiControlStrip;

            if (mdiControlStrip is not null)
            {
                if (mdiControlStrip.MergedMenu is not null)
                {
#if DEBUG
                    int numWindowListItems = 0;
                    if (MdiWindowListStrip is not null && MdiWindowListStrip.MergedMenu is not null && MdiWindowListStrip.MergedMenu.MdiWindowListItem is not null)
                    {
                        numWindowListItems = MdiWindowListStrip.MergedMenu.MdiWindowListItem.DropDownItems.Count;
                    }
#endif

                    ToolStripManager.RevertMergeInternal(mdiControlStrip.MergedMenu, mdiControlStrip, revertMDIControls: true);

#if DEBUG
                    // double check that RevertMerge doesn't accidentally revert more than it should.
                    if (MdiWindowListStrip is not null && MdiWindowListStrip.MergedMenu is not null && MdiWindowListStrip.MergedMenu.MdiWindowListItem is not null)
                    {
                        Debug.Assert(numWindowListItems == MdiWindowListStrip.MergedMenu.MdiWindowListItem.DropDownItems.Count, "Calling RevertMerge modified the mdiwindowlistitem");
                    }
#endif
                }

                mdiControlStrip.MergedMenu = null;
                mdiControlStrip.Dispose();
                MdiControlStrip = null;
            }

            if (ActiveMdiChildInternal is not null && maximized && ActiveMdiChildInternal.ControlBox)
            {
                // Determine if we need to add control gadgets into the MenuStrip.
                // Double check GetMenu incase someone is using interop.
                HMENU hMenu = PInvoke.GetMenu(this);
                if (hMenu == HMENU.Null)
                {
                    MenuStrip? sourceMenuStrip = ToolStripManager.GetMainMenuStrip(this);
                    if (sourceMenuStrip is not null)
                    {
                        MdiControlStrip = new MdiControlStrip(ActiveMdiChildInternal);
                        ToolStripManager.Merge(MdiControlStrip, sourceMenuStrip);
                        MdiControlStrip.MergedMenu = sourceMenuStrip;
                    }
                }
            }
        }
        finally
        {
            _formStateEx[s_formStateExInUpdateMdiControlStrip] = 0;
        }
    }

    internal void UpdateMdiWindowListStrip()
    {
        if (IsMdiContainer)
        {
            if (MdiWindowListStrip is not null && MdiWindowListStrip.MergedMenu is not null)
            {
                ToolStripManager.RevertMergeInternal(MdiWindowListStrip.MergedMenu, MdiWindowListStrip, revertMDIControls: true);
            }

            MenuStrip? sourceMenuStrip = ToolStripManager.GetMainMenuStrip(this);
            if (sourceMenuStrip is not null && sourceMenuStrip.MdiWindowListItem is not null)
            {
                MdiWindowListStrip ??= new MdiWindowListStrip();

                int nSubItems = sourceMenuStrip.MdiWindowListItem.DropDownItems.Count;
                bool shouldIncludeSeparator = (nSubItems > 0 &&
                    !(sourceMenuStrip.MdiWindowListItem.DropDownItems[nSubItems - 1] is ToolStripSeparator));
                MdiWindowListStrip.PopulateItems(this, sourceMenuStrip.MdiWindowListItem, shouldIncludeSeparator);
                ToolStripManager.Merge(MdiWindowListStrip, sourceMenuStrip);
                MdiWindowListStrip.MergedMenu = sourceMenuStrip;
            }
        }
    }

    /// <summary>
    ///  Raises the <see cref="ResizeBegin"/>
    ///  event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnResizeBegin(EventArgs e)
    {
        if (CanRaiseEvents)
        {
            ((EventHandler?)Events[s_resizeBeginEvent])?.Invoke(this, e);
        }
    }

    /// <summary>
    ///  Raises the <see cref="ResizeEnd"/>
    ///  event.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnResizeEnd(EventArgs e)
    {
        if (CanRaiseEvents)
        {
            ((EventHandler?)Events[s_resizeEndEvent])?.Invoke(this, e);
        }
    }

    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void OnStyleChanged(EventArgs e)
    {
        base.OnStyleChanged(e);
        AdjustSystemMenu();
    }

    /// <summary>
    ///  Updates the window icon.
    /// </summary>
    private unsafe void UpdateWindowIcon(bool redrawFrame, int dpi = 0)
    {
        if (IsHandleCreated)
        {
            Icon? icon;

            if (dpi == 0)
            {
                dpi = DeviceDpi;
            }

            // Preserve Win32 behavior by keeping the icon we set NULL if
            // the user hasn't specified an icon and we are a dialog frame.
            if ((FormBorderStyle == FormBorderStyle.FixedDialog && _formState[s_formStateIconSet] == 0) || !ShowIcon)
            {
                icon = null;
            }
            else
            {
                icon = Icon;
            }

            if (icon is not null)
            {
                try
                {
                    // As we dispose the _smallIcon in multiple places, we'd need to track when we've
                    // actually created a scaled icon to know when we should free it selectively (so we
                    // don't free user provided Icons. For now, just always create a new scaled icon.
                    _smallIcon?.Dispose();
                    _smallIcon = null;
                    _smallIcon = ScaleHelper.ScaleSmallIconToDpi(icon, dpi, alwaysCreateNew: true);
                }
                catch
                {
                }

                if (_smallIcon is not null)
                {
                    PInvokeCore.SendMessage(this, PInvokeCore.WM_SETICON, (WPARAM)PInvoke.ICON_SMALL, (LPARAM)_smallIcon.Handle);
                }

                PInvokeCore.SendMessage(this, PInvokeCore.WM_SETICON, (WPARAM)PInvoke.ICON_BIG, (LPARAM)icon.Handle);
            }
            else
            {
                PInvokeCore.SendMessage(this, PInvokeCore.WM_SETICON, (WPARAM)PInvoke.ICON_SMALL);
                PInvokeCore.SendMessage(this, PInvokeCore.WM_SETICON, (WPARAM)PInvoke.ICON_BIG);
            }

            if (WindowState == FormWindowState.Maximized && MdiParent?.MdiControlStrip is not null)
            {
                MdiParent.MdiControlStrip.updateIcon();
            }

            if (redrawFrame)
            {
                PInvoke.RedrawWindow(this, lprcUpdate: null, HRGN.Null, REDRAW_WINDOW_FLAGS.RDW_INVALIDATE | REDRAW_WINDOW_FLAGS.RDW_FRAME);
            }
        }
    }

    /// <summary>
    ///  Update the window state from the handle, if created.
    /// </summary>
    private unsafe void UpdateWindowState()
    {
        // This function is called from all over the place, including my personal favorite,
        // WM_ERASEBKGRND. Seems that's one of the first messages we get when a user clicks the min/max
        // button, even before WM_WINDOWPOSCHANGED.

        if (!IsHandleCreated)
        {
            return;
        }

        FormWindowState oldState = WindowState;
        WINDOWPLACEMENT wp = new()
        {
            length = (uint)sizeof(WINDOWPLACEMENT)
        };
        PInvoke.GetWindowPlacement(HWND, &wp);

        switch (wp.showCmd)
        {
            case SHOW_WINDOW_CMD.SW_NORMAL:
            case SHOW_WINDOW_CMD.SW_RESTORE:
            case SHOW_WINDOW_CMD.SW_SHOW:
            case SHOW_WINDOW_CMD.SW_SHOWNA:
            case SHOW_WINDOW_CMD.SW_SHOWNOACTIVATE:
                if (_formState[s_formStateWindowState] != (int)FormWindowState.Normal)
                {
                    _formState[s_formStateWindowState] = (int)FormWindowState.Normal;
                }

                break;
            case SHOW_WINDOW_CMD.SW_SHOWMAXIMIZED:
                if (_formState[s_formStateMdiChildMax] == 0)
                {
                    _formState[s_formStateWindowState] = (int)FormWindowState.Maximized;
                }

                break;
            case SHOW_WINDOW_CMD.SW_SHOWMINIMIZED:
            case SHOW_WINDOW_CMD.SW_MINIMIZE:
            case SHOW_WINDOW_CMD.SW_SHOWMINNOACTIVE:
                if (_formState[s_formStateMdiChildMax] == 0)
                {
                    _formState[s_formStateWindowState] = (int)FormWindowState.Minimized;
                }

                break;
            case SHOW_WINDOW_CMD.SW_HIDE:
            default:
                break;
        }

        // If we used to be normal and we just became minimized or maximized,
        // stash off our current bounds so we can properly restore.
        if (oldState == FormWindowState.Normal && WindowState != FormWindowState.Normal)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                SuspendLayoutForMinimize();
            }

            if (!OsVersion.IsWindows11_OrGreater())
            {
                _restoredWindowBounds.Size = ClientSize;
                _formStateEx[s_formStateExWindowBoundsWidthIsClientSize] = 1;
                _formStateEx[s_formStateExWindowBoundsHeightIsClientSize] = 1;
                _restoredWindowBoundsSpecified = BoundsSpecified.Size;
                _restoredWindowBounds.Location = Location;
                _restoredWindowBoundsSpecified |= BoundsSpecified.Location;
            }

            // stash off restoreBounds As well...
            _restoreBounds.Size = Size;
            _restoreBounds.Location = Location;
        }

        // If we just became normal or maximized resume
        if (oldState == FormWindowState.Minimized && WindowState != FormWindowState.Minimized)
        {
            ResumeLayoutFromMinimize();
        }

        switch (WindowState)
        {
            case FormWindowState.Normal:
                SetState(States.SizeLockedByOS, false);
                break;
            case FormWindowState.Maximized:
            case FormWindowState.Minimized:
                SetState(States.SizeLockedByOS, true);
                break;
        }

        if (oldState != WindowState)
        {
            AdjustSystemMenu();
        }
    }

    /// <summary>
    ///  Validates all selectable child controls in the container, including descendants. This is
    ///  equivalent to calling ValidateChildren(ValidationConstraints.Selectable). See <see cref="ValidationConstraints.Selectable"/>
    ///  for details of exactly which child controls will be validated.
    /// </summary>
    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public override bool ValidateChildren()
    {
        return base.ValidateChildren();
    }

    /// <summary>
    ///  Validates all the child controls in the container. Exactly which controls are
    ///  validated and which controls are skipped is determined by <paramref name="validationConstraints"/>.
    /// </summary>
    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public override bool ValidateChildren(ValidationConstraints validationConstraints)
    {
        return base.ValidateChildren(validationConstraints);
    }

    /// <summary>
    ///  WM_ACTIVATE handler
    /// </summary>
    private void WmActivate(ref Message m)
    {
        Application.FormActivated(Modal, true);
        Active = m.WParamInternal.LOWORD != PInvoke.WA_INACTIVE;
        Application.FormActivated(Modal, Active);
    }

    /// <summary>
    ///  WM_ENTERSIZEMOVE handler, so that user can hook up OnResizeBegin event.
    /// </summary>
    private void WmEnterSizeMove()
    {
        _formStateEx[s_formStateExInModalSizingLoop] = 1;
        OnResizeBegin(EventArgs.Empty);
    }

    /// <summary>
    ///  WM_EXITSIZEMOVE handler, so that user can hook up OnResizeEnd event.
    /// </summary>
    private void WmExitSizeMove()
    {
        _formStateEx[s_formStateExInModalSizingLoop] = 0;
        OnResizeEnd(EventArgs.Empty);
    }

    /// <summary>
    ///  WM_CREATE handler
    /// </summary>
    private void WmCreate(ref Message m)
    {
        base.WndProc(ref m);
        PInvoke.GetStartupInfo(out STARTUPINFOW si);

        // If we've been created from explorer, it may
        // force us to show up normal. Force our current window state to
        // the specified state, unless it's _specified_ max or min
        if (TopLevel && (si.dwFlags & STARTUPINFOW_FLAGS.STARTF_USESHOWWINDOW) != 0)
        {
            switch ((SHOW_WINDOW_CMD)si.wShowWindow)
            {
                case SHOW_WINDOW_CMD.SW_MAXIMIZE:
                    WindowState = FormWindowState.Maximized;
                    break;
                case SHOW_WINDOW_CMD.SW_MINIMIZE:
                    WindowState = FormWindowState.Minimized;
                    break;
            }
        }
    }

    /// <summary>
    ///  WM_CLOSE, WM_QUERYENDSESSION, and WM_ENDSESSION handler
    /// </summary>
    private void WmClose(ref Message m)
    {
        FormClosingEventArgs e = new(CloseReason, false);

        // Pass 1 (WM_CLOSE & WM_QUERYENDSESSION)... Closing
        if (m.Msg != (int)PInvokeCore.WM_ENDSESSION)
        {
            if (Modal)
            {
                if (_dialogResult == DialogResult.None)
                {
                    _dialogResult = DialogResult.Cancel;
                }

                CalledClosing = false;

                // if this comes back false, someone canceled the close. we want
                // to call this here so that we can get the cancel event properly,
                // and if this is a WM_QUERYENDSESSION, appropriately set the result
                // based on this call.
                //
                // NOTE: We should also check !Validate(true) below too in the modal case,
                // but we cannot, because we didn't to this in Everett, and doing so
                // now would introduce a breaking change. User can always validate in the
                // FormClosing event if they really need to.

                e.Cancel = !CheckCloseDialog(true);
            }
            else
            {
                e.Cancel = !Validate(true);

                // Call OnClosing/OnFormClosing on all MDI children
                if (IsMdiContainer)
                {
                    FormClosingEventArgs fe = new(CloseReason.MdiFormClosing, e.Cancel);
                    foreach (Form mdiChild in MdiChildren)
                    {
                        if (mdiChild.IsHandleCreated)
                        {
#pragma warning disable WFDEV004 // Type or member is obsolete - compat
                            mdiChild.OnClosing(fe);
#pragma warning restore WFDEV004
                            mdiChild.OnFormClosing(fe);
                            if (fe.Cancel)
                            {
                                // Set the Cancel property for the MDI Container's
                                // FormClosingEventArgs, as well, so that closing the MDI container
                                // will be cancelled.
                                e.Cancel = true;
                                break;
                            }
                        }
                    }
                }

                // Always fire OnClosing irrespectively of the validation result
                // Pass the validation result into the EventArgs.

                // Call OnClosing/OnFormClosing on all the forms that current form owns.

                if (Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms))
                {
                    for (int i = ownedForms.Count - 1; i >= 0; i--)
                    {
                        FormClosingEventArgs cfe = new(CloseReason.FormOwnerClosing, e.Cancel);

                        // Call OnFormClosing on the child forms.
                        ownedForms[i].OnFormClosing(cfe);
                        if (cfe.Cancel)
                        {
                            // Set the cancel flag for the Owner form
                            e.Cancel = true;
                            break;
                        }
                    }
                }

#pragma warning disable WFDEV004 // Type or member is obsolete - compat
                OnClosing(e);
#pragma warning restore WFDEV004
                OnFormClosing(e);
            }

            if (m.MsgInternal == PInvokeCore.WM_QUERYENDSESSION)
            {
                m.ResultInternal = (LRESULT)(BOOL)!e.Cancel;
            }
            else if (e.Cancel && (MdiParent is not null))
            {
                // This is the case of an MDI child close event being canceled by the user.
                CloseReason = CloseReason.None;
            }

            if (Modal)
            {
                return;
            }
        }
        else
        {
            e.Cancel = m.WParamInternal == 0;
        }

        // Pass 2 (WM_CLOSE & WM_ENDSESSION)... Fire closed
        // event on all mdi children and ourselves
        if (m.Msg != (int)PInvokeCore.WM_QUERYENDSESSION)
        {
            FormClosedEventArgs fc;
            if (!e.Cancel)
            {
                IsClosing = true;

                if (IsMdiContainer)
                {
                    fc = new FormClosedEventArgs(CloseReason.MdiFormClosing);
                    foreach (Form mdiChild in MdiChildren)
                    {
                        if (mdiChild.IsHandleCreated)
                        {
                            mdiChild.IsTopMdiWindowClosing = IsClosing;
#pragma warning disable WFDEV004 // Type or member is obsolete - compat
                            mdiChild.OnClosed(fc);
#pragma warning restore WFDEV004
                            mdiChild.OnFormClosed(fc);
                        }
                    }
                }

                // Call OnClosed/OnFormClosed on all the forms that current form owns.
                if (Properties.TryGetValue(s_propOwnedForms, out List<Form>? ownedForms))
                {
                    for (int i = ownedForms.Count - 1; i >= 0; i--)
                    {
                        fc = new FormClosedEventArgs(CloseReason.FormOwnerClosing);
                        // Call OnClosed and OnFormClosed on the child forms.
#pragma warning disable WFDEV004 // Type or member is obsolete - compat
                        ownedForms[i].OnClosed(fc);
#pragma warning restore WFDEV004
                        ownedForms[i].OnFormClosed(fc);
                    }
                }

                fc = new FormClosedEventArgs(CloseReason);
#pragma warning disable WFDEV004 // Type or member is obsolete - compat
                OnClosed(fc);
#pragma warning restore WFDEV004
                OnFormClosed(fc);

                Dispose();
            }
        }
    }

    /// <summary>
    ///  WM_ENTERMENULOOP handler
    /// </summary>
    private void WmEnterMenuLoop(ref Message m)
    {
        OnMenuStart(EventArgs.Empty);
        base.WndProc(ref m);
    }

    /// <summary>
    ///  Handles the WM_ERASEBKGND message
    /// </summary>
    private void WmEraseBkgnd(ref Message m)
    {
        UpdateWindowState();
        base.WndProc(ref m);
    }

    /// <summary>
    ///  WM_EXITMENULOOP handler
    /// </summary>
    private void WmExitMenuLoop(ref Message m)
    {
        OnMenuComplete(EventArgs.Empty);
        base.WndProc(ref m);
    }

    /// <summary>
    ///  WM_GETMINMAXINFO handler
    /// </summary>
    private void WmGetMinMaxInfo(ref Message m)
    {
        // Form should gracefully stop at the minimum preferred size.
        // When we're set to AutoSize true, we should take a look at minAutoSize - which is snapped in onlayout.
        // as the form contracts, we should not let it size past here as we're just going to readjust the size
        // back to it later.
        Size minTrack = (AutoSize && _formStateEx[s_formStateExInModalSizingLoop] == 1) ? LayoutUtils.UnionSizes(_minAutoSize, MinimumSize) : MinimumSize;

        Size maxTrack = MaximumSize;
        Rectangle maximizedBounds = MaximizedBounds;

        if (!minTrack.IsEmpty || !maxTrack.IsEmpty || !maximizedBounds.IsEmpty)
        {
            WmGetMinMaxInfoHelper(ref m, minTrack, maxTrack, maximizedBounds);
        }

        if (IsMdiChild)
        {
            base.WndProc(ref m);
        }
    }

    private unsafe void WmGetMinMaxInfoHelper(ref Message m, Size minTrack, Size maxTrack, Rectangle maximizedBounds)
    {
        MINMAXINFO* mmi = (MINMAXINFO*)(nint)m.LParamInternal;
        if (!minTrack.IsEmpty)
        {
            mmi->ptMinTrackSize.X = minTrack.Width;
            mmi->ptMinTrackSize.Y = minTrack.Height;

            // When the MinTrackSize is set to a value larger than the screen
            // size but the MaxTrackSize is not set to a value equal to or greater than the
            // MinTrackSize and the user attempts to "grab" a resizing handle, Windows makes
            // the window move a distance equal to either the width when attempting to resize
            // horizontally or the height of the window when attempting to resize vertically.
            // So, the workaround to prevent this problem is to set the MaxTrackSize to something
            // whenever the MinTrackSize is set to a value larger than the respective dimension
            // of the virtual screen.
            if (maxTrack.IsEmpty)
            {
                // Only set the max track size dimensions if the min track size dimensions
                // are larger than the VirtualScreen dimensions.
                Size virtualScreen = SystemInformation.VirtualScreen.Size;
                if (minTrack.Height > virtualScreen.Height)
                {
                    mmi->ptMaxTrackSize.Y = int.MaxValue;
                }

                if (minTrack.Width > virtualScreen.Width)
                {
                    mmi->ptMaxTrackSize.X = int.MaxValue;
                }
            }
        }

        if (!maxTrack.IsEmpty)
        {
            // Is the specified MaxTrackSize smaller than the smallest allowable Window size?
            Size minTrackWindowSize = SystemInformation.MinWindowTrackSize;
            mmi->ptMaxTrackSize.X = Math.Max(maxTrack.Width, minTrackWindowSize.Width);
            mmi->ptMaxTrackSize.Y = Math.Max(maxTrack.Height, minTrackWindowSize.Height);
        }

        if (!maximizedBounds.IsEmpty)
        {
            mmi->ptMaxPosition.X = maximizedBounds.X;
            mmi->ptMaxPosition.Y = maximizedBounds.Y;
            mmi->ptMaxSize.X = maximizedBounds.Width;
            mmi->ptMaxSize.Y = maximizedBounds.Height;
        }

        m.ResultInternal = (LRESULT)0;
    }

    /// <summary>
    ///  WM_MDIACTIVATE handler
    /// </summary>
    private void WmMdiActivate(ref Message m)
    {
        base.WndProc(ref m);
        Debug.Assert(Properties.ContainsKey(s_propFormMdiParent), "how is formMdiParent null?");
        Debug.Assert(IsHandleCreated, "how is handle 0?");

        if (Properties.TryGetValue(s_propFormMdiParent, out Form? formMdiParent))
        {
            // This message is propagated twice by the MDIClient window. Once to the
            // window being deactivated and once to the window being activated.
            if (HWND == (HWND)m.WParamInternal)
            {
                formMdiParent.DeactivateMdiChild();
            }
            else if (HWND == m.LParamInternal)
            {
                formMdiParent.ActivateMdiChild(this);
            }
        }
    }

    private void WmNcButtonDown(ref Message m)
    {
        if (IsMdiChild)
        {
            if (MdiParentInternal.ActiveMdiChildInternal == this)
            {
                if (ActiveControl is not null && !ActiveControl.ContainsFocus)
                {
                    InnerMostActiveContainerControl.FocusActiveControlInternal();
                }
            }
        }

        base.WndProc(ref m);
    }

    /// <summary>
    ///  WM_NCDESTROY handler
    /// </summary>
    private void WmNCDestroy(ref Message m)
    {
        base.WndProc(ref m);

        // Destroy the owner window, if we created one. We
        // cannot do this in OnHandleDestroyed, because at
        // that point our handle is not actually destroyed so
        // destroying our parent actually causes a recursive
        // WM_DESTROY.
        _ownerWindow?.DestroyHandle();
        _ownerWindow = null;

        if (Modal && _dialogResult == DialogResult.None)
        {
            if (!GetState(States.Recreate))
            {
                DialogResult = DialogResult.Cancel;
            }
        }
    }

    /// <summary>
    ///  WM_NCHITTEST handler.
    /// </summary>
    private void WmNCHitTest(ref Message m)
    {
        if (_formState[s_formStateRenderSizeGrip] != 0)
        {
            // Convert to client coordinates
            Point point = PointToClient(PARAM.ToPoint(m.LParamInternal));

            Size clientSize = ClientSize;

            // If the grip is not fully visible the grip area could overlap with the system control box; we need to disable
            // the grip area in this case not to get in the way of the control box. We only need to check for the client's
            // height since the window width will be at least the size of the control box which is always bigger than the
            // grip width.
            if (point.X >= (clientSize.Width - SizeGripSize) &&
                point.Y >= (clientSize.Height - SizeGripSize) &&
                clientSize.Height >= SizeGripSize)
            {
                m.ResultInternal = (LRESULT)(nint)(IsMirrored ? PInvoke.HTBOTTOMLEFT : PInvoke.HTBOTTOMRIGHT);
                return;
            }
        }

        base.WndProc(ref m);

        // If we got any of the "edge" hits (bottom, top, topleft, etc),
        // and we're AutoSizeMode.GrowAndShrink, return non-resizable border
        // The edge values are the 8 values from HTLEFT (10) to HTBOTTOMRIGHT (17).
        if (AutoSizeMode == AutoSizeMode.GrowAndShrink)
        {
            int result = (int)m.ResultInternal;
            if (result is >= ((int)PInvoke.HTLEFT) and <= ((int)PInvoke.HTBOTTOMRIGHT))
            {
                m.ResultInternal = (LRESULT)(nint)PInvoke.HTBORDER;
            }
        }
    }

    /// <summary>
    ///  WM_SHOWWINDOW handler
    /// </summary>
    private void WmShowWindow(ref Message m)
    {
        _formState[s_formStateSWCalled] = 1;
        base.WndProc(ref m);
    }

    /// <summary>
    ///  WM_SYSCOMMAND handler
    /// </summary>
    private void WmSysCommand(ref Message m)
    {
        bool callDefault = true;

        uint sc = (uint)(m.WParamInternal.LOWORD & 0xFFF0);
        switch (sc)
        {
            case PInvoke.SC_CLOSE:
                CloseReason = CloseReason.UserClosing;
                if (IsMdiChild && !ControlBox)
                {
                    callDefault = false;
                }

                break;
            case PInvoke.SC_KEYMENU:
                if (IsMdiChild && !ControlBox)
                {
                    callDefault = false;
                }

                break;
            case PInvoke.SC_SIZE:
            case PInvoke.SC_MOVE:
                // Set this before WM_ENTERSIZELOOP because WM_GETMINMAXINFO can be called before WM_ENTERSIZELOOP.
                _formStateEx[s_formStateExInModalSizingLoop] = 1;
                break;
            case PInvoke.SC_CONTEXTHELP:
                CancelEventArgs e = new(false);
                OnHelpButtonClicked(e);
                if (e.Cancel)
                {
                    callDefault = false;
                }

                break;
        }

        if (Command.DispatchID(m.WParamInternal.LOWORD))
        {
            callDefault = false;
        }

        if (callDefault)
        {
            base.WndProc(ref m);
        }
    }

    /// <summary>
    ///  WM_SIZE handler.
    /// </summary>
    private void WmSize(ref Message m)
    {
        // If this is an MDI parent, don't pass WM_SIZE to the default window proc. We handle resizing the
        // MDIClient window ourselves (using ControlDock.FILL).
        if (_ctlClient is null)
        {
            base.WndProc(ref m);
            if (MdiControlStrip is null && MdiParentInternal is not null && MdiParentInternal.ActiveMdiChildInternal == this)
            {
                MdiParentInternal.UpdateMdiControlStrip((nint)m.WParamInternal == PInvoke.SIZE_MAXIMIZED);
            }
        }
    }

    /// <summary>
    ///  WM_WINDOWPOSCHANGED handler
    /// </summary>
    private void WmWindowPosChanged(ref Message m)
    {
        // We must update the windowState, because resize is fired from here (in Control).
        UpdateWindowState();
        base.WndProc(ref m);

        RestoreWindowBoundsIfNecessary();
    }

    /// <summary>
    ///  Base wndProc encapsulation.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void WndProc(ref Message m)
    {
        switch (m.MsgInternal)
        {
            case PInvokeCore.WM_NCACTIVATE:
                base.WndProc(ref m);
                break;
            case PInvokeCore.WM_NCLBUTTONDOWN:
            case PInvokeCore.WM_NCRBUTTONDOWN:
            case PInvokeCore.WM_NCMBUTTONDOWN:
            case PInvokeCore.WM_NCXBUTTONDOWN:
                WmNcButtonDown(ref m);
                break;
            case PInvokeCore.WM_ACTIVATE:
                WmActivate(ref m);
                break;
            case PInvokeCore.WM_MDIACTIVATE:
                WmMdiActivate(ref m);
                break;
            case PInvokeCore.WM_CLOSE:
                if (CloseReason == CloseReason.None)
                {
                    CloseReason = CloseReason.TaskManagerClosing;
                }

                WmClose(ref m);
                break;

            case PInvokeCore.WM_QUERYENDSESSION:
            case PInvokeCore.WM_ENDSESSION:
                CloseReason = CloseReason.WindowsShutDown;
                WmClose(ref m);
                break;
            case PInvokeCore.WM_ENTERSIZEMOVE:
                WmEnterSizeMove();
                DefWndProc(ref m);
                break;
            case PInvokeCore.WM_EXITSIZEMOVE:
                WmExitSizeMove();
                DefWndProc(ref m);
                break;
            case PInvokeCore.WM_CREATE:
                WmCreate(ref m);
                break;
            case PInvokeCore.WM_ERASEBKGND:
                WmEraseBkgnd(ref m);
                break;
            case PInvokeCore.WM_PAINT:
                base.WndProc(ref m);
#if NET11_0_OR_GREATER
                // Fallback deferred-reveal trigger. RevealDeferredAppearance is idempotent and forces
                // a full-tree paint before uncloaking, so even if OnShown was delayed the window is
                // never revealed mid-paint and never stays stuck cloaked.
                RevealDeferredAppearance();
#endif
                break;

            case PInvokeCore.WM_NCDESTROY:
                WmNCDestroy(ref m);
                break;
            case PInvokeCore.WM_NCHITTEST:
                WmNCHitTest(ref m);
                break;
            case PInvokeCore.WM_SHOWWINDOW:
                WmShowWindow(ref m);
                break;
            case PInvokeCore.WM_SIZE:
                WmSize(ref m);
                break;
            case PInvokeCore.WM_SYSCOMMAND:
                WmSysCommand(ref m);
                break;
            case PInvokeCore.WM_GETMINMAXINFO:
                WmGetMinMaxInfo(ref m);
                break;
            case PInvokeCore.WM_WINDOWPOSCHANGED:
                WmWindowPosChanged(ref m);
                break;
            // case PInvokeCore.WM_WINDOWPOSCHANGING:
            //    WmWindowPosChanging(ref m);
            //    break;
            case PInvokeCore.WM_ENTERMENULOOP:
                WmEnterMenuLoop(ref m);
                break;
            case PInvokeCore.WM_EXITMENULOOP:
                WmExitMenuLoop(ref m);
                break;
            case PInvokeCore.WM_CAPTURECHANGED:
                base.WndProc(ref m);

                // This is a work-around for the Win32 scroll bar; it doesn't release
                // it's capture in response to a CAPTURECHANGED message, so we force
                // capture away if no button is down.

                if (Capture && MouseButtons == MouseButtons.None)
                {
                    Capture = false;
                }

                break;
            case PInvokeCore.WM_GETDPISCALEDSIZE:
                WmGetDpiScaledSize(ref m);
                break;
            case PInvokeCore.WM_DPICHANGED:
                WmDpiChanged(ref m);
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }

    // Unsupported types don't support nullability.
#nullable disable
    /// <summary>
    ///  This property is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code.
    /// </summary>
    [Obsolete(
        Obsoletions.MainMenuMessage,
        error: false,
        DiagnosticId = Obsoletions.UnsupportedControlsDiagnosticId,
        UrlFormat = Obsoletions.SharedUrlFormat)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public MainMenu Menu
    {
        get;
        set;
    }

    /// <summary>
    ///  This property is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code.
    /// </summary>
    [Obsolete(
        Obsoletions.MainMenuMessage,
        error: false,
        DiagnosticId = Obsoletions.UnsupportedControlsDiagnosticId,
        UrlFormat = Obsoletions.SharedUrlFormat)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public MainMenu MergedMenu
    {
        get;
    }
#nullable enable
}
