From a792166e19a87e3174e8245e6ca01700d511b118 Mon Sep 17 00:00:00 2001 From: Tanya Solyanik Date: Tue, 13 Feb 2024 18:50:57 -0800 Subject: [PATCH 01/30] TreeNodeAccessibleObject can't be created when the parent TreeView is not found. This could be the case when a node is being added or deleted from the Nodes collection Fixes #10876 --- .../Forms/Controls/TreeView/TreeNode.cs | 6 +++-- .../Forms/Controls/TreeView/TreeView.cs | 24 +++++++++++++------ .../TreeViewLabelEditAccessibleObject.cs | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs index 3a403eac303..7be9b5e5df4 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs @@ -1107,8 +1107,10 @@ public TreeView? TreeView } } - internal TreeNodeAccessibleObject AccessibilityObject - => _accessibleObject ??= new TreeNodeAccessibleObject(this, TreeView!); + internal TreeNodeAccessibleObject? AccessibilityObject => + _accessibleObject ??= TreeView is null + ? null + : new TreeNodeAccessibleObject(this, TreeView); /// /// Adds a new child node at the appropriate sorted position diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 7b95d2b739b..af9f4fd6cae 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -2098,7 +2098,7 @@ protected virtual void OnAfterLabelEdit(NodeLabelEditEventArgs e) // if editing hasn't been canceled. if (IsAccessibilityObjectCreated && !e.CancelEdit) { - e.Node!.AccessibilityObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); + e.Node!.AccessibilityObject?.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); } } @@ -2120,7 +2120,12 @@ protected virtual void OnAfterCheck(TreeViewEventArgs e) // Raise an event to announce a toggle state change. if (IsAccessibilityObjectCreated) { - AccessibleObject nodeAccessibleObject = e.Node!.AccessibilityObject; + AccessibleObject? nodeAccessibleObject = e.Node!.AccessibilityObject; + if (nodeAccessibleObject is null) + { + return; + } + ToggleState newState = nodeAccessibleObject.ToggleState; ToggleState oldState = newState == ToggleState.ToggleState_On ? ToggleState.ToggleState_Off @@ -2151,7 +2156,7 @@ protected internal virtual void OnAfterCollapse(TreeViewEventArgs e) // Raise an event to announce the expand-collapse state change. if (IsAccessibilityObjectCreated) { - e.Node!.AccessibilityObject.RaiseAutomationPropertyChangedEvent( + e.Node!.AccessibilityObject?.RaiseAutomationPropertyChangedEvent( UIA_PROPERTY_ID.UIA_ExpandCollapseExpandCollapseStatePropertyId, oldValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Expanded, newValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Collapsed); @@ -2176,7 +2181,7 @@ protected virtual void OnAfterExpand(TreeViewEventArgs e) // Raise an event to announce the expand-collapse state change. if (IsAccessibilityObjectCreated) { - e.Node!.AccessibilityObject.RaiseAutomationPropertyChangedEvent( + e.Node!.AccessibilityObject?.RaiseAutomationPropertyChangedEvent( UIA_PROPERTY_ID.UIA_ExpandCollapseExpandCollapseStatePropertyId, oldValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Collapsed, newValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Expanded); @@ -2217,7 +2222,12 @@ protected virtual void OnAfterSelect(TreeViewEventArgs e) // Raise an event to highlight & announce the selected node. if (IsAccessibilityObjectCreated) { - AccessibleObject nodeAccessibleObject = e.Node!.AccessibilityObject; + AccessibleObject? nodeAccessibleObject = e.Node!.AccessibilityObject; + if (nodeAccessibleObject is null) + { + return; + } + nodeAccessibleObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); nodeAccessibleObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_SelectionItem_ElementSelectedEventId); @@ -3094,7 +3104,7 @@ protected override void OnGotFocus(EventArgs e) // Raise an event to highlight & announce the selected node. if (IsAccessibilityObjectCreated) { - SelectedNode?.AccessibilityObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); + SelectedNode?.AccessibilityObject?.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); } } @@ -3452,7 +3462,7 @@ protected override unsafe void WndProc(ref Message m) if (m.LParamInternal == PInvoke.UiaRootObjectId && SupportsUiaProviders && !IsAccessibilityObjectCreated && Focused) { base.WndProc(ref m); - SelectedNode?.AccessibilityObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); + SelectedNode?.AccessibilityObject?.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); } else { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeViewLabelEditAccessibleObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeViewLabelEditAccessibleObject.cs index 3737b707efd..ce0ea931335 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeViewLabelEditAccessibleObject.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeViewLabelEditAccessibleObject.cs @@ -20,7 +20,7 @@ public TreeViewLabelEditAccessibleObject(TreeView owningTreeView, TreeViewLabelE private protected override string? AutomationId => _owningTreeView.TryGetTarget(out TreeView? target) - ? target._editNode?.AccessibilityObject.Name + ? target._editNode?.AccessibilityObject?.Name : null; internal override IRawElementProviderFragmentRoot.Interface? FragmentRoot => From 91d9ced9fb2cab19b0257c1623522dccd7fe0c0d Mon Sep 17 00:00:00 2001 From: Tanya Solyanik Date: Wed, 14 Feb 2024 10:58:15 -0800 Subject: [PATCH 02/30] Replaced null-forgiving operator from TreeViewEventArgs.Node, and NodeLabelEditEventArgs.Node with a null-check because these arguments could be created during node insertion according to this comment on NodeFromHandle --- .../Forms/Controls/TreeView/TreeView.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index af9f4fd6cae..4df5096ff4f 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -2096,9 +2096,9 @@ protected virtual void OnAfterLabelEdit(NodeLabelEditEventArgs e) // Raise an event to highlight & announce the edited node // if editing hasn't been canceled. - if (IsAccessibilityObjectCreated && !e.CancelEdit) + if (IsAccessibilityObjectCreated && !e.CancelEdit && e.Node is not null) { - e.Node!.AccessibilityObject?.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); + e.Node.AccessibilityObject?.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); } } @@ -2118,9 +2118,9 @@ protected virtual void OnAfterCheck(TreeViewEventArgs e) _onAfterCheck?.Invoke(this, e); // Raise an event to announce a toggle state change. - if (IsAccessibilityObjectCreated) + if (IsAccessibilityObjectCreated && e.Node is not null) { - AccessibleObject? nodeAccessibleObject = e.Node!.AccessibilityObject; + TreeNodeAccessibleObject? nodeAccessibleObject = e.Node.AccessibilityObject; if (nodeAccessibleObject is null) { return; @@ -2154,9 +2154,9 @@ protected internal virtual void OnAfterCollapse(TreeViewEventArgs e) _onAfterCollapse?.Invoke(this, e); // Raise an event to announce the expand-collapse state change. - if (IsAccessibilityObjectCreated) + if (IsAccessibilityObjectCreated && e.Node is not null) { - e.Node!.AccessibilityObject?.RaiseAutomationPropertyChangedEvent( + e.Node.AccessibilityObject?.RaiseAutomationPropertyChangedEvent( UIA_PROPERTY_ID.UIA_ExpandCollapseExpandCollapseStatePropertyId, oldValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Expanded, newValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Collapsed); @@ -2179,9 +2179,9 @@ protected virtual void OnAfterExpand(TreeViewEventArgs e) _onAfterExpand?.Invoke(this, e); // Raise an event to announce the expand-collapse state change. - if (IsAccessibilityObjectCreated) + if (IsAccessibilityObjectCreated && e.Node is not null) { - e.Node!.AccessibilityObject?.RaiseAutomationPropertyChangedEvent( + e.Node.AccessibilityObject?.RaiseAutomationPropertyChangedEvent( UIA_PROPERTY_ID.UIA_ExpandCollapseExpandCollapseStatePropertyId, oldValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Collapsed, newValue: (VARIANT)(int)ExpandCollapseState.ExpandCollapseState_Expanded); @@ -2220,9 +2220,9 @@ protected virtual void OnAfterSelect(TreeViewEventArgs e) _onAfterSelect?.Invoke(this, e); // Raise an event to highlight & announce the selected node. - if (IsAccessibilityObjectCreated) + if (IsAccessibilityObjectCreated && e.Node is not null) { - AccessibleObject? nodeAccessibleObject = e.Node!.AccessibilityObject; + TreeNodeAccessibleObject? nodeAccessibleObject = e.Node.AccessibilityObject; if (nodeAccessibleObject is null) { return; @@ -2856,14 +2856,14 @@ private unsafe void CustomDraw(ref Message m) { g.FillRectangle(SystemBrushes.Highlight, bounds); ControlPaint.DrawFocusRectangle(g, bounds, color, SystemColors.Highlight); - TextRenderer.DrawText(g, e.Node!.Text, font, bounds, color, TextFormatFlags.Default); + TextRenderer.DrawText(g, node.Text, font, bounds, color, TextFormatFlags.Default); } else { using var brush = BackColor.GetCachedSolidBrushScope(); g.FillRectangle(brush, bounds); - TextRenderer.DrawText(g, e.Node!.Text, font, bounds, color, TextFormatFlags.Default); + TextRenderer.DrawText(g, node.Text, font, bounds, color, TextFormatFlags.Default); } } } From 0d78f4f0e6974f4b065aad6ead6f7ab8817b5477 Mon Sep 17 00:00:00 2001 From: Tanya Solyanik Date: Wed, 14 Feb 2024 11:15:05 -0800 Subject: [PATCH 03/30] cover accessibility path in the unittests --- .../UnitTests/System/Windows/Forms/TreeViewTests.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TreeViewTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TreeViewTests.cs index 90d468c8876..4b012551e1d 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TreeViewTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TreeViewTests.cs @@ -5414,9 +5414,9 @@ public void TreeView_HitTest_InvokeIntIntNotEmptyInvalidWithHandle_Success(Point public static IEnumerable TreeViewEventArgs_TestData() { - yield return new object[] { null }; yield return new object[] { new TreeViewEventArgs(null) }; yield return new object[] { new TreeViewEventArgs(new TreeNode()) }; + yield return new object[] { new TreeViewEventArgs(new TreeNode(), TreeViewAction.ByMouse) }; } [WinFormsTheory] @@ -5432,6 +5432,8 @@ public void TreeView_OnAfterCheck_Invoke_CallsAfterCheck(TreeViewEventArgs event callCount++; }; + Assert.NotNull(control.AccessibilityObject); + // Call with handler. control.AfterCheck += handler; control.OnAfterCheck(eventArgs); @@ -5456,6 +5458,8 @@ public void TreeView_OnAfterCollapse_Invoke_CallsAfterCollapse(TreeViewEventArgs callCount++; }; + Assert.NotNull(control.AccessibilityObject); + // Call with handler. control.AfterCollapse += handler; control.OnAfterCollapse(eventArgs); @@ -5480,6 +5484,8 @@ public void TreeView_OnAfterExpand_Invoke_CallsAfterExpand(TreeViewEventArgs eve callCount++; }; + Assert.NotNull(control.AccessibilityObject); + // Call with handler. control.AfterExpand += handler; control.OnAfterExpand(eventArgs); @@ -5493,7 +5499,6 @@ public void TreeView_OnAfterExpand_Invoke_CallsAfterExpand(TreeViewEventArgs eve public static IEnumerable NodeLabelEditEventArgs_TestData() { - yield return new object[] { null }; yield return new object[] { new NodeLabelEditEventArgs(null) }; yield return new object[] { new NodeLabelEditEventArgs(new TreeNode()) }; yield return new object[] { new NodeLabelEditEventArgs(new TreeNode(), "label") }; @@ -5512,6 +5517,8 @@ public void TreeView_OnAfterLabelEdit_Invoke_CallsAfterLabelEdit(NodeLabelEditEv callCount++; }; + Assert.NotNull(control.AccessibilityObject); + // Call with handler. control.AfterLabelEdit += handler; control.OnAfterLabelEdit(eventArgs); @@ -5536,6 +5543,8 @@ public void TreeView_OnAfterSelect_Invoke_CallsOnAfterSelect(TreeViewEventArgs e callCount++; }; + Assert.NotNull(control.AccessibilityObject); + // Call with handler. control.AfterSelect += handler; control.OnAfterSelect(eventArgs); From bae7c63254d9ca1b873c08702d62cd34159a87af Mon Sep 17 00:00:00 2001 From: Tanya Solyanik Date: Wed, 14 Feb 2024 11:15:14 -0800 Subject: [PATCH 04/30] mechanical cleanup --- .../Forms/Controls/TreeView/TreeNode.cs | 14 +-- .../Forms/Controls/TreeView/TreeView.cs | 95 ++++++++----------- 2 files changed, 45 insertions(+), 64 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs index 7be9b5e5df4..a39a2f968eb 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs @@ -13,10 +13,10 @@ namespace System.Windows.Forms; /// -/// Implements a node of a . +/// Implements a node of a . /// -[TypeConverterAttribute(typeof(TreeNodeConverter))] -[Serializable] // This class participates in resx serialization. +[TypeConverter(typeof(TreeNodeConverter))] +[Serializable] // This class participates in ResX serialization. [DefaultProperty(nameof(Text))] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] public partial class TreeNode : MarshalByRefObject, ICloneable, ISerializable @@ -152,9 +152,9 @@ public TreeNode(string? text, int imageIndex, int selectedImageIndex, TreeNode[] Nodes.AddRange(children); } - /** - * Constructor used in deserialization - */ + /// + /// Constructor used in deserialization from resources. + /// protected TreeNode(SerializationInfo serializationInfo, StreamingContext context) : this() { @@ -1686,7 +1686,7 @@ public void ExpandAll() internal List GetSelfAndChildNodes() { - List nodes = new() { this }; + List nodes = [this]; AggregateChildNodesToList(this); return nodes; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 4df5096ff4f..0390deaa5bf 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -10,6 +10,7 @@ using System.Windows.Forms.VisualStyles; using Windows.Win32.System.Variant; using Windows.Win32.UI.Accessibility; +using static System.Windows.Forms.TreeNode; namespace System.Windows.Forms; @@ -1830,12 +1831,10 @@ protected override bool IsInputKey(Keys keyData) } /// - /// Fires the DrawNode event. + /// Raises the DrawNode event. /// - protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) - { + protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) => _onDrawNode?.Invoke(this, e); - } protected override void OnHandleCreated(EventArgs e) { @@ -2080,15 +2079,13 @@ protected override void OnMouseHover(EventArgs e) } /// - /// Fires the beforeLabelEdit event. + /// Raises the beforeLabelEdit event. /// - protected virtual void OnBeforeLabelEdit(NodeLabelEditEventArgs e) - { + protected virtual void OnBeforeLabelEdit(NodeLabelEditEventArgs e) => _onBeforeLabelEdit?.Invoke(this, e); - } /// - /// Fires the afterLabelEdit event. + /// Raises the afterLabelEdit event. /// protected virtual void OnAfterLabelEdit(NodeLabelEditEventArgs e) { @@ -2103,15 +2100,13 @@ protected virtual void OnAfterLabelEdit(NodeLabelEditEventArgs e) } /// - /// Fires the beforeCheck event. + /// Raises the beforeCheck event. /// - protected virtual void OnBeforeCheck(TreeViewCancelEventArgs e) - { + protected virtual void OnBeforeCheck(TreeViewCancelEventArgs e) => _onBeforeCheck?.Invoke(this, e); - } /// - /// Fires the afterCheck event. + /// Raises the afterCheck event. /// protected virtual void OnAfterCheck(TreeViewEventArgs e) { @@ -2139,15 +2134,13 @@ protected virtual void OnAfterCheck(TreeViewEventArgs e) } /// - /// Fires the beforeCollapse event. + /// Raises the beforeCollapse event. /// - protected internal virtual void OnBeforeCollapse(TreeViewCancelEventArgs e) - { + protected internal virtual void OnBeforeCollapse(TreeViewCancelEventArgs e) => _onBeforeCollapse?.Invoke(this, e); - } /// - /// Fires the afterCollapse event. + /// Raises the afterCollapse event. /// protected internal virtual void OnAfterCollapse(TreeViewEventArgs e) { @@ -2164,15 +2157,13 @@ protected internal virtual void OnAfterCollapse(TreeViewEventArgs e) } /// - /// Fires the beforeExpand event. + /// Raises the beforeExpand event. /// - protected virtual void OnBeforeExpand(TreeViewCancelEventArgs e) - { + protected virtual void OnBeforeExpand(TreeViewCancelEventArgs e) => _onBeforeExpand?.Invoke(this, e); - } /// - /// Fires the afterExpand event. + /// Raises the afterExpand event. /// protected virtual void OnAfterExpand(TreeViewEventArgs e) { @@ -2189,31 +2180,25 @@ protected virtual void OnAfterExpand(TreeViewEventArgs e) } /// - /// Fires the ItemDrag event. + /// Raises the ItemDrag event. /// - protected virtual void OnItemDrag(ItemDragEventArgs e) - { + protected virtual void OnItemDrag(ItemDragEventArgs e) => _onItemDrag?.Invoke(this, e); - } /// - /// Fires the NodeMouseHover event. + /// Raises the NodeMouseHover event. /// - protected virtual void OnNodeMouseHover(TreeNodeMouseHoverEventArgs e) - { + protected virtual void OnNodeMouseHover(TreeNodeMouseHoverEventArgs e) => _onNodeMouseHover?.Invoke(this, e); - } /// - /// Fires the beforeSelect event. + /// Raises the beforeSelect event. /// - protected virtual void OnBeforeSelect(TreeViewCancelEventArgs e) - { + protected virtual void OnBeforeSelect(TreeViewCancelEventArgs e) => _onBeforeSelect?.Invoke(this, e); - } /// - /// Fires the afterSelect event. + /// Raises the afterSelect event. /// protected virtual void OnAfterSelect(TreeViewEventArgs e) { @@ -2240,20 +2225,16 @@ protected virtual void OnAfterSelect(TreeViewEventArgs e) } /// - /// Fires the onNodeMouseClick event. + /// Raises the onNodeMouseClick event. /// - protected virtual void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) - { + protected virtual void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) => _onNodeMouseClick?.Invoke(this, e); - } /// - /// Fires the onNodeMouseDoubleClick event. + /// Raises the onNodeMouseDoubleClick event. /// - protected virtual void OnNodeMouseDoubleClick(TreeNodeMouseClickEventArgs e) - { + protected virtual void OnNodeMouseDoubleClick(TreeNodeMouseClickEventArgs e) => _onNodeMouseDoubleClick?.Invoke(this, e); - } /// /// Handles the OnBeforeCheck / OnAfterCheck for keyboard clicks @@ -2383,20 +2364,20 @@ private bool ShouldSerializeSelectedImageIndex() { if (_imageList is not null) { - return (SelectedImageIndex != 0); + return SelectedImageIndex != 0; } - return (SelectedImageIndex != ImageList.Indexer.DefaultIndex); + return SelectedImageIndex != ImageList.Indexer.DefaultIndex; } private bool ShouldSerializeImageIndex() { if (_imageList is not null) { - return (ImageIndex != 0); + return ImageIndex != 0; } - return (ImageIndex != ImageList.Indexer.DefaultIndex); + return ImageIndex != ImageList.Indexer.DefaultIndex; } /// @@ -2443,14 +2424,14 @@ private unsafe void TvnBeginDrag(MouseButtons buttons, NMTREEVIEWW* nmtv) OnItemDrag(new ItemDragEventArgs(buttons, node)); } - private unsafe IntPtr TvnExpanding(NMTREEVIEWW* nmtv) + private unsafe nint TvnExpanding(NMTREEVIEWW* nmtv) { TVITEMW item = nmtv->itemNew; // Check for invalid node handle if (item.hItem == IntPtr.Zero) { - return IntPtr.Zero; + return 0; } TreeViewCancelEventArgs? e = null; @@ -2465,7 +2446,7 @@ private unsafe IntPtr TvnExpanding(NMTREEVIEWW* nmtv) OnBeforeCollapse(e); } - return (IntPtr)(e.Cancel ? 1 : 0); + return e.Cancel ? 1 : 0; } private unsafe void TvnExpanded(NMTREEVIEWW* nmtv) @@ -2494,17 +2475,17 @@ private unsafe void TvnExpanded(NMTREEVIEWW* nmtv) } } - private unsafe IntPtr TvnSelecting(NMTREEVIEWW* nmtv) + private unsafe nint TvnSelecting(NMTREEVIEWW* nmtv) { if (_treeViewState[TREEVIEWSTATE_ignoreSelects]) { - return (IntPtr)1; + return 1; } // Check for invalid node handle if (nmtv->itemNew.hItem == IntPtr.Zero) { - return IntPtr.Zero; + return 0; } TreeNode? node = NodeFromHandle(nmtv->itemNew.hItem); @@ -2524,7 +2505,7 @@ private unsafe IntPtr TvnSelecting(NMTREEVIEWW* nmtv) TreeViewCancelEventArgs e = new(node, false, action); OnBeforeSelect(e); - return (IntPtr)(e.Cancel ? 1 : 0); + return e.Cancel ? 1 : 0; } private unsafe void TvnSelected(NMTREEVIEWW* nmtv) @@ -3115,7 +3096,7 @@ protected override void OnLostFocus(EventArgs e) } /// - /// Shows the context menu for the Treenode. + /// Shows the context menu for the . /// private void ShowContextMenu(TreeNode treeNode) { From 2048b5f8d1d9581e399d8691d501ec600529c0b3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:37:13 +0000 Subject: [PATCH 05/30] [main] Update dependencies from dotnet/arcade (#10896) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 6 +++--- global.json | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index bf529cff234..5b7ec4cd0a6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -183,29 +183,29 @@ Note: if the Uri is a new place, you will need to add a subscription from that p - + https://github.com/dotnet/arcade - c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb + d5b02a4900c4d521cb48b8f0d7e3f28175268f7c - + https://github.com/dotnet/arcade - c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb + d5b02a4900c4d521cb48b8f0d7e3f28175268f7c - + https://github.com/dotnet/arcade - c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb + d5b02a4900c4d521cb48b8f0d7e3f28175268f7c - + https://github.com/dotnet/arcade - c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb + d5b02a4900c4d521cb48b8f0d7e3f28175268f7c - + https://github.com/dotnet/arcade - c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb + d5b02a4900c4d521cb48b8f0d7e3f28175268f7c - + https://github.com/dotnet/arcade - c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb + d5b02a4900c4d521cb48b8f0d7e3f28175268f7c diff --git a/eng/Versions.props b/eng/Versions.props index a4f3844786c..15304deeed7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -56,9 +56,9 @@ - 9.0.0-beta.24112.1 - 9.0.0-beta.24112.1 - 9.0.0-beta.24112.1 + 9.0.0-beta.24114.1 + 9.0.0-beta.24114.1 + 9.0.0-beta.24114.1 17.4.0-preview-20220707-01 diff --git a/global.json b/global.json index eca3d4a3a5a..54a4b5c4932 100644 --- a/global.json +++ b/global.json @@ -14,9 +14,9 @@ "version": "9.0.100-alpha.1.23618.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24112.1", - "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24112.1", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24112.1", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24114.1", + "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24115.1" }, From 980b02212d847cc3e9f294bbb900ccb3249bc0a2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:37:35 +0000 Subject: [PATCH 06/30] [main] Update dependencies from dotnet/runtime (#10897) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 172 ++++++++++++++++++++-------------------- eng/Versions.props | 54 ++++++------- global.json | 2 +- 3 files changed, 114 insertions(+), 114 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5b7ec4cd0a6..501727ea65e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,178 +7,178 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + a3f74163d65fbbd81b9ed946e9d74f080be1dc70 diff --git a/eng/Versions.props b/eng/Versions.props index 15304deeed7..3805814d461 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,35 +15,35 @@ - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 5.0.0-preview.7.20320.5 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 6.0.0 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 - 9.0.0-preview.2.24115.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.1 diff --git a/global.json b/global.json index 54a4b5c4932..f5f0b4691ef 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24115.1" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24116.1" }, "native-tools": { "cmake": "latest" From f8e6d3b434f6e58bdc5ec1900586071d17650cc8 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Fri, 16 Feb 2024 10:58:48 -0800 Subject: [PATCH 07/30] Bump Nugetpackaging version (#10901) --- eng/Versions.props | 1 + .../UnitTests/System.Windows.Forms.Analyzers.CSharp.Tests.csproj | 1 + .../tests/UnitTests/System.Windows.Forms.Analyzers.Tests.csproj | 1 + 3 files changed, 3 insertions(+) diff --git a/eng/Versions.props b/eng/Versions.props index 3805814d461..6024bd4e01f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -103,6 +103,7 @@ $(MicrosoftCodeAnalysisAnalyzersVersion) 8.0.0-preview.23327.3 1.2.0-beta.507 + 6.3.4 diff --git a/src/System.Windows.Forms.Analyzers.CSharp/tests/UnitTests/System.Windows.Forms.Analyzers.CSharp.Tests.csproj b/src/System.Windows.Forms.Analyzers.CSharp/tests/UnitTests/System.Windows.Forms.Analyzers.CSharp.Tests.csproj index dacf2b356ce..53b7a42f399 100644 --- a/src/System.Windows.Forms.Analyzers.CSharp/tests/UnitTests/System.Windows.Forms.Analyzers.CSharp.Tests.csproj +++ b/src/System.Windows.Forms.Analyzers.CSharp/tests/UnitTests/System.Windows.Forms.Analyzers.CSharp.Tests.csproj @@ -15,6 +15,7 @@ + diff --git a/src/System.Windows.Forms.Analyzers/tests/UnitTests/System.Windows.Forms.Analyzers.Tests.csproj b/src/System.Windows.Forms.Analyzers/tests/UnitTests/System.Windows.Forms.Analyzers.Tests.csproj index 60cd05a24b5..45d417503e7 100644 --- a/src/System.Windows.Forms.Analyzers/tests/UnitTests/System.Windows.Forms.Analyzers.Tests.csproj +++ b/src/System.Windows.Forms.Analyzers/tests/UnitTests/System.Windows.Forms.Analyzers.Tests.csproj @@ -23,6 +23,7 @@ + From 2441a36314a2312e219278e0459ba0aef8a2b7f6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 17 Feb 2024 13:36:23 +0000 Subject: [PATCH 08/30] [main] Update dependencies from dotnet/runtime (#10903) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 172 ++++++++++++++++++++-------------------- eng/Versions.props | 54 ++++++------- global.json | 2 +- 3 files changed, 114 insertions(+), 114 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 501727ea65e..b50cd327993 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,178 +7,178 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 - + https://github.com/dotnet/runtime - a3f74163d65fbbd81b9ed946e9d74f080be1dc70 + d972a19c077e899d0b3fff97d955968e50906396 diff --git a/eng/Versions.props b/eng/Versions.props index 6024bd4e01f..157795109ec 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,35 +15,35 @@ - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 5.0.0-preview.7.20320.5 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 6.0.0 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 - 9.0.0-preview.2.24116.1 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24116.2 diff --git a/global.json b/global.json index f5f0b4691ef..5bc63471e2c 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24116.1" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24116.2" }, "native-tools": { "cmake": "latest" From 852f7ef241402c2336e085c82dca6f70b7400c21 Mon Sep 17 00:00:00 2001 From: Epica3055 <135201996+Epica3055@users.noreply.github.com> Date: Mon, 19 Feb 2024 09:47:52 +0800 Subject: [PATCH 09/30] fix bug: No text for new tabpage item that added by TabPages property in the properties window in the DemoConsole application (#10720) --- ...onEditor.CollectionEditorCollectionForm.cs | 204 +++--- .../DemoConsole/MainForm.Designer.cs | 603 +++++++++--------- .../DesignSurface/DemoConsole/MainForm.cs | 17 +- .../DesignSurfaceExt/PropertyGridExt.cs | 19 + 4 files changed, 437 insertions(+), 406 deletions(-) create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DesignSurfaceExt/PropertyGridExt.cs diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/CollectionEditor.CollectionEditorCollectionForm.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/CollectionEditor.CollectionEditorCollectionForm.cs index 6f7b878f142..0d8a6410350 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/CollectionEditor.CollectionEditorCollectionForm.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/CollectionEditor.CollectionEditorCollectionForm.cs @@ -28,7 +28,7 @@ private class CollectionEditorCollectionForm : CollectionForm private readonly CollectionEditor _editor; - private FilterListBox _listbox; + private FilterListBox _listBox; private SplitButton _addButton; private Button _removeButton; private Button _cancelButton; @@ -80,7 +80,7 @@ private bool IsImmutable { get { - foreach (ListItem item in _listbox.SelectedItems) + foreach (ListItem item in _listBox.SelectedItems) { Type type = item.Value.GetType(); @@ -128,7 +128,7 @@ private void AddItems(IList instances) { _createdItems ??= new List(); - _listbox.BeginUpdate(); + _listBox.BeginUpdate(); try { foreach (object? instance in instances) @@ -138,19 +138,19 @@ private void AddItems(IList instances) _dirty = true; _createdItems.Add(instance); ListItem created = new(_editor, instance); - _listbox.Items.Add(created); + _listBox.Items.Add(created); } } } finally { - _listbox.EndUpdate(); + _listBox.EndUpdate(); } if (instances.Count == 1) { // optimize for the case where we just added one thing... - UpdateItemWidths(_listbox.Items[_listbox.Items.Count - 1] as ListItem); + UpdateItemWidths(_listBox.Items[_listBox.Items.Count - 1] as ListItem); } else { @@ -160,23 +160,23 @@ private void AddItems(IList instances) SuspendEnabledUpdates(); try { - _listbox.ClearSelected(); - _listbox.SelectedIndex = _listbox.Items.Count - 1; + _listBox.ClearSelected(); + _listBox.SelectedIndex = _listBox.Items.Count - 1; - object[] items = new object[_listbox.Items.Count]; + object[] items = new object[_listBox.Items.Count]; for (int i = 0; i < items.Length; i++) { - items[i] = ((ListItem)_listbox.Items[i]).Value; + items[i] = ((ListItem)_listBox.Items[i]).Value; } Items = items; // If someone changes the edit value which resets the selindex, we // should keep the new index. - if (_listbox.Items.Count > 0 && _listbox.SelectedIndex != _listbox.Items.Count - 1) + if (_listBox.Items.Count > 0 && _listBox.SelectedIndex != _listBox.Items.Count - 1) { - _listbox.ClearSelected(); - _listbox.SelectedIndex = _listbox.Items.Count - 1; + _listBox.ClearSelected(); + _listBox.SelectedIndex = _listBox.Items.Count - 1; } } finally @@ -187,7 +187,7 @@ private void AddItems(IList instances) private void AdjustListBoxItemHeight() { - _listbox.ItemHeight = Font.Height + SystemInformation.BorderSize.Width * 2; + _listBox.ItemHeight = Font.Height + SystemInformation.BorderSize.Width * 2; } /// @@ -208,8 +208,8 @@ private bool AllowRemoveInstance(object value) private int CalcItemWidth(Graphics g, ListItem item) { - int c = Math.Max(2, _listbox.Items.Count); - SizeF sizeW = g.MeasureString(c.ToString(CultureInfo.CurrentCulture), _listbox.Font); + int c = Math.Max(2, _listBox.Items.Count); + SizeF sizeW = g.MeasureString(c.ToString(CultureInfo.CurrentCulture), _listBox.Font); int charactersInNumber = ((int)(Math.Log(c - 1) / s_log10) + 1); int w = 4 + charactersInNumber * (Font.Height / 2); @@ -217,7 +217,7 @@ private int CalcItemWidth(Graphics g, ListItem item) w = Math.Max(w, (int)Math.Ceiling(sizeW.Width)); w += SystemInformation.BorderSize.Width * 4; - SizeF size = g.MeasureString(GetDisplayText(item), _listbox.Font); + SizeF size = g.MeasureString(GetDisplayText(item), _listBox.Font); int pic = 0; if (item.Editor is not null && item.Editor.GetPaintValueSupported()) { @@ -242,7 +242,7 @@ private void CancelButton_click(object? sender, EventArgs e) } _dirty = false; - _listbox.Items.Clear(); + _listBox.Items.Clear(); if (_createdItems is not null) { @@ -317,24 +317,24 @@ private void DownButton_click(object? sender, EventArgs e) { SuspendEnabledUpdates(); _dirty = true; - int index = _listbox.SelectedIndex; - if (index == _listbox.Items.Count - 1) + int index = _listBox.SelectedIndex; + if (index == _listBox.Items.Count - 1) { return; } - int ti = _listbox.TopIndex; - object itemMove = _listbox.Items[index]; - _listbox.Items[index] = _listbox.Items[index + 1]; - _listbox.Items[index + 1] = itemMove; + int ti = _listBox.TopIndex; + object itemMove = _listBox.Items[index]; + _listBox.Items[index] = _listBox.Items[index + 1]; + _listBox.Items[index + 1] = itemMove; - if (ti < _listbox.Items.Count - 1) + if (ti < _listBox.Items.Count - 1) { - _listbox.TopIndex = ti + 1; + _listBox.TopIndex = ti + 1; } - _listbox.ClearSelected(); - _listbox.SelectedIndex = index + 1; + _listBox.ClearSelected(); + _listBox.SelectedIndex = index + 1; // enabling/disabling the buttons has moved the focus to the OK button, move it back to the sender Control ctrlSender = (Control)sender!; @@ -374,10 +374,10 @@ private static string GetDisplayText(ListItem? item) private void HookEvents() { - _listbox.KeyDown += Listbox_keyDown; - _listbox.DrawItem += Listbox_drawItem; - _listbox.SelectedIndexChanged += Listbox_SelectedIndexChanged; - _listbox.HandleCreated += Listbox_HandleCreated; + _listBox.KeyDown += ListBox_keyDown; + _listBox.DrawItem += ListBox_drawItem; + _listBox.SelectedIndexChanged += ListBox_SelectedIndexChanged; + _listBox.HandleCreated += ListBox_HandleCreated; _upButton.Click += UpButton_Click; _downButton.Click += DownButton_click; _propertyGrid.PropertyValueChanged += PropertyGrid_propertyValueChanged; @@ -391,7 +391,7 @@ private void HookEvents() } [MemberNotNull(nameof(_membersLabel))] - [MemberNotNull(nameof(_listbox))] + [MemberNotNull(nameof(_listBox))] [MemberNotNull(nameof(_upButton))] [MemberNotNull(nameof(_downButton))] [MemberNotNull(nameof(_propertiesLabel))] @@ -407,7 +407,7 @@ private void InitializeComponent() { ComponentResourceManager resources = new(typeof(CollectionEditor)); _membersLabel = new Label(); - _listbox = new FilterListBox(); + _listBox = new FilterListBox(); _upButton = new Button(); _downButton = new Button(); _propertiesLabel = new Label(); @@ -428,13 +428,13 @@ private void InitializeComponent() _membersLabel.Margin = new Padding(0, 0, 3, 3); _membersLabel.Name = "membersLabel"; - resources.ApplyResources(_listbox, "listbox"); - _listbox.SelectionMode = (CanSelectMultipleInstances() ? SelectionMode.MultiExtended : SelectionMode.One); - _listbox.DrawMode = DrawMode.OwnerDrawFixed; - _listbox.FormattingEnabled = true; - _listbox.Margin = new Padding(0, 3, 3, 3); - _listbox.Name = "listbox"; - _overArchingTableLayoutPanel.SetRowSpan(_listbox, 2); + resources.ApplyResources(_listBox, "listbox"); + _listBox.SelectionMode = (CanSelectMultipleInstances() ? SelectionMode.MultiExtended : SelectionMode.One); + _listBox.DrawMode = DrawMode.OwnerDrawFixed; + _listBox.FormattingEnabled = true; + _listBox.Margin = new Padding(0, 3, 3, 3); + _listBox.Name = "listbox"; + _overArchingTableLayoutPanel.SetRowSpan(_listBox, 2); resources.ApplyResources(_upButton, "upButton"); _upButton.Name = "upButton"; @@ -483,7 +483,7 @@ private void InitializeComponent() _overArchingTableLayoutPanel.Controls.Add(_addRemoveTableLayoutPanel, 0, 3); _overArchingTableLayoutPanel.Controls.Add(_propertiesLabel, 2, 0); _overArchingTableLayoutPanel.Controls.Add(_membersLabel, 0, 0); - _overArchingTableLayoutPanel.Controls.Add(_listbox, 0, 1); + _overArchingTableLayoutPanel.Controls.Add(_listBox, 0, 1); _overArchingTableLayoutPanel.Controls.Add(_propertyGrid, 2, 1); _overArchingTableLayoutPanel.Controls.Add(_okCancelTableLayoutPanel, 0, 4); _overArchingTableLayoutPanel.Controls.Add(_upButton, 1, 1); @@ -517,27 +517,27 @@ private void InitializeComponent() private void UpdateItemWidths(ListItem? item) { - if (!_listbox.IsHandleCreated) + if (!_listBox.IsHandleCreated) { return; } - using (Graphics g = _listbox.CreateGraphics()) + using (Graphics g = _listBox.CreateGraphics()) { - int old = _listbox.HorizontalExtent; + int old = _listBox.HorizontalExtent; if (item is not null) { int w = CalcItemWidth(g, item); if (w > old) { - _listbox.HorizontalExtent = w; + _listBox.HorizontalExtent = w; } } else { int max = 0; - foreach (ListItem i in _listbox.Items) + foreach (ListItem i in _listBox.Items) { int w = CalcItemWidth(g, i); if (w > max) @@ -546,26 +546,26 @@ private void UpdateItemWidths(ListItem? item) } } - _listbox.HorizontalExtent = max; + _listBox.HorizontalExtent = max; } } } /// - /// This draws a row of the listbox. + /// This draws a row of the listBox. /// - private void Listbox_drawItem(object? sender, DrawItemEventArgs e) + private void ListBox_drawItem(object? sender, DrawItemEventArgs e) { if (e.Index != -1) { - ListItem item = (ListItem)_listbox.Items[e.Index]; + ListItem item = (ListItem)_listBox.Items[e.Index]; Graphics g = e.Graphics; - int c = _listbox.Items.Count; + int c = _listBox.Items.Count; int maxC = (c > 1) ? c - 1 : c; // We add the +4 is a fudge factor... - SizeF sizeW = g.MeasureString(maxC.ToString(CultureInfo.CurrentCulture), _listbox.Font); + SizeF sizeW = g.MeasureString(maxC.ToString(CultureInfo.CurrentCulture), _listBox.Font); int charactersInNumber = ((int)(Math.Log(maxC) / s_log10) + 1); // Luckily, this is never called if count = 0 int w = 4 + charactersInNumber * (Font.Height / 2); @@ -621,11 +621,11 @@ private void Listbox_drawItem(object? sender, DrawItemEventArgs e) e.Bounds with { X = e.Bounds.X + offset, Width = e.Bounds.Width - offset }); } - // Check to see if we need to change the horizontal extent of the listbox + // Check to see if we need to change the horizontal extent of the listBox int width = offset + (int)g.MeasureString(itemText, Font).Width; - if (width > e.Bounds.Width && _listbox.HorizontalExtent < width) + if (width > e.Bounds.Width && _listBox.HorizontalExtent < width) { - _listbox.HorizontalExtent = width; + _listBox.HorizontalExtent = width; } } } @@ -633,9 +633,9 @@ private void Listbox_drawItem(object? sender, DrawItemEventArgs e) /// /// Handles keypress events for the list box. /// - private void Listbox_keyDown(object? sender, KeyEventArgs kevent) + private void ListBox_keyDown(object? sender, KeyEventArgs e) { - switch (kevent.KeyData) + switch (e.KeyData) { case Keys.Delete: PerformRemove(); @@ -649,7 +649,7 @@ private void Listbox_keyDown(object? sender, KeyEventArgs kevent) /// /// Event that fires when the selected list box index changes. /// - private void Listbox_SelectedIndexChanged(object? sender, EventArgs e) + private void ListBox_SelectedIndexChanged(object? sender, EventArgs e) { UpdateEnabled(); } @@ -657,7 +657,7 @@ private void Listbox_SelectedIndexChanged(object? sender, EventArgs e) /// /// Event that fires when the list box's window handle is created. /// - private void Listbox_HandleCreated(object? sender, EventArgs e) + private void ListBox_HandleCreated(object? sender, EventArgs e) { UpdateItemWidths(null); } @@ -678,10 +678,10 @@ private void OKButton_Click(object? sender, EventArgs e) if (_dirty) { - object[] items = new object[_listbox.Items.Count]; + object[] items = new object[_listBox.Items.Count]; for (int i = 0; i < items.Length; i++) { - items[i] = ((ListItem)_listbox.Items[i]).Value; + items[i] = ((ListItem)_listBox.Items[i]).Value; } Items = items; @@ -702,7 +702,7 @@ private void OKButton_Click(object? sender, EventArgs e) _createdItems?.Clear(); _originalItems?.Clear(); - _listbox.Items.Clear(); + _listBox.Items.Clear(); _dirty = false; } catch (Exception ex) @@ -748,7 +748,7 @@ protected override void OnEditValueChanged() _originalItems.Clear(); // Now update the list box. - _listbox.Items.Clear(); + _listBox.Items.Clear(); _propertyGrid.Site = new PropertyGridSite(Context, _propertyGrid); if (EditValue is not null) { @@ -758,13 +758,13 @@ protected override void OnEditValueChanged() object[] items = Items; for (int i = 0; i < items.Length; i++) { - _listbox.Items.Add(new ListItem(_editor, items[i])); + _listBox.Items.Add(new ListItem(_editor, items[i])); _originalItems.Add(items[i]); } - if (_listbox.Items.Count > 0) + if (_listBox.Items.Count > 0) { - _listbox.SelectedIndex = 0; + _listBox.SelectedIndex = 0; } } finally @@ -802,16 +802,16 @@ private void PerformAdd() /// private void PerformRemove() { - int index = _listbox.SelectedIndex; + int index = _listBox.SelectedIndex; if (index != -1) { SuspendEnabledUpdates(); try { - if (_listbox.SelectedItems.Count > 1) + if (_listBox.SelectedItems.Count > 1) { - List toBeDeleted = _listbox.SelectedItems.Cast().ToList(); + List toBeDeleted = _listBox.SelectedItems.Cast().ToList(); foreach (ListItem item in toBeDeleted) { RemoveInternal(item); @@ -819,16 +819,16 @@ private void PerformRemove() } else { - RemoveInternal((ListItem?)_listbox.SelectedItem); + RemoveInternal((ListItem?)_listBox.SelectedItem); } - if (index < _listbox.Items.Count) + if (index < _listBox.Items.Count) { - _listbox.SelectedIndex = index; + _listBox.SelectedIndex = index; } - else if (_listbox.Items.Count > 0) + else if (_listBox.Items.Count > 0) { - _listbox.SelectedIndex = _listbox.Items.Count - 1; + _listBox.SelectedIndex = _listBox.Items.Count - 1; } } finally @@ -845,14 +845,14 @@ private void PropertyGrid_propertyValueChanged(object? sender, PropertyValueChan { _dirty = true; - // Refresh selected listbox item so that it picks up any name change + // Refresh selected listBox item so that it picks up any name change SuspendEnabledUpdates(); try { - int selectedItem = _listbox.SelectedIndex; + int selectedItem = _listBox.SelectedIndex; if (selectedItem >= 0) { - _listbox.RefreshItem(_listbox.SelectedIndex); + _listBox.RefreshItem(_listBox.SelectedIndex); } } finally @@ -862,10 +862,10 @@ private void PropertyGrid_propertyValueChanged(object? sender, PropertyValueChan // if a property changes, invalidate the grid in case it affects the item's name. UpdateItemWidths(null); - _listbox.Invalidate(); + _listBox.Invalidate(); // also update the string above the grid. - _propertiesLabel.Text = string.Format(SR.CollectionEditorProperties, GetDisplayText((ListItem?)_listbox.SelectedItem)); + _propertiesLabel.Text = string.Format(SR.CollectionEditorProperties, GetDisplayText((ListItem?)_listBox.SelectedItem)); } /// @@ -883,7 +883,7 @@ private void RemoveInternal(ListItem? item) { DestroyInstance(item.Value); _createdItems.Remove(item.Value); - _listbox.Items.Remove(item); + _listBox.Items.Remove(item); } else { @@ -894,7 +894,7 @@ private void RemoveInternal(ListItem? item) _removedItems ??= new List(); _removedItems.Add(item.Value); - _listbox.Items.Remove(item); + _listBox.Items.Remove(item); } else { @@ -967,7 +967,7 @@ protected internal override DialogResult ShowEditorDialog(IWindowsFormsEditorSer } // This is cached across requests, so reset the initial focus. - ActiveControl = _listbox; + ActiveControl = _listBox; result = base.ShowEditorDialog(edSvc); } finally @@ -986,7 +986,7 @@ protected internal override DialogResult ShowEditorDialog(IWindowsFormsEditorSer /// private void UpButton_Click(object? sender, EventArgs e) { - int index = _listbox.SelectedIndex; + int index = _listBox.SelectedIndex; if (index == 0) { return; @@ -996,18 +996,18 @@ private void UpButton_Click(object? sender, EventArgs e) try { SuspendEnabledUpdates(); - int ti = _listbox.TopIndex; - object itemMove = _listbox.Items[index]; - _listbox.Items[index] = _listbox.Items[index - 1]; - _listbox.Items[index - 1] = itemMove; + int ti = _listBox.TopIndex; + object itemMove = _listBox.Items[index]; + _listBox.Items[index] = _listBox.Items[index - 1]; + _listBox.Items[index - 1] = itemMove; if (ti > 0) { - _listbox.TopIndex = ti - 1; + _listBox.TopIndex = ti - 1; } - _listbox.ClearSelected(); - _listbox.SelectedIndex = index - 1; + _listBox.ClearSelected(); + _listBox.SelectedIndex = index - 1; // enabling/disabling the buttons has moved the focus to the OK button, move it back to the sender Control ctrlSender = (Control)sender!; @@ -1034,14 +1034,14 @@ private void UpdateEnabled() return; } - bool editEnabled = (_listbox.SelectedItem is not null) && CollectionEditable; - _removeButton.Enabled = editEnabled && AllowRemoveInstance(((ListItem)_listbox.SelectedItem!).Value); - _upButton.Enabled = editEnabled && _listbox.Items.Count > 1; - _downButton.Enabled = editEnabled && _listbox.Items.Count > 1; + bool editEnabled = (_listBox.SelectedItem is not null) && CollectionEditable; + _removeButton.Enabled = editEnabled && AllowRemoveInstance(((ListItem)_listBox.SelectedItem!).Value); + _upButton.Enabled = editEnabled && _listBox.Items.Count > 1; + _downButton.Enabled = editEnabled && _listBox.Items.Count > 1; _propertyGrid.Enabled = editEnabled; _addButton.Enabled = CollectionEditable; - if (_listbox.SelectedItem is not null) + if (_listBox.SelectedItem is not null) { object[] items; @@ -1049,22 +1049,22 @@ private void UpdateEnabled() // otherwise, the user will be presented with a batch of read only properties, which isn't terribly useful. if (IsImmutable) { - items = new object[] { new SelectionWrapper(CollectionType, CollectionItemType, _listbox, _listbox.SelectedItems) }; + items = new object[] { new SelectionWrapper(CollectionType, CollectionItemType, _listBox, _listBox.SelectedItems) }; } else { - items = new object[_listbox.SelectedItems.Count]; + items = new object[_listBox.SelectedItems.Count]; for (int i = 0; i < items.Length; i++) { - items[i] = ((ListItem)_listbox.SelectedItems[i]!).Value; + items[i] = ((ListItem)_listBox.SelectedItems[i]!).Value; } } - int selectedItemCount = _listbox.SelectedItems.Count; + int selectedItemCount = _listBox.SelectedItems.Count; if (selectedItemCount is 1 or -1) { - // handle both single select listboxes and a single item selected in a multi-select listbox - _propertiesLabel.Text = string.Format(SR.CollectionEditorProperties, GetDisplayText((ListItem)_listbox.SelectedItem)); + // handle both single select listBoxes and a single item selected in a multi-select listBox + _propertiesLabel.Text = string.Format(SR.CollectionEditorProperties, GetDisplayText((ListItem)_listBox.SelectedItem)); } else { diff --git a/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.Designer.cs b/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.Designer.cs index 80e8b5b6e12..0f6615aa0cb 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.Designer.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.Designer.cs @@ -1,168 +1,166 @@ -namespace TestConsole; +using DesignSurfaceExt; -partial class MainForm { -/// -/// Required designer variable. -/// -private System.ComponentModel.IContainer components = null; +namespace TestConsole; -/// -/// Clean up any resources being used. -/// -/// true if managed resources should be disposed; otherwise, false. -protected override void Dispose ( bool disposing ) { - if ( disposing && ( components != null ) ) { - components.Dispose(); +partial class MainForm +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); } - base.Dispose ( disposing ); -} -#region Windows Form Designer generated code + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new(typeof(MainForm)); + this.splitContainer = new System.Windows.Forms.SplitContainer(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.tabPage4 = new System.Windows.Forms.TabPage(); + this.tabPage5 = new System.Windows.Forms.TabPage(); + this.propertyGrid = new PropertyGridExt(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolStripMenuItemUnDo = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolStripMenuItemReDo = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + this.ToolStripMenuItemCut = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolStripMenuItemCopy = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolStripMenuItemPaste = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolStripMenuItemDelete = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripMenuItemTools = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItemTabOrder = new System.Windows.Forms.ToolStripMenuItem(); + this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolStripMenuItemAbout = new System.Windows.Forms.ToolStripMenuItem(); + this.splitContainer.Panel1.SuspendLayout(); + this.splitContainer.Panel2.SuspendLayout(); + this.splitContainer.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.menuStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer + // + this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer.Location = new System.Drawing.Point(0, 28); + this.splitContainer.Margin = new System.Windows.Forms.Padding(4); + this.splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + this.splitContainer.Panel1.BackColor = System.Drawing.SystemColors.Window; + this.splitContainer.Panel1.Controls.Add(this.tabControl1); + // + // splitContainer.Panel2 + // + this.splitContainer.Panel2.Controls.Add(this.propertyGrid); + this.splitContainer.Size = new System.Drawing.Size(824, 502); + this.splitContainer.SplitterDistance = 593; + this.splitContainer.SplitterWidth = 5; + this.splitContainer.TabIndex = 0; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Controls.Add(this.tabPage4); + this.tabControl1.Controls.Add(this.tabPage5); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(593, 502); + this.tabControl1.TabIndex = 0; + // + // tabPage1 + // + this.tabPage1.Location = new System.Drawing.Point(4, 25); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(585, 473); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "tabPage1"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // tabPage2 + // + this.tabPage2.Location = new System.Drawing.Point(4, 25); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(585, 473); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "tabPage2"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // tabPage3 + // + this.tabPage3.Location = new System.Drawing.Point(4, 25); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Padding = new System.Windows.Forms.Padding(3); + this.tabPage3.Size = new System.Drawing.Size(585, 473); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "tabPage3"; + this.tabPage3.UseVisualStyleBackColor = true; + // + // tabPage4 + // + this.tabPage4.Location = new System.Drawing.Point(4, 25); + this.tabPage4.Name = "tabPage4"; + this.tabPage4.Padding = new System.Windows.Forms.Padding(3); + this.tabPage4.Size = new System.Drawing.Size(585, 473); + this.tabPage4.TabIndex = 3; + this.tabPage4.Text = "tabPage4"; + this.tabPage4.UseVisualStyleBackColor = true; + // + // tabPage5 + // + this.tabPage5.Location = new System.Drawing.Point(4, 25); + this.tabPage5.Name = "tabPage5"; + this.tabPage5.Padding = new System.Windows.Forms.Padding(3); + this.tabPage5.Size = new System.Drawing.Size(585, 473); + this.tabPage5.TabIndex = 3; + this.tabPage5.Text = "tabPage5"; + this.tabPage5.UseVisualStyleBackColor = true; -/// -/// Required method for Designer support - do not modify -/// the contents of this method with the code editor. -/// -private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new( typeof( MainForm ) ); - this.splitContainer = new System.Windows.Forms.SplitContainer(); - this.tabControl1 = new System.Windows.Forms.TabControl(); - this.tabPage1 = new System.Windows.Forms.TabPage(); - this.tabPage2 = new System.Windows.Forms.TabPage(); - this.tabPage3 = new System.Windows.Forms.TabPage(); - this.tabPage4 = new System.Windows.Forms.TabPage(); - this.tabPage5 = new System.Windows.Forms.TabPage(); - this.propertyGrid = new System.Windows.Forms.PropertyGrid(); - this.menuStrip1 = new System.Windows.Forms.MenuStrip(); - this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.ToolStripMenuItemUnDo = new System.Windows.Forms.ToolStripMenuItem(); - this.ToolStripMenuItemReDo = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.ToolStripMenuItemCut = new System.Windows.Forms.ToolStripMenuItem(); - this.ToolStripMenuItemCopy = new System.Windows.Forms.ToolStripMenuItem(); - this.ToolStripMenuItemPaste = new System.Windows.Forms.ToolStripMenuItem(); - this.ToolStripMenuItemDelete = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripMenuItemTools = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItemTabOrder = new System.Windows.Forms.ToolStripMenuItem(); - this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.ToolStripMenuItemAbout = new System.Windows.Forms.ToolStripMenuItem(); - this.splitContainer.Panel1.SuspendLayout(); - this.splitContainer.Panel2.SuspendLayout(); - this.splitContainer.SuspendLayout(); - this.tabControl1.SuspendLayout(); - this.menuStrip1.SuspendLayout(); - this.SuspendLayout(); - // - // splitContainer - // - this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer.Location = new System.Drawing.Point( 0, 28 ); - this.splitContainer.Margin = new System.Windows.Forms.Padding( 4 ); - this.splitContainer.Name = "splitContainer"; - // - // splitContainer.Panel1 - // - this.splitContainer.Panel1.BackColor = System.Drawing.SystemColors.Window; - this.splitContainer.Panel1.Controls.Add( this.tabControl1 ); - // - // splitContainer.Panel2 - // - this.splitContainer.Panel2.Controls.Add( this.propertyGrid ); - this.splitContainer.Size = new System.Drawing.Size( 824, 502 ); - this.splitContainer.SplitterDistance = 593; - this.splitContainer.SplitterWidth = 5; - this.splitContainer.TabIndex = 0; - // - // tabControl1 - // - this.tabControl1.Controls.Add( this.tabPage1 ); - this.tabControl1.Controls.Add( this.tabPage2 ); - this.tabControl1.Controls.Add( this.tabPage3 ); - this.tabControl1.Controls.Add( this.tabPage4 ); - this.tabControl1.Controls.Add( this.tabPage5 ); - this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; - this.tabControl1.Location = new System.Drawing.Point( 0, 0 ); - this.tabControl1.Name = "tabControl1"; - this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size( 593, 502 ); - this.tabControl1.TabIndex = 0; - // - // tabPage1 - // - this.tabPage1.Location = new System.Drawing.Point( 4, 25 ); - this.tabPage1.Name = "tabPage1"; - this.tabPage1.Padding = new System.Windows.Forms.Padding( 3 ); - this.tabPage1.Size = new System.Drawing.Size( 585, 473 ); - this.tabPage1.TabIndex = 0; - this.tabPage1.Text = "tabPage1"; - this.tabPage1.UseVisualStyleBackColor = true; - // - // tabPage2 - // - this.tabPage2.Location = new System.Drawing.Point( 4, 25 ); - this.tabPage2.Name = "tabPage2"; - this.tabPage2.Padding = new System.Windows.Forms.Padding( 3 ); - this.tabPage2.Size = new System.Drawing.Size( 585, 473 ); - this.tabPage2.TabIndex = 1; - this.tabPage2.Text = "tabPage2"; - this.tabPage2.UseVisualStyleBackColor = true; - // - // tabPage3 - // - this.tabPage3.Location = new System.Drawing.Point( 4, 25 ); - this.tabPage3.Name = "tabPage3"; - this.tabPage3.Padding = new System.Windows.Forms.Padding( 3 ); - this.tabPage3.Size = new System.Drawing.Size( 585, 473 ); - this.tabPage3.TabIndex = 2; - this.tabPage3.Text = "tabPage3"; - this.tabPage3.UseVisualStyleBackColor = true; - // - // tabPage4 - // - this.tabPage4.Location = new System.Drawing.Point( 4, 25 ); - this.tabPage4.Name = "tabPage4"; - this.tabPage4.Padding = new System.Windows.Forms.Padding( 3 ); - this.tabPage4.Size = new System.Drawing.Size( 585, 473 ); - this.tabPage4.TabIndex = 3; - this.tabPage4.Text = "tabPage4"; - this.tabPage4.UseVisualStyleBackColor = true; - // - // tabPage5 - // - this.tabPage5.Location = new System.Drawing.Point(4, 25); - this.tabPage5.Name = "tabPage5"; - this.tabPage5.Padding = new System.Windows.Forms.Padding(3); - this.tabPage5.Size = new System.Drawing.Size(585, 473); - this.tabPage5.TabIndex = 3; - this.tabPage5.Text = "tabPage5"; - this.tabPage5.UseVisualStyleBackColor = true; - // - // propertyGrid - // - this.propertyGrid.Dock = System.Windows.Forms.DockStyle.Fill; - this.propertyGrid.Location = new System.Drawing.Point( 0, 0 ); - this.propertyGrid.Margin = new System.Windows.Forms.Padding( 4 ); - this.propertyGrid.Name = "propertyGrid"; - this.propertyGrid.Size = new System.Drawing.Size( 226, 502 ); - this.propertyGrid.TabIndex = 0; - // - // menuStrip1 - // - this.menuStrip1.Items.AddRange( new System.Windows.Forms.ToolStripItem[] { + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.editToolStripMenuItem, this.toolStripMenuItemTools, - this.helpToolStripMenuItem} ); - this.menuStrip1.Location = new System.Drawing.Point( 0, 0 ); - this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Padding = new System.Windows.Forms.Padding( 8, 2, 0, 2 ); - this.menuStrip1.Size = new System.Drawing.Size( 824, 28 ); - this.menuStrip1.TabIndex = 1; - this.menuStrip1.Text = "menuStrip1"; - // - // editToolStripMenuItem - // - this.editToolStripMenuItem.DropDownItems.AddRange( new System.Windows.Forms.ToolStripItem[] { + this.helpToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Padding = new System.Windows.Forms.Padding(8, 2, 0, 2); + this.menuStrip1.Size = new System.Drawing.Size(824, 28); + this.menuStrip1.TabIndex = 1; + this.menuStrip1.Text = "menuStrip1"; + // + // editToolStripMenuItem + // + this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.ToolStripMenuItemUnDo, this.ToolStripMenuItemReDo, this.toolStripSeparator3, @@ -170,153 +168,152 @@ private void InitializeComponent() { this.ToolStripMenuItemCopy, this.ToolStripMenuItemPaste, this.ToolStripMenuItemDelete, - this.toolStripSeparator4} ); - this.editToolStripMenuItem.Name = "editToolStripMenuItem"; - this.editToolStripMenuItem.Size = new System.Drawing.Size( 47, 24 ); - this.editToolStripMenuItem.Text = "&Edit"; - // - // ToolStripMenuItemUnDo - // - this.ToolStripMenuItemUnDo.Name = "ToolStripMenuItemUnDo"; - this.ToolStripMenuItemUnDo.ShortcutKeys = ((System.Windows.Forms.Keys) ((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z))); - this.ToolStripMenuItemUnDo.Size = new System.Drawing.Size( 165, 24 ); - this.ToolStripMenuItemUnDo.Text = "Undo"; - this.ToolStripMenuItemUnDo.Click += new System.EventHandler( this.undoToolStripMenuItem_Click ); - // - // ToolStripMenuItemReDo - // - this.ToolStripMenuItemReDo.Name = "ToolStripMenuItemReDo"; - this.ToolStripMenuItemReDo.ShortcutKeys = ((System.Windows.Forms.Keys) ((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y))); - this.ToolStripMenuItemReDo.Size = new System.Drawing.Size( 165, 24 ); - this.ToolStripMenuItemReDo.Text = "Redo"; - this.ToolStripMenuItemReDo.Click += new System.EventHandler( this.redoToolStripMenuItem_Click ); - // - // toolStripSeparator3 - // - this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size( 162, 6 ); - // - // ToolStripMenuItemCut - // - this.ToolStripMenuItemCut.Image = ((System.Drawing.Image) (resources.GetObject( "ToolStripMenuItemCut.Image" ))); - this.ToolStripMenuItemCut.ImageTransparentColor = System.Drawing.Color.Magenta; - this.ToolStripMenuItemCut.Name = "ToolStripMenuItemCut"; - this.ToolStripMenuItemCut.ShortcutKeys = ((System.Windows.Forms.Keys) ((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X))); - this.ToolStripMenuItemCut.Size = new System.Drawing.Size( 165, 24 ); - this.ToolStripMenuItemCut.Text = "Cut"; - this.ToolStripMenuItemCut.Click += new System.EventHandler( this.OnMenuClick ); - // - // ToolStripMenuItemCopy - // - this.ToolStripMenuItemCopy.Image = ((System.Drawing.Image) (resources.GetObject( "ToolStripMenuItemCopy.Image" ))); - this.ToolStripMenuItemCopy.ImageTransparentColor = System.Drawing.Color.Magenta; - this.ToolStripMenuItemCopy.Name = "ToolStripMenuItemCopy"; - this.ToolStripMenuItemCopy.ShortcutKeys = ((System.Windows.Forms.Keys) ((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C))); - this.ToolStripMenuItemCopy.Size = new System.Drawing.Size( 165, 24 ); - this.ToolStripMenuItemCopy.Text = "Copy"; - this.ToolStripMenuItemCopy.Click += new System.EventHandler( this.OnMenuClick ); - // - // ToolStripMenuItemPaste - // - this.ToolStripMenuItemPaste.Image = ((System.Drawing.Image) (resources.GetObject( "ToolStripMenuItemPaste.Image" ))); - this.ToolStripMenuItemPaste.ImageTransparentColor = System.Drawing.Color.Magenta; - this.ToolStripMenuItemPaste.Name = "ToolStripMenuItemPaste"; - this.ToolStripMenuItemPaste.ShortcutKeys = ((System.Windows.Forms.Keys) ((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); - this.ToolStripMenuItemPaste.Size = new System.Drawing.Size( 165, 24 ); - this.ToolStripMenuItemPaste.Text = "Paste"; - this.ToolStripMenuItemPaste.Click += new System.EventHandler( this.OnMenuClick ); - // - // ToolStripMenuItemDelete - // - this.ToolStripMenuItemDelete.Name = "ToolStripMenuItemDelete"; - this.ToolStripMenuItemDelete.ShortcutKeys = System.Windows.Forms.Keys.Delete; - this.ToolStripMenuItemDelete.Size = new System.Drawing.Size( 165, 24 ); - this.ToolStripMenuItemDelete.Text = "Delete"; - this.ToolStripMenuItemDelete.Click += new System.EventHandler( this.OnMenuClick ); - // - // toolStripSeparator4 - // - this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size( 162, 6 ); - // - // toolStripMenuItemTools - // - this.toolStripMenuItemTools.DropDownItems.AddRange( new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItemTabOrder} ); - this.toolStripMenuItemTools.Name = "toolStripMenuItemTools"; - this.toolStripMenuItemTools.Size = new System.Drawing.Size( 57, 24 ); - this.toolStripMenuItemTools.Text = "&Tools"; - // - // toolStripMenuItemTabOrder - // - this.toolStripMenuItemTabOrder.Name = "toolStripMenuItemTabOrder"; - this.toolStripMenuItemTabOrder.Size = new System.Drawing.Size( 145, 24 ); - this.toolStripMenuItemTabOrder.Text = "Tab Order"; - this.toolStripMenuItemTabOrder.Click += new System.EventHandler( this.toolStripMenuItemTabOrder_Click ); - // - // helpToolStripMenuItem - // - this.helpToolStripMenuItem.DropDownItems.AddRange( new System.Windows.Forms.ToolStripItem[] { - this.ToolStripMenuItemAbout} ); - this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; - this.helpToolStripMenuItem.Size = new System.Drawing.Size( 53, 24 ); - this.helpToolStripMenuItem.Text = "&Help"; - // - // ToolStripMenuItemAbout - // - this.ToolStripMenuItemAbout.Name = "ToolStripMenuItemAbout"; - this.ToolStripMenuItemAbout.Size = new System.Drawing.Size( 128, 24 ); - this.ToolStripMenuItemAbout.Text = "About..."; - this.ToolStripMenuItemAbout.Click += new System.EventHandler( this.OnAbout ); - // - // MainForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF( 8F, 16F ); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size( 824, 530 ); - this.Controls.Add( this.splitContainer ); - this.Controls.Add( this.menuStrip1 ); - this.Icon = ((System.Drawing.Icon) (resources.GetObject( "$this.Icon" ))); - this.MainMenuStrip = this.menuStrip1; - this.Margin = new System.Windows.Forms.Padding( 4 ); - this.Name = "MainForm"; - this.Text = "Tiny Form Designer"; - this.Load += new System.EventHandler( this.MainForm_Load ); - this.splitContainer.Panel1.ResumeLayout( false ); - this.splitContainer.Panel2.ResumeLayout( false ); - this.splitContainer.ResumeLayout( false ); - this.tabControl1.ResumeLayout( false ); - this.menuStrip1.ResumeLayout( false ); - this.menuStrip1.PerformLayout(); - this.ResumeLayout( false ); - this.PerformLayout(); + this.toolStripSeparator4}); + this.editToolStripMenuItem.Name = "editToolStripMenuItem"; + this.editToolStripMenuItem.Size = new System.Drawing.Size(47, 24); + this.editToolStripMenuItem.Text = "&Edit"; + // + // ToolStripMenuItemUnDo + // + this.ToolStripMenuItemUnDo.Name = "ToolStripMenuItemUnDo"; + this.ToolStripMenuItemUnDo.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z))); + this.ToolStripMenuItemUnDo.Size = new System.Drawing.Size(165, 24); + this.ToolStripMenuItemUnDo.Text = "Undo"; + this.ToolStripMenuItemUnDo.Click += new System.EventHandler(this.undoToolStripMenuItem_Click); + // + // ToolStripMenuItemReDo + // + this.ToolStripMenuItemReDo.Name = "ToolStripMenuItemReDo"; + this.ToolStripMenuItemReDo.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y))); + this.ToolStripMenuItemReDo.Size = new System.Drawing.Size(165, 24); + this.ToolStripMenuItemReDo.Text = "Redo"; + this.ToolStripMenuItemReDo.Click += new System.EventHandler(this.redoToolStripMenuItem_Click); + // + // toolStripSeparator3 + // + this.toolStripSeparator3.Name = "toolStripSeparator3"; + this.toolStripSeparator3.Size = new System.Drawing.Size(162, 6); + // + // ToolStripMenuItemCut + // + this.ToolStripMenuItemCut.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripMenuItemCut.Image"))); + this.ToolStripMenuItemCut.ImageTransparentColor = System.Drawing.Color.Magenta; + this.ToolStripMenuItemCut.Name = "ToolStripMenuItemCut"; + this.ToolStripMenuItemCut.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X))); + this.ToolStripMenuItemCut.Size = new System.Drawing.Size(165, 24); + this.ToolStripMenuItemCut.Text = "Cut"; + this.ToolStripMenuItemCut.Click += new System.EventHandler(this.OnMenuClick); + // + // ToolStripMenuItemCopy + // + this.ToolStripMenuItemCopy.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripMenuItemCopy.Image"))); + this.ToolStripMenuItemCopy.ImageTransparentColor = System.Drawing.Color.Magenta; + this.ToolStripMenuItemCopy.Name = "ToolStripMenuItemCopy"; + this.ToolStripMenuItemCopy.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C))); + this.ToolStripMenuItemCopy.Size = new System.Drawing.Size(165, 24); + this.ToolStripMenuItemCopy.Text = "Copy"; + this.ToolStripMenuItemCopy.Click += new System.EventHandler(this.OnMenuClick); + // + // ToolStripMenuItemPaste + // + this.ToolStripMenuItemPaste.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripMenuItemPaste.Image"))); + this.ToolStripMenuItemPaste.ImageTransparentColor = System.Drawing.Color.Magenta; + this.ToolStripMenuItemPaste.Name = "ToolStripMenuItemPaste"; + this.ToolStripMenuItemPaste.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); + this.ToolStripMenuItemPaste.Size = new System.Drawing.Size(165, 24); + this.ToolStripMenuItemPaste.Text = "Paste"; + this.ToolStripMenuItemPaste.Click += new System.EventHandler(this.OnMenuClick); + // + // ToolStripMenuItemDelete + // + this.ToolStripMenuItemDelete.Name = "ToolStripMenuItemDelete"; + this.ToolStripMenuItemDelete.ShortcutKeys = System.Windows.Forms.Keys.Delete; + this.ToolStripMenuItemDelete.Size = new System.Drawing.Size(165, 24); + this.ToolStripMenuItemDelete.Text = "Delete"; + this.ToolStripMenuItemDelete.Click += new System.EventHandler(this.OnMenuClick); + // + // toolStripSeparator4 + // + this.toolStripSeparator4.Name = "toolStripSeparator4"; + this.toolStripSeparator4.Size = new System.Drawing.Size(162, 6); + // + // toolStripMenuItemTools + // + this.toolStripMenuItemTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripMenuItemTabOrder}); + this.toolStripMenuItemTools.Name = "toolStripMenuItemTools"; + this.toolStripMenuItemTools.Size = new System.Drawing.Size(57, 24); + this.toolStripMenuItemTools.Text = "&Tools"; + // + // toolStripMenuItemTabOrder + // + this.toolStripMenuItemTabOrder.Name = "toolStripMenuItemTabOrder"; + this.toolStripMenuItemTabOrder.Size = new System.Drawing.Size(145, 24); + this.toolStripMenuItemTabOrder.Text = "Tab Order"; + this.toolStripMenuItemTabOrder.Click += new System.EventHandler(this.toolStripMenuItemTabOrder_Click); + // + // helpToolStripMenuItem + // + this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.ToolStripMenuItemAbout}); + this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; + this.helpToolStripMenuItem.Size = new System.Drawing.Size(53, 24); + this.helpToolStripMenuItem.Text = "&Help"; + // + // ToolStripMenuItemAbout + // + this.ToolStripMenuItemAbout.Name = "ToolStripMenuItemAbout"; + this.ToolStripMenuItemAbout.Size = new System.Drawing.Size(128, 24); + this.ToolStripMenuItemAbout.Text = "About..."; + this.ToolStripMenuItemAbout.Click += new System.EventHandler(this.OnAbout); + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(824, 530); + this.Controls.Add(this.splitContainer); + this.Controls.Add(this.menuStrip1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStrip1; + this.Margin = new System.Windows.Forms.Padding(4); + this.Name = "MainForm"; + this.Text = "Tiny Form Designer"; + this.Load += new System.EventHandler(this.MainForm_Load); + this.splitContainer.Panel1.ResumeLayout(false); + this.splitContainer.Panel2.ResumeLayout(false); + this.splitContainer.ResumeLayout(false); + this.tabControl1.ResumeLayout(false); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); -} + } -#endregion + #endregion -private System.Windows.Forms.SplitContainer splitContainer; -private System.Windows.Forms.PropertyGrid propertyGrid; -private System.Windows.Forms.MenuStrip menuStrip1; -private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; -private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemUnDo; -private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemReDo; -private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; -private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemCut; -private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemCopy; -private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemPaste; -private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; -private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemDelete; -private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; -private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemAbout; -private System.Windows.Forms.TabControl tabControl1; -private System.Windows.Forms.TabPage tabPage1; -private System.Windows.Forms.TabPage tabPage2; -private System.Windows.Forms.TabPage tabPage3; -private System.Windows.Forms.TabPage tabPage4; -private System.Windows.Forms.TabPage tabPage5; -private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemTools; -private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemTabOrder; + private System.Windows.Forms.SplitContainer splitContainer; + private PropertyGridExt propertyGrid; + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemUnDo; + private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemReDo; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemCut; + private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemCopy; + private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemPaste; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; + private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemDelete; + private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemAbout; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.TabPage tabPage3; + private System.Windows.Forms.TabPage tabPage4; + private System.Windows.Forms.TabPage tabPage5; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemTools; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemTabOrder; } - diff --git a/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.cs b/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.cs index 419903599b5..79214b5f823 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.cs @@ -315,7 +315,22 @@ private void SelectRootComponent() // - find out the DesignSurfaceExt control hosted by the TabPage IDesignSurfaceExt isurf = _listOfDesignSurface[tabControl1.SelectedIndex]; if (isurf is not null) - propertyGrid.SelectedObject = isurf.GetIDesignerHost().RootComponent; + { + splitContainer.Panel2.Controls.Remove(propertyGrid); + propertyGrid = new() + { + DesignerHost = isurf.GetIDesignerHost(), + Dock = DockStyle.Fill, + Location = new Point(0, 0), + Margin = new Padding(4), + Name = "propertyGrid", + Size = new Size(226, 502), + TabIndex = 0, + SelectedObject = isurf.GetIDesignerHost().RootComponent + }; + + splitContainer.Panel2.Controls.Add(propertyGrid); + } } private void undoToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DesignSurfaceExt/PropertyGridExt.cs b/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DesignSurfaceExt/PropertyGridExt.cs new file mode 100644 index 00000000000..005e3451c17 --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DesignSurfaceExt/PropertyGridExt.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel.Design; +using System.Windows.Forms; + +namespace DesignSurfaceExt; +public class PropertyGridExt : PropertyGrid +{ + public IDesignerHost DesignerHost { get; set; } + + protected override void OnSelectedObjectsChanged(EventArgs e) => base.OnSelectedObjectsChanged(e); + + protected override object GetService(Type serviceType) + { + object service = DesignerHost?.GetService(serviceType); + return service ?? base.GetService(serviceType); + } +} From da7bb656430a3990534237d1418822688368932c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 13:36:22 +0000 Subject: [PATCH 10/30] [main] Update dependencies from dotnet/runtime (#10915) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 172 ++++++++++++++++++++-------------------- eng/Versions.props | 54 ++++++------- global.json | 2 +- 3 files changed, 114 insertions(+), 114 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b50cd327993..3dfcdf39389 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,178 +7,178 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 - + https://github.com/dotnet/runtime - d972a19c077e899d0b3fff97d955968e50906396 + 9dc6ea62a4d195ae4559f4609a56933c61889756 diff --git a/eng/Versions.props b/eng/Versions.props index 157795109ec..a54c69032e3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,35 +15,35 @@ - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 5.0.0-preview.7.20320.5 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 6.0.0 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 - 9.0.0-preview.2.24116.2 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.1 diff --git a/global.json b/global.json index 5bc63471e2c..3d4b6a3f100 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24116.2" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24120.1" }, "native-tools": { "cmake": "latest" From 905aac1753702a3b06dda63233d36ae0995e5aab Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Tue, 20 Feb 2024 17:11:35 -0800 Subject: [PATCH 11/30] Clean up code around the painting loop (#10917) Various cleanup with painting. - Add a SuspendLayoutScope to simplify scoping and validation - Don't update layout for the parent if you don't change size (SetBoundsCore) - Fix remaining info messages in Control - Don't paint transparent background twice in PaintBackground - Cache checking image transparency in PaintBackground - Suppress all relevant warnings in NotSupported.cs to avoid the 10000 warnings that pop when you accidentally open it Stops caching high contrast setting. By caching and starting the SystemEvents window this was causing a nested paint on the main form during startup if you you had a background image. The call is not so expensive to need creating a window look for changes. This also moves a few bitmap related APIs to Core to allow for Direct2D related scenarios. --- src/System.Drawing.Common/src/GlobalUsings.cs | 2 + .../src/NativeMethods.txt | 5 - .../src/Special/NotSupported.cs | 4 +- .../src/System/Drawing/Bitmap.cs | 16 +- .../src/System/Drawing/Drawing2D/WrapMode.cs | 21 +- .../src/System/Drawing/Icon.cs | 1 - .../src/System/Drawing/Image.cs | 21 +- .../System/Drawing/Imaging/ImageLockMode.cs | 22 +- .../src/System/Drawing/Imaging/PixelFormat.cs | 188 +++----- .../src/NativeMethods.txt | 11 +- .../Graphics/GdiPlus/GpBitmapExtensions.cs | 34 ++ .../Graphics/GdiPlus/GpImageExtensions.cs | 31 ++ .../Win32/Graphics/GdiPlus/PixelFormat.cs | 128 +++++ .../Win32/PInvoke.SystemParametersInfo.cs | 2 + .../src/GlobalSuppressions.cs | 6 +- .../Forms/Control.ControlCollection.cs | 104 ++-- .../Forms/Control.SuspendLayoutScope.cs | 42 ++ .../src/System/Windows/Forms/Control.cs | 453 +++++++----------- .../DataGridView/DataGridView.Methods.cs | 395 ++++++++------- .../Controls/PropertyGrid/PropertyGrid.cs | 136 +++--- .../PropertyGridInternal/HelpPane.cs | 4 +- .../PropertyGridView.DropDownHolder.cs | 7 +- .../src/System/Windows/Forms/Form.cs | 56 +-- .../Forms/Layout/Containers/SplitContainer.cs | 6 +- .../Windows/Forms/Layout/LayoutTransaction.cs | 2 +- .../src/System/Windows/Forms/MDI/MDIClient.cs | 17 +- .../Forms/Scrolling/ScrollableControl.cs | 9 +- .../System/Windows/Forms/SystemInformation.cs | 33 +- .../Windows/Forms/ControlTests.Handlers.cs | 10 +- .../Windows/Forms/ScrollableControlTests.cs | 8 +- .../System/Windows/Forms/TabPageTests.cs | 8 +- .../System/Windows/Forms/ToolStripTests.cs | 8 +- 32 files changed, 900 insertions(+), 890 deletions(-) create mode 100644 src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpBitmapExtensions.cs create mode 100644 src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpImageExtensions.cs create mode 100644 src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/PixelFormat.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/Control.SuspendLayoutScope.cs diff --git a/src/System.Drawing.Common/src/GlobalUsings.cs b/src/System.Drawing.Common/src/GlobalUsings.cs index 9b5ed3dc48b..a9c3f798d7a 100644 --- a/src/System.Drawing.Common/src/GlobalUsings.cs +++ b/src/System.Drawing.Common/src/GlobalUsings.cs @@ -19,11 +19,13 @@ global using DashStyle = System.Drawing.Drawing2D.DashStyle; global using EmfPlusRecordType = System.Drawing.Imaging.EmfPlusRecordType; global using ImageCodecInfo = System.Drawing.Imaging.ImageCodecInfo; +global using ImageLockMode = System.Drawing.Imaging.ImageLockMode; global using LineCap = System.Drawing.Drawing2D.LineCap; global using LineJoin = System.Drawing.Drawing2D.LineJoin; global using Matrix = System.Drawing.Drawing2D.Matrix; global using MatrixOrder = System.Drawing.Drawing2D.MatrixOrder; global using PenAlignment = System.Drawing.Drawing2D.PenAlignment; +global using PixelFormat = System.Drawing.Imaging.PixelFormat; global using PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode; global using TextRenderingHint = System.Drawing.Text.TextRenderingHint; diff --git a/src/System.Drawing.Common/src/NativeMethods.txt b/src/System.Drawing.Common/src/NativeMethods.txt index 4b00a2ebc25..c229f74b43a 100644 --- a/src/System.Drawing.Common/src/NativeMethods.txt +++ b/src/System.Drawing.Common/src/NativeMethods.txt @@ -55,10 +55,8 @@ GdipBeginContainer2 GdipBitmapApplyEffect GdipBitmapConvertFormat GdipBitmapGetPixel -GdipBitmapLockBits GdipBitmapSetPixel GdipBitmapSetResolution -GdipBitmapUnlockBits GdipClearPathMarkers GdipCloneBitmapArea GdipCloneBitmapAreaI @@ -250,7 +248,6 @@ GdipGetHatchForegroundColor GdipGetHatchStyle GdipGetHemfFromMetafile GdipGetImageAttributesAdjustedPalette -GdipGetImageBounds GdipGetImageDecoders GdipGetImageDecodersSize GdipGetImageDimension @@ -260,7 +257,6 @@ GdipGetImageHeight GdipGetImageHorizontalResolution GdipGetImagePalette GdipGetImagePaletteSize -GdipGetImagePixelFormat GdipGetImageRawFormat GdipGetImageThumbnail GdipGetImageType @@ -558,7 +554,6 @@ LevelsParams PALETTEENTRY PaletteFlags PaletteType -PixelFormat* PRINTER_ENUM_CONNECTIONS PRINTER_ENUM_LOCAL PRINTER_INFO_4W diff --git a/src/System.Drawing.Common/src/Special/NotSupported.cs b/src/System.Drawing.Common/src/Special/NotSupported.cs index c06f8032199..3dd33389543 100644 --- a/src/System.Drawing.Common/src/Special/NotSupported.cs +++ b/src/System.Drawing.Common/src/Special/NotSupported.cs @@ -5,7 +5,7 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ -#pragma warning disable CS8618,CS0169,CA1823,CA1066 +#pragma warning disable CS8618,CS0169,CA1725,CA1823,CA1066,IDE0001,IDE0002,IDE1006,IDE0034,IDE0044,IDE0051,IDE0055,IDE1006 namespace System.Drawing { @@ -3221,4 +3221,4 @@ public enum TextRenderingHint } } -#pragma warning restore CS8618 +#pragma warning restore CS8618,CS0169,CA1725,CA1823,CA1066,IDE0001,IDE0002,IDE1006,IDE0034,IDE0044,IDE0051,IDE0055,IDE1006 diff --git a/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs b/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs index 92f40ab43fd..79a0ec21b4f 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs @@ -8,6 +8,7 @@ using System.Runtime.Versioning; #endif using System.IO; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace System.Drawing; @@ -15,7 +16,7 @@ namespace System.Drawing; [Editor($"System.Drawing.Design.BitmapEditor, {AssemblyRef.SystemDrawingDesign}", $"System.Drawing.Design.UITypeEditor, {AssemblyRef.SystemDrawing}")] [Serializable] -[Runtime.CompilerServices.TypeForwardedFrom(AssemblyRef.SystemDrawing)] +[TypeForwardedFrom(AssemblyRef.SystemDrawing)] public sealed unsafe class Bitmap : Image, IPointer { private static readonly Color s_defaultTransparentColor = Color.LightGray; @@ -267,12 +268,11 @@ public BitmapData LockBits(Rectangle rect, ImageLockMode flags, PixelFormat form fixed (void* data = &bitmapData.GetPinnableReference()) { - PInvoke.GdipBitmapLockBits( - this.Pointer(), - rect.IsEmpty ? null : (Rect*)&rect, - (uint)flags, - (int)format, - (GdiPlus.BitmapData*)data).ThrowIfFailed(); + this.LockBits( + rect, + (GdiPlus.ImageLockMode)flags, + (GdiPlus.PixelFormat)format, + ref Unsafe.AsRef(data)); } GC.KeepAlive(this); @@ -285,7 +285,7 @@ public void UnlockBits(BitmapData bitmapdata) fixed (void* data = &bitmapdata.GetPinnableReference()) { - PInvoke.GdipBitmapUnlockBits(this.Pointer(), (GdiPlus.BitmapData*)data).ThrowIfFailed(); + this.UnlockBits(ref Unsafe.AsRef(data)); } GC.KeepAlive(this); diff --git a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/WrapMode.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/WrapMode.cs index c49d848b585..6ef54ddc5f2 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/WrapMode.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/WrapMode.cs @@ -5,9 +5,28 @@ namespace System.Drawing.Drawing2D; public enum WrapMode { + /// + /// Tiles the gradient or texture. + /// Tile = GdiPlus.WrapMode.WrapModeTile, + + /// + /// Reverses the texture or gradient horizontally and then tiles the texture or gradient. + /// TileFlipX = GdiPlus.WrapMode.WrapModeTileFlipX, + + /// + /// Reverses the texture or gradient vertically and then tiles the texture or gradient. + /// TileFlipY = GdiPlus.WrapMode.WrapModeTileFlipY, + + /// + /// Reverses the texture or gradient horizontally and vertically and then tiles the texture or gradient. + /// TileFlipXY = GdiPlus.WrapMode.WrapModeTileFlipXY, - Clamp = GdiPlus.WrapMode.WrapModeClamp, + + /// + /// The texture or gradient is not tiled. + /// + Clamp = GdiPlus.WrapMode.WrapModeClamp } diff --git a/src/System.Drawing.Common/src/System/Drawing/Icon.cs b/src/System.Drawing.Common/src/System/Drawing/Icon.cs index d725ec44dc3..e64752e40a6 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Icon.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Icon.cs @@ -3,7 +3,6 @@ using System.Buffers; using System.ComponentModel; -using System.Drawing.Imaging; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/System.Drawing.Common/src/System/Drawing/Image.cs b/src/System.Drawing.Common/src/System/Drawing/Image.cs index d345db6bdd3..09c6a3e56a6 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Image.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Image.cs @@ -387,7 +387,7 @@ public void SaveAdd(Imaging.EncoderParameters? encoderParams) } /// - /// Adds an to the specified . + /// Adds an to the specified . /// public void SaveAdd(Image image, Imaging.EncoderParameters? encoderParams) { @@ -543,16 +543,7 @@ public ImageFormat RawFormat /// /// Gets the pixel format for this . /// - public PixelFormat PixelFormat - { - get - { - PixelFormat format; - Status status = PInvoke.GdipGetImagePixelFormat(_nativeImage, (int*)&format); - GC.KeepAlive(this); - return (status != Status.Ok) ? PixelFormat.Undefined : format; - } - } + public PixelFormat PixelFormat => (PixelFormat)this.GetPixelFormat(); /// /// Gets an array of the property IDs stored in this . @@ -619,11 +610,9 @@ public Imaging.PropertyItem[] PropertyItems /// public RectangleF GetBounds(ref GraphicsUnit pageUnit) { - RectF bounds; - Unit unit = (Unit)pageUnit; - PInvoke.GdipGetImageBounds(_nativeImage, &bounds, &unit).ThrowIfFailed(); - pageUnit = (GraphicsUnit)unit; - GC.KeepAlive(this); + // The Unit is hard coded to GraphicsUnit.Pixel in GDI+. + RectangleF bounds = this.GetImageBounds(); + pageUnit = GraphicsUnit.Pixel; return bounds; } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageLockMode.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageLockMode.cs index ed068239c4b..79661d98696 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageLockMode.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageLockMode.cs @@ -1,28 +1,30 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Drawing.Imaging; -// Access modes used when calling IImage::LockBits /// -/// Indicates the access mode for an . +/// Indicates the access mode for an . /// public enum ImageLockMode { /// - /// Specifies the image is read-only. + /// Specifies the image is read-only. /// - ReadOnly = 0x0001, + ReadOnly = GdiPlus.ImageLockMode.ImageLockModeRead, + /// - /// Specifies the image is write-only. + /// Specifies the image is write-only. /// - WriteOnly = 0x0002, + WriteOnly = GdiPlus.ImageLockMode.ImageLockModeWrite, + /// - /// Specifies the image is read-write. + /// Specifies the image is read-write. /// ReadWrite = ReadOnly | WriteOnly, + /// - /// Indicates the image resides in a user input buffer, to which the user controls access. + /// Indicates the image resides in a user input buffer, to which the user controls access. /// - UserInputBuffer = 0x0004, + UserInputBuffer = GdiPlus.ImageLockMode.ImageLockModeUserInputBuf } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/PixelFormat.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/PixelFormat.cs index 4986a7c75bc..d9907797e66 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/PixelFormat.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/PixelFormat.cs @@ -8,124 +8,72 @@ namespace System.Drawing.Imaging; /// public enum PixelFormat { - /// - /// Specifies that pixel data contains color indexed values which means they are an index to colors in the - /// system color table, as opposed to individual color values. - /// - Indexed = (int)PInvoke.PixelFormatIndexed, - - /// - /// Specifies that pixel data contains GDI colors. - /// - Gdi = (int)PInvoke.PixelFormatGDI, - - /// - /// Specifies that pixel data contains alpha values that are not pre-multiplied. - /// - Alpha = (int)PInvoke.PixelFormatAlpha, - - /// - /// Specifies that pixel format contains pre-multiplied alpha values. - /// - PAlpha = (int)PInvoke.PixelFormatPAlpha, - - /// - /// Specifies that pixel format contains extended color values of 16 bits per channel. - /// - Extended = (int)PInvoke.PixelFormatExtended, - - Canonical = (int)PInvoke.PixelFormatCanonical, - - /// - /// Specifies that pixel format is undefined. - /// - Undefined = (int)PInvoke.PixelFormatUndefined, - - /// - /// Specifies that pixel format doesn't matter. - /// - DontCare = (int)PInvoke.PixelFormatDontCare, - - /// - /// Specifies that pixel format is 1 bit per pixel indexed color. The color table therefore has two colors in it. - /// - Format1bppIndexed = 1 | (1 << 8) | Indexed | Gdi, - - /// - /// Specifies that pixel format is 4 bits per pixel indexed color. The color table therefore has 16 colors in it. - /// - Format4bppIndexed = 2 | (4 << 8) | Indexed | Gdi, - - /// - /// Specifies that pixel format is 8 bits per pixel indexed color. The color table therefore has 256 colors in it. - /// - Format8bppIndexed = 3 | (8 << 8) | Indexed | Gdi, - - /// - /// Specifies that pixel format is 16 bits per pixel. The color information specifies 65536 shades of gray. - /// - Format16bppGrayScale = 4 | (16 << 8) | Extended, - - /// - /// Specifies that pixel format is 16 bits per pixel. The color information specifies 32768 shades of color of - /// which 5 bits are red, 5 bits are green and 5 bits are blue. - /// - Format16bppRgb555 = 5 | (16 << 8) | Gdi, - - Format16bppRgb565 = 6 | (16 << 8) | Gdi, - - /// - /// Specifies that pixel format is 16 bits per pixel. The color information specifies 32768 shades of color of - /// which 5 bits are red, 5 bits are green, 5 bits are blue and 1 bit is alpha. - /// - Format16bppArgb1555 = 7 | (16 << 8) | Alpha | Gdi, - - /// - /// Specifies that pixel format is 24 bits per pixel. The color information specifies 16777216 shades of color - /// of which 8 bits are red, 8 bits are green and 8 bits are blue. - /// - Format24bppRgb = 8 | (24 << 8) | Gdi, - - /// - /// Specifies that pixel format is 24 bits per pixel. The color information specifies 16777216 shades of color - /// of which 8 bits are red, 8 bits are green and 8 bits are blue. - /// - Format32bppRgb = 9 | (32 << 8) | Gdi, - - /// - /// Specifies that pixel format is 32 bits per pixel. The color information specifies 16777216 shades of color - /// of which 8 bits are red, 8 bits are green and 8 bits are blue. The 8 additional bits are alpha bits. - /// - Format32bppArgb = 10 | (32 << 8) | Alpha | Gdi | Canonical, - - /// - /// Specifies that pixel format is 32 bits per pixel. The color information specifies 16777216 shades of color - /// of which 8 bits are red, 8 bits are green and 8 bits are blue. The 8 additional bits are pre-multiplied alpha bits. - /// - Format32bppPArgb = 11 | (32 << 8) | Alpha | PAlpha | Gdi, - - /// - /// Specifies that pixel format is 48 bits per pixel. The color information specifies 16777216 shades of color - /// of which 8 bits are red, 8 bits are green and 8 bits are blue. The 8 additional bits are alpha bits. - /// - Format48bppRgb = 12 | (48 << 8) | Extended, - - /// - /// Specifies pixel format is 64 bits per pixel. The color information specifies 16777216 shades of color of - /// which 16 bits are red, 16 bits are green and 16 bits are blue. The 16 additional bits are alpha bits. - /// - Format64bppArgb = 13 | (64 << 8) | Alpha | Canonical | Extended, - - /// - /// Specifies that pixel format is 64 bits per pixel. The color information specifies 16777216 shades of color - /// of which 16 bits are red, 16 bits are green and 16 bits are blue. The 16 additional bits are pre-multiplied - /// alpha bits. - /// - Format64bppPArgb = 14 | (64 << 8) | Alpha | PAlpha | Extended, - - /// - /// Specifies that pixel format is 64 bits per pixel. The color information specifies 16777216 shades of color - /// of which 16 bits are red, 16 bits are green and 16 bits are blue. The 16 additional bits are alpha bits. - /// - Max = 15, + /// + Indexed = GdiPlus.PixelFormat.Indexed, + + /// + Gdi = GdiPlus.PixelFormat.Gdi, + + /// + Alpha = GdiPlus.PixelFormat.Alpha, + + /// + PAlpha = GdiPlus.PixelFormat.PAlpha, + + /// + Extended = GdiPlus.PixelFormat.Extended, + + /// + Canonical = GdiPlus.PixelFormat.Canonical, + + /// + Undefined = GdiPlus.PixelFormat.Undefined, + + /// + DontCare = GdiPlus.PixelFormat.DontCare, + + /// + Format1bppIndexed = GdiPlus.PixelFormat.Format1bppIndexed, + + /// + Format4bppIndexed = GdiPlus.PixelFormat.Format4bppIndexed, + + /// + Format8bppIndexed = GdiPlus.PixelFormat.Format8bppIndexed, + + /// + Format16bppGrayScale = GdiPlus.PixelFormat.Format16bppGrayScale, + + /// + Format16bppRgb555 = GdiPlus.PixelFormat.Format16bppRgb555, + + /// + Format16bppRgb565 = GdiPlus.PixelFormat.Format16bppRgb565, + + /// + Format16bppArgb1555 = GdiPlus.PixelFormat.Format16bppArgb1555, + + /// + Format24bppRgb = GdiPlus.PixelFormat.Format24bppRgb, + + /// + Format32bppRgb = GdiPlus.PixelFormat.Format32bppRgb, + + /// + Format32bppArgb = GdiPlus.PixelFormat.Format32bppArgb, + + /// + Format32bppPArgb = GdiPlus.PixelFormat.Format32bppPArgb, + + /// + Format48bppRgb = GdiPlus.PixelFormat.Format48bppRgb, + + /// + Format64bppArgb = GdiPlus.PixelFormat.Format64bppArgb, + + /// + Format64bppPArgb = GdiPlus.PixelFormat.Format64bppPArgb, + + /// + Max = GdiPlus.PixelFormat.Max, } diff --git a/src/System.Private.Windows.Core/src/NativeMethods.txt b/src/System.Private.Windows.Core/src/NativeMethods.txt index 86b41eb0cd7..e7a4cfb28b1 100644 --- a/src/System.Private.Windows.Core/src/NativeMethods.txt +++ b/src/System.Private.Windows.Core/src/NativeMethods.txt @@ -60,15 +60,19 @@ EncoderParameters fdex* FDEX_PROP_FLAGS FILETIME +GdipBitmapLockBits +GdipBitmapUnlockBits GdipCreateFromHWND GdipDeleteGraphics +GdipGetImageBounds GdipGetImageEncoders GdipGetImageEncodersSize +GdipGetImagePixelFormat GdipGetImageRawFormat GdipGetRegionHRgn GdipIsInfiniteRegion -GetClientRect GdipSaveImageToStream +GetClientRect GetClipRgn GetDC GetDCEx @@ -94,6 +98,7 @@ GlobalLock GlobalReAlloc GlobalSize GlobalUnlock +GpBitmap GpGraphics GpImage GpRegion @@ -116,6 +121,7 @@ IDI_* IEnumUnknown IGlobalInterfaceTable ImageFormat* +ImageLockMode INPLACE_E_NOTOOLSPACE IntersectClipRect IStream @@ -138,12 +144,13 @@ OLE_E_ADVISENOTSUPPORTED OLE_E_INVALIDRECT OLE_E_NOCONNECTION OLE_E_PROMPTSAVECANCELLED +PixelFormat* POINTS PRINTDLGEX_FLAGS PropVariantClear PWSTR -Rect RECT +Rect RectF REGDB_E_CLASSNOTREG ReleaseDC diff --git a/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpBitmapExtensions.cs b/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpBitmapExtensions.cs new file mode 100644 index 00000000000..8a4f4ba89c6 --- /dev/null +++ b/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpBitmapExtensions.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing; +using System.Runtime.CompilerServices; + +namespace Windows.Win32.Graphics.GdiPlus; + +internal static unsafe class GpBitmapExtensions +{ + public static void LockBits( + this IPointer bitmap, + Rectangle rect, + ImageLockMode flags, + PixelFormat format, + ref BitmapData data) + { + // LockBits always creates a temporary copy of the data. + PInvokeCore.GdipBitmapLockBits( + bitmap.Pointer, + rect.IsEmpty ? null : (Rect*)&rect, + (uint)flags, + (int)format, + (BitmapData*)Unsafe.AsPointer(ref data)).ThrowIfFailed(); + + GC.KeepAlive(bitmap); + } + + public static void UnlockBits(this IPointer bitmap, ref BitmapData data) + { + PInvokeCore.GdipBitmapUnlockBits(bitmap.Pointer, (BitmapData*)Unsafe.AsPointer(ref data)).ThrowIfFailed(); + GC.KeepAlive(bitmap); + } +} diff --git a/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpImageExtensions.cs b/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpImageExtensions.cs new file mode 100644 index 00000000000..c6f9b78b787 --- /dev/null +++ b/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/GpImageExtensions.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing; +using System.Runtime.CompilerServices; + +namespace Windows.Win32.Graphics.GdiPlus; + +internal static unsafe class GpImageExtensions +{ + [SkipLocalsInit] + internal static RectangleF GetImageBounds(this IPointer image) + { + RectangleF bounds; + Unit unit; + + PInvokeCore.GdipGetImageBounds(image.Pointer, (RectF*)&bounds, &unit).ThrowIfFailed(); + GC.KeepAlive(image); + return bounds; + } + + [SkipLocalsInit] + internal static PixelFormat GetPixelFormat(this IPointer image) + { + int format; + + Status status = PInvokeCore.GdipGetImagePixelFormat(image.Pointer, &format); + GC.KeepAlive(image); + return status == Status.Ok ? (PixelFormat)format : PixelFormat.Undefined; + } +} diff --git a/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/PixelFormat.cs b/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/PixelFormat.cs new file mode 100644 index 00000000000..e404ff0e819 --- /dev/null +++ b/src/System.Private.Windows.Core/src/Windows/Win32/Graphics/GdiPlus/PixelFormat.cs @@ -0,0 +1,128 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Windows.Win32.Graphics.GdiPlus; + +internal enum PixelFormat +{ + /// + /// Specifies that pixel data contains color indexed values which means they are an index to colors in the + /// system color table, as opposed to individual color values. + /// + Indexed = (int)PInvokeCore.PixelFormatIndexed, + + /// + /// Specifies that pixel data contains GDI colors. + /// + Gdi = (int)PInvokeCore.PixelFormatGDI, + + /// + /// Specifies that pixel data contains alpha values that are not pre-multiplied. + /// + Alpha = (int)PInvokeCore.PixelFormatAlpha, + + /// + /// Specifies that pixel format contains pre-multiplied alpha values. + /// + PAlpha = (int)PInvokeCore.PixelFormatPAlpha, + + /// + /// Specifies that pixel format contains extended color values of 16 bits per channel. + /// + Extended = (int)PInvokeCore.PixelFormatExtended, + + Canonical = (int)PInvokeCore.PixelFormatCanonical, + + /// + /// Specifies that pixel format is undefined. + /// + Undefined = (int)PInvokeCore.PixelFormatUndefined, + + /// + /// Specifies that pixel format doesn't matter. + /// + DontCare = (int)PInvokeCore.PixelFormatDontCare, + + /// + /// Specifies that pixel format is 1 bit per pixel indexed color. The color table therefore has two colors in it. + /// + Format1bppIndexed = 1 | (1 << 8) | Indexed | Gdi, + + /// + /// Specifies that pixel format is 4 bits per pixel indexed color. The color table therefore has 16 colors in it. + /// + Format4bppIndexed = 2 | (4 << 8) | Indexed | Gdi, + + /// + /// Specifies that pixel format is 8 bits per pixel indexed color. The color table therefore has 256 colors in it. + /// + Format8bppIndexed = 3 | (8 << 8) | Indexed | Gdi, + + /// + /// Specifies that pixel format is 16 bits per pixel. The color information specifies 65536 shades of gray. + /// + Format16bppGrayScale = 4 | (16 << 8) | Extended, + + /// + /// Specifies that pixel format is 16 bits per pixel. The color information specifies 32768 shades of color of + /// which 5 bits are red, 5 bits are green and 5 bits are blue. + /// + Format16bppRgb555 = 5 | (16 << 8) | Gdi, + + Format16bppRgb565 = 6 | (16 << 8) | Gdi, + + /// + /// Specifies that pixel format is 16 bits per pixel. The color information specifies 32768 shades of color of + /// which 5 bits are red, 5 bits are green, 5 bits are blue and 1 bit is alpha. + /// + Format16bppArgb1555 = 7 | (16 << 8) | Alpha | Gdi, + + /// + /// Specifies that pixel format is 24 bits per pixel. The color information specifies 16777216 shades of color + /// of which 8 bits are red, 8 bits are green and 8 bits are blue. + /// + Format24bppRgb = 8 | (24 << 8) | Gdi, + + /// + /// Specifies that pixel format is 24 bits per pixel. The color information specifies 16777216 shades of color + /// of which 8 bits are red, 8 bits are green and 8 bits are blue. + /// + Format32bppRgb = 9 | (32 << 8) | Gdi, + + /// + /// Specifies that pixel format is 32 bits per pixel. The color information specifies 16777216 shades of color + /// of which 8 bits are red, 8 bits are green and 8 bits are blue. The 8 additional bits are alpha bits. + /// + Format32bppArgb = 10 | (32 << 8) | Alpha | Gdi | Canonical, + + /// + /// Specifies that pixel format is 32 bits per pixel. The color information specifies 16777216 shades of color + /// of which 8 bits are red, 8 bits are green and 8 bits are blue. The 8 additional bits are pre-multiplied alpha bits. + /// + Format32bppPArgb = 11 | (32 << 8) | Alpha | PAlpha | Gdi, + + /// + /// Specifies that pixel format is 48 bits per pixel. The color information specifies 16777216 shades of color + /// of which 8 bits are red, 8 bits are green and 8 bits are blue. The 8 additional bits are alpha bits. + /// + Format48bppRgb = 12 | (48 << 8) | Extended, + + /// + /// Specifies pixel format is 64 bits per pixel. The color information specifies 16777216 shades of color of + /// which 16 bits are red, 16 bits are green and 16 bits are blue. The 16 additional bits are alpha bits. + /// + Format64bppArgb = 13 | (64 << 8) | Alpha | Canonical | Extended, + + /// + /// Specifies that pixel format is 64 bits per pixel. The color information specifies 16777216 shades of color + /// of which 16 bits are red, 16 bits are green and 16 bits are blue. The 16 additional bits are pre-multiplied + /// alpha bits. + /// + Format64bppPArgb = 14 | (64 << 8) | Alpha | PAlpha | Extended, + + /// + /// Specifies that pixel format is 64 bits per pixel. The color information specifies 16777216 shades of color + /// of which 16 bits are red, 16 bits are green and 16 bits are blue. The 16 additional bits are alpha bits. + /// + Max = 15, +} diff --git a/src/System.Private.Windows.Core/src/Windows/Win32/PInvoke.SystemParametersInfo.cs b/src/System.Private.Windows.Core/src/Windows/Win32/PInvoke.SystemParametersInfo.cs index 749fd306be8..c52fc3df81c 100644 --- a/src/System.Private.Windows.Core/src/Windows/Win32/PInvoke.SystemParametersInfo.cs +++ b/src/System.Private.Windows.Core/src/Windows/Win32/PInvoke.SystemParametersInfo.cs @@ -47,6 +47,8 @@ public static unsafe bool SystemParametersInfo(ref HIGHCONTRASTW highContrast) { fixed (void* p = &highContrast) { + // Note that the documentation for HIGHCONTRASTW says that the lpszDefaultScheme member needs to be + // freed, but this is incorrect. No internal users ever free the pointer and the pointer never changes. highContrast.cbSize = (uint)sizeof(HIGHCONTRASTW); return SystemParametersInfo( SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETHIGHCONTRAST, diff --git a/src/System.Windows.Forms/src/GlobalSuppressions.cs b/src/System.Windows.Forms/src/GlobalSuppressions.cs index aabf597fc63..3291098e324 100644 --- a/src/System.Windows.Forms/src/GlobalSuppressions.cs +++ b/src/System.Windows.Forms/src/GlobalSuppressions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // Publicly shipped API - [assembly: SuppressMessage("Naming", "CA1725:Parameter names should match base declaration", Justification = "Public API", Scope = "member", Target = "~M:System.Windows.Forms.ButtonBase.OnKeyDown(System.Windows.Forms.KeyEventArgs)")] [assembly: SuppressMessage("Naming", "CA1725:Parameter names should match base declaration", Justification = "Public API", Scope = "member", Target = "~M:System.Windows.Forms.ButtonBase.OnKeyUp(System.Windows.Forms.KeyEventArgs)")] [assembly: SuppressMessage("Naming", "CA1725:Parameter names should match base declaration", Justification = "Public API", Scope = "member", Target = "~M:System.Windows.Forms.ButtonBase.OnMouseDown(System.Windows.Forms.MouseEventArgs)")] @@ -18,6 +17,7 @@ [assembly: SuppressMessage("Naming", "CA1725:Parameter names should match base declaration", Justification = "Public API", Scope = "member", Target = "~M:System.Windows.Forms.PrintPreviewControl.OnPaint(System.Windows.Forms.PaintEventArgs)")] [assembly: SuppressMessage("Naming", "CA1725:Parameter names should match base declaration", Justification = "Public API", Scope = "member", Target = "~M:System.Windows.Forms.FontDialog.RunDialog(System.IntPtr)~System.Boolean")] [assembly: SuppressMessage("Naming", "CA1725:Parameter names should match base declaration", Justification = "Public API", Scope = "member", Target = "~M:System.Windows.Forms.ImageListStreamer.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)")] +[assembly: SuppressMessage("Naming", "CA1725:Parameter names should match base declaration", Justification = "Public API", Scope = "member", Target = "~M:System.Windows.Forms.Control.EndInvoke(System.IAsyncResult)~System.Object")] [assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Public API", Scope = "member", Target = "~F:System.Windows.Forms.FontDialog.EventApply")] [assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Public API", Scope = "member", Target = "~F:System.Windows.Forms.FileDialog.EventFileOk")] [assembly: SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "Public API", Scope = "type", Target = "~T:System.Windows.Forms.ImeModeConversion")] @@ -32,3 +32,7 @@ [assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Thread local", Scope = "member", Target = "~F:System.Windows.Forms.VisualStyles.VisualStyleRenderer.t_themeHandles")] [assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Thread local", Scope = "member", Target = "~F:System.Windows.Forms.VisualStyles.VisualStyleRenderer.t_threadCacheVersion")] [assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Thread local", Scope = "member", Target = "~F:System.Windows.Forms.RadioButtonRenderer.t_visualStyleRenderer")] + +// Matches native naming +[assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Matches native naming", Scope = "member", Target = "~F:System.Windows.Forms.Control.WM_GETCONTROLNAME")] +[assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Matches native naming", Scope = "member", Target = "~F:System.Windows.Forms.Control.WM_GETCONTROLTYPE")] diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.ControlCollection.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.ControlCollection.cs index 233b8404b70..13c0e246d8b 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.ControlCollection.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.ControlCollection.cs @@ -88,14 +88,10 @@ public virtual void Add(Control? value) value._tabIndex = nextTabIndex; } - // if we don't suspend layout, AssignParent will indirectly trigger a layout event + // If we don't suspend layout, AssignParent will indirectly trigger a layout event // before we're ready (AssignParent will fire a PropertyChangedEvent("Visible"), which calls PerformLayout) -#if DEBUG - int dbgLayoutCheck = Owner.LayoutSuspendCount; -#endif - Owner.SuspendLayout(); - try + using (SuspendLayoutScope scope = new(Owner, performLayout: false)) { Control? oldParent = value._parent; try @@ -116,17 +112,10 @@ public virtual void Add(Control? value) } } } - - value.InitLayout(); - } - finally - { - Owner.ResumeLayout(false); -#if DEBUG - Owner.AssertLayoutSuspendCount(dbgLayoutCheck); -#endif } + value.InitLayout(); + // Not putting in the finally block, as it would eat the original // exception thrown from AssignParent if the following throws an exception. LayoutTransaction.DoLayout(Owner, value, PropertyNames.Parent); @@ -151,26 +140,15 @@ public virtual void AddRange(params Control[] controls) { ArgumentNullException.ThrowIfNull(controls); - if (controls.Length > 0) + if (controls.Length == 0) { -#if DEBUG - int dbgLayoutCheck = Owner.LayoutSuspendCount; -#endif - Owner.SuspendLayout(); - try - { - for (int i = 0; i < controls.Length; ++i) - { - Add(controls[i]); - } - } - finally - { - Owner.ResumeLayout(true); - } -#if DEBUG - Owner.AssertLayoutSuspendCount(dbgLayoutCheck); -#endif + return; + } + + using SuspendLayoutScope scope = new(Owner, performLayout: true); + for (int i = 0; i < controls.Length; ++i) + { + Add(controls[i]); } } @@ -195,9 +173,9 @@ public Control[] Find(string key, bool searchAllChildren) { key.ThrowIfNullOrEmptyWithMessage(SR.FindKeyMayNotBeEmptyOrNull); - List foundControls = new(); + List foundControls = []; FindInternal(key, searchAllChildren, this, foundControls); - return foundControls.ToArray(); + return [.. foundControls]; } /// @@ -401,46 +379,26 @@ public virtual Control? this[string? key] public virtual void Clear() { -#if DEBUG - int layoutSuspendCount = Owner.LayoutSuspendCount; -#endif - Owner.SuspendLayout(); - // clear all preferred size caches in the tree - - // inherited fonts could go away, etc. + using SuspendLayoutScope scope = new(Owner); + + // Clear all preferred size caches in the tree - inherited fonts could go away, etc. CommonProperties.xClearAllPreferredSizeCaches(Owner); - try + while (Count != 0) { - while (Count != 0) - { - RemoveAt(Count - 1); - } - } - finally - { - Owner.ResumeLayout(); -#if DEBUG - Debug.Assert(Owner.LayoutSuspendCount == layoutSuspendCount, "Suspend/Resume layout mismatch!"); -#endif + RemoveAt(Count - 1); } } /// - /// Retrieves the index of the specified - /// child control in this array. An ArgumentException - /// is thrown if child is not parented to this - /// Control. + /// Retrieves the index of the specified child control in this array. An ArgumentException + /// is thrown if child is not parented to this Control. /// - public int GetChildIndex(Control child) - { - return GetChildIndex(child, true); - } + public int GetChildIndex(Control child) => GetChildIndex(child, true); /// - /// Retrieves the index of the specified - /// child control in this array. An ArgumentException - /// is thrown if child is not parented to this - /// Control. + /// Retrieves the index of the specified child control in this array. An ArgumentException + /// is thrown if child is not parented to this Control. /// public virtual int GetChildIndex(Control child, bool throwException) { @@ -454,8 +412,8 @@ public virtual int GetChildIndex(Control child, bool throwException) } /// - /// This is internal virtual method so that "Readonly Collections" can override this and throw as they should not allow changing - /// the child control indices. + /// This is internal virtual method so that "Readonly Collections" can override this and throw as they + /// should not allow changing the child control indices. /// internal virtual void SetChildIndexInternal(Control child, int newIndex) { @@ -481,14 +439,10 @@ internal virtual void SetChildIndexInternal(Control child, int newIndex) } /// - /// Sets the index of the specified - /// child control in this array. An ArgumentException - /// is thrown if child is not parented to this - /// Control. + /// Sets the index of the specified child control in this array. An ArgumentException + /// is thrown if child is not parented to this Control. /// - public virtual void SetChildIndex(Control child, int newIndex) - { + public virtual void SetChildIndex(Control child, int newIndex) => SetChildIndexInternal(child, newIndex); - } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.SuspendLayoutScope.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.SuspendLayoutScope.cs new file mode 100644 index 00000000000..148e11334a1 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.SuspendLayoutScope.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Windows.Forms; + +public unsafe partial class Control +{ + internal readonly ref struct SuspendLayoutScope + { + private readonly Control? _control; + private readonly bool _performLayout; + +#if DEBUG + private readonly int _layoutSuspendCount; +#endif + + public SuspendLayoutScope(Control? control, bool performLayout = true) + { + _control = control; + _performLayout = performLayout; + + if (_control is not null) + { +#if DEBUG + _layoutSuspendCount = _control.LayoutSuspendCount; +#endif + _control.SuspendLayout(); + } + } + + public readonly void Dispose() + { + if (_control is not null) + { + _control.ResumeLayout(_performLayout); +#if DEBUG + Debug.Assert(_layoutSuspendCount == _control.LayoutSuspendCount, "Suspend/Resume layout mismatch!"); +#endif + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs index 64ec0d49701..cb35f22e7b2 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -338,24 +338,6 @@ private protected void TraceCanProcessMnemonic() internal byte LayoutSuspendCount { get; private set; } -#if DEBUG - internal void AssertLayoutSuspendCount(int value) - { - Debug.Assert(value == LayoutSuspendCount, "Suspend/Resume layout mismatch!"); - } - - /* - example usage - -#if DEBUG - int dbgLayoutCheck = LayoutSuspendCount; -#endif -#if DEBUG - AssertLayoutSuspendCount(dbgLayoutCheck); -#endif - */ -#endif - /// /// Initializes a new instance of the class. /// @@ -850,12 +832,14 @@ internal HBRUSH BackColorBrush /// This is an ambient property. /// /// - /// Data context is a concept that allows elements to inherit information from their parent elements - /// about the data source that is used for binding. It's the duty of deriving controls which inherit from - /// this class to handle the provided data source accordingly. For example, UserControls, which use - /// components for data binding scenarios could either handle the - /// event or override to provide - /// the relevant data from the data context to a BindingSource component's . + /// + /// Data context is a concept that allows elements to inherit information from their parent elements + /// about the data source that is used for binding. It's the duty of deriving controls which inherit from + /// this class to handle the provided data source accordingly. For example, UserControls, which use + /// components for data binding scenarios could either handle the + /// event or override to provide + /// the relevant data from the data context to a BindingSource component's . + /// /// [SRCategory(nameof(SR.CatData))] [Browsable(false)] @@ -979,17 +963,16 @@ public event EventHandler? BackColorChanged [SRDescription(nameof(SR.ControlBackgroundImageDescr))] public virtual Image? BackgroundImage { - get - { - return (Image?)Properties.GetObject(s_backgroundImageProperty); - } + get => (Image?)Properties.GetObject(s_backgroundImageProperty); set { - if (BackgroundImage != value) + if (BackgroundImage == value) { - Properties.SetObject(s_backgroundImageProperty, value); - OnBackgroundImageChanged(EventArgs.Empty); + return; } + + Properties.SetObject(s_backgroundImageProperty, value); + OnBackgroundImageChanged(EventArgs.Empty); } } @@ -1015,26 +998,28 @@ public virtual ImageLayout BackgroundImageLayout : ImageLayout.Tile; set { - if (BackgroundImageLayout != value) + if (BackgroundImageLayout == value) + { + return; + } + + // Valid values are 0x0 to 0x4 + SourceGenerated.EnumValidator.Validate(value); + + // Check if the value is either center, stretch or zoom; + if (value is ImageLayout.Center or ImageLayout.Zoom or ImageLayout.Stretch) { - // Valid values are 0x0 to 0x4 - SourceGenerated.EnumValidator.Validate(value); + SetStyle(ControlStyles.ResizeRedraw, true); - // Check if the value is either center, stretch or zoom; - if (value == ImageLayout.Center || value == ImageLayout.Zoom || value == ImageLayout.Stretch) + // Only for images that support transparency. + if (ControlPaint.IsImageTransparent(BackgroundImage)) { - SetStyle(ControlStyles.ResizeRedraw, true); - - // Only for images that support transparency. - if (ControlPaint.IsImageTransparent(BackgroundImage)) - { - DoubleBuffered = true; - } + DoubleBuffered = true; } - - Properties.SetObject(s_backgroundImageLayoutProperty, value); - OnBackgroundImageLayoutChanged(EventArgs.Empty); } + + Properties.SetObject(s_backgroundImageLayoutProperty, value); + OnBackgroundImageLayoutChanged(EventArgs.Empty); } } @@ -1186,7 +1171,7 @@ public bool CanFocus /// hosted as an ActiveX control, this property will return false if the ActiveX /// control has its events frozen. /// - protected override bool CanRaiseEvents => !IsActiveX ? true : !ActiveXEventsFrozen; + protected override bool CanRaiseEvents => !IsActiveX || !ActiveXEventsFrozen; /// /// Indicates whether the control can be selected. This property @@ -1932,22 +1917,9 @@ public virtual DockStyle Dock { if (value != Dock) { -#if DEBUG - int dbgLayoutCheck = LayoutSuspendCount; -#endif - SuspendLayout(); - try - { - DefaultLayout.SetDock(this, value); - OnDockChanged(EventArgs.Empty); - } - finally - { - ResumeLayout(); - } -#if DEBUG - AssertLayoutSuspendCount(dbgLayoutCheck); -#endif + using SuspendLayoutScope scope = new(this); + DefaultLayout.SetDock(this, value); + OnDockChanged(EventArgs.Empty); } } } @@ -2648,7 +2620,7 @@ public bool IsAccessible [EditorBrowsable(EditorBrowsableState.Advanced)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsAncestorSiteInDesignMode => - GetSitedParentSite(this) is ISite parentSite ? parentSite.DesignMode : false; + GetSitedParentSite(this) is ISite parentSite && parentSite.DesignMode; private static ISite? GetSitedParentSite(Control control) { @@ -3621,7 +3593,7 @@ protected internal virtual bool ShowKeyboardCues else { // if we're in the hidden state, we need to manufacture an update message so everyone knows it. - uint actionMask = (uint)PInvoke.UISF_HIDEACCEL << 16; + uint actionMask = PInvoke.UISF_HIDEACCEL << 16; _uiCuesState |= UICuesStates.KeyboardHidden; // The side effect of this initial state is that adding new controls may clear the accelerator @@ -3629,7 +3601,7 @@ protected internal virtual bool ShowKeyboardCues PInvoke.SendMessage( TopMostParent, PInvoke.WM_CHANGEUISTATE, - (WPARAM)(actionMask | (uint)PInvoke.UIS_SET)); + (WPARAM)(actionMask | PInvoke.UIS_SET)); } } @@ -3805,7 +3777,7 @@ public bool Visible } // We are only visible if our parent is visible - return ParentInternal is null ? true : ParentInternal.Visible; + return ParentInternal is null || ParentInternal.Visible; } set => SetVisibleCore(value); } @@ -5043,7 +5015,7 @@ protected virtual void DestroyHandle() if (((WINDOW_EX_STYLE)PInvoke.GetWindowLong(_window, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE)) .HasFlag(WINDOW_EX_STYLE.WS_EX_MDICHILD)) { - PInvoke.DefMDIChildProc(InternalHandle, (uint)PInvoke.WM_CLOSE, default, default); + PInvoke.DefMDIChildProc(InternalHandle, PInvoke.WM_CLOSE, default, default); } else { @@ -5377,18 +5349,17 @@ internal bool EndUpdateInternal(bool invalidate) } /// - /// Retrieves the form that this control is on. The control's parent may not be - /// the same as the form. + /// Retrieves the form that this control is on. The control's parent may not be the same as the form. /// public Form? FindForm() { - Control? cur = this; - while (cur is not null && cur is not Form) + Control? current = this; + while (current is not null and not Form) { - cur = cur.ParentInternal; + current = current.ParentInternal; } - return (Form?)cur; + return (Form?)current; } /// @@ -5590,7 +5561,7 @@ internal virtual Rectangle ApplyBoundsConstraints(int suggestedX, int suggestedY int value = (int)skipValue; // Since this is a flags enumeration the only way to validate skipValue is by checking if its within the range. - if (value < 0 || value > 7) + if (value is < 0 or > 7) { throw new InvalidEnumArgumentException(nameof(skipValue), value, typeof(GetChildAtPointSkip)); } @@ -5601,27 +5572,18 @@ internal virtual Rectangle ApplyBoundsConstraints(int suggestedX, int suggestedY return (control == this) ? null : control; } - private protected virtual string? GetCaptionForTool(ToolTip toolTip) - { - IKeyboardToolTip? host = ToolStripControlHost; - - return host is null - ? toolTip.GetCaptionForTool(this) - : host.GetCaptionForTool(toolTip); - } + private protected virtual string? GetCaptionForTool(ToolTip toolTip) => + ToolStripControlHost is IKeyboardToolTip host + ? host.GetCaptionForTool(toolTip) + : toolTip.GetCaptionForTool(this); /// - /// Retrieves the child control that is located at the specified client - /// coordinates. + /// Retrieves the child control that is located at the specified client coordinates. /// - public Control? GetChildAtPoint(Point pt) - { - return GetChildAtPoint(pt, GetChildAtPointSkip.None); - } + public Control? GetChildAtPoint(Point pt) => GetChildAtPoint(pt, GetChildAtPointSkip.None); /// - /// Returns the closest ContainerControl in the control's chain of parent controls - /// and forms. + /// Returns the closest ContainerControl in the control's chain of parent controls and forms. /// public IContainerControl? GetContainerControl() { @@ -5785,7 +5747,7 @@ internal bool GetAnyDisposingInHierarchy() /// private int[] GetChildWindowsInTabOrder() { - List holders = new(); + List holders = []; for (HWND hWndChild = PInvoke.GetWindow(this, GET_WINDOW_CMD.GW_CHILD); !hWndChild.IsNull; @@ -6005,30 +5967,20 @@ private protected virtual IList GetNeighboringToolsRectangles() int targetIndex = ctl._tabIndex; bool hitCtl = false; Control? found = null; - Control? parent = ctl._parent; + Control? parent = ctl._parent ?? throw new InvalidOperationException( + string.Format(SR.ParentPropertyNotSetInGetNextControl, nameof(Parent), ctl)); - if (parent is null) - { - throw new InvalidOperationException( - string.Format(SR.ParentPropertyNotSetInGetNextControl, nameof(Parent), ctl)); - } - - ControlCollection? siblings = GetControlCollection(parent); - - if (siblings is null) - { - throw new InvalidOperationException( - string.Format(SR.ControlsPropertyNotSetInGetNextControl, - nameof(Controls), parent)); - } + ControlCollection? siblings = GetControlCollection(parent) ?? throw new InvalidOperationException( + string.Format(SR.ControlsPropertyNotSetInGetNextControl, nameof(Controls), parent)); int siblingCount = siblings.Count; if (siblingCount == 0) { - throw new InvalidOperationException( - string.Format(SR.ControlsCollectionShouldNotBeEmptyInGetNextControl, - nameof(Control.Controls), parent)); + throw new InvalidOperationException(string.Format( + SR.ControlsCollectionShouldNotBeEmptyInGetNextControl, + nameof(Controls), + parent)); } // Cycle through the controls in reverse z-order looking for the next lowest tab index. We must @@ -6510,17 +6462,15 @@ private static void InvokeMarshaledCallbackDo(ThreadMethodEntry? tme) { action(); } - else if (tme._method is WaitCallback) + else if (tme._method is WaitCallback waitCallback) { - Debug.Assert(tme._args!.Length == 1, - "Arguments are wrong for WaitCallback"); - ((WaitCallback)tme._method)(tme._args[0]); + Debug.Assert(tme._args!.Length == 1, "Arguments are wrong for WaitCallback"); + waitCallback(tme._args[0]); } - else if (tme._method is SendOrPostCallback) + else if (tme._method is SendOrPostCallback sendOrPostCallback) { - Debug.Assert(tme._args!.Length == 1, - "Arguments are wrong for SendOrPostCallback"); - ((SendOrPostCallback)tme._method)(tme._args[0]); + Debug.Assert(tme._args!.Length == 1, "Arguments are wrong for SendOrPostCallback"); + sendOrPostCallback(tme._args[0]); } else { @@ -6655,7 +6605,7 @@ internal bool IsDescendant(Control? descendant) /// public static bool IsKeyLocked(Keys keyVal) { - if (keyVal == Keys.Insert || keyVal == Keys.NumLock || keyVal == Keys.CapsLock || keyVal == Keys.Scroll) + if (keyVal is Keys.Insert or Keys.NumLock or Keys.CapsLock or Keys.Scroll) { int result = PInvoke.GetKeyState((int)keyVal); @@ -6666,7 +6616,7 @@ public static bool IsKeyLocked(Keys keyVal) // and off when the key is untoggled. // Toggle keys (only low bit is of interest). - if (keyVal == Keys.Insert || keyVal == Keys.CapsLock) + if (keyVal is Keys.Insert or Keys.CapsLock) { return (result & 0x1) != 0x0; } @@ -6683,10 +6633,12 @@ public static bool IsKeyLocked(Keys keyVal) /// Determines if is an input character that the control wants. /// /// - /// This method is called during window message pre-processing to determine whether the given input - /// character should be pre-processed or sent directly to the control. The pre-processing of a character - /// includes checking whether the character is a mnemonic of another control. - /// () + /// + /// This method is called during window message pre-processing to determine whether the given input + /// character should be pre-processed or sent directly to the control. The pre-processing of a character + /// includes checking whether the character is a mnemonic of another control. + /// () + /// /// /// /// 'true' if the should be sent directly to the control. @@ -6967,7 +6919,7 @@ private static void MarshalStringToMessage(string value, ref Message m) } // Copy the name into the given IntPtr - char[] nullChar = new char[] { (char)0 }; + char[] nullChar = [(char)0]; byte[] nullBytes; byte[] bytes; @@ -8586,21 +8538,15 @@ protected virtual void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew // This is basically OnPaintBackground, put in a separate method for ButtonBase, // which does all painting under OnPaint, and tries very hard to avoid double-painting the border pixels. - internal void PaintBackground(PaintEventArgs e, Rectangle rectangle) - { + internal void PaintBackground(PaintEventArgs e, Rectangle rectangle) => PaintBackground(e, rectangle, BackColor, Point.Empty); - } - internal void PaintBackground(PaintEventArgs e, Rectangle rectangle, Color backColor) - { - PaintBackground(e, rectangle, backColor, Point.Empty); - } - - internal void PaintBackground(PaintEventArgs e, Rectangle rectangle, Color backColor, Point scrollOffset) + internal void PaintBackground(PaintEventArgs e, Rectangle rectangle, Color backColor, Point scrollOffset = default) { ArgumentNullException.ThrowIfNull(e); - if (RenderColorTransparent(backColor)) + bool renderColorTransparent = RenderColorTransparent(backColor); + if (renderColorTransparent) { PaintTransparentBackground(e, rectangle); } @@ -8613,12 +8559,10 @@ internal void PaintBackground(PaintEventArgs e, Rectangle rectangle, Color backC if (BackgroundImage is not null && !DisplayInformation.HighContrast && !formRTL) { - if (BackgroundImageLayout == ImageLayout.Tile) + bool imageIsTransparent = ControlPaint.IsImageTransparent(BackgroundImage); + if (!renderColorTransparent && BackgroundImageLayout == ImageLayout.Tile && imageIsTransparent) { - if (ControlPaint.IsImageTransparent(BackgroundImage)) - { - PaintTransparentBackground(e, rectangle); - } + PaintTransparentBackground(e, rectangle); } Point scrollLocation = scrollOffset; @@ -8627,7 +8571,7 @@ internal void PaintBackground(PaintEventArgs e, Rectangle rectangle, Color backC scrollLocation = scrollControl.AutoScrollPosition; } - if (ControlPaint.IsImageTransparent(BackgroundImage)) + if (imageIsTransparent) { PaintBackColor(e, rectangle, backColor); } @@ -8694,23 +8638,20 @@ private void PaintException(PaintEventArgs e) clientRectangle.Right, clientRectangle.Top); } - internal void PaintTransparentBackground(PaintEventArgs e, Rectangle rectangle) - { - PaintTransparentBackground(e, rectangle, null); - } - /// /// Trick our parent into painting our background for us, or paint some default color if that doesn't work. /// /// - /// This method is the hardest part of implementing transparent controls; call this in - /// . + /// + /// This method is the hardest part of implementing transparent controls; call this in + /// . + /// /// /// The area to redraw. /// /// Region of the rectangle to be transparent, or null for the entire control. /// - internal unsafe void PaintTransparentBackground(PaintEventArgs e, Rectangle rectangle, Region? transparentRegion) + internal unsafe void PaintTransparentBackground(PaintEventArgs e, Rectangle rectangle, Region? transparentRegion = null) { Control? parent = ParentInternal; @@ -9165,7 +9106,7 @@ internal static PreProcessControlState PreProcessControlMessageInternal(Control? Keys keyData = (Keys)(nint)message.WParamInternal | ModifierKeys; // Allow control to preview key down message. - if (message.Msg == (int)PInvoke.WM_KEYDOWN || message.Msg == (int)PInvoke.WM_SYSKEYDOWN) + if (message.Msg is ((int)PInvoke.WM_KEYDOWN) or ((int)PInvoke.WM_SYSKEYDOWN)) { target.ProcessUICues(ref message); @@ -9288,7 +9229,7 @@ private protected virtual void PrintToMetaFileRecursive(HDC hDC, IntPtr lParam, using DCMapping mapping = new(hDC, bounds); // Print the non-client area. - PrintToMetaFile_SendPrintMessage(hDC, (IntPtr)(lParam & (long)~PInvoke.PRF_CLIENT)); + PrintToMetaFile_SendPrintMessage(hDC, (nint)(lParam & (long)~PInvoke.PRF_CLIENT)); // Figure out mapping for the client area. bool success = PInvoke.GetWindowRect(this, out var windowRect); @@ -9300,7 +9241,7 @@ private protected virtual void PrintToMetaFileRecursive(HDC hDC, IntPtr lParam, using DCMapping clientMapping = new(hDC, clientBounds); // Print the client area. - PrintToMetaFile_SendPrintMessage(hDC, (IntPtr)(lParam & (long)~PInvoke.PRF_NONCLIENT)); + PrintToMetaFile_SendPrintMessage(hDC, (nint)(lParam & (long)~PInvoke.PRF_NONCLIENT)); // Paint children in reverse Z-Order. int count = Controls.Count; @@ -9358,7 +9299,7 @@ private void PrintToMetaFile_SendPrintMessage(HDC hDC, nint lParam) protected virtual bool ProcessDialogChar(char charCode) { s_controlKeyboardRouting.TraceVerbose($"Control.ProcessDialogChar [{charCode}]"); - return _parent is null ? false : _parent.ProcessDialogChar(charCode); + return _parent is not null && _parent.ProcessDialogChar(charCode); } /// @@ -9379,7 +9320,7 @@ protected virtual bool ProcessDialogChar(char charCode) protected virtual bool ProcessDialogKey(Keys keyData) { s_controlKeyboardRouting.TraceVerbose($"Control.ProcessDialogKey {keyData}"); - return _parent is null ? false : _parent.ProcessDialogKey(keyData); + return _parent is not null && _parent.ProcessDialogKey(keyData); } /// @@ -9564,7 +9505,7 @@ internal void ProcessUICues(ref Message msg) { Keys keyCode = (Keys)(nint)msg.WParamInternal & Keys.KeyCode; - if (keyCode != Keys.F10 && keyCode != Keys.Menu && keyCode != Keys.Tab) + if (keyCode is not Keys.F10 and not Keys.Menu and not Keys.Tab) { return; // PERF: don't WM_QUERYUISTATE if we don't have to. } @@ -9588,7 +9529,7 @@ internal void ProcessUICues(ref Message msg) // the opposite of what we want to do. So if we want to show accelerators, // we OR in UISF_HIDEACCEL, then call UIS_CLEAR to clear the "hidden" state. - if (keyCode == Keys.F10 || keyCode == Keys.Menu) + if (keyCode is Keys.F10 or Keys.Menu) { if ((current & PInvoke.UISF_HIDEACCEL) != 0) { @@ -10000,10 +9941,7 @@ private void ResetVisible() /// Resumes normal layout logic. This will force a layout immediately /// if there are any pending layout requests. /// - public void ResumeLayout() - { - ResumeLayout(true); - } + public void ResumeLayout() => ResumeLayout(performLayout: true); /// /// Resumes normal layout logic. If performLayout is set to true then @@ -10031,9 +9969,7 @@ public void ResumeLayout(bool performLayout) } LayoutSuspendCount--; - if (LayoutSuspendCount == 0 - && GetState(States.LayoutDeferred) - && performLayout) + if (LayoutSuspendCount == 0 && GetState(States.LayoutDeferred) && performLayout) { PerformLayout(); performedLayout = true; @@ -10045,23 +9981,19 @@ public void ResumeLayout(bool performLayout) SetExtendedState(ExtendedStates.ClearLayoutArgs, true); } - /* - - We've had this since Everett,but it seems wrong, redundant and a performance hit. The - correct layout calls are already made when bounds or parenting changes, which is all - we care about. We may want to call this at layout suspend count == 0, but certainly - not for all resumes. I tried removing it, and doing it only when suspendCount == 0, - but we break things at every step. + // We've had this since Everett, but it seems wrong, redundant and a performance hit. The + // correct layout calls are already made when bounds or parenting changes, which is all + // we care about. We may want to call this at layout suspend count == 0, but certainly + // not for all resumes. I tried removing it, and doing it only when suspendCount == 0, + // but we break things at every step. - */ if (!performLayout) { CommonProperties.xClearPreferredSizeCache(this); ControlCollection? controlsCollection = (ControlCollection?)Properties.GetObject(s_controlsCollectionProperty); - // PERFNOTE: This is more efficient than using Foreach. Foreach - // forces the creation of an array subset enum each time we - // enumerate + // PERFNOTE: This is more efficient than using Foreach. Foreach forces the creation of an array subset + // enum each time we enumerate. if (controlsCollection is not null) { for (int i = 0; i < controlsCollection.Count; i++) @@ -10141,21 +10073,8 @@ public void Scale(float ratio) [EditorBrowsable(EditorBrowsableState.Never)] public void Scale(float dx, float dy) { -#if DEBUG - int dbgLayoutCheck = LayoutSuspendCount; -#endif - SuspendLayout(); - try - { - ScaleCore(dx, dy); - } - finally - { - ResumeLayout(); -#if DEBUG - AssertLayoutSuspendCount(dbgLayoutCheck); -#endif - } + using SuspendLayoutScope scope = new(this); + ScaleCore(dx, dy); } /// @@ -10164,10 +10083,10 @@ public void Scale(float dx, float dy) [EditorBrowsable(EditorBrowsableState.Advanced)] public void Scale(SizeF factor) { - // manually call ScaleControl recursively instead of the internal scale method + // Manually call ScaleControl recursively instead of the internal scale method // when someone calls this method, they really do want to do some sort of // zooming feature, as opposed to AutoScale. - using (new LayoutTransaction(this, this, PropertyNames.Bounds, false)) + using (new LayoutTransaction(this, this, PropertyNames.Bounds, resumeLayout: false)) { ScaleControl(factor, factor, this); if (ScaleChildren) @@ -10450,49 +10369,38 @@ protected virtual void ScaleControl(SizeF factor, BoundsSpecified specified) protected virtual void ScaleCore(float dx, float dy) { Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, $"{GetType().Name}::ScaleCore({dx}, {dy})"); -#if DEBUG - int dbgLayoutCheck = LayoutSuspendCount; -#endif - SuspendLayout(); - try - { - int sx = (int)Math.Round(_x * dx); - int sy = (int)Math.Round(_y * dy); - int sw = _width; - if ((_controlStyle & ControlStyles.FixedWidth) != ControlStyles.FixedWidth) - { - sw = (int)(Math.Round((_x + _width) * dx)) - sx; - } + using SuspendLayoutScope scope = new(this); - int sh = _height; - if ((_controlStyle & ControlStyles.FixedHeight) != ControlStyles.FixedHeight) - { - sh = (int)(Math.Round((_y + _height) * dy)) - sy; - } + int sx = (int)Math.Round(_x * dx); + int sy = (int)Math.Round(_y * dy); - SetBounds(sx, sy, sw, sh, BoundsSpecified.All); + int sw = _width; + if ((_controlStyle & ControlStyles.FixedWidth) != ControlStyles.FixedWidth) + { + sw = (int)(Math.Round((_x + _width) * dx)) - sx; + } - ControlCollection? controlsCollection = (ControlCollection?)Properties.GetObject(s_controlsCollectionProperty); + int sh = _height; + if ((_controlStyle & ControlStyles.FixedHeight) != ControlStyles.FixedHeight) + { + sh = (int)(Math.Round((_y + _height) * dy)) - sy; + } - if (controlsCollection is not null) + SetBounds(sx, sy, sw, sh, BoundsSpecified.All); + + ControlCollection? controlsCollection = (ControlCollection?)Properties.GetObject(s_controlsCollectionProperty); + + if (controlsCollection is not null) + { + // PERFNOTE: This is more efficient than using Foreach. Foreach + // forces the creation of an array subset enum each time we + // enumerate + for (int i = 0; i < controlsCollection.Count; i++) { - // PERFNOTE: This is more efficient than using Foreach. Foreach - // forces the creation of an array subset enum each time we - // enumerate - for (int i = 0; i < controlsCollection.Count; i++) - { - controlsCollection[i].Scale(dx, dy); - } + controlsCollection[i].Scale(dx, dy); } } - finally - { - ResumeLayout(); -#if DEBUG - AssertLayoutSuspendCount(dbgLayoutCheck); -#endif - } } /// @@ -10723,61 +10631,61 @@ protected virtual void SetBoundsCore(int x, int y, int width, int height, Bounds { Debug.WriteLineIf(CompModSwitches.SetBounds.TraceInfo, $"{Name}::SetBoundsCore(x={x} y={y} width={width} height={height} specified={specified})"); + // SetWindowPos below sends a WmWindowPositionChanged (not posts) so we immediately // end up in WmWindowPositionChanged which may cause the parent to layout. We need to // suspend/resume to defer the parent from laying out until after InitLayout has been called // to update the layout engine's state with the new control bounds. -#if DEBUG - int suspendCount = -44371; // Arbitrary negative prime to surface bugs. - suspendCount = ParentInternal is not null ? ParentInternal.LayoutSuspendCount : suspendCount; -#endif - ParentInternal?.SuspendLayout(); + + if (_x == x && _y == y && _width == width && _height == height) + { + return; + } + + using SuspendLayoutScope scope = new(ParentInternal); try { - if (_x != x || _y != y || _width != width || _height != height) - { - CommonProperties.UpdateSpecifiedBounds(this, x, y, width, height, specified); + CommonProperties.UpdateSpecifiedBounds(this, x, y, width, height, specified); - // Provide control with an opportunity to apply self imposed constraints on its size. - Rectangle adjustedBounds = ApplyBoundsConstraints(x, y, width, height); - width = adjustedBounds.Width; - height = adjustedBounds.Height; - x = adjustedBounds.X; - y = adjustedBounds.Y; + // Provide control with an opportunity to apply self imposed constraints on its size. + Rectangle adjustedBounds = ApplyBoundsConstraints(x, y, width, height); + width = adjustedBounds.Width; + height = adjustedBounds.Height; + x = adjustedBounds.X; + y = adjustedBounds.Y; - if (!IsHandleCreated) - { - // Handle is not created, just record our new position and we're done. - UpdateBounds(x, y, width, height); - } - else + if (!IsHandleCreated) + { + // Handle is not created, just record our new position and we're done. + UpdateBounds(x, y, width, height); + } + else + { + if (!GetState(States.SizeLockedByOS)) { - if (!GetState(States.SizeLockedByOS)) - { - SET_WINDOW_POS_FLAGS flags = SET_WINDOW_POS_FLAGS.SWP_NOZORDER | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE; + SET_WINDOW_POS_FLAGS flags = SET_WINDOW_POS_FLAGS.SWP_NOZORDER | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE; - if (_x == x && _y == y) - { - flags |= SET_WINDOW_POS_FLAGS.SWP_NOMOVE; - } + if (_x == x && _y == y) + { + flags |= SET_WINDOW_POS_FLAGS.SWP_NOMOVE; + } - if (_width == width && _height == height) - { - flags |= SET_WINDOW_POS_FLAGS.SWP_NOSIZE; - } + if (_width == width && _height == height) + { + flags |= SET_WINDOW_POS_FLAGS.SWP_NOSIZE; + } - // Give a chance for derived controls to do what they want, just before we resize. - OnBoundsUpdate(x, y, width, height); + // Give a chance for derived controls to do what they want, just before we resize. + OnBoundsUpdate(x, y, width, height); - PInvoke.SetWindowPos(this, HWND.Null, x, y, width, height, flags); + PInvoke.SetWindowPos(this, HWND.Null, x, y, width, height, flags); - // NOTE: SetWindowPos causes a WM_WINDOWPOSCHANGED which is processed - // synchronously so we effectively end up in UpdateBounds immediately following - // SetWindowPos. - // - // UpdateBounds(x, y, width, height); - } + // NOTE: SetWindowPos causes a WM_WINDOWPOSCHANGED which is processed + // synchronously so we effectively end up in UpdateBounds immediately following + // SetWindowPos. + // + // UpdateBounds(x, y, width, height); } } } @@ -10799,10 +10707,6 @@ protected virtual void SetBoundsCore(int x, int y, int width, int height, Bounds // LayoutEngine which manages your layout, so we call into the parent's // LayoutEngine. ParentInternal.LayoutEngine.InitLayout(this, specified); - ParentInternal.ResumeLayout(/* performLayout = */ true); -#if DEBUG - Debug.Assert(ParentInternal.LayoutSuspendCount == suspendCount, "Suspend/Resume layout mismatch!"); -#endif } } } @@ -11881,7 +11785,7 @@ private void WmEraseBkgnd(ref Message m) { // When possible, it's best to do all painting directly from WM_PAINT. // OptimizedDoubleBuffer is the "same" as turning on AllPaintingInWMPaint - if (!(GetStyle(ControlStyles.AllPaintingInWmPaint))) + if (!GetStyle(ControlStyles.AllPaintingInWmPaint)) { HDC dc = (HDC)(nint)m.WParamInternal; if (dc.IsNull) @@ -13596,19 +13500,18 @@ static bool IsKeyDown(Keys key, ReadOnlySpan stateArray) internal virtual ToolInfoWrapper GetToolInfoWrapper(TOOLTIP_FLAGS flags, string? caption, ToolTip tooltip) => new(this, flags, caption); - private readonly WeakReference toolStripControlHostReference - = new(null); + private readonly WeakReference _toolStripControlHostReference = new(null); internal ToolStripControlHost? ToolStripControlHost { get { - toolStripControlHostReference.TryGetTarget(out ToolStripControlHost? value); + _toolStripControlHostReference.TryGetTarget(out ToolStripControlHost? value); return value; } set { - toolStripControlHostReference.SetTarget(value); + _toolStripControlHostReference.SetTarget(value); } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs index cce1b6d07d0..d9a982f0770 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs @@ -806,7 +806,7 @@ internal void AdjustFillingColumn(DataGridViewColumn dataGridViewColumn, int wid if (dataGridViewColumnTmp.Visible && dataGridViewColumnTmp.InheritedAutoSizeMode == DataGridViewAutoSizeColumnMode.Fill) { - if (dataGridViewColumnTmp.FillWeight < (dataGridViewColumnTmp.MinimumWidth * weightSum) / (float)availableWidth) + if (dataGridViewColumnTmp.FillWeight < (dataGridViewColumnTmp.MinimumWidth * weightSum) / availableWidth) { desiredWidthTooSmall = true; dataGridViewColumnTmp.DesiredFillWidth = -1; @@ -10541,87 +10541,139 @@ protected override bool IsInputKey(Keys keyData) } /// - /// Determines if Scrollbars should be visible, - /// updates their bounds and the bounds of all + /// Determines if Scrollbars should be visible, updates their bounds and the bounds of all /// other regions in the dataGridView's Layout. /// private void LayoutScrollBars() { - SuspendLayout(); - try - { - // Scrollbars are a tricky issue. - // We need to see if we can cram our columns and rows - // in without scrollbars and if they don't fit, we make - // scrollbars visible and then fixup our regions for the - // data. - bool allowHorizScrollbar = ((_scrollBars == ScrollBars.Both) || (_scrollBars == ScrollBars.Horizontal)) - && _dataGridViewState2[State2_AllowHorizontalScrollbar]; - bool allowVertScrollbar = _scrollBars is ScrollBars.Both or ScrollBars.Vertical; - bool needHorizScrollbarWithoutVertScrollbar = false; - bool needHorizScrollbar = false; - bool needVertScrollbar = false; - bool rightToLeftInternal = RightToLeftInternal; - int oldfirstDisplayedScrollingRow; - - int totalVisibleColCount = Columns.GetColumnCount(DataGridViewElementStates.Visible); - int totalVisibleRowCount = Rows.GetRowCount(DataGridViewElementStates.Visible); - int totalVisibleWidth = Columns.GetColumnsWidth(DataGridViewElementStates.Visible); - int totalVisibleFrozenWidth = Columns.GetColumnsWidth(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen); - - // Expensive call - dataGridView could have a mode where no row is resizable which would result in better perf - int totalVisibleHeight = Rows.GetRowsHeight(DataGridViewElementStates.Visible); - int totalVisibleFrozenHeight = Rows.GetRowsHeight(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen); + using SuspendLayoutScope scope = new(this, performLayout: false); + + // Scrollbars are a tricky issue. We need to see if we can cram our columns and rows in without scrollbars + // and if they don't fit, we make scrollbars visible and then fixup our regions for the data. + bool allowHorizScrollbar = ((_scrollBars == ScrollBars.Both) || (_scrollBars == ScrollBars.Horizontal)) + && _dataGridViewState2[State2_AllowHorizontalScrollbar]; + bool allowVertScrollbar = _scrollBars is ScrollBars.Both or ScrollBars.Vertical; + bool needHorizScrollbarWithoutVertScrollbar = false; + bool needHorizScrollbar = false; + bool needVertScrollbar = false; + bool rightToLeftInternal = RightToLeftInternal; + int oldfirstDisplayedScrollingRow; + + int totalVisibleColCount = Columns.GetColumnCount(DataGridViewElementStates.Visible); + int totalVisibleRowCount = Rows.GetRowCount(DataGridViewElementStates.Visible); + int totalVisibleWidth = Columns.GetColumnsWidth(DataGridViewElementStates.Visible); + int totalVisibleFrozenWidth = Columns.GetColumnsWidth(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen); + + // Expensive call - dataGridView could have a mode where no row is resizable which would result in better perf + int totalVisibleHeight = Rows.GetRowsHeight(DataGridViewElementStates.Visible); + int totalVisibleFrozenHeight = Rows.GetRowsHeight(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen); - int horizScrollBarHeight = _horizScrollBar.Height = SystemInformation.HorizontalScrollBarHeight; - int vertScrollBarWidth = _vertScrollBar.Width = SystemInformation.VerticalScrollBarWidth; + int horizScrollBarHeight = _horizScrollBar.Height = SystemInformation.HorizontalScrollBarHeight; + int vertScrollBarWidth = _vertScrollBar.Width = SystemInformation.VerticalScrollBarWidth; - if (allowHorizScrollbar - && totalVisibleWidth > _layout.Data.Width - && totalVisibleFrozenWidth < _layout.Data.Width - && horizScrollBarHeight <= _layout.Data.Height) + if (allowHorizScrollbar + && totalVisibleWidth > _layout.Data.Width + && totalVisibleFrozenWidth < _layout.Data.Width + && horizScrollBarHeight <= _layout.Data.Height) + { + int oldDataHeight = _layout.Data.Height; + _layout.Data.Height -= horizScrollBarHeight; + Debug.Assert(_layout.Data.Height >= 0); + needHorizScrollbarWithoutVertScrollbar = needHorizScrollbar = true; + if (totalVisibleWidth - _layout.Data.Width <= vertScrollBarWidth + || _layout.Data.Width - totalVisibleFrozenWidth <= vertScrollBarWidth) { - int oldDataHeight = _layout.Data.Height; - _layout.Data.Height -= horizScrollBarHeight; - Debug.Assert(_layout.Data.Height >= 0); - needHorizScrollbarWithoutVertScrollbar = needHorizScrollbar = true; - if (totalVisibleWidth - _layout.Data.Width <= vertScrollBarWidth - || _layout.Data.Width - totalVisibleFrozenWidth <= vertScrollBarWidth) + // Would we still need a horizontal scrollbar if there were a vertical one? + oldfirstDisplayedScrollingRow = DisplayedBandsInfo.FirstDisplayedScrollingRow; + ComputeVisibleRows(); + if (DisplayedBandsInfo.NumTotallyDisplayedFrozenRows == Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) + && DisplayedBandsInfo.NumTotallyDisplayedScrollingRows != totalVisibleRowCount - Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) + && (totalVisibleHeight - totalVisibleFrozenHeight != ComputeHeightOfFittingTrailingScrollingRows(totalVisibleFrozenHeight))) { - // Would we still need a horizontal scrollbar if there were a vertical one? - oldfirstDisplayedScrollingRow = DisplayedBandsInfo.FirstDisplayedScrollingRow; - ComputeVisibleRows(); - if (DisplayedBandsInfo.NumTotallyDisplayedFrozenRows == Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) - && DisplayedBandsInfo.NumTotallyDisplayedScrollingRows != totalVisibleRowCount - Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) - && (totalVisibleHeight - totalVisibleFrozenHeight != ComputeHeightOfFittingTrailingScrollingRows(totalVisibleFrozenHeight))) - { - needHorizScrollbar = totalVisibleFrozenWidth < _layout.Data.Width - vertScrollBarWidth; - } + needHorizScrollbar = totalVisibleFrozenWidth < _layout.Data.Width - vertScrollBarWidth; + } + + DisplayedBandsInfo.FirstDisplayedScrollingRow = oldfirstDisplayedScrollingRow; + } - DisplayedBandsInfo.FirstDisplayedScrollingRow = oldfirstDisplayedScrollingRow; + if (needHorizScrollbar) + { + if (_layout.RowHeadersVisible) + { + _layout.RowHeaders.Height -= horizScrollBarHeight; + Debug.Assert(_layout.RowHeaders.Height >= 0); } + } + else + { + // Restore old data height because turns out a horizontal scroll bar wouldn't make sense + _layout.Data.Height = oldDataHeight; + } + } - if (needHorizScrollbar) + oldfirstDisplayedScrollingRow = DisplayedBandsInfo.FirstDisplayedScrollingRow; + + ComputeVisibleRows(); + if (allowVertScrollbar + && DisplayedBandsInfo.NumTotallyDisplayedFrozenRows == Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) + && DisplayedBandsInfo.NumTotallyDisplayedScrollingRows != totalVisibleRowCount - Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) + && (totalVisibleHeight - totalVisibleFrozenHeight != ComputeHeightOfFittingTrailingScrollingRows(totalVisibleFrozenHeight)) + && _layout.Data.Height > totalVisibleFrozenHeight + && vertScrollBarWidth <= _layout.Data.Width) + { + _layout.Data.Width -= vertScrollBarWidth; + Debug.Assert(_layout.Data.Width >= 0); + if (rightToLeftInternal) + { + _layout.Data.X += vertScrollBarWidth; + } + + if (_layout.ColumnHeadersVisible) + { + _layout.ColumnHeaders.Width -= vertScrollBarWidth; + Debug.Assert(_layout.ColumnHeaders.Width >= 0); + if (rightToLeftInternal) { - if (_layout.RowHeadersVisible) - { - _layout.RowHeaders.Height -= horizScrollBarHeight; - Debug.Assert(_layout.RowHeaders.Height >= 0); - } + _layout.ColumnHeaders.X += vertScrollBarWidth; } - else + } + + needVertScrollbar = true; + } + + DisplayedBandsInfo.FirstDisplayedScrollingCol = ComputeFirstVisibleScrollingColumn(); + + // Compute the number of visible columns only after setting up the vertical scroll bar. + ComputeVisibleColumns(); + + if (allowHorizScrollbar + && needVertScrollbar && !needHorizScrollbar + && totalVisibleWidth > _layout.Data.Width && totalVisibleFrozenWidth < _layout.Data.Width + && horizScrollBarHeight <= _layout.Data.Height) + { + DisplayedBandsInfo.FirstDisplayedScrollingRow = oldfirstDisplayedScrollingRow; + if (_layout.ColumnHeadersVisible) + { + _layout.ColumnHeaders.Width += vertScrollBarWidth; + if (rightToLeftInternal) { - // Restore old data height because turns out a horizontal scroll bar wouldn't make sense - _layout.Data.Height = oldDataHeight; + _layout.ColumnHeaders.X -= vertScrollBarWidth; } } - oldfirstDisplayedScrollingRow = DisplayedBandsInfo.FirstDisplayedScrollingRow; + _layout.Data.Width += vertScrollBarWidth; + if (rightToLeftInternal) + { + _layout.Data.X -= vertScrollBarWidth; + } + + _layout.Data.Height -= horizScrollBarHeight; + Debug.Assert(_layout.Data.Height >= 0); + needVertScrollbar = false; ComputeVisibleRows(); - if (allowVertScrollbar - && DisplayedBandsInfo.NumTotallyDisplayedFrozenRows == Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) - && DisplayedBandsInfo.NumTotallyDisplayedScrollingRows != totalVisibleRowCount - Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) + if (DisplayedBandsInfo.NumTotallyDisplayedFrozenRows == Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) + && DisplayedBandsInfo.NumTotallyDisplayedScrollingRows != totalVisibleRowCount && (totalVisibleHeight - totalVisibleFrozenHeight != ComputeHeightOfFittingTrailingScrollingRows(totalVisibleFrozenHeight)) && _layout.Data.Height > totalVisibleFrozenHeight && vertScrollBarWidth <= _layout.Data.Width) @@ -10646,159 +10698,98 @@ private void LayoutScrollBars() needVertScrollbar = true; } - DisplayedBandsInfo.FirstDisplayedScrollingCol = ComputeFirstVisibleScrollingColumn(); - // we compute the number of visible columns only after we set up the vertical scroll bar. - ComputeVisibleColumns(); - - if (allowHorizScrollbar - && needVertScrollbar && !needHorizScrollbar - && totalVisibleWidth > _layout.Data.Width && totalVisibleFrozenWidth < _layout.Data.Width - && horizScrollBarHeight <= _layout.Data.Height) + if (needVertScrollbar) { - DisplayedBandsInfo.FirstDisplayedScrollingRow = oldfirstDisplayedScrollingRow; - if (_layout.ColumnHeadersVisible) - { - _layout.ColumnHeaders.Width += vertScrollBarWidth; - if (rightToLeftInternal) - { - _layout.ColumnHeaders.X -= vertScrollBarWidth; - } - } - - _layout.Data.Width += vertScrollBarWidth; - if (rightToLeftInternal) - { - _layout.Data.X -= vertScrollBarWidth; - } - - _layout.Data.Height -= horizScrollBarHeight; - Debug.Assert(_layout.Data.Height >= 0); - needVertScrollbar = false; - - ComputeVisibleRows(); - if (DisplayedBandsInfo.NumTotallyDisplayedFrozenRows == Rows.GetRowCount(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen) - && DisplayedBandsInfo.NumTotallyDisplayedScrollingRows != totalVisibleRowCount - && (totalVisibleHeight - totalVisibleFrozenHeight != ComputeHeightOfFittingTrailingScrollingRows(totalVisibleFrozenHeight)) - && _layout.Data.Height > totalVisibleFrozenHeight - && vertScrollBarWidth <= _layout.Data.Width) - { - _layout.Data.Width -= vertScrollBarWidth; - Debug.Assert(_layout.Data.Width >= 0); - if (rightToLeftInternal) - { - _layout.Data.X += vertScrollBarWidth; - } - - if (_layout.ColumnHeadersVisible) - { - _layout.ColumnHeaders.Width -= vertScrollBarWidth; - Debug.Assert(_layout.ColumnHeaders.Width >= 0); - if (rightToLeftInternal) - { - _layout.ColumnHeaders.X += vertScrollBarWidth; - } - } - - needVertScrollbar = true; - } - - if (needVertScrollbar) - { - needHorizScrollbar = true; - } - else - { - needHorizScrollbar = needHorizScrollbarWithoutVertScrollbar; - } + needHorizScrollbar = true; } - - _layout.ResizeBoxRect = default; - if (needVertScrollbar && needHorizScrollbar) + else { - _layout.ResizeBoxRect = new Rectangle( - rightToLeftInternal ? _layout.Data.X - _vertScrollBar.Width : _layout.Data.Right, - _layout.Data.Bottom, - _vertScrollBar.Width, - _horizScrollBar.Height); + needHorizScrollbar = needHorizScrollbarWithoutVertScrollbar; } + } - if (needHorizScrollbar && totalVisibleColCount > 0) - { - int widthNotVisible = totalVisibleWidth - _layout.Data.Width; - - _horizScrollBar.Minimum = 0; - _horizScrollBar.Maximum = totalVisibleWidth - totalVisibleFrozenWidth; - Debug.Assert(_horizScrollBar.Maximum > 0); - _horizScrollBar.SmallChange = 1; - _horizScrollBar.LargeChange = Math.Max(totalVisibleWidth - totalVisibleFrozenWidth - widthNotVisible, 0); - _horizScrollBar.Enabled = Enabled; - _horizScrollBar.Bounds = new Rectangle( - rightToLeftInternal ? _layout.Inside.X + _layout.ResizeBoxRect.Width : _layout.Inside.X, - _layout.Data.Bottom, - _layout.Inside.Width - _layout.ResizeBoxRect.Width, - _horizScrollBar.Height); - _horizScrollBar.Visible = true; - _horizScrollBar.Invalidate(); - } - else - { - _horizScrollBar.Visible = false; - HorizontalOffset = 0; + _layout.ResizeBoxRect = default; + if (needVertScrollbar && needHorizScrollbar) + { + _layout.ResizeBoxRect = new Rectangle( + rightToLeftInternal ? _layout.Data.X - _vertScrollBar.Width : _layout.Data.Right, + _layout.Data.Bottom, + _vertScrollBar.Width, + _horizScrollBar.Height); + } - _horizScrollBar.Enabled = false; - _horizScrollBar.Minimum = 0; - _horizScrollBar.Maximum = 1; - _horizScrollBar.SmallChange = 1; - _horizScrollBar.LargeChange = 1; - _horizScrollBar.Value = 0; - } + if (needHorizScrollbar && totalVisibleColCount > 0) + { + int widthNotVisible = totalVisibleWidth - _layout.Data.Width; - if (needVertScrollbar) - { - int vertScrollBarTop = _layout.Data.Y; - int vertScrollBarHeight = _layout.Data.Height; - if (_layout.ColumnHeadersVisible) - { - vertScrollBarTop = _layout.ColumnHeaders.Y; - vertScrollBarHeight += _layout.ColumnHeaders.Height; - } - else if (SingleHorizontalBorderAdded) - { - vertScrollBarTop--; - vertScrollBarHeight++; - } + _horizScrollBar.Minimum = 0; + _horizScrollBar.Maximum = totalVisibleWidth - totalVisibleFrozenWidth; + Debug.Assert(_horizScrollBar.Maximum > 0); + _horizScrollBar.SmallChange = 1; + _horizScrollBar.LargeChange = Math.Max(totalVisibleWidth - totalVisibleFrozenWidth - widthNotVisible, 0); + _horizScrollBar.Enabled = Enabled; + _horizScrollBar.Bounds = new Rectangle( + rightToLeftInternal ? _layout.Inside.X + _layout.ResizeBoxRect.Width : _layout.Inside.X, + _layout.Data.Bottom, + _layout.Inside.Width - _layout.ResizeBoxRect.Width, + _horizScrollBar.Height); + _horizScrollBar.Visible = true; + _horizScrollBar.Invalidate(); + } + else + { + _horizScrollBar.Visible = false; + HorizontalOffset = 0; - _vertScrollBar.Minimum = 0; - _vertScrollBar.Maximum = totalVisibleHeight - totalVisibleFrozenHeight; - Debug.Assert(_vertScrollBar.Maximum > 0); - _vertScrollBar.Value = ComputeHeightOfScrolledOffRows(); - _vertScrollBar.LargeChange = _layout.Data.Height - totalVisibleFrozenHeight; - _vertScrollBar.Bounds = new Rectangle( - rightToLeftInternal ? _layout.Data.X - _vertScrollBar.Width : _layout.Data.Right, - vertScrollBarTop, - _vertScrollBar.Width, - vertScrollBarHeight); - _vertScrollBar.Enabled = Enabled; - _vertScrollBar.Visible = true; - _vertScrollBar.Invalidate(); + _horizScrollBar.Enabled = false; + _horizScrollBar.Minimum = 0; + _horizScrollBar.Maximum = 1; + _horizScrollBar.SmallChange = 1; + _horizScrollBar.LargeChange = 1; + _horizScrollBar.Value = 0; + } - VerticalScrollingOffset = _vertScrollBar.Value; + if (needVertScrollbar) + { + int vertScrollBarTop = _layout.Data.Y; + int vertScrollBarHeight = _layout.Data.Height; + if (_layout.ColumnHeadersVisible) + { + vertScrollBarTop = _layout.ColumnHeaders.Y; + vertScrollBarHeight += _layout.ColumnHeaders.Height; } - else + else if (SingleHorizontalBorderAdded) { - _vertScrollBar.Visible = false; - VerticalScrollingOffset = ComputeHeightOfScrolledOffRows(); - - _vertScrollBar.Enabled = false; - _vertScrollBar.Minimum = 0; - _vertScrollBar.Maximum = 1; - _vertScrollBar.LargeChange = 1; - _vertScrollBar.Value = 0; + vertScrollBarTop--; + vertScrollBarHeight++; } + + _vertScrollBar.Minimum = 0; + _vertScrollBar.Maximum = totalVisibleHeight - totalVisibleFrozenHeight; + Debug.Assert(_vertScrollBar.Maximum > 0); + _vertScrollBar.Value = ComputeHeightOfScrolledOffRows(); + _vertScrollBar.LargeChange = _layout.Data.Height - totalVisibleFrozenHeight; + _vertScrollBar.Bounds = new Rectangle( + rightToLeftInternal ? _layout.Data.X - _vertScrollBar.Width : _layout.Data.Right, + vertScrollBarTop, + _vertScrollBar.Width, + vertScrollBarHeight); + _vertScrollBar.Enabled = Enabled; + _vertScrollBar.Visible = true; + _vertScrollBar.Invalidate(); + + VerticalScrollingOffset = _vertScrollBar.Value; } - finally + else { - ResumeLayout(false); + _vertScrollBar.Visible = false; + VerticalScrollingOffset = ComputeHeightOfScrolledOffRows(); + + _vertScrollBar.Enabled = false; + _vertScrollBar.Minimum = 0; + _vertScrollBar.Maximum = 1; + _vertScrollBar.LargeChange = 1; + _vertScrollBar.Value = 0; } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGrid.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGrid.cs index 19de619a6ff..8d9c0e31b27 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGrid.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGrid.cs @@ -140,7 +140,7 @@ public PropertyGrid() _onComponentRemoved = OnComponentRemoved; _onComponentChanged = OnComponentChanged; - SuspendLayout(); + using SuspendLayoutScope layoutScope = new(this); // Scaling PropertyGrid but its children will be excluded from AutoScale. Please see OnLayoutInternal(). AutoScaleMode = AutoScaleMode.Inherit; @@ -155,14 +155,11 @@ public PropertyGrid() { RescaleConstants(); } - else + else if (!s_isScalingInitialized) { - if (!s_isScalingInitialized) - { - s_normalButtonSize = LogicalToDeviceUnits(s_defaultNormalButtonSize); - s_largeButtonSize = LogicalToDeviceUnits(s_defaultLargeButtonSize); - s_isScalingInitialized = true; - } + s_normalButtonSize = LogicalToDeviceUnits(s_defaultNormalButtonSize); + s_largeButtonSize = LogicalToDeviceUnits(s_defaultLargeButtonSize); + s_isScalingInitialized = true; } try @@ -177,57 +174,62 @@ public PropertyGrid() _separator2 = CreateSeparatorButton(); _toolStrip = new PropertyGridToolStrip(this); - _toolStrip.SuspendLayout(); - _toolStrip.ShowItemToolTips = true; - - _toolStrip.AccessibleRole = AccessibleRole.ToolBar; - _toolStrip.TabStop = true; - _toolStrip.AllowMerge = false; - - // This caption is for testing. - _toolStrip.Text = "PropertyGridToolBar"; - - // LayoutInternal handles positioning, and for perf reasons, we manually size. - _toolStrip.Dock = DockStyle.None; - _toolStrip.AutoSize = false; - _toolStrip.TabIndex = 1; - _toolStrip.ImageScalingSize = s_normalButtonSize; - - // Parity with the old... - _toolStrip.CanOverflow = false; - - // Hide the grip but add in a few more pixels of padding. - _toolStrip.GripStyle = ToolStripGripStyle.Hidden; - Padding toolStripPadding = _toolStrip.Padding; - toolStripPadding.Left = 2; - _toolStrip.Padding = toolStripPadding; - SetToolStripRenderer(); - - // Always add the property tab here. - AddTab(DefaultTabType, PropertyTabScope.Static); - - _helpPane = new(this); - _helpPane.SuspendLayout(); - _helpPane.TabStop = false; - _helpPane.Dock = DockStyle.None; - _helpPane.BackColor = SystemColors.Control; - _helpPane.ForeColor = SystemColors.ControlText; - _helpPane.MouseMove += OnChildMouseMove; - _helpPane.MouseDown += OnChildMouseDown; - - _commandsPane = new CommandsPane(this); - _commandsPane.SuspendLayout(); - _commandsPane.TabIndex = 3; - _commandsPane.Dock = DockStyle.None; - SetHotCommandColors(); - _commandsPane.Visible = false; - _commandsPane.MouseMove += OnChildMouseMove; - _commandsPane.MouseDown += OnChildMouseDown; - Controls.AddRange(new Control[] { _helpPane, _commandsPane, _gridView, _toolStrip }); + // SetupToolbar should perform the layout + using SuspendLayoutScope suspendToolStripLayout = new(_toolStrip, performLayout: false); + { + _toolStrip.ShowItemToolTips = true; + + _toolStrip.AccessibleRole = AccessibleRole.ToolBar; + _toolStrip.TabStop = true; + _toolStrip.AllowMerge = false; + + // This caption is for testing. + _toolStrip.Text = "PropertyGridToolBar"; + + // LayoutInternal handles positioning, and for perf reasons, we manually size. + _toolStrip.Dock = DockStyle.None; + _toolStrip.AutoSize = false; + _toolStrip.TabIndex = 1; + _toolStrip.ImageScalingSize = s_normalButtonSize; + + // Parity with the old. + _toolStrip.CanOverflow = false; + + // Hide the grip but add in a few more pixels of padding. + _toolStrip.GripStyle = ToolStripGripStyle.Hidden; + Padding toolStripPadding = _toolStrip.Padding; + toolStripPadding.Left = 2; + _toolStrip.Padding = toolStripPadding; + SetToolStripRenderer(); + + // Always add the property tab here. + AddTab(DefaultTabType, PropertyTabScope.Static); + + _helpPane = new(this); + using SuspendLayoutScope suspendHelpPaneLayout = new(_helpPane, performLayout: false); + + _helpPane.TabStop = false; + _helpPane.Dock = DockStyle.None; + _helpPane.BackColor = SystemColors.Control; + _helpPane.ForeColor = SystemColors.ControlText; + _helpPane.MouseMove += OnChildMouseMove; + _helpPane.MouseDown += OnChildMouseDown; + + _commandsPane = new CommandsPane(this); + using SuspendLayoutScope suspendCommandsPaneLayout = new(_commandsPane, performLayout: false); + _commandsPane.TabIndex = 3; + _commandsPane.Dock = DockStyle.None; + SetHotCommandColors(); + _commandsPane.Visible = false; + _commandsPane.MouseMove += OnChildMouseMove; + _commandsPane.MouseDown += OnChildMouseDown; + + Controls.AddRange([_helpPane, _commandsPane, _gridView, _toolStrip]); + + SetActiveControl(_gridView); + } - SetActiveControl(_gridView); - _toolStrip.ResumeLayout(performLayout: false); // SetupToolbar should perform the layout SetupToolbar(); PropertySort = PropertySort.Categorized | PropertySort.Alphabetical; SetSelectState(0); @@ -236,13 +238,6 @@ public PropertyGrid() { Debug.Fail(ex.ToString()); } - finally - { - _helpPane?.ResumeLayout(performLayout: false); - _commandsPane?.ResumeLayout(performLayout: false); - - ResumeLayout(performLayout: true); - } } internal IDesignerHost? ActiveDesigner @@ -3966,6 +3961,7 @@ private void SetupToolbar(bool fullRebuild) designPage, propertyPagesButtonHandler, useRadioButtonRole: false); + _viewPropertyPagesButton.Enabled = false; buttonList.Add(_viewPropertyPagesButton); @@ -3980,15 +3976,15 @@ private void SetupToolbar(bool fullRebuild) _toolStrip.ImageList = LargeButtons ? _largeButtonImages : _normalButtonImages; - _toolStrip.SuspendLayout(); - _toolStrip.Items.Clear(); - for (int j = 0; j < buttonList.Count; j++) + using (SuspendLayoutScope scope = new(_toolStrip)) { - _toolStrip.Items.Add(buttonList[j]); + _toolStrip.Items.Clear(); + for (int j = 0; j < buttonList.Count; j++) + { + _toolStrip.Items.Add(buttonList[j]); + } } - _toolStrip.ResumeLayout(); - if (_tabsDirty) { // If we're redoing our tabs make sure we setup the toolbar area correctly. diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/HelpPane.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/HelpPane.cs index 372c0d360cf..338bab2e926 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/HelpPane.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/HelpPane.cs @@ -32,7 +32,8 @@ internal partial class HelpPane : PropertyGrid.SnappableControl internal HelpPane(PropertyGrid owner) : base(owner) { - SuspendLayout(); + using SuspendLayoutScope scope = new(this, performLayout: false); + _titleLabel = new() { UseMnemonic = false, @@ -54,7 +55,6 @@ internal HelpPane(PropertyGrid owner) : base(owner) Text = SR.PropertyGridHelpPaneTitle; SetStyle(ControlStyles.Selectable, false); - ResumeLayout(false); } public virtual int Lines diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/PropertyGridView.DropDownHolder.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/PropertyGridView.DropDownHolder.cs index bcf9207e3e5..7be831ce063 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/PropertyGridView.DropDownHolder.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/PropertyGridView.DropDownHolder.cs @@ -597,9 +597,8 @@ public void SetDropDownControl(Control? control, bool resizable) } // Parent the control now. That way it can inherit our font and scale itself if it wants to. - try + using (SuspendLayoutScope scope = new(this, performLayout: true)) { - SuspendLayout(); Controls.Add(control); Size size = new(2 * DropDownHolderBorder + control.Width, 2 * DropDownHolderBorder + control.Height); @@ -657,10 +656,6 @@ public void SetDropDownControl(Control? control, bool resizable) Controls.Add(CreateNewLink); } } - finally - { - ResumeLayout(true); - } // Hook the resize event. _currentControl.Resize += OnCurrentControlResize; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Form.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Form.cs index 7f56640d19b..54b069fe66b 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Form.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Form.cs @@ -2317,23 +2317,16 @@ protected override void SetVisibleCore(bool value) if (ParentInternal is not null && ParentInternal.Visible) { - SuspendLayout(); - try - { - 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); - } - } - finally + 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) { - ResumeLayout(); + MdiParentInternal.UpdateWindowIcon(true); } } } @@ -2341,8 +2334,6 @@ protected override void SetVisibleCore(bool value) OnVisibleChanged(EventArgs.Empty); } - // ( - if (value && !IsMdiChild && (WindowState == FormWindowState.Maximized || TopMost)) { if (ActiveControl is null) @@ -4929,26 +4920,21 @@ protected override void Select(bool directed, bool forward) protected override void ScaleCore(float x, float y) { Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, $"{GetType().Name}::ScaleCore({x}, {y})"); - SuspendLayout(); - try - { - // 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) - { - control?.Scale(x, 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); } - finally + + foreach (Control control in Controls) { - ResumeLayout(); + control?.Scale(x, y); } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Layout/Containers/SplitContainer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Layout/Containers/SplitContainer.cs index 0be88c30f0a..f528783c53e 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Layout/Containers/SplitContainer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Layout/Containers/SplitContainer.cs @@ -1596,12 +1596,14 @@ private void ResizeSplitContainer() Panel2.SuspendLayout(); if (Width == 0) - { // Set the correct Width iif the WIDTH has changed to ZERO. + { + // Set the correct Width iif the WIDTH has changed to ZERO. Panel1.Size = new Size(0, Panel1.Height); Panel2.Size = new Size(0, Panel2.Height); } else if (Height == 0) - { // Set the correct Height iif the HEIGHT has changed to ZERO. + { + // Set the correct Height iif the HEIGHT has changed to ZERO. Panel1.Size = new Size(Panel1.Width, 0); Panel2.Size = new Size(Panel2.Width, 0); } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Layout/LayoutTransaction.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Layout/LayoutTransaction.cs index e140fe8fae8..908a4ff7409 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Layout/LayoutTransaction.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Layout/LayoutTransaction.cs @@ -116,7 +116,7 @@ public static void DoLayoutIf(bool condition, IArrangedElement? elementToLayout, } else { - LayoutTransaction.DoLayout(elementToLayout, elementCausingLayout, property); + DoLayout(elementToLayout, elementCausingLayout, property); } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/MDI/MDIClient.cs b/src/System.Windows.Forms/src/System/Windows/Forms/MDI/MDIClient.cs index 0cde5fbb190..30523e80b35 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/MDI/MDIClient.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/MDI/MDIClient.cs @@ -7,20 +7,21 @@ namespace System.Windows.Forms; /// -/// Represents the container for multiple-document interface (MDI) child forms. -/// This class cannot be inherited. +/// Represents the container for multiple-document interface (MDI) child forms. +/// This class cannot be inherited. /// /// -/// Don't create an control. -/// A form creates and uses the when you set the property to . +/// +/// Don't create an control. A form creates and uses the when you set +/// the property to . +/// /// [ToolboxItem(false)] [DesignTimeVisible(false)] public sealed partial class MdiClient : Control { - // kept in add order, not ZOrder. Need to return the correct - // array of items... - private readonly List
_children = new(); + // Kept in add order, not ZOrder. Need to return the correct array of items. + private readonly List _children = []; /// /// Creates a new MdiClient. @@ -179,7 +180,7 @@ protected override void OnResize(EventArgs e) [EditorBrowsable(EditorBrowsableState.Never)] protected override void ScaleCore(float dx, float dy) { - // Don't scale child forms... + // Don't scale child forms. SuspendLayout(); try diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Scrolling/ScrollableControl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Scrolling/ScrollableControl.cs index 2bec9af458a..3bb12124367 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Scrolling/ScrollableControl.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Scrolling/ScrollableControl.cs @@ -696,7 +696,14 @@ BackgroundImage is not null && PaintTransparentBackground(e, _displayRect); } - ControlPaint.DrawBackgroundImage(e.Graphics, BackgroundImage, BackColor, BackgroundImageLayout, _displayRect, _displayRect, _displayRect.Location); + ControlPaint.DrawBackgroundImage( + e.Graphics, + BackgroundImage, + BackColor, + BackgroundImageLayout, + _displayRect, + _displayRect, + _displayRect.Location); } else { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/SystemInformation.cs b/src/System.Windows.Forms/src/System/Windows/Forms/SystemInformation.cs index d52d53370e7..144f9f6bfb3 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/SystemInformation.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/SystemInformation.cs @@ -6,7 +6,6 @@ using System.Drawing.Interop; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Microsoft.Win32; using Windows.Win32.System.StationsAndDesktops; using Windows.Win32.UI.Accessibility; using static Windows.Win32.UI.WindowsAndMessaging.SYSTEM_METRICS_INDEX; @@ -21,9 +20,6 @@ public static class SystemInformation { private static bool s_checkMultiMonitorSupport; private static bool s_multiMonitorSupport; - private static bool s_highContrast; - private static bool s_systemEventsAttached; - private static bool s_systemEventsDirty = true; private static HWINSTA s_processWinStation; private static bool s_isUserInteractive; @@ -43,18 +39,9 @@ public static bool HighContrast { get { - EnsureSystemEvents(); - if (s_systemEventsDirty) - { - HIGHCONTRASTW data = default; - - s_highContrast = PInvokeCore.SystemParametersInfo(ref data) - && data.dwFlags.HasFlag(HIGHCONTRASTW_FLAGS.HCF_HIGHCONTRASTON); - - s_systemEventsDirty = false; - } - - return s_highContrast; + HIGHCONTRASTW data = default; + return PInvokeCore.SystemParametersInfo(ref data) + && data.dwFlags.HasFlag(HIGHCONTRASTW_FLAGS.HCF_HIGHCONTRASTON); } } @@ -536,20 +523,6 @@ public static unsafe bool UserInteractive /// public static string UserName => Environment.UserName; - private static void EnsureSystemEvents() - { - if (!s_systemEventsAttached) - { - SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged; - s_systemEventsAttached = true; - } - } - - private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs pref) - { - s_systemEventsDirty = true; - } - /// /// Gets whether the drop shadow effect in enabled. /// diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.Handlers.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.Handlers.cs index e0744b19d82..c8590e08cb7 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.Handlers.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ControlTests.Handlers.cs @@ -3935,10 +3935,10 @@ public static IEnumerable OnPaintBackground_VisualStyles_on_WithParent { Bounds = new Rectangle(1, 2, 30, 40) }; + foreach (Control parent in new Control[] { control, tabPage }) { int expected1 = parent == tabPage ? 0 : 1; - int expected2 = parent == tabPage ? 0 : 2; foreach (Image backgroundImage in new Image[] { null, new Bitmap(10, 10, PixelFormat.Format32bppRgb) }) { @@ -3964,8 +3964,8 @@ public static IEnumerable OnPaintBackground_VisualStyles_on_WithParent yield return new object[] { parent, true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; yield return new object[] { parent, false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; yield return new object[] { parent, false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; - yield return new object[] { parent, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; - yield return new object[] { parent, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; + yield return new object[] { parent, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; + yield return new object[] { parent, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; } } @@ -4090,8 +4090,8 @@ public static IEnumerable OnPaintBackground_WithParentWithHandle_TestD yield return new object[] { true, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; - yield return new object[] { true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; - yield return new object[] { true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; + yield return new object[] { true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; + yield return new object[] { true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ScrollableControlTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ScrollableControlTests.cs index 534c79059a3..b17d7a1164d 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ScrollableControlTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ScrollableControlTests.cs @@ -1652,8 +1652,8 @@ public static IEnumerable OnPaintBackground_VisualStyles_on_WithParent yield return new object[] { parentFactory(), hScroll, vScroll, true, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; yield return new object[] { parentFactory(), hScroll, vScroll, true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; - yield return new object[] { parentFactory(), hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; - yield return new object[] { parentFactory(), hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; + yield return new object[] { parentFactory(), hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; + yield return new object[] { parentFactory(), hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; yield return new object[] { parentFactory(), hScroll, vScroll, false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; yield return new object[] { parentFactory(), hScroll, vScroll, false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected1 }; } @@ -1802,8 +1802,8 @@ public static IEnumerable OnPaintBackground_WithParentWithHandle_TestD yield return new object[] { hScroll, vScroll, true, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { hScroll, vScroll, true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; - yield return new object[] { hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; - yield return new object[] { hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; + yield return new object[] { hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; + yield return new object[] { hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { hScroll, vScroll, false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { hScroll, vScroll, false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs index b557db896e3..9aeabd9f955 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/TabPageTests.cs @@ -4031,8 +4031,8 @@ public static IEnumerable OnPaintBackground_WithParent_TestData() yield return new object[] { appearance, useVisualStyleBackColor, true, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { appearance, useVisualStyleBackColor, true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; - yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; - yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; + yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; + yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { appearance, useVisualStyleBackColor, false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { appearance, useVisualStyleBackColor, false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; } @@ -4170,8 +4170,8 @@ public static IEnumerable OnPaintBackground_WithParentWithHandle_TestD yield return new object[] { appearance, useVisualStyleBackColor, true, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { appearance, useVisualStyleBackColor, true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; - yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; - yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; + yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; + yield return new object[] { appearance, useVisualStyleBackColor, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { appearance, useVisualStyleBackColor, false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { appearance, useVisualStyleBackColor, false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ToolStripTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ToolStripTests.cs index 9381e10edd9..ee786551c2c 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ToolStripTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ToolStripTests.cs @@ -5964,8 +5964,8 @@ public static IEnumerable OnPaintBackground_VisualStyles_on_WithParent yield return new object[] { parent, hScroll, vScroll, true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; yield return new object[] { parent, hScroll, vScroll, false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; yield return new object[] { parent, hScroll, vScroll, false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; - yield return new object[] { parent, hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected3 }; - yield return new object[] { parent, hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected3 }; + yield return new object[] { parent, hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; + yield return new object[] { parent, hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, expected2 }; } } } @@ -6101,8 +6101,8 @@ public static IEnumerable OnPaintBackground_WithParentWithHandle_TestD yield return new object[] { hScroll, vScroll, true, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { hScroll, vScroll, true, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; - yield return new object[] { hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; - yield return new object[] { hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 2 }; + yield return new object[] { hScroll, vScroll, true, Color.FromArgb(100, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; + yield return new object[] { hScroll, vScroll, true, Color.FromArgb(0, 50, 100, 150), new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { hScroll, vScroll, false, Color.Empty, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; yield return new object[] { hScroll, vScroll, false, Color.Red, new Bitmap(10, 10, PixelFormat.Format32bppArgb), ImageLayout.Tile, 1 }; } From f8177cd318df76a162f8c971f26a179528617f81 Mon Sep 17 00:00:00 2001 From: halgab <24685886+halgab@users.noreply.github.com> Date: Wed, 21 Feb 2024 02:22:51 +0100 Subject: [PATCH 12/30] Add missing Stream overloads in DataStreamFromComStream (#10857) * add missing Stream overloads in DataStreamFromComStream * review feedback --- .../Windows/Forms/ActiveX/DataStreamFromComStream.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ActiveX/DataStreamFromComStream.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ActiveX/DataStreamFromComStream.cs index 0e695b8c190..ec182413871 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ActiveX/DataStreamFromComStream.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ActiveX/DataStreamFromComStream.cs @@ -82,6 +82,13 @@ public override int Read(Span buffer) return (int)bytesRead; } + public override int ReadByte() + { + byte data = default; + int r = Read(new Span(ref data)); + return r == 0 ? -1 : data; + } + public override void SetLength(long value) { _comStream->SetSize((ulong)value); @@ -140,6 +147,8 @@ public override void Write(ReadOnlySpan buffer) } } + public override void WriteByte(byte value) => Write([value]); + protected override void Dispose(bool disposing) { if (disposing && _comStream is not null) From 571dc7ae1946b0795cec00b0ac81b112cabcd883 Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Wed, 21 Feb 2024 11:24:05 -0800 Subject: [PATCH 13/30] Update Effects per API review (#10919) This updates Effects to match the approved API and removes [RequiresPreviewFeatures]. Fixes #8835 https://github.com/dotnet/winforms/issues/8835#issuecomment-1954987873 --- .../src/System/Drawing/Bitmap.cs | 1 - .../src/System/Drawing/Graphics.cs | 18 +++- ...ffect.cs => BlackSaturationCurveEffect.cs} | 9 +- .../Drawing/Imaging/Effects/BlurEffect.cs | 3 - .../Effects/BrightnessContrastEffect.cs | 3 - .../Imaging/Effects/ColorBalanceEffect.cs | 3 - .../Imaging/Effects/ColorCurveEffect.cs | 3 - .../Imaging/Effects/ColorLookupTableEffect.cs | 36 ++++--- .../Imaging/Effects/ColorMatrixEffect.cs | 13 ++- ...ntrastEffect.cs => ContrastCurveEffect.cs} | 9 +- .../Drawing/Imaging/Effects/CurveChannel.cs | 8 +- ...DensityEffect.cs => DensityCurveEffect.cs} | 9 +- .../System/Drawing/Imaging/Effects/Effect.cs | 7 +- ...posureEffect.cs => ExposureCurveEffect.cs} | 9 +- .../Imaging/Effects/GrayScaleEffect.cs | 3 - ...lightEffect.cs => HighlightCurveEffect.cs} | 9 +- .../Drawing/Imaging/Effects/InvertEffect.cs | 3 - .../Drawing/Imaging/Effects/LevelsEffect.cs | 5 +- ...MidtoneEffect.cs => MidtoneCurveEffect.cs} | 9 +- .../Drawing/Imaging/Effects/SepiaEffect.cs | 3 - .../{ShadowEffect.cs => ShadowCurveEffect.cs} | 9 +- .../Drawing/Imaging/Effects/SharpenEffect.cs | 3 - .../Drawing/Imaging/Effects/TintEffect.cs | 3 - .../Drawing/Imaging/Effects/VividEffect.cs | 3 - ...ffect.cs => WhiteSaturationCurveEffect.cs} | 9 +- .../src/System/Drawing/PointerExtensions.cs | 2 - .../Drawing/Imaging/Effects/EffectsTests.cs | 94 ++++++++++++------- 27 files changed, 138 insertions(+), 148 deletions(-) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{BlackSaturationEffect.cs => BlackSaturationCurveEffect.cs} (85%) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{ContrastEffect.cs => ContrastCurveEffect.cs} (80%) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{DensityEffect.cs => DensityCurveEffect.cs} (82%) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{ExposureEffect.cs => ExposureCurveEffect.cs} (80%) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{HighlightEffect.cs => HighlightCurveEffect.cs} (81%) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{MidtoneEffect.cs => MidtoneCurveEffect.cs} (84%) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{ShadowEffect.cs => ShadowCurveEffect.cs} (84%) rename src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/{WhiteSaturationEffect.cs => WhiteSaturationCurveEffect.cs} (85%) diff --git a/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs b/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs index 79a0ec21b4f..3e2069f9cc5 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Bitmap.cs @@ -365,7 +365,6 @@ public Bitmap Clone(Rectangle rect, PixelFormat format) ///
/// The effect to apply. /// The area to apply to, or for the entire image. - [RequiresPreviewFeatures] public void ApplyEffect(Effect effect, Rectangle area = default) { RECT rect = area; diff --git a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs index 8c45cb461db..d20d874e6b5 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs @@ -3366,7 +3366,20 @@ public void DrawCachedBitmap(CachedBitmap cachedBitmap, int x, int y) #endif #if NET9_0_OR_GREATER - [RequiresPreviewFeatures] + /// + public void DrawImage( + Image image, + Effect effect) => DrawImage(image, effect, default, default, GraphicsUnit.Pixel, null); + + /// + /// Draws a portion of an image after applying a specified effect. + /// + /// to be drawn. + /// The effect to be applied when drawing. + /// The portion of the image to be drawn. draws the full image. + /// The transform to apply to the to determine the destination. + /// Unit of measure of the . + /// Additional adjustments to be applied, if any. public void DrawImage( Image image, Effect effect, @@ -3384,6 +3397,9 @@ public void DrawImage( imageAttr.Pointer(), (Unit)srcUnit).ThrowIfFailed(); + GC.KeepAlive(effect); + GC.KeepAlive(imageAttr); + GC.KeepAlive(image); GC.KeepAlive(this); } #endif diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlackSaturationEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlackSaturationCurveEffect.cs similarity index 85% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlackSaturationEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlackSaturationCurveEffect.cs index 1fdf840a365..0873aae2bbe 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlackSaturationEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlackSaturationCurveEffect.cs @@ -3,19 +3,16 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Sets the black saturation of an image. The black saturation is the point at which the darkest areas of the image /// are converted to black. /// -[RequiresPreviewFeatures] -public class BlackSaturationEffect : ColorCurveEffect +public class BlackSaturationCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given parameters. + /// Creates a new with the given parameters. /// /// The channel or channels that the effect is applied to. /// @@ -24,7 +21,7 @@ public class BlackSaturationEffect : ColorCurveEffect /// so that they spread out over the interval [0, 255]. Color channel values less than 15 are set to 0. /// /// is less than 0 or greater than 254. - public BlackSaturationEffect(CurveChannel channel, int blackSaturation) + public BlackSaturationCurveEffect(CurveChannel channel, int blackSaturation) : base(CurveAdjustments.AdjustBlackSaturation, channel, blackSaturation) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlurEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlurEffect.cs index d284540fda0..ec5dc82e87c 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlurEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BlurEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Applies a Gaussian blur. /// -[RequiresPreviewFeatures] public unsafe class BlurEffect : Effect { private readonly BlurParams _blurParams; diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BrightnessContrastEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BrightnessContrastEffect.cs index d051ab344b9..807b955b19c 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BrightnessContrastEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/BrightnessContrastEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Changes the brightness and contrast of an image. /// -[RequiresPreviewFeatures] public unsafe class BrightnessContrastEffect : Effect { private readonly BrightnessContrastParams _brightnessContrastParams; diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorBalanceEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorBalanceEffect.cs index c4f84176910..b33ed2da525 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorBalanceEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorBalanceEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Adjusts the color balance of an image. /// -[RequiresPreviewFeatures] public class ColorBalanceEffect : Effect { private readonly ColorBalanceParams _colorBalanceParams; diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorCurveEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorCurveEffect.cs index 038e6bb857a..818ef74ce76 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorCurveEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorCurveEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Base class for several effects that can be applied to an image. /// -[RequiresPreviewFeatures] public abstract class ColorCurveEffect : Effect { private readonly ColorCurveParams _parameters; diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorLookupTableEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorLookupTableEffect.cs index 491737e0ce4..47275419e3f 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorLookupTableEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorLookupTableEffect.cs @@ -4,7 +4,6 @@ #if NET9_0_OR_GREATER using System.Runtime.CompilerServices; -using System.Runtime.Versioning; namespace System.Drawing.Imaging.Effects; @@ -12,10 +11,9 @@ namespace System.Drawing.Imaging.Effects; /// Allows modification of the color components of an image. Individual color component values are changed to entries /// in a series of lookup tables. ///
-[RequiresPreviewFeatures] public unsafe class ColorLookupTableEffect : Effect { - private readonly ColorLUTParams _parameters; + private readonly byte[] _bytes = new byte[1024]; /// /// Creates a new with the given parameters. @@ -40,33 +38,41 @@ public ColorLookupTableEffect( ReadOnlySpan blueLookupTable, ReadOnlySpan alphaLookupTable) : base(PInvoke.ColorLUTEffectGuid) { - // ColorLUTParams will validate that the length fits. + ArgumentOutOfRangeException.ThrowIfGreaterThan(redLookupTable.Length, 256, nameof(redLookupTable)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(greenLookupTable.Length, 256, nameof(greenLookupTable)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(blueLookupTable.Length, 256, nameof(blueLookupTable)); + ArgumentOutOfRangeException.ThrowIfGreaterThan(alphaLookupTable.Length, 256, nameof(alphaLookupTable)); - Unsafe.SkipInit(out _parameters); - _parameters.lutR = redLookupTable; - _parameters.lutG = greenLookupTable; - _parameters.lutB = blueLookupTable; - _parameters.lutA = alphaLookupTable; + Span bytes = _bytes; + blueLookupTable.CopyTo(bytes); + greenLookupTable.CopyTo(bytes[256..]); + redLookupTable.CopyTo(bytes[512..]); + alphaLookupTable.CopyTo(bytes[768..]); + + fixed (byte* b = _bytes) + { + SetParameters(ref Unsafe.AsRef(b)); + } } /// - /// The lookup table for the red channel. + /// The lookup table for the blue channel. /// - public ReadOnlySpan RedLookupTable => _parameters.lutR.AsReadOnlySpan(); + public ReadOnlyMemory BlueLookupTable => new(_bytes, 0, 256); /// /// The lookup table for the green channel. /// - public ReadOnlySpan GreenLookupTable => _parameters.lutG.AsReadOnlySpan(); + public ReadOnlyMemory GreenLookupTable => new(_bytes, 256, 256); /// - /// The lookup table for the blue channel. + /// The lookup table for the red channel. /// - public ReadOnlySpan BlueLookupTable => _parameters.lutB.AsReadOnlySpan(); + public ReadOnlyMemory RedLookupTable => new(_bytes, 512, 256); /// /// The lookup table for the alpha channel. /// - public ReadOnlySpan AlphaLookupTable => _parameters.lutA.AsReadOnlySpan(); + public ReadOnlyMemory AlphaLookupTable => new(_bytes, 768, 256); } #endif diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorMatrixEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorMatrixEffect.cs index c510d12e094..f50dcab66c3 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorMatrixEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ColorMatrixEffect.cs @@ -3,8 +3,6 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// @@ -16,7 +14,6 @@ namespace System.Drawing.Imaging.Effects; /// examples of using a color matrix to adjust the colors of an image. /// /// -[RequiresPreviewFeatures] public unsafe class ColorMatrixEffect : Effect { private readonly ColorMatrix _matrix; @@ -35,5 +32,15 @@ public ColorMatrixEffect(ColorMatrix matrix) : base(PInvoke.ColorMatrixEffectGui _matrix = matrix; } + + /// + /// The color transform matrix. + /// + /// + /// + /// is mutable, but effects do not support changing the matrix after creation. + /// + /// + public ColorMatrix Matrix => _matrix; } #endif diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ContrastEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ContrastCurveEffect.cs similarity index 80% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ContrastEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ContrastCurveEffect.cs index 242061fd8eb..48305ed617d 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ContrastEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ContrastCurveEffect.cs @@ -3,18 +3,15 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Increases or decreases the contrast of an image. /// -[RequiresPreviewFeatures] -public class ContrastEffect : ColorCurveEffect +public class ContrastCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given adjustment value. + /// Creates a new with the given adjustment value. /// /// The channel or channels that the effect is applied to. /// @@ -22,7 +19,7 @@ public class ContrastEffect : ColorCurveEffect /// specify increased contrast and negative values specify decreased contrast. /// /// is less than -100 or greater than 100. - public ContrastEffect(CurveChannel channel, int contrast) + public ContrastCurveEffect(CurveChannel channel, int contrast) : base(CurveAdjustments.AdjustContrast, channel, contrast) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/CurveChannel.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/CurveChannel.cs index 8a75f401efe..de4fd779031 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/CurveChannel.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/CurveChannel.cs @@ -13,21 +13,21 @@ public enum CurveChannel /// /// Specifies that the color adjustment applies to all channels. /// - CurveChannelAll = GdiPlus.CurveChannel.CurveChannelAll, + All = GdiPlus.CurveChannel.CurveChannelAll, /// /// Specifies that the color adjustment applies only to the red channel. /// - CurveChannelRed = GdiPlus.CurveChannel.CurveChannelRed, + Red = GdiPlus.CurveChannel.CurveChannelRed, /// /// Specifies that the color adjustment applies only to the green channel. /// - CurveChannelGreen = GdiPlus.CurveChannel.CurveChannelGreen, + Green = GdiPlus.CurveChannel.CurveChannelGreen, /// /// Specifies that the color adjustment applies only to the blue channel. /// - CurveChannelBlue = GdiPlus.CurveChannel.CurveChannelBlue + Blue = GdiPlus.CurveChannel.CurveChannelBlue } #endif diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/DensityEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/DensityCurveEffect.cs similarity index 82% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/DensityEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/DensityCurveEffect.cs index bada8a7a9f5..cb1e2d647de 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/DensityEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/DensityCurveEffect.cs @@ -3,18 +3,15 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Simulates increasing or decreasing the film density of a photograph. /// -[RequiresPreviewFeatures] -public class DensityEffect : ColorCurveEffect +public class DensityCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given . + /// Creates a new with the given . /// /// The channel or channels that the effect is applied to. /// @@ -22,7 +19,7 @@ public class DensityEffect : ColorCurveEffect /// increased density (lighter picture) and negative values specify decreased density (darker picture). /// /// is less than -256 or greater than 256. - public DensityEffect(CurveChannel channel, int density) + public DensityCurveEffect(CurveChannel channel, int density) : base(CurveAdjustments.AdjustDensity, channel, density) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/Effect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/Effect.cs index 9c15f5e661e..5510ee888a0 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/Effect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/Effect.cs @@ -3,21 +3,18 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Base class for all effects. /// -[RequiresPreviewFeatures] public unsafe abstract class Effect : IDisposable { private CGpEffect* _nativeEffect; internal CGpEffect* NativeEffect => _nativeEffect; - protected Effect(Guid guid) + private protected Effect(Guid guid) { CGpEffect* nativeEffect; PInvoke.GdipCreateEffect(guid, &nativeEffect).ThrowIfFailed(); @@ -41,7 +38,7 @@ private protected void SetParameters(ref T parameters) where T : unmanaged ~Effect() => Dispose(disposing: false); - private void Dispose(bool disposing) + public virtual void Dispose(bool disposing) { if (_nativeEffect is not null) { diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ExposureEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ExposureCurveEffect.cs similarity index 80% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ExposureEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ExposureCurveEffect.cs index eeb425817a6..d318124bd99 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ExposureEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ExposureCurveEffect.cs @@ -3,18 +3,15 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Simulates increasing or decreasing the exposure of a photograph /// -[RequiresPreviewFeatures] -public class ExposureEffect : ColorCurveEffect +public class ExposureCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given adjustment. + /// Creates a new with the given adjustment. /// /// The channel or channels that the effect is applied to. /// @@ -22,7 +19,7 @@ public class ExposureEffect : ColorCurveEffect /// specify increased exposure and negative values specify decreased exposure. /// /// is less than -256 or greater than 256. - public ExposureEffect(CurveChannel channel, int exposure) + public ExposureCurveEffect(CurveChannel channel, int exposure) : base(CurveAdjustments.AdjustExposure, channel, exposure) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/GrayScaleEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/GrayScaleEffect.cs index 36e121336c9..9802c10cd7c 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/GrayScaleEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/GrayScaleEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Effect that converts an image to grayscale. /// -[RequiresPreviewFeatures] public sealed class GrayScaleEffect : ColorMatrixEffect { public GrayScaleEffect() : base( diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/HighlightEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/HighlightCurveEffect.cs similarity index 81% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/HighlightEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/HighlightCurveEffect.cs index bc0a4094a98..c8a6c60abfd 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/HighlightEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/HighlightCurveEffect.cs @@ -3,8 +3,6 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// @@ -12,18 +10,17 @@ namespace System.Drawing.Imaging.Effects; /// intensity. You can use this effect to get more definition in the light areas of an image without affecting /// the dark areas. /// -[RequiresPreviewFeatures] -public class HighlightEffect : ColorCurveEffect +public class HighlightCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given adjustment. + /// Creates a new with the given adjustment. /// /// The channel or channels that the effect is applied to. /// /// A value in the range of -100 through 100. A value of 0 specifies no change. Positive values specify that the /// light areas are made lighter, and negative values specify that the light areas are made darker. /// - public HighlightEffect(CurveChannel channel, int highlight) + public HighlightCurveEffect(CurveChannel channel, int highlight) : base(CurveAdjustments.AdjustHighlight, channel, highlight) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/InvertEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/InvertEffect.cs index 40b05c8a694..bb7cb6cad3f 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/InvertEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/InvertEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Effect that inverts the colors in an image. /// -[RequiresPreviewFeatures] public sealed class InvertEffect : ColorMatrixEffect { public InvertEffect() : base( diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/LevelsEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/LevelsEffect.cs index 5f66bdaf23b..4eddd9ce7ca 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/LevelsEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/LevelsEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// -/// Adjusts the light, midtone, or dark areas of an image. +/// Adjusts the light, mid-tone, or dark areas of an image. /// -[RequiresPreviewFeatures] public class LevelsEffect : Effect { private readonly LevelsParams _levelsParams; diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/MidtoneEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/MidtoneCurveEffect.cs similarity index 84% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/MidtoneEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/MidtoneCurveEffect.cs index 6fd97dd5d73..9453219edbf 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/MidtoneEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/MidtoneCurveEffect.cs @@ -3,8 +3,6 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// @@ -12,11 +10,10 @@ namespace System.Drawing.Imaging.Effects; /// color channel values near the minimum or maximum intensity. You can use this effect to lighten (or darken) /// an image without loosing the contrast between the darkest and lightest portions of the image. /// -[RequiresPreviewFeatures] -public class MidtoneEffect : ColorCurveEffect +public class MidtoneCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given adjustment. + /// Creates a new with the given adjustment. /// /// The channel or channels that the effect is applied to. /// @@ -24,7 +21,7 @@ public class MidtoneEffect : ColorCurveEffect /// mid-tones are made lighter, and negative values specify that the mid-tones are made darker. /// /// is less than -100 or greater than 100. - public MidtoneEffect(CurveChannel channel, int midtone) + public MidtoneCurveEffect(CurveChannel channel, int midtone) : base(CurveAdjustments.AdjustMidtone, channel, midtone) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SepiaEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SepiaEffect.cs index 9bfd7d60be5..6a941f3208e 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SepiaEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SepiaEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Effect that converts an image to sepia. /// -[RequiresPreviewFeatures] public sealed class SepiaEffect : ColorMatrixEffect { public SepiaEffect() : base( diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ShadowEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ShadowCurveEffect.cs similarity index 84% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ShadowEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ShadowCurveEffect.cs index e0417c29671..c80a244b5cb 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ShadowEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/ShadowCurveEffect.cs @@ -3,8 +3,6 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// @@ -12,11 +10,10 @@ namespace System.Drawing.Imaging.Effects; /// intensity. You can use this effect to get more definition in the dark areas of an image without affecting /// the light areas. /// -[RequiresPreviewFeatures] -public class ShadowEffect : ColorCurveEffect +public class ShadowCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given . + /// Creates a new with the given . /// /// The channel or channels that the effect is applied to. /// @@ -24,7 +21,7 @@ public class ShadowEffect : ColorCurveEffect /// dark areas are made lighter, and negative values specify that the dark areas are made darker. /// /// is less than -100 or greater than 100. - public ShadowEffect(CurveChannel channel, int shadow) + public ShadowCurveEffect(CurveChannel channel, int shadow) : base(CurveAdjustments.AdjustShadow, channel, shadow) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SharpenEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SharpenEffect.cs index 534b733c66f..37beae8386c 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SharpenEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/SharpenEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Sharpens an image. /// -[RequiresPreviewFeatures] public unsafe class SharpenEffect : Effect { private readonly SharpenParams _sharpenParams; diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/TintEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/TintEffect.cs index bc11c8d1c58..1aed7ec0271 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/TintEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/TintEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Allows you to apply a tint to an image. /// -[RequiresPreviewFeatures] public unsafe class TintEffect : Effect { private readonly TintParams _tintParams; diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/VividEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/VividEffect.cs index 9c69119e4cd..1d9260a1492 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/VividEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/VividEffect.cs @@ -3,14 +3,11 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Effect that makes colors more vivid. /// -[RequiresPreviewFeatures] public sealed class VividEffect : ColorMatrixEffect { public VividEffect() : base( diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/WhiteSaturationEffect.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/WhiteSaturationCurveEffect.cs similarity index 85% rename from src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/WhiteSaturationEffect.cs rename to src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/WhiteSaturationCurveEffect.cs index 60fb1feb2b3..767b7621d42 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/WhiteSaturationEffect.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Effects/WhiteSaturationCurveEffect.cs @@ -3,19 +3,16 @@ #if NET9_0_OR_GREATER -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects; /// /// Sets the white saturation of an image. The white saturation is the point at which the lightest areas of the image /// are converted to white. /// -[RequiresPreviewFeatures] -public class WhiteSaturationEffect : ColorCurveEffect +public class WhiteSaturationCurveEffect : ColorCurveEffect { /// - /// Creates a new with the given parameters. + /// Creates a new with the given parameters. /// /// The channel or channels that the effect is applied to. /// @@ -24,7 +21,7 @@ public class WhiteSaturationEffect : ColorCurveEffect /// so that they spread out over the interval [0, 255]. Color channel values greater than 240 are set to 255. /// /// was less than 1 or greater than 255. - public WhiteSaturationEffect(CurveChannel channel, int whiteSaturation) + public WhiteSaturationCurveEffect(CurveChannel channel, int whiteSaturation) : base(CurveAdjustments.AdjustWhiteSaturation, channel, whiteSaturation) { } diff --git a/src/System.Drawing.Common/src/System/Drawing/PointerExtensions.cs b/src/System.Drawing.Common/src/System/Drawing/PointerExtensions.cs index 6de168f5c8e..736b7fef876 100644 --- a/src/System.Drawing.Common/src/System/Drawing/PointerExtensions.cs +++ b/src/System.Drawing.Common/src/System/Drawing/PointerExtensions.cs @@ -4,7 +4,6 @@ using System.Drawing.Imaging; #if NET9_0_OR_GREATER using System.Drawing.Imaging.Effects; -using System.Runtime.Versioning; #endif namespace System.Drawing; @@ -24,7 +23,6 @@ internal static unsafe class PointerExtensions public static GpMetafile* Pointer(this Metafile? metafile) => metafile is null ? null : (GpMetafile*)((Image)metafile).Pointer(); public static GpImage* Pointer(this Image? image) => image is null ? null : ((IPointer)image).Pointer; #if NET9_0_OR_GREATER - [RequiresPreviewFeatures] public static CGpEffect* Pointer(this Effect? effect) => effect is null ? null : effect.NativeEffect; #endif } diff --git a/src/System.Drawing.Common/tests/System/Drawing/Imaging/Effects/EffectsTests.cs b/src/System.Drawing.Common/tests/System/Drawing/Imaging/Effects/EffectsTests.cs index 460dd31b565..a35ed6b6b6f 100644 --- a/src/System.Drawing.Common/tests/System/Drawing/Imaging/Effects/EffectsTests.cs +++ b/src/System.Drawing.Common/tests/System/Drawing/Imaging/Effects/EffectsTests.cs @@ -1,11 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Runtime.Versioning; - namespace System.Drawing.Imaging.Effects.Tests; -[RequiresPreviewFeatures] public class EffectsTests { [Fact] @@ -23,18 +20,18 @@ public void SepiaEffect_Apply() } [Theory] - [InlineData(CurveChannel.CurveChannelAll, 0)] - [InlineData(CurveChannel.CurveChannelRed, 0)] - [InlineData(CurveChannel.CurveChannelGreen, 0)] - [InlineData(CurveChannel.CurveChannelBlue, 0)] - [InlineData(CurveChannel.CurveChannelAll, 254)] - [InlineData(CurveChannel.CurveChannelRed, 254)] - [InlineData(CurveChannel.CurveChannelGreen, 254)] - [InlineData(CurveChannel.CurveChannelBlue, 254)] + [InlineData(CurveChannel.All, 0)] + [InlineData(CurveChannel.Red, 0)] + [InlineData(CurveChannel.Green, 0)] + [InlineData(CurveChannel.Blue, 0)] + [InlineData(CurveChannel.All, 254)] + [InlineData(CurveChannel.Red, 254)] + [InlineData(CurveChannel.Green, 254)] + [InlineData(CurveChannel.Blue, 254)] public void BlackSaturationEffect_Apply(CurveChannel channel, int blackPoint) { using Bitmap bitmap = new(10, 10); - using BlackSaturationEffect effect = new(channel, blackPoint); + using BlackSaturationCurveEffect effect = new(channel, blackPoint); bitmap.ApplyEffect(effect); } @@ -43,23 +40,23 @@ public void BlackSaturationEffect_Apply(CurveChannel channel, int blackPoint) [InlineData(255)] public void BlackSaturationEffect_Apply_Invalid(int blackPoint) { - Action action = () => _ = new BlackSaturationEffect(CurveChannel.CurveChannelAll, blackPoint); + Action action = () => _ = new BlackSaturationCurveEffect(CurveChannel.All, blackPoint); action.Should().Throw(); } [Theory] - [InlineData(CurveChannel.CurveChannelAll, 1)] - [InlineData(CurveChannel.CurveChannelRed, 1)] - [InlineData(CurveChannel.CurveChannelGreen, 1)] - [InlineData(CurveChannel.CurveChannelBlue, 1)] - [InlineData(CurveChannel.CurveChannelAll, 255)] - [InlineData(CurveChannel.CurveChannelRed, 255)] - [InlineData(CurveChannel.CurveChannelGreen, 255)] - [InlineData(CurveChannel.CurveChannelBlue, 255)] + [InlineData(CurveChannel.All, 1)] + [InlineData(CurveChannel.Red, 1)] + [InlineData(CurveChannel.Green, 1)] + [InlineData(CurveChannel.Blue, 1)] + [InlineData(CurveChannel.All, 255)] + [InlineData(CurveChannel.Red, 255)] + [InlineData(CurveChannel.Green, 255)] + [InlineData(CurveChannel.Blue, 255)] public void WhiteSaturationEffect_Apply(CurveChannel channel, int whitePoint) { using Bitmap bitmap = new(10, 10); - using WhiteSaturationEffect effect = new(channel, whitePoint); + using WhiteSaturationCurveEffect effect = new(channel, whitePoint); bitmap.ApplyEffect(effect); } @@ -69,7 +66,7 @@ public void WhiteSaturationEffect_Apply(CurveChannel channel, int whitePoint) [InlineData(256)] public void WhiteSaturationEffect_Apply_Invalid(int whitePoint) { - Action action = () => _ = new WhiteSaturationEffect(CurveChannel.CurveChannelAll, whitePoint); + Action action = () => _ = new WhiteSaturationCurveEffect(CurveChannel.All, whitePoint); action.Should().Throw(); } @@ -186,11 +183,38 @@ public void ColorLookupTableEffect_Apply(byte tableValue) Span buffer = stackalloc byte[256]; buffer.Fill(tableValue); using ColorLookupTableEffect effect = new(buffer, buffer, buffer, buffer); + + effect.AlphaLookupTable.Length.Should().Be(256); + effect.AlphaLookupTable.Span[0].Should().Be(tableValue); + effect.AlphaLookupTable.Span[255].Should().Be(tableValue); + effect.BlueLookupTable.Length.Should().Be(256); + effect.BlueLookupTable.Span[0].Should().Be(tableValue); + effect.BlueLookupTable.Span[255].Should().Be(tableValue); + effect.GreenLookupTable.Length.Should().Be(256); + effect.GreenLookupTable.Span[0].Should().Be(tableValue); + effect.GreenLookupTable.Span[255].Should().Be(tableValue); + effect.RedLookupTable.Length.Should().Be(256); + effect.RedLookupTable.Span[0].Should().Be(tableValue); + effect.RedLookupTable.Span[255].Should().Be(tableValue); + bitmap.ApplyEffect(effect); // The final values will be padded with zeros using ColorLookupTableEffect effect2 = new(buffer[..100], buffer[..1], buffer, buffer); bitmap.ApplyEffect(effect); + + effect2.RedLookupTable.Length.Should().Be(256); + effect2.RedLookupTable.Span[0].Should().Be(tableValue); + effect2.RedLookupTable.Span[255].Should().Be(0); + effect2.GreenLookupTable.Length.Should().Be(256); + effect2.GreenLookupTable.Span[0].Should().Be(tableValue); + effect2.GreenLookupTable.Span[255].Should().Be(0); + effect2.BlueLookupTable.Length.Should().Be(256); + effect2.BlueLookupTable.Span[0].Should().Be(tableValue); + effect2.BlueLookupTable.Span[255].Should().Be(tableValue); + effect2.AlphaLookupTable.Length.Should().Be(256); + effect2.AlphaLookupTable.Span[0].Should().Be(tableValue); + effect2.AlphaLookupTable.Span[255].Should().Be(tableValue); } [Fact] @@ -227,7 +251,7 @@ public void ColorMatrixEffect_Apply(float value) public void ContrastEffect_Apply(int contrast) { using Bitmap bitmap = new(10, 10); - using ContrastEffect effect = new(CurveChannel.CurveChannelAll, contrast); + using ContrastCurveEffect effect = new(CurveChannel.All, contrast); bitmap.ApplyEffect(effect); } @@ -236,7 +260,7 @@ public void ContrastEffect_Apply(int contrast) [InlineData(101)] public void ContrastEffect_Apply_Invalid(int contrast) { - Action action = () => _ = new ContrastEffect(CurveChannel.CurveChannelAll, contrast); + Action action = () => _ = new ContrastCurveEffect(CurveChannel.All, contrast); action.Should().Throw(); } @@ -247,7 +271,7 @@ public void ContrastEffect_Apply_Invalid(int contrast) public void DensityEffect_Apply(int density) { using Bitmap bitmap = new(10, 10); - using DensityEffect effect = new(CurveChannel.CurveChannelAll, density); + using DensityCurveEffect effect = new(CurveChannel.All, density); bitmap.ApplyEffect(effect); } @@ -256,7 +280,7 @@ public void DensityEffect_Apply(int density) [InlineData(257)] public void DensityEffect_Apply_Invalid(int density) { - Action action = () => _ = new DensityEffect(CurveChannel.CurveChannelAll, density); + Action action = () => _ = new DensityCurveEffect(CurveChannel.All, density); action.Should().Throw(); } @@ -267,7 +291,7 @@ public void DensityEffect_Apply_Invalid(int density) public void ExposureEffect_Apply(int exposure) { using Bitmap bitmap = new(10, 10); - using ExposureEffect effect = new(CurveChannel.CurveChannelAll, exposure); + using ExposureCurveEffect effect = new(CurveChannel.All, exposure); bitmap.ApplyEffect(effect); } @@ -276,7 +300,7 @@ public void ExposureEffect_Apply(int exposure) [InlineData(257)] public void ExposureEffect_Apply_Invalid(int exposure) { - Action action = () => _ = new ExposureEffect(CurveChannel.CurveChannelAll, exposure); + Action action = () => _ = new ExposureCurveEffect(CurveChannel.All, exposure); action.Should().Throw(); } @@ -287,7 +311,7 @@ public void ExposureEffect_Apply_Invalid(int exposure) public void HighlightEffect_Apply(int highlight) { using Bitmap bitmap = new(10, 10); - using HighlightEffect effect = new(CurveChannel.CurveChannelAll, highlight); + using HighlightCurveEffect effect = new(CurveChannel.All, highlight); bitmap.ApplyEffect(effect); } @@ -296,7 +320,7 @@ public void HighlightEffect_Apply(int highlight) [InlineData(101)] public void HighlightEffect_Apply_Invalid(int highlight) { - Action action = () => _ = new HighlightEffect(CurveChannel.CurveChannelAll, highlight); + Action action = () => _ = new HighlightCurveEffect(CurveChannel.All, highlight); action.Should().Throw(); } @@ -307,7 +331,7 @@ public void HighlightEffect_Apply_Invalid(int highlight) public void MidtoneEffect_Apply(int midtone) { using Bitmap bitmap = new(10, 10); - using MidtoneEffect effect = new(CurveChannel.CurveChannelAll, midtone); + using MidtoneCurveEffect effect = new(CurveChannel.All, midtone); bitmap.ApplyEffect(effect); } @@ -316,7 +340,7 @@ public void MidtoneEffect_Apply(int midtone) [InlineData(101)] public void MidtoneEffect_Apply_Invalid(int midtone) { - Action action = () => _ = new MidtoneEffect(CurveChannel.CurveChannelAll, midtone); + Action action = () => _ = new MidtoneCurveEffect(CurveChannel.All, midtone); action.Should().Throw(); } @@ -327,7 +351,7 @@ public void MidtoneEffect_Apply_Invalid(int midtone) public void ShadowEffect_Apply(int shadow) { using Bitmap bitmap = new(10, 10); - using ShadowEffect effect = new(CurveChannel.CurveChannelAll, shadow); + using ShadowCurveEffect effect = new(CurveChannel.All, shadow); bitmap.ApplyEffect(effect); } @@ -336,7 +360,7 @@ public void ShadowEffect_Apply(int shadow) [InlineData(101)] public void ShadowEffect_Apply_Invalid(int shadow) { - Action action = () => _ = new ShadowEffect(CurveChannel.CurveChannelAll, shadow); + Action action = () => _ = new ShadowCurveEffect(CurveChannel.All, shadow); action.Should().Throw(); } From 17a3fcdcf0b78be20c0694a7f2e234615c9dbf55 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:50:38 -0800 Subject: [PATCH 14/30] [main] Update dependencies from dotnet/runtime (#10925) Update dependencies from https://github.com/dotnet/runtime build 20240220.11 Microsoft.Internal.Runtime.WindowsDesktop.Transport , Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.ILAsm , Microsoft.NETCore.ILDAsm , Microsoft.NETCore.Platforms , Microsoft.Win32.Registry.AccessControl , Microsoft.Win32.SystemEvents , runtime.win-x64.Microsoft.NETCore.ILAsm , runtime.win-x86.Microsoft.NETCore.ILAsm , System.CodeDom , System.ComponentModel.Composition , System.ComponentModel.Composition.Registration , System.Configuration.ConfigurationManager , System.Data.Odbc , System.Data.OleDb , System.Diagnostics.EventLog , System.Diagnostics.PerformanceCounter , System.DirectoryServices , System.DirectoryServices.AccountManagement , System.DirectoryServices.Protocols , System.IO.Hashing , System.IO.Packaging , System.IO.Ports , System.Management , System.Reflection.Context , System.Reflection.MetadataLoadContext , System.Resources.Extensions , System.Runtime.Caching , System.Security.Cryptography.Pkcs , System.Security.Cryptography.ProtectedData , System.Security.Cryptography.Xml , System.Security.Permissions , System.ServiceModel.Syndication , System.ServiceProcess.ServiceController , System.Speech , System.Text.Encoding.CodePages , System.Text.Encodings.Web , System.Text.Json , System.Threading.AccessControl , System.Windows.Extensions , VS.Redist.Common.NetCore.SharedFramework.x64.9.0 From Version 9.0.0-preview.2.24120.1 -> To Version 9.0.0-preview.2.24120.11 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 172 ++++++++++++++++++++-------------------- eng/Versions.props | 54 ++++++------- global.json | 2 +- 3 files changed, 114 insertions(+), 114 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3dfcdf39389..1fe9637c011 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,178 +7,178 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d - + https://github.com/dotnet/runtime - 9dc6ea62a4d195ae4559f4609a56933c61889756 + 1b1d26ac74e374309fb101382026ba0480d3821d diff --git a/eng/Versions.props b/eng/Versions.props index a54c69032e3..653a371160c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,35 +15,35 @@ - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 5.0.0-preview.7.20320.5 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 6.0.0 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 - 9.0.0-preview.2.24120.1 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24120.11 diff --git a/global.json b/global.json index 3d4b6a3f100..bad8b4c2ee5 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24120.1" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24120.11" }, "native-tools": { "cmake": "latest" From b86f81069a90056f80487f7bac4604b19a4996b8 Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Wed, 21 Feb 2024 14:36:30 -0800 Subject: [PATCH 15/30] Update APIs for API review (#10926) Update RoundedRectangle APIs, ColorMap APIs and PrinterSettings.StringCollection per API review. --- .../System/Drawing/Drawing2D/GraphicsPath.cs | 32 +++++++++---------- .../src/System/Drawing/Graphics.cs | 22 ++++++------- .../System/Drawing/Imaging/ImageAttributes.cs | 16 +++++++--- .../System/Drawing/Imaging/ValueColorMap.cs | 12 ------- .../PrinterSettings.StringCollection.cs | 2 +- src/System.Drawing.Common/tests/Helpers.cs | 2 +- ...onPanel.EditorPropertyLine.EditorButton.cs | 4 +-- .../DataGridView/DataGridViewRowHeaderCell.cs | 4 +-- .../ToolStripHighContrastRenderer.cs | 8 ++--- .../Windows/Forms/Rendering/ControlPaint.cs | 6 ++-- 10 files changed, 52 insertions(+), 56 deletions(-) delete mode 100644 src/System.Drawing.Common/src/System/Drawing/Imaging/ValueColorMap.cs diff --git a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs index 5165a26ba42..d2bfb7b427c 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs @@ -494,40 +494,40 @@ public void AddRectangles(Rectangle[] rects) #if NET9_0_OR_GREATER /// - public void AddRoundedRectangle(Rectangle rect, Size corner) => - AddRoundedRectangle((RectangleF)rect, corner); + public void AddRoundedRectangle(Rectangle rect, Size radius) => + AddRoundedRectangle((RectangleF)rect, radius); /// /// Adds a rounded rectangle to this path. /// /// The bounds of the rectangle to add. - /// The size of the ellipse used to round the corners of the rectangle. - public void AddRoundedRectangle(RectangleF rect, SizeF corner) + /// The radius width and height used to round the corners of the rectangle. + public void AddRoundedRectangle(RectangleF rect, SizeF radius) { StartFigure(); AddArc( - rect.Right - corner.Width, + rect.Right - radius.Width, rect.Top, - corner.Width, - corner.Height, + radius.Width, + radius.Height, -90.0f, 90.0f); AddArc( - rect.Right - corner.Width, - rect.Bottom - corner.Height, - corner.Width, - corner.Height, + rect.Right - radius.Width, + rect.Bottom - radius.Height, + radius.Width, + radius.Height, 0.0f, 90.0f); AddArc( rect.Left, - rect.Bottom - corner.Height, - corner.Width, - corner.Height, + rect.Bottom - radius.Height, + radius.Width, + radius.Height, 90.0f, 90.0f); AddArc( rect.Left, rect.Top, - corner.Width, - corner.Height, + radius.Width, + radius.Height, 180.0f, 90.0f); CloseFigure(); } diff --git a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs index d20d874e6b5..8b2d58f785b 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs @@ -747,18 +747,18 @@ public void DrawBezier(Pen pen, Point pt1, Point pt2, Point pt3, Point pt4) => #if NET9_0_OR_GREATER /// - public void DrawRoundedRectangle(Pen pen, Rectangle rect, Size corner) => - DrawRoundedRectangle(pen, (RectangleF)rect, corner); + public void DrawRoundedRectangle(Pen pen, Rectangle rect, Size radius) => + DrawRoundedRectangle(pen, (RectangleF)rect, radius); /// /// Draws the outline of the specified rounded rectangle. /// /// The to draw the outline with. /// - public void DrawRoundedRectangle(Pen pen, RectangleF rect, SizeF corner) + public void DrawRoundedRectangle(Pen pen, RectangleF rect, SizeF radius) { using GraphicsPath path = new(); - path.AddRoundedRectangle(rect, corner); + path.AddRoundedRectangle(rect, radius); DrawPath(pen, path); } #endif @@ -1114,19 +1114,19 @@ public void DrawClosedCurve(Pen pen, Point[] points, float tension, Drawing2D.Fi #if NET9_0_OR_GREATER /// /> - public void FillRoundedRectangle(Brush brush, Rectangle rect, Size corner) => - FillRoundedRectangle(brush, (RectangleF)rect, corner); + public void FillRoundedRectangle(Brush brush, Rectangle rect, Size radius) => + FillRoundedRectangle(brush, (RectangleF)rect, radius); /// /// Fills the interior of a rounded rectangle with a . /// /// The to fill the rounded rectangle with. /// The bounds of the rounded rectangle. - /// The size of the ellipse used to round the corners of the rectangle. - public void FillRoundedRectangle(Brush brush, RectangleF rect, SizeF corner) + /// The radius width and height used to round the corners of the rectangle. + public void FillRoundedRectangle(Brush brush, RectangleF rect, SizeF radius) { using GraphicsPath path = new(); - path.AddRoundedRectangle(rect, corner); + path.AddRoundedRectangle(rect, radius); FillPath(brush, path); } #endif @@ -3366,10 +3366,10 @@ public void DrawCachedBitmap(CachedBitmap cachedBitmap, int x, int y) #endif #if NET9_0_OR_GREATER - /// + /// public void DrawImage( Image image, - Effect effect) => DrawImage(image, effect, default, default, GraphicsUnit.Pixel, null); + Effect effect) => DrawImage(image, effect, srcRect: default, transform: default, GraphicsUnit.Pixel, imageAttr: null); /// /// Draws a portion of an image after applying a specified effect. diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageAttributes.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageAttributes.cs index 465db667858..4bc968a51f7 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageAttributes.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/ImageAttributes.cs @@ -4,6 +4,9 @@ using System.Runtime.InteropServices; using System.IO; using System.Runtime.CompilerServices; +#if NET9_0_OR_GREATER +using System.ComponentModel; +#endif namespace System.Drawing.Imaging; @@ -341,12 +344,15 @@ public void ClearOutputChannelColorProfile(ColorAdjustType type) } /// - public void SetRemapTable(ColorMap[] map) => SetRemapTable(map, ColorAdjustType.Default); + public void SetRemapTable(params ColorMap[] map) => SetRemapTable(map, ColorAdjustType.Default); /// /// Sets the default color-remap table. /// /// +#if NET9_0_OR_GREATER + [EditorBrowsable(EditorBrowsableState.Never)] +#endif public void SetRemapTable(ColorMap[] map, ColorAdjustType type) { ArgumentNullException.ThrowIfNull(map); @@ -358,7 +364,7 @@ public void SetRemapTable(ColorMap[] map, ColorAdjustType type) public void SetRemapTable(ReadOnlySpan map) => SetRemapTable(ColorAdjustType.Default, map); /// - public void SetRemapTable(ReadOnlySpan map) => SetRemapTable(ColorAdjustType.Default, map); + public void SetRemapTable(ReadOnlySpan<(Color OldColor, Color NewColor)> map) => SetRemapTable(ColorAdjustType.Default, map); #endif /// @@ -403,7 +409,7 @@ void SetRemapTable(ColorAdjustType type, ReadOnlySpan map) #if NET9_0_OR_GREATER /// - public void SetRemapTable(ColorAdjustType type, ReadOnlySpan map) + public void SetRemapTable(ColorAdjustType type, ReadOnlySpan<(Color OldColor, Color NewColor)> map) { StackBuffer stackBuffer = default; using BufferScope<(ARGB, ARGB)> buffer = new(stackBuffer, map.Length); @@ -447,10 +453,12 @@ public void ClearRemapTable(ColorAdjustType type) GC.KeepAlive(this); } - public void SetBrushRemapTable(ColorMap[] map) => SetRemapTable(map, ColorAdjustType.Brush); + public void SetBrushRemapTable(params ColorMap[] map) => SetRemapTable(map, ColorAdjustType.Brush); #if NET9_0_OR_GREATER public void SetBrushRemapTable(ReadOnlySpan map) => SetRemapTable(ColorAdjustType.Brush, map); + + public void SetBrushRemapTable(ReadOnlySpan<(Color OldColor, Color NewColor)> map) => SetRemapTable(ColorAdjustType.Brush, map); #endif public void ClearBrushRemapTable() => ClearRemapTable(ColorAdjustType.Brush); diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/ValueColorMap.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/ValueColorMap.cs deleted file mode 100644 index 42794b554eb..00000000000 --- a/src/System.Drawing.Common/src/System/Drawing/Imaging/ValueColorMap.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Drawing.Imaging; -#if NET9_0_OR_GREATER -/// -/// Defines a map for converting colors. -/// -/// Specifies the existing to be converted. -/// Specifies the new to which to convert. -public readonly record struct ValueColorMap(Color OldColor, Color NewColor); -#endif diff --git a/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.StringCollection.cs b/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.StringCollection.cs index cfc973818ec..15dc585aa9c 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.StringCollection.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.StringCollection.cs @@ -8,7 +8,7 @@ namespace System.Drawing.Printing; public partial class PrinterSettings { - public class StringCollection : ICollection, IReadOnlyList + public class StringCollection : ICollection, IEnumerable { private readonly List _list; diff --git a/src/System.Drawing.Common/tests/Helpers.cs b/src/System.Drawing.Common/tests/Helpers.cs index 5f23e83d0e2..974d0f0a343 100644 --- a/src/System.Drawing.Common/tests/Helpers.cs +++ b/src/System.Drawing.Common/tests/Helpers.cs @@ -13,7 +13,7 @@ namespace System.Drawing; public unsafe static class Helpers { // This MUST come before s_anyInstalledPrinters. Caching for performance in tests. - public static IReadOnlyList InstalledPrinters { get; } = PrinterSettings.InstalledPrinters; + public static PrinterSettings.StringCollection InstalledPrinters { get; } = PrinterSettings.InstalledPrinters; private static bool s_anyInstalledPrinters = InstalledPrinters.Count > 0; diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerActionPanel.EditorPropertyLine.EditorButton.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerActionPanel.EditorPropertyLine.EditorButton.cs index f1e85190350..2b6c0487111 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerActionPanel.EditorPropertyLine.EditorButton.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerActionPanel.EditorPropertyLine.EditorButton.cs @@ -128,8 +128,8 @@ protected override void OnPaint(PaintEventArgs e) // Make sure we draw properly under high contrast by re-mapping // the arrow color to the WindowText color using ImageAttributes attributes = new(); - ValueColorMap map = new(Color.Black, SystemColors.WindowText); - attributes.SetRemapTable(ColorAdjustType.Bitmap, new ReadOnlySpan(ref map)); + (Color OldColor, Color NewColor) map = new(Color.Black, SystemColors.WindowText); + attributes.SetRemapTable(ColorAdjustType.Bitmap, new ReadOnlySpan<(Color OldColor, Color NewColor)>(ref map)); int imageWidth = arrowBitmap.Width; int imageHeight = arrowBitmap.Height; g.DrawImage( diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs index aeff9fdaeea..cb0c2e2655d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs @@ -1036,9 +1036,9 @@ private void PaintIcon( int height = bounds.Y + (bounds.Height - s_iconsHeight) / 2; Rectangle bmpRect = new(width, height, s_iconsWidth, s_iconsHeight); - ValueColorMap map = new(Color.Black, foreColor); + (Color OldColor, Color NewColor) map = new(Color.Black, foreColor); using ImageAttributes attr = new(); - attr.SetRemapTable(ColorAdjustType.Bitmap, new ReadOnlySpan(ref map)); + attr.SetRemapTable(ColorAdjustType.Bitmap, new ReadOnlySpan<(Color OldColor, Color NewColor)>(ref map)); if (SystemInformation.HighContrast && // We can't replace black with white and vice versa as in other cases due to the colors of images are not exactly black and white. diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStripHighContrastRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStripHighContrastRenderer.cs index be9809e4b3a..5f0b6cc636e 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStripHighContrastRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStripHighContrastRenderer.cs @@ -492,11 +492,11 @@ private void RenderItemImageOfLowColorDepth(ToolStripItemImageRenderEventArgs e) if (IsHighContrastWhiteOnBlack() && !(FillWhenSelected && (item.Pressed || item.Selected))) { // Translate white, black and blue to colors visible in high contrast mode. - Span map = + Span<(Color OldColor, Color NewColor)> map = [ - new ValueColorMap(Color.Black, Color.White), - new ValueColorMap(Color.White, Color.Black), - new ValueColorMap(Color.FromArgb(0, 0, 128), Color.White) + new(Color.Black, Color.White), + new(Color.White, Color.Black), + new(Color.FromArgb(0, 0, 128), Color.White) ]; attrs.SetRemapTable(ColorAdjustType.Bitmap, map); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Rendering/ControlPaint.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Rendering/ControlPaint.cs index 1ce7c5c12cd..bf80ec74bd9 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Rendering/ControlPaint.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Rendering/ControlPaint.cs @@ -1457,7 +1457,7 @@ private static void DrawFrameControl( // Replace black/white with foreColor/backColor. ImageAttributes attributes = new(); - Span map = + Span<(Color OldColor, Color NewColor)> map = [ new(Color.Black, foreColor), new(Color.White, backColor) @@ -1581,8 +1581,8 @@ internal static void DrawImageReplaceColor(Graphics g, Image image, Rectangle de { using ImageAttributes attributes = new(); - ValueColorMap map = new(oldColor, newColor); - attributes.SetRemapTable(ColorAdjustType.Bitmap, new ReadOnlySpan(ref map)); + (Color OldColor, Color NewColor) map = new(oldColor, newColor); + attributes.SetRemapTable(ColorAdjustType.Bitmap, new ReadOnlySpan<(Color OldColor, Color NewColor)>(ref map)); g.DrawImage(image, dest, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes, null, 0); } From 8f56143a2a8e20070f740bc8c7cfdad5f09b66e9 Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Thu, 22 Feb 2024 10:03:59 +1000 Subject: [PATCH 16/30] Fix `PrintDialog` to return `DialogResult.Cancel` when cancelled or closed (#10928) Fix PrintDialog to return DialogResult.Cancel when cancelled or closed and add tests --- .../src/Windows/Win32/PInvoke.PrintDlg.cs | 4 +- .../Windows/Forms/Printing/PrintDialog.cs | 11 +++-- .../UIIntegrationTests/PrintDialogTests.cs | 41 +++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/UIIntegrationTests/PrintDialogTests.cs diff --git a/src/System.Windows.Forms.Primitives/src/Windows/Win32/PInvoke.PrintDlg.cs b/src/System.Windows.Forms.Primitives/src/Windows/Win32/PInvoke.PrintDlg.cs index 635db492e28..8d322e2d5fa 100644 --- a/src/System.Windows.Forms.Primitives/src/Windows/Win32/PInvoke.PrintDlg.cs +++ b/src/System.Windows.Forms.Primitives/src/Windows/Win32/PInvoke.PrintDlg.cs @@ -9,9 +9,9 @@ namespace Windows.Win32; internal static partial class PInvoke { [DllImport("COMDLG32.dll", ExactSpelling = true, EntryPoint = "PrintDlgW")] - internal static extern unsafe HRESULT PrintDlg(PRINTDLGW_64* pPD); + internal static extern unsafe BOOL PrintDlg(PRINTDLGW_64* pPD); - internal static unsafe HRESULT PrintDlg(PRINTDLGW_32* pPD) + internal static unsafe BOOL PrintDlg(PRINTDLGW_32* pPD) { Debug.Assert(RuntimeInformation.ProcessArchitecture == Architecture.X86); return PrintDlg((PRINTDLGW_64*)pPD); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Printing/PrintDialog.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Printing/PrintDialog.cs index a530a1918bf..c7dc527522d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Printing/PrintDialog.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Printing/PrintDialog.cs @@ -292,15 +292,18 @@ private unsafe bool ShowPrintDialog(HWND hwndOwner) dialogSettings->nMaxPage = (ushort)PrinterSettings.MaximumPage; } - HRESULT result = RuntimeInformation.ProcessArchitecture == Architecture.X86 + BOOL result = RuntimeInformation.ProcessArchitecture == Architecture.X86 ? PInvoke.PrintDlg(&dialogSettings32) : PInvoke.PrintDlg(&dialogSettings64); - if (result.Failed) + if (!result) { #if DEBUG var extendedResult = PInvoke.CommDlgExtendedError(); - Debug.Fail($"PrintDlg returned non zero error code: {extendedResult}"); + if (extendedResult != COMMON_DLG_ERRORS.CDERR_GENERALCODES) + { + Debug.Fail($"PrintDlg returned non zero error code: {extendedResult}"); + } #endif return false; } @@ -331,7 +334,7 @@ private unsafe bool ShowPrintDialog(HWND hwndOwner) PrinterSettings.Collate = dialogSettings->Flags.HasFlag(PRINTDLGEX_FLAGS.PD_COLLATE); } - return true; + return result; } finally { diff --git a/src/System.Windows.Forms/tests/IntegrationTests/UIIntegrationTests/PrintDialogTests.cs b/src/System.Windows.Forms/tests/IntegrationTests/UIIntegrationTests/PrintDialogTests.cs new file mode 100644 index 00000000000..1b0e9b6bfb4 --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/UIIntegrationTests/PrintDialogTests.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit.Abstractions; + +namespace System.Windows.Forms.UITests; + +public class PrintDialogTests : ControlTestBase +{ + public PrintDialogTests(ITestOutputHelper testOutputHelper) + : base(testOutputHelper) + { + } + + // Regression test for https://github.com/dotnet/winforms/issues/10920 + [WinFormsFact] + public void PrintDialogTests_UseEXDialog_Cancel_Success() + { + using DialogHostForm dialogOwnerForm = new(); + using PrintDialog dialog = new(); + dialog.UseEXDialog = false; + Assert.Equal(DialogResult.Cancel, dialog.ShowDialog(dialogOwnerForm)); + } + + [WinFormsFact] + public void PrintDialogTests_UseEXDialog_Success() + { + using AcceptDialogForm dialogOwnerForm = new(); + using PrintDialog dialog = new(); + dialog.UseEXDialog = false; + Assert.Equal(DialogResult.OK, dialog.ShowDialog(dialogOwnerForm)); + } + + private class AcceptDialogForm : DialogHostForm + { + protected override void OnDialogIdle(HWND dialogHandle) + { + Accept(dialogHandle); + } + } +} From da164d6862d16649eaa4b92e7c8065d8b75f95c6 Mon Sep 17 00:00:00 2001 From: Milena Hristova Date: Thu, 22 Feb 2024 01:30:00 +0100 Subject: [PATCH 17/30] Set ProducesDotNetReleaseShippingAssets property in Publishing.props (#10923) add ProducesDotNetReleaseShippingAssets property --- eng/Publishing.props | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/Publishing.props b/eng/Publishing.props index 10bc8c8684d..579a1360d90 100644 --- a/eng/Publishing.props +++ b/eng/Publishing.props @@ -2,5 +2,6 @@ 3 + true From 34d6061bdb78b539e12bc2ab185193098402f3d9 Mon Sep 17 00:00:00 2001 From: Epica3055 <135201996+Epica3055@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:31:44 +0800 Subject: [PATCH 18/30] fix Issue "ColumnType is disabled for Columns in EditColumns dialog" (#10907) --- .../src/System.Design.Forwards.cs | 1 + .../DataGridViewColumnCollectionDialog.cs | 2 +- ...ViewColumnTypeEditor.Picker.ListBoxItem.cs | 20 +++ .../DataGridViewColumnTypeEditor.Picker.cs | 139 ++++++++++++++++++ .../Design/DataGridViewColumnTypeEditor.cs | 49 ++++++ 5 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.ListBoxItem.cs create mode 100644 src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.cs create mode 100644 src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.cs diff --git a/src/System.Design/src/System.Design.Forwards.cs b/src/System.Design/src/System.Design.Forwards.cs index d804f92e945..87dda003697 100644 --- a/src/System.Design/src/System.Design.Forwards.cs +++ b/src/System.Design/src/System.Design.Forwards.cs @@ -9,6 +9,7 @@ [assembly: TypeForwardedTo(typeof(System.Windows.Forms.Design.ColumnHeaderCollectionEditor))] [assembly: TypeForwardedTo(typeof(System.Windows.Forms.Design.DataMemberFieldConverter))] [assembly: TypeForwardedTo(typeof(System.Windows.Forms.Design.DataGridViewCellStyleEditor))] +[assembly: TypeForwardedTo(typeof(System.Windows.Forms.Design.DataGridViewColumnTypeEditor))] [assembly: TypeForwardedTo(typeof(System.Windows.Forms.Design.DataSourceListEditor))] [assembly: TypeForwardedTo(typeof(System.Windows.Forms.Design.FormatStringEditor))] [assembly: TypeForwardedTo(typeof(System.Windows.Forms.Design.HelpNamespaceEditor))] diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnCollectionDialog.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnCollectionDialog.cs index c63452255a0..efd4fcc9bea 100644 --- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnCollectionDialog.cs +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnCollectionDialog.cs @@ -1348,7 +1348,7 @@ public override AttributeCollection Attributes { get { - EditorAttribute editorAttr = new("Design.DataGridViewColumnTypeEditor, " + AssemblyRef.SystemDesign, typeof(System.Drawing.Design.UITypeEditor)); + EditorAttribute editorAttr = new($"System.Windows.Forms.Design.DataGridViewColumnTypeEditor, {AssemblyRef.SystemDesign}", typeof(System.Drawing.Design.UITypeEditor)); DescriptionAttribute descriptionAttr = new(SR.DataGridViewColumnTypePropertyDescription); CategoryAttribute categoryAttr = CategoryAttribute.Design; // add the description attribute and the categories attribute diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.ListBoxItem.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.ListBoxItem.cs new file mode 100644 index 00000000000..6a89fe77070 --- /dev/null +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.ListBoxItem.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Windows.Forms.Design; + +internal partial class DataGridViewColumnTypePicker : ContainerControl +{ + private class ListBoxItem + { + private Type _columnType; + public ListBoxItem(Type columnType) + { + _columnType = columnType; + } + + public override string ToString() => _columnType.Name; + + public Type ColumnType => _columnType; + } +} diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.cs new file mode 100644 index 00000000000..a1d49130800 --- /dev/null +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.Picker.cs @@ -0,0 +1,139 @@ +// 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; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; + +namespace System.Windows.Forms.Design; + +[ToolboxItem(false)] +[DesignTimeVisible(false)] +internal partial class DataGridViewColumnTypePicker : ContainerControl +{ + private ListBox _typesListBox; + private Type? _selectedType; + + // The current editor service that we need to close the drop down. + private IWindowsFormsEditorService? _windowsFormsEditorService; + private static Type _dataGridViewColumnType = typeof(DataGridViewColumn); + + private const int MinimumHeight = 90; + private const int MinimumWidth = 100; + + public DataGridViewColumnTypePicker() + { + _typesListBox = new(); + Size = _typesListBox.Size; + _typesListBox.Dock = DockStyle.Fill; + _typesListBox.Sorted = true; + _typesListBox.HorizontalScrollbar = true; + _typesListBox.SelectedIndexChanged += typesListBox_SelectedIndexChanged; + Controls.Add(_typesListBox); + BackColor = SystemColors.Control; + ActiveControl = _typesListBox; + } + + public Type? SelectedType => _selectedType; + + private int PreferredWidth + { + get + { + int width = 0; + using Graphics g = _typesListBox.CreateGraphics(); + + for (int i = 0; i < _typesListBox.Items.Count; i++) + { + ListBoxItem item = (ListBoxItem)_typesListBox.Items[i]; + width = Math.Max(width, Size.Ceiling(g.MeasureString(item.ToString(), _typesListBox.Font)).Width); + } + + return width; + } + } + + private void CloseDropDown() => _windowsFormsEditorService?.CloseDropDown(); + + protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) + { + if ((BoundsSpecified.Width & specified) == BoundsSpecified.Width) + { + width = Math.Max(width, MinimumWidth); + } + + if ((BoundsSpecified.Height & specified) == BoundsSpecified.Height) + { + height = Math.Max(height, MinimumHeight); + } + + base.SetBoundsCore(x, y, width, height, specified); + } + + /// + /// Setup the picker, and fill it with type information + /// + public void Start(IWindowsFormsEditorService edSvc, ITypeDiscoveryService discoveryService, Type defaultType) + { + _windowsFormsEditorService = edSvc; + + _typesListBox.Items.Clear(); + + ICollection columnTypes = DesignerUtils.FilterGenericTypes(discoveryService.GetTypes(_dataGridViewColumnType, excludeGlobalTypes: false)); + + foreach (Type t in columnTypes) + { + if (t == _dataGridViewColumnType) + { + continue; + } + + if (t.IsAbstract) + { + continue; + } + + if (!t.IsPublic && !t.IsNestedPublic) + { + continue; + } + + DataGridViewColumnDesignTimeVisibleAttribute? attr = TypeDescriptor.GetAttributes(t)[typeof(DataGridViewColumnDesignTimeVisibleAttribute)] as DataGridViewColumnDesignTimeVisibleAttribute; + if (attr is not null && !attr.Visible) + { + continue; + } + + _typesListBox.Items.Add(new ListBoxItem(t)); + } + + _typesListBox.SelectedIndex = TypeToSelectedIndex(defaultType); + + _selectedType = null; + + // Set our default width. + Width = Math.Max(Width, PreferredWidth + (SystemInformation.VerticalScrollBarWidth * 2)); + } + + private void typesListBox_SelectedIndexChanged(object? sender, EventArgs e) + { + _selectedType = _typesListBox.SelectedItem is ListBoxItem selectedItem ? selectedItem.ColumnType : null; + _windowsFormsEditorService?.CloseDropDown(); + } + + private int TypeToSelectedIndex(Type type) + { + for (int i = 0; i < _typesListBox.Items.Count; i++) + { + if (type == ((ListBoxItem)_typesListBox.Items[i]).ColumnType) + { + return i; + } + } + + Debug.Assert(false, "we should have found a type by now"); + + return -1; + } +} diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.cs new file mode 100644 index 00000000000..ba1a8bfe4df --- /dev/null +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/DataGridViewColumnTypeEditor.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing.Design; + +namespace System.Windows.Forms.Design; +internal class DataGridViewColumnTypeEditor : UITypeEditor +{ + public DataGridViewColumnTypeEditor() : base() { } + + private DataGridViewColumnTypePicker? _columnTypePicker; + + public override bool IsDropDownResizable => true; + + public override object? EditValue(ITypeDescriptorContext? context, IServiceProvider provider, object? value) + { + if (provider is not null) + { + IWindowsFormsEditorService? windowsFormsEditorService = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService; + + if (windowsFormsEditorService is not null && context?.Instance is not null) + { + _columnTypePicker ??= new DataGridViewColumnTypePicker(); + + DataGridViewColumnCollectionDialog.ListBoxItem item = (DataGridViewColumnCollectionDialog.ListBoxItem)context.Instance; + + IDesignerHost? host = provider.GetService(typeof(IDesignerHost)) as IDesignerHost; + ITypeDiscoveryService? discoveryService = null; + if (host is not null) + { + discoveryService = host.GetService(typeof(ITypeDiscoveryService)) as ITypeDiscoveryService; + } + + _columnTypePicker.Start(windowsFormsEditorService, discoveryService!, item.DataGridViewColumn.GetType()); + windowsFormsEditorService.DropDownControl(_columnTypePicker); + if (_columnTypePicker.SelectedType is not null) + { + value = _columnTypePicker.SelectedType; + } + } + } + + return value; + } + + public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext? context) => UITypeEditorEditStyle.DropDown; +} From 822e882f4080b6197234cd82ad0d2f2a485a4f35 Mon Sep 17 00:00:00 2001 From: Leaf Shi <132890443+LeafShi1@users.noreply.github.com> Date: Thu, 22 Feb 2024 17:09:07 +0800 Subject: [PATCH 19/30] Add ToolStripMenuItem test UI in WinformsControlTests (#10914) * Add ToolStripMenuItem test UI in WinformsControlTests * Update the layout of the ToolStrip test page --- .../ToolStripTests.Designer.cs | 92 ++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ToolStripTests.Designer.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ToolStripTests.Designer.cs index c68c53eed49..62d245b0117 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ToolStripTests.Designer.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ToolStripTests.Designer.cs @@ -53,6 +53,14 @@ private void InitializeComponent() this.toolStrip2_DropDownButton1_ChildButton2 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStrip2_SplitButton1_ChildButton1 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStrip2_SplitButton1_ChildButton2 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStrip3 = new System.Windows.Forms.ToolStrip(); + this.toolStrip3_MenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStrip3_MenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); + this.uncheckedCheckOnClickToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.checkCheckOnClickToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.checkedCheckOnClickFToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.indeterminateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.indeterminateCheckOnClickFToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStrip2.SuspendLayout(); this.toolStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -81,6 +89,8 @@ private void InitializeComponent() this.toolStrip2_Button4, this.toolStrip2_Button5, this.toolStrip2_Button6, + this.toolStrip3_MenuItem1, + this.toolStrip3_MenuItem2, this.toolStrip2_SplitButton1, this.toolStrip2_DropDownButton1,}); this.toolStrip2.Location = new System.Drawing.Point(0, 22); @@ -90,6 +100,18 @@ private void InitializeComponent() this.toolStrip2.Text = "toolStrip2"; this.toolStrip2.TabStop = true; // + // toolStrip3 + // + this.toolStrip3.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStrip3_MenuItem1, + this.toolStrip3_MenuItem2,}); + this.toolStrip3.Location = new System.Drawing.Point(0, 45); + this.toolStrip3.Name = "toolStrip3"; + this.toolStrip3.Size = new System.Drawing.Size(481, 22); + this.toolStrip3.TabIndex = 1; + this.toolStrip3.Text = "toolStrip3"; + this.toolStrip3.TabStop = true; + // // toolStrip2_Button1 // this.toolStrip2_Button1.CheckState = System.Windows.Forms.CheckState.Unchecked; @@ -150,6 +172,63 @@ private void InitializeComponent() this.toolStrip2_SplitButton1_ChildButton2.Size = new System.Drawing.Size(180, 22); this.toolStrip2_SplitButton1_ChildButton2.Text = "toolStrip2_SplitButton1_ChildButton2"; // + // toolStrip3_MenuItem1 + // + this.toolStrip3_MenuItem1.CheckState = System.Windows.Forms.CheckState.Checked; + this.toolStrip3_MenuItem1.Name = "toolStripMenuItem_checked"; + this.toolStrip3_MenuItem1.Size = new System.Drawing.Size(180, 40); + this.toolStrip3_MenuItem1.Text = "toolStripMenuItem_checked"; + this.toolStrip3_MenuItem1.ToolTipText = "toolStripMenuItem_checked"; + // + // toolStrip3_MenuItem2 + // + this.toolStrip3_MenuItem2.DropDownItems.AddRange(new ToolStripItem[] { uncheckedCheckOnClickToolStripMenuItem, checkCheckOnClickToolStripMenuItem, checkedCheckOnClickFToolStripMenuItem, indeterminateToolStripMenuItem, indeterminateCheckOnClickFToolStripMenuItem }); + this.toolStrip3_MenuItem2.Name = "toolStripMenuItemWithDropDownItem"; + this.toolStrip3_MenuItem2.Size = new System.Drawing.Size(180, 40); + this.toolStrip3_MenuItem2.Text = "toolStripMenuItemWithDropDownItem_unchecked"; + this.toolStrip3_MenuItem2.ToolTipText = "toolStripMenuItemWithDropDownItem"; + // + // uncheckedCheckOnClickToolStripMenuItem + // + this.uncheckedCheckOnClickToolStripMenuItem.CheckOnClick = true; + this.uncheckedCheckOnClickToolStripMenuItem.Name = "uncheckedCheckOnClickToolStripMenuItem"; + this.uncheckedCheckOnClickToolStripMenuItem.Size = new System.Drawing.Size(481, 44); + this.uncheckedCheckOnClickToolStripMenuItem.Text = "Unchecked_CheckOnClick(T)"; + // + // checkCheckOnClickToolStripMenuItem + // + this.checkCheckOnClickToolStripMenuItem.Checked = true; + this.checkCheckOnClickToolStripMenuItem.CheckOnClick = true; + this.checkCheckOnClickToolStripMenuItem.CheckState = CheckState.Checked; + this.checkCheckOnClickToolStripMenuItem.Name = "checkCheckOnClickToolStripMenuItem"; + this.checkCheckOnClickToolStripMenuItem.Size = new System.Drawing.Size(481, 44); + this.checkCheckOnClickToolStripMenuItem.Text = "Checked_CheckOnClick(T)"; + // + // checkedCheckOnClickFToolStripMenuItem + // + this.checkedCheckOnClickFToolStripMenuItem.Checked = true; + this.checkedCheckOnClickFToolStripMenuItem.CheckState = CheckState.Checked; + this.checkedCheckOnClickFToolStripMenuItem.Name = "checkedCheckOnClickFToolStripMenuItem"; + this.checkedCheckOnClickFToolStripMenuItem.Size = new System.Drawing.Size(481, 44); + this.checkedCheckOnClickFToolStripMenuItem.Text = "Checked_CheckOnClick(F)"; + // + // indeterminateToolStripMenuItem + // + this.indeterminateToolStripMenuItem.Checked = true; + this.indeterminateToolStripMenuItem.CheckOnClick = true; + this.indeterminateToolStripMenuItem.CheckState = CheckState.Indeterminate; + this.indeterminateToolStripMenuItem.Name = "indeterminateToolStripMenuItem"; + this.indeterminateToolStripMenuItem.Size = new System.Drawing.Size(481, 44); + this.indeterminateToolStripMenuItem.Text = "Indeterminate_CheckOnClick(T)"; + // + // indeterminateCheckOnClickFToolStripMenuItem + // + this.indeterminateCheckOnClickFToolStripMenuItem.Checked = true; + this.indeterminateCheckOnClickFToolStripMenuItem.CheckState = CheckState.Indeterminate; + this.indeterminateCheckOnClickFToolStripMenuItem.Name = "indeterminateCheckOnClickFToolStripMenuItem"; + this.indeterminateCheckOnClickFToolStripMenuItem.Size = new System.Drawing.Size(481, 44); + this.indeterminateCheckOnClickFToolStripMenuItem.Text = "Indeterminate_CheckOnClick(F)"; + // // toolStrip2_SplitButton1 // this.toolStrip2_SplitButton1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -198,7 +277,7 @@ private void InitializeComponent() // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 56); + this.label1.Location = new System.Drawing.Point(12, 78); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(78, 13); this.label1.TabIndex = 2; @@ -247,6 +326,7 @@ private void InitializeComponent() this.ClientSize = new System.Drawing.Size(881, 123); this.Controls.Add(this.label1); this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.toolStrip3); this.Controls.Add(this.toolStrip2); this.Controls.Add(this.toolStrip1); this.Name = "ToolStripTests"; @@ -257,6 +337,8 @@ private void InitializeComponent() this.statusStrip1.PerformLayout(); this.toolStrip2.ResumeLayout(false); this.toolStrip2.PerformLayout(); + this.toolStrip3.ResumeLayout(false); + this.toolStrip3.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -274,6 +356,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripProgressBar toolStripProgressBar2; private System.Windows.Forms.Label label1; private System.Windows.Forms.ToolStrip toolStrip2; + private System.Windows.Forms.ToolStrip toolStrip3; private System.Windows.Forms.ToolStripButton toolStrip2_Button1; private System.Windows.Forms.ToolStripButton toolStrip2_Button2; private System.Windows.Forms.ToolStripButton toolStrip2_Button3; @@ -286,4 +369,11 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem toolStrip2_DropDownButton1_ChildButton2; private System.Windows.Forms.ToolStripMenuItem toolStrip2_SplitButton1_ChildButton1; private System.Windows.Forms.ToolStripMenuItem toolStrip2_SplitButton1_ChildButton2; + private System.Windows.Forms.ToolStripMenuItem toolStrip3_MenuItem1; + private System.Windows.Forms.ToolStripMenuItem toolStrip3_MenuItem2; + private System.Windows.Forms.ToolStripMenuItem uncheckedCheckOnClickToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem checkCheckOnClickToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem checkedCheckOnClickFToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem indeterminateToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem indeterminateCheckOnClickFToolStripMenuItem; } From 4567dfbd17117ecf5b4794854cf7a4e3196712d1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:36:27 +0000 Subject: [PATCH 20/30] [main] Update dependencies from dotnet/runtime (#10932) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 172 ++++++++++++++++++++-------------------- eng/Versions.props | 54 ++++++------- global.json | 2 +- 3 files changed, 114 insertions(+), 114 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1fe9637c011..9f5a4c95674 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,178 +7,178 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc - + https://github.com/dotnet/runtime - 1b1d26ac74e374309fb101382026ba0480d3821d + d908f00305588dcf577cd5f9c99ff0464000efdc diff --git a/eng/Versions.props b/eng/Versions.props index 653a371160c..023e5262cbb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,35 +15,35 @@ - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 5.0.0-preview.7.20320.5 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 6.0.0 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 - 9.0.0-preview.2.24120.11 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.1 diff --git a/global.json b/global.json index bad8b4c2ee5..0403448c220 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24120.11" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24122.1" }, "native-tools": { "cmake": "latest" From 057eeb0a29b75c9f2c614fa191104a2b25976377 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Thu, 22 Feb 2024 08:58:57 -0800 Subject: [PATCH 21/30] Refactor DataObject (#10918) * Refactor DataObject * address feedback * Support runtime IDataObject when built in COM interop turned off * optimize constructor * Remove unneeded constructor --- Winforms.sln | 19 + .../src/Properties/AssemblyInfo.cs | 1 + .../src/Properties/AssemblyInfo.cs | 1 + .../System/Com/STATDATA.AdviseSinkWrapper.cs | 58 -- .../src/Windows/Win32/System/Com/STATDATA.cs | 37 - .../src/Windows/Win32/System/Com/STGMEDIUM.cs | 8 + .../src/Properties/AssemblyInfo.cs | 1 + .../src/System/Windows/Forms/Control.cs | 35 +- .../RichTextBox/RichTextBox.OleCallback.cs | 2 +- .../src/System/Windows/Forms/OLE/Clipboard.cs | 12 +- .../System/Windows/Forms/OLE/DataFormats.cs | 16 +- .../OLE/DataObject.ComDataObjectAdapter.cs | 511 ------------ ...Object.NativeDataObjectToRuntimeAdapter.cs | 116 +++ ...bject.NativeDataObjectToWinFormsAdapter.cs | 556 +++++++++++++ ...Object.RuntimeDataObjectToNativeAdapter.cs | 151 ++++ ...bject.WinFormsDataObjectToNativeAdapter.cs | 554 +++++++++++++ .../OLE/DataObject.ComposedDataObject.cs | 137 ++++ .../OLE/DataObject.EnumFormatEtcWrapper.cs | 54 -- .../OLE/DataObject.EnumStatDataWrapper.cs | 83 -- .../System/Windows/Forms/OLE/DataObject.cs | 767 +----------------- .../Windows/Forms/OLE/DragDropFormat.cs | 41 +- .../Windows/Forms/OLE/DragDropHelper.cs | 4 +- .../System/Windows/Forms/OLE/DropTarget.cs | 27 +- .../ComDisabledTests/ClipboardComTests.cs | 15 + .../ComDisabledTests/ComDisabled.Tests.csproj | 54 ++ .../ComDisabledTests/DataObjectComTests.cs | 78 ++ .../tests/ComDisabledTests/GlobalUsings.cs | 6 + .../System/Windows/Forms/ClipboardComTests.cs | 15 + .../System/Windows/Forms/ClipboardTests.cs | 28 +- .../Windows/Forms/DataObjectComTests.cs | 79 ++ .../System/Windows/Forms/DataObjectTests.cs | 176 +--- .../Windows/Forms/DragDropFormatTests.cs | 90 +- .../Windows/Forms/DragDropHelperTests.cs | 34 +- 33 files changed, 1992 insertions(+), 1774 deletions(-) delete mode 100644 src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.AdviseSinkWrapper.cs delete mode 100644 src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.cs delete mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComDataObjectAdapter.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToRuntimeAdapter.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToWinFormsAdapter.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.RuntimeDataObjectToNativeAdapter.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.WinFormsDataObjectToNativeAdapter.cs create mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.cs delete mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumFormatEtcWrapper.cs delete mode 100644 src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumStatDataWrapper.cs create mode 100644 src/System.Windows.Forms/tests/ComDisabledTests/ClipboardComTests.cs create mode 100644 src/System.Windows.Forms/tests/ComDisabledTests/ComDisabled.Tests.csproj create mode 100644 src/System.Windows.Forms/tests/ComDisabledTests/DataObjectComTests.cs create mode 100644 src/System.Windows.Forms/tests/ComDisabledTests/GlobalUsings.cs create mode 100644 src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardComTests.cs create mode 100644 src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectComTests.cs diff --git a/Winforms.sln b/Winforms.sln index 7dc72d4753d..2d53b291607 100644 --- a/Winforms.sln +++ b/Winforms.sln @@ -171,6 +171,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "eng", "eng", "{8B4B1E09-B3C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScratchProjectWithInternals", "src\System.Windows.Forms\tests\IntegrationTests\ScratchProjectWithInternals\ScratchProjectWithInternals.csproj", "{522EBAB3-E4D2-45F3-ACBD-B25FC457BF78}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComDisabled.Tests", "src\System.Windows.Forms\tests\ComDisabledTests\ComDisabled.Tests.csproj", "{55F3174F-C1FE-4C8F-AF71-2512630088F8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -943,6 +945,22 @@ Global {522EBAB3-E4D2-45F3-ACBD-B25FC457BF78}.Release|x64.Build.0 = Release|Any CPU {522EBAB3-E4D2-45F3-ACBD-B25FC457BF78}.Release|x86.ActiveCfg = Release|Any CPU {522EBAB3-E4D2-45F3-ACBD-B25FC457BF78}.Release|x86.Build.0 = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|arm64.ActiveCfg = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|arm64.Build.0 = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|x64.ActiveCfg = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|x64.Build.0 = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|x86.ActiveCfg = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Debug|x86.Build.0 = Debug|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|Any CPU.Build.0 = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|arm64.ActiveCfg = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|arm64.Build.0 = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|x64.ActiveCfg = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|x64.Build.0 = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|x86.ActiveCfg = Release|Any CPU + {55F3174F-C1FE-4C8F-AF71-2512630088F8}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1004,6 +1022,7 @@ Global {7650F24E-7132-42CF-ADCE-830C8DB26EE5} = {583F1292-AE8D-4511-B8D8-A81FE4642DDC} {BA61D5A8-29E9-41AA-A3FA-B7F0A7F9A191} = {680FB14C-7B0C-4D63-9F1A-18ACCDB0F52A} {61376D2A-4AD5-48F4-BF99-2BB630E21945} = {77FEDB47-F7F6-490D-AF7C-ABB4A9E0B9D7} + {55F3174F-C1FE-4C8F-AF71-2512630088F8} = {583F1292-AE8D-4511-B8D8-A81FE4642DDC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7B1B0433-F612-4E5A-BE7E-FCF5B9F6E136} diff --git a/src/System.Private.Windows.Core/src/Properties/AssemblyInfo.cs b/src/System.Private.Windows.Core/src/Properties/AssemblyInfo.cs index fb2cfc5a402..7f66f0d08ee 100644 --- a/src/System.Private.Windows.Core/src/Properties/AssemblyInfo.cs +++ b/src/System.Private.Windows.Core/src/Properties/AssemblyInfo.cs @@ -31,6 +31,7 @@ [assembly: InternalsVisibleTo("NativeHost.ManagedControl, PublicKey=00000000000000000400000000000000")] [assembly: InternalsVisibleTo("MauiToolStripTests, PublicKey=00000000000000000400000000000000")] [assembly: InternalsVisibleTo("ScratchProjectWithInternals, PublicKey=00000000000000000400000000000000")] +[assembly: InternalsVisibleTo("ComDisabled.Tests, PublicKey=00000000000000000400000000000000")] // This is needed in order to Moq internal interfaces for testing [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/System.Windows.Forms.Primitives/src/Properties/AssemblyInfo.cs b/src/System.Windows.Forms.Primitives/src/Properties/AssemblyInfo.cs index 32aaff2944a..7a7c61edc57 100644 --- a/src/System.Windows.Forms.Primitives/src/Properties/AssemblyInfo.cs +++ b/src/System.Windows.Forms.Primitives/src/Properties/AssemblyInfo.cs @@ -28,6 +28,7 @@ [assembly: InternalsVisibleTo("NativeHost.ManagedControl, PublicKey=00000000000000000400000000000000")] [assembly: InternalsVisibleTo("MauiToolStripTests, PublicKey=00000000000000000400000000000000")] [assembly: InternalsVisibleTo("ScratchProjectWithInternals, PublicKey=00000000000000000400000000000000")] +[assembly: InternalsVisibleTo("ComDisabled.Tests, PublicKey=00000000000000000400000000000000")] // This is needed in order to Moq internal interfaces for testing [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.AdviseSinkWrapper.cs b/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.AdviseSinkWrapper.cs deleted file mode 100644 index fd601828e9a..00000000000 --- a/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.AdviseSinkWrapper.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using ComType = System.Runtime.InteropServices.ComTypes; - -namespace Windows.Win32.System.Com; - -internal unsafe partial struct STATDATA -{ - private class AdviseSinkWrapper : ComType.IAdviseSink - { - private readonly AgileComPointer _adviseSink; - - public AdviseSinkWrapper(IAdviseSink* adviseSink) - { - _adviseSink = new(adviseSink, takeOwnership: false); - } - - void ComType.IAdviseSink.OnClose() - { - using var adviseSink = _adviseSink.GetInterface(); - adviseSink.Value->OnClose(); - } - - void ComType.IAdviseSink.OnDataChange(ref ComType.FORMATETC format, ref ComType.STGMEDIUM stgmedium) - { - using var adviseSink = _adviseSink.GetInterface(); - STGMEDIUM comMedium = (STGMEDIUM)stgmedium; - adviseSink.Value->OnDataChange(Unsafe.As(ref format), comMedium); - stgmedium = (ComType.STGMEDIUM)comMedium; - - if (comMedium.pUnkForRelease is not null) - { - comMedium.pUnkForRelease->Release(); - } - } - - void ComType.IAdviseSink.OnRename(ComType.IMoniker moniker) - { - using var adviseSink = _adviseSink.GetInterface(); - using var comMoniker = ComHelpers.GetComScope(moniker); - adviseSink.Value->OnRename(comMoniker); - } - - void ComType.IAdviseSink.OnSave() - { - using var adviseSink = _adviseSink.GetInterface(); - adviseSink.Value->OnSave(); - } - - void ComType.IAdviseSink.OnViewChange(int aspect, int index) - { - using var adviseSink = _adviseSink.GetInterface(); - adviseSink.Value->OnViewChange((uint)aspect, index); - } - } -} diff --git a/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.cs b/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.cs deleted file mode 100644 index 13a9000ebad..00000000000 --- a/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STATDATA.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using ComType = System.Runtime.InteropServices.ComTypes; - -namespace Windows.Win32.System.Com; - -internal unsafe partial struct STATDATA -{ - /// - /// Converts to - /// - /// - /// - /// This will release the of the that was passed in - /// so that the runtime type will have ownership. - /// - /// - public static ComType.STATDATA ConvertToRuntimeStatData(STATDATA statData) - { - using ComScope pAdvSink = new(statData.pAdvSink); - ComType.STATDATA result = new() - { - formatetc = Unsafe.As(ref statData.formatetc), - advf = (ComType.ADVF)statData.advf, - advSink = ComHelpers.TryGetObjectForIUnknown( - pAdvSink.Query(), - out ComType.IAdviseSink? adviseSink) - ? adviseSink - : new AdviseSinkWrapper(pAdvSink), - connection = (int)statData.dwConnection - }; - - return result; - } -} diff --git a/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STGMEDIUM.cs b/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STGMEDIUM.cs index bf4c70720a4..e7ee4dad4d3 100644 --- a/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STGMEDIUM.cs +++ b/src/System.Windows.Forms.Primitives/src/Windows/Win32/System/Com/STGMEDIUM.cs @@ -33,4 +33,12 @@ public static explicit operator STGMEDIUM(ComType.STGMEDIUM comTypeStg) tymed = (ComType.TYMED)stg.tymed, unionmember = stg.u.hGlobal }; + + public void ReleaseUnknown() + { + if (pUnkForRelease is not null) + { + pUnkForRelease->Release(); + } + } } diff --git a/src/System.Windows.Forms/src/Properties/AssemblyInfo.cs b/src/System.Windows.Forms/src/Properties/AssemblyInfo.cs index fea22851da7..8762d57e683 100644 --- a/src/System.Windows.Forms/src/Properties/AssemblyInfo.cs +++ b/src/System.Windows.Forms/src/Properties/AssemblyInfo.cs @@ -18,6 +18,7 @@ [assembly: InternalsVisibleTo("MauiScrollBarTests, PublicKey=00000000000000000400000000000000")] [assembly: InternalsVisibleTo("MauiToolStripTests, PublicKey=00000000000000000400000000000000")] [assembly: InternalsVisibleTo("ScratchProjectWithInternals, PublicKey=00000000000000000400000000000000")] +[assembly: InternalsVisibleTo("ComDisabled.Tests, PublicKey=00000000000000000400000000000000")] // This is needed in order to Moq internal interfaces for testing [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs index cb35f22e7b2..13aab3c9f86 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -5177,7 +5177,7 @@ public DragDropEffects DoDragDrop( Point cursorOffset, bool useDefaultDragImage) { - ComTypes.IDataObject dataObject = PrepareIncomingDragData(data); + ComTypes.IDataObject dataObject = CreateRuntimeDataObjectForDrag(data); DROPEFFECT finalEffect; @@ -5203,36 +5203,11 @@ public DragDropEffects DoDragDrop( } /// - /// Prepares the incoming drag data for consumption. - /// The incoming should implement to be taken as is. - /// Otherwise, the data will be wrapped in a . + /// Creates for drag operation. + /// The incoming will always be wrapped. /// - private static ComTypes.IDataObject PrepareIncomingDragData(object data) - { - ComTypes.IDataObject dataObject; - - if (data is ComTypes.IDataObject comDataObject) - { - dataObject = comDataObject; - } - else - { - DataObject iwdata; - if (data is IDataObject dataAsDataObject) - { - iwdata = new DataObject(dataAsDataObject); - } - else - { - iwdata = new DataObject(); - iwdata.SetData(data); - } - - dataObject = iwdata; - } - - return dataObject; - } + private static DataObject CreateRuntimeDataObjectForDrag(object data) => + data is DataObject dataObject ? dataObject : new DataObject(data); public void DrawToBitmap(Bitmap bitmap, Rectangle targetBounds) { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.OleCallback.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.OleCallback.cs index ef8fed3f530..74eb21cc9f9 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.OleCallback.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/RichTextBox/RichTextBox.OleCallback.cs @@ -139,7 +139,7 @@ public HRESULT QueryAcceptData(Com.IDataObject* lpdataobj, ushort* lpcfFormat, R keyState |= MODIFIERKEYS_FLAGS.MK_SHIFT; } - _lastDataObject = DataObject.FromComPointer(lpdataobj); + _lastDataObject = new DataObject(lpdataobj); if (!_owner.EnableAutoDragDrop) { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/Clipboard.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/Clipboard.cs index 7ae5f58a050..4ec6d085c02 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/Clipboard.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/Clipboard.cs @@ -6,7 +6,6 @@ using System.Runtime.InteropServices; using Windows.Win32.System.Com; using Com = Windows.Win32.System.Com; -using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; namespace System.Windows.Forms; @@ -87,7 +86,7 @@ public static unsafe void SetDataObject(object data, bool copy, int retryTimes, } int retryTimes = 10; - ComScope proxyDataObject = new(null); + using ComScope proxyDataObject = new(null); HRESULT hr; while ((hr = PInvoke.OleGetClipboard(proxyDataObject)).Failed) { @@ -112,7 +111,6 @@ public static unsafe void SetDataObject(object data, bool copy, int retryTimes, if (hr.Succeeded) { target = realDataObject.AsUnknown; - proxyDataObject.Dispose(); } else { @@ -125,13 +123,15 @@ public static unsafe void SetDataObject(object data, bool copy, int retryTimes, return null; } - if (managedDataObject is not IComDataObject dataObject) + if (managedDataObject is not Com.IDataObject.Interface dataObject) { - // If we do not have a IComDataObject, built-in com support is turned off and + // We always wrap data set on the Clipboard in a DataObject, so if we do not have + // a IDataObject.Interface this means built-in com support is turned off and // we have a proxy where there is no way to retrieve the original data object // pointer from it likely because either the clipboard was flushed or the data on the // clipboard is from another process. We need to mimic built-in com behavior and wrap the proxy ourselves. - return new DataObject(proxyDataObject, managedDataObject); + // DataObject will ref count proxyDataObject properly to take ownership. + return new DataObject(proxyDataObject.Value); } if (dataObject is DataObject { IsWrappedForClipboard: true } wrappedData) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataFormats.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataFormats.cs index 5d9a043775d..58dbae2baef 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataFormats.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataFormats.cs @@ -197,20 +197,22 @@ public static Format GetFormat(string format) /// /// Gets a with the Windows Clipboard numeric ID and name for the specified ID. /// - public static unsafe Format GetFormat(int id) - { + public static Format GetFormat(int id) => // Win32 uses an unsigned 16 bit type as a format ID, thus stripping off the leading bits. // Registered format IDs are in the range 0xC000 through 0xFFFF, thus it's important // to represent format as an unsigned type. - ushort clampedId = (ushort)(id & 0xFFFF); + GetFormat((ushort)(id & 0xFFFF)); + /// + internal static unsafe Format GetFormat(ushort id) + { lock (s_internalSyncObject) { EnsurePredefined(); for (int n = 0; n < s_formatCount; n++) { - if (s_formatList[n].Id == clampedId) + if (s_formatList[n].Id == id) { return s_formatList[n]; } @@ -224,7 +226,7 @@ public static unsafe Format GetFormat(int id) Span formatName = stackalloc char[256]; fixed (char* pFormatName = formatName) { - int length = PInvoke.GetClipboardFormatName(clampedId, pFormatName, 256); + int length = PInvoke.GetClipboardFormatName(id, pFormatName, 256); if (length != 0) { name = formatName.Slice(0, length).ToString(); @@ -233,10 +235,10 @@ public static unsafe Format GetFormat(int id) // This can happen if windows adds a standard format that we don't know about, // so we should play it safe. - name ??= $"Format{clampedId}"; + name ??= $"Format{id}"; EnsureFormatSpace(1); - s_formatList[s_formatCount] = new Format(name, clampedId); + s_formatList[s_formatCount] = new Format(name, id); return s_formatList[s_formatCount++]; } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComDataObjectAdapter.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComDataObjectAdapter.cs deleted file mode 100644 index a0520b2b883..00000000000 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComDataObjectAdapter.cs +++ /dev/null @@ -1,511 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.ComponentModel; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Runtime.Serialization.Formatters; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using System.Windows.Forms.BinaryFormat; -using static Windows.Win32.System.Memory.GLOBAL_ALLOC_FLAGS; -using Com = Windows.Win32.System.Com; -using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; - -namespace System.Windows.Forms; - -public partial class DataObject -{ - /// - /// Maps to for reading data only. - /// - private unsafe sealed class ComDataObjectAdapter : IDataObject - { - // We use the pointer, but ComWrappers or built-in Com interop is managing the lifetime for us. - // Keep a referenced to the managed object to prevent it from being collected. - private readonly object _innerData; - private readonly Com.IDataObject* _innerDataPtr; - - public ComDataObjectAdapter(IComDataObject data) - { - Debug.Assert(data is not null); - CompModSwitches.DataObject.TraceVerbose("OleConverter: Constructed OleConverter"); - _innerData = data; - _innerDataPtr = ComHelpers.GetComPointer(data); - } - - public ComDataObjectAdapter(Com.IDataObject* dataPtr, object managedData) - { - Debug.Assert(managedData is not null); - CompModSwitches.DataObject.TraceVerbose("OleConverter: Constructed OleConverter"); - _innerData = managedData; - _innerDataPtr = dataPtr; - } - - public Com.IDataObject* OleDataObject => _innerDataPtr; - - /// - /// Retrieves the specified format from the specified hglobal. - /// - private static object? GetDataFromHGLOBAL(HGLOBAL hglobal, string format) - { - if (hglobal == 0) - { - return null; - } - - return format switch - { - DataFormats.TextConstant or DataFormats.RtfConstant or DataFormats.OemTextConstant - => ReadStringFromHGLOBAL(hglobal, unicode: false), - DataFormats.HtmlConstant => ReadUtf8StringFromHGLOBAL(hglobal), - DataFormats.UnicodeTextConstant => ReadStringFromHGLOBAL(hglobal, unicode: true), - DataFormats.FileDropConstant => ReadFileListFromHDROP((HDROP)(nint)hglobal), - CF_DEPRECATED_FILENAME => new string[] { ReadStringFromHGLOBAL(hglobal, unicode: false) }, - CF_DEPRECATED_FILENAMEW => new string[] { ReadStringFromHGLOBAL(hglobal, unicode: true) }, - _ => ReadObjectFromHGLOBAL(hglobal, RestrictDeserializationToSafeTypes(format)) - }; - - static unsafe string ReadStringFromHGLOBAL(HGLOBAL hglobal, bool unicode) - { - string? stringData = null; - - void* buffer = PInvokeCore.GlobalLock(hglobal); - try - { - stringData = unicode ? new string((char*)buffer) : new string((sbyte*)buffer); - } - finally - { - PInvokeCore.GlobalUnlock(hglobal); - } - - return stringData; - } - - static unsafe string ReadUtf8StringFromHGLOBAL(HGLOBAL hglobal) - { - void* buffer = PInvokeCore.GlobalLock(hglobal); - try - { - int size = (int)PInvokeCore.GlobalSize(hglobal); - return Encoding.UTF8.GetString((byte*)buffer, size - 1); - } - finally - { - PInvokeCore.GlobalUnlock(hglobal); - } - } - - static unsafe string[]? ReadFileListFromHDROP(HDROP hdrop) - { - uint count = PInvoke.DragQueryFile(hdrop, iFile: 0xFFFFFFFF, lpszFile: null, cch: 0); - if (count == 0) - { - return null; - } - - Span fileName = stackalloc char[PInvoke.MAX_PATH + 1]; - string[] files = new string[count]; - - fixed (char* buffer = fileName) - { - for (uint i = 0; i < count; i++) - { - uint charactersCopied = PInvoke.DragQueryFile(hdrop, i, buffer, (uint)fileName.Length); - if (charactersCopied == 0) - { - continue; - } - - string s = fileName[..(int)charactersCopied].ToString(); - files[i] = s; - } - } - - return files; - } - - static object ReadObjectFromHGLOBAL(HGLOBAL hglobal, bool restrictDeserialization) - { - Stream stream = ReadByteStreamFromHGLOBAL(hglobal, out bool isSerializedObject); - return !isSerializedObject ? stream : ReadObjectFromHandleDeserializer(stream, restrictDeserialization); - - static object ReadObjectFromHandleDeserializer(Stream stream, bool restrictDeserialization) - { - long startPosition = stream.Position; - try - { - if (new BinaryFormattedObject(stream, leaveOpen: true).TryGetObject(out object? value)) - { - return value; - } - } - catch (Exception ex) when (!ex.IsCriticalException()) - { - // Couldn't parse for some reason, let the BinaryFormatter try to handle it. - } - - stream.Position = startPosition; - -#pragma warning disable SYSLIB0011 // Type or member is obsolete -#pragma warning disable SYSLIB0050 // Type or member is obsolete - return new BinaryFormatter() - { - Binder = restrictDeserialization ? new BitmapBinder() : null, - AssemblyFormat = FormatterAssemblyStyle.Simple - }.Deserialize(stream); -#pragma warning restore SYSLIB0050 -#pragma warning restore SYSLIB0011 - } - - static unsafe Stream ReadByteStreamFromHGLOBAL(HGLOBAL hglobal, out bool isSerializedObject) - { - void* buffer = PInvokeCore.GlobalLock(hglobal); - if (buffer is null) - { - throw new ExternalException(SR.ExternalException, (int)HRESULT.E_OUTOFMEMORY); - } - - try - { - int size = (int)PInvokeCore.GlobalSize(hglobal); - byte[] bytes = new byte[size]; - Marshal.Copy((nint)buffer, bytes, 0, size); - int index = 0; - - // The object here can either be a stream or a serialized object. We identify a serialized object - // by writing the bytes for the guid serializedObjectID at the front of the stream. - - if (isSerializedObject = bytes.AsSpan().StartsWith(s_serializedObjectID)) - { - index = s_serializedObjectID.Length; - } - - return new MemoryStream(bytes, index, bytes.Length - index); - } - finally - { - PInvokeCore.GlobalUnlock(hglobal); - } - } - } - } - - /// - /// Extracts a managed object from of the specified format. - /// - /// - /// A restricted type was encountered, do not continue trying to deserialize. - /// - private static object? GetObjectFromDataObject(Com.IDataObject* dataObject, string format, out bool doNotContinue) - { - object? data = null; - doNotContinue = false; - try - { - // Try to get the data as a bitmap first. - data = TryGetBitmapData(dataObject, format); - - // Check for one of our standard data types. - data ??= TryGetHGLOBALData(dataObject, format, out doNotContinue); - - if (data is null && !doNotContinue) - { - // Lastly check to see if the data is an IStream. - data = TryGetIStreamData(dataObject, format); - } - } - catch (Exception e) - { - Debug.Fail(e.ToString()); - } - - return data; - - static object? TryGetBitmapData(Com.IDataObject* dataObject, string format) - { - if (format != DataFormats.BitmapConstant) - { - return null; - } - - Com.FORMATETC formatEtc = new() - { - cfFormat = (ushort)DataFormats.GetFormat(format).Id, - dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, - lindex = -1, - tymed = (uint)Com.TYMED.TYMED_GDI - }; - - Com.STGMEDIUM medium = default; - - if (dataObject->QueryGetData(formatEtc).Succeeded) - { - HRESULT hr = dataObject->GetData(formatEtc, out medium); - // One of the ways this can happen is when we attempt to put binary formatted data onto the - // clipboard, which will succeed as Windows ignores all errors when putting data on the clipboard. - // The data state, however, is not good, and this error will be returned by Windows when asking to - // get the data out. - Debug.WriteLineIf(hr == HRESULT.CLIPBRD_E_BAD_DATA, "CLIPBRD_E_BAD_DATA returned when trying to get clipboard data."); - } - - object? data = null; - - try - { - // GDI+ doesn't own this HBITMAP, but we can't delete it while the object is still around. So we - // have to do the really expensive thing of cloning the image so we can release the HBITMAP. - if ((uint)medium.tymed == (uint)TYMED.TYMED_GDI - && !medium.hGlobal.IsNull - && format.Equals(DataFormats.BitmapConstant) - && Image.FromHbitmap(medium.hGlobal) is Image clipboardImage) - { - data = (Image)clipboardImage.Clone(); - clipboardImage.Dispose(); - } - } - finally - { - PInvoke.ReleaseStgMedium(ref medium); - } - - return data; - } - - static object? TryGetHGLOBALData(Com.IDataObject* dataObject, string format, out bool doNotContinue) - { - doNotContinue = false; - - Com.FORMATETC formatetc = new() - { - cfFormat = (ushort)DataFormats.GetFormat(format).Id, - dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, - lindex = -1, - tymed = (uint)Com.TYMED.TYMED_HGLOBAL - }; - - if (dataObject->QueryGetData(formatetc).Failed) - { - return null; - } - - object? data = null; - HRESULT result = dataObject->GetData(formatetc, out Com.STGMEDIUM medium); - - // One of the ways this can happen is when we attempt to put binary formatted data onto the - // clipboard, which will succeed as Windows ignores all errors when putting data on the clipboard. - // The data state, however, is not good, and this error will be returned by Windows when asking to - // get the data out. - Debug.WriteLineIf(result == HRESULT.CLIPBRD_E_BAD_DATA, "CLIPBRD_E_BAD_DATA returned when trying to get clipboard data."); - - try - { - if (medium.tymed == Com.TYMED.TYMED_HGLOBAL && !medium.hGlobal.IsNull) - { - data = GetDataFromHGLOBAL(medium.hGlobal, format); - } - } - catch (RestrictedTypeDeserializationException) - { - doNotContinue = true; - } - catch - { - } - finally - { - PInvoke.ReleaseStgMedium(ref medium); - } - - return data; - } - - static unsafe object? TryGetIStreamData(Com.IDataObject* dataObject, string format) - { - Com.FORMATETC formatEtc = new() - { - cfFormat = (ushort)DataFormats.GetFormat(format).Id, - dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, - lindex = -1, - tymed = (uint)Com.TYMED.TYMED_ISTREAM - }; - - // Limit the # of exceptions we may throw below. - if (dataObject->QueryGetData(formatEtc).Failed - || dataObject->GetData(formatEtc, out Com.STGMEDIUM medium).Failed) - { - return null; - } - - HGLOBAL hglobal = default; - try - { - if (medium.tymed != Com.TYMED.TYMED_ISTREAM || medium.hGlobal.IsNull) - { - return null; - } - - using ComScope pStream = new((Com.IStream*)medium.hGlobal); - pStream.Value->Stat(out Com.STATSTG sstg, (uint)Com.STATFLAG.STATFLAG_DEFAULT); - - hglobal = PInvokeCore.GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (uint)sstg.cbSize); - - // Not throwing here because the other out of memory condition on GlobalAlloc - // happens inside innerData.GetData and gets turned into a null return value. - if (hglobal.IsNull) - { - return null; - } - - void* ptr = PInvokeCore.GlobalLock(hglobal); - pStream.Value->Read((byte*)ptr, (uint)sstg.cbSize, null); - PInvokeCore.GlobalUnlock(hglobal); - - return GetDataFromHGLOBAL(hglobal, format); - } - finally - { - if (!hglobal.IsNull) - { - PInvokeCore.GlobalFree(hglobal); - } - - PInvoke.ReleaseStgMedium(ref medium); - } - } - } - - public object? GetData(string format, bool autoConvert) - { - object? data = GetObjectFromDataObject(OleDataObject, format, out bool doNotContinue); - - if (doNotContinue - || !autoConvert - || (data is not null && data is not MemoryStream) - || GetMappedFormats(format) is not { } mappedFormats) - { - return data; - } - - object? originalData = data; - - // Try to find a mapped format that works better. - foreach (string mappedFormat in mappedFormats) - { - if (!format.Equals(mappedFormat)) - { - data = GetObjectFromDataObject(OleDataObject, mappedFormat, out doNotContinue); - if (doNotContinue) - { - break; - } - - if (data is not null and not MemoryStream) - { - return data; - } - } - } - - return originalData ?? data; - } - - public object? GetData(string format) => GetData(format, autoConvert: true); - - public object? GetData(Type format) => GetData(format.FullName!); - - public void SetData(string format, bool autoConvert, object? data) { } - public void SetData(string format, object? data) { } - - public void SetData(Type format, object? data) { } - - public void SetData(object? data) { } - - public bool GetDataPresent(Type format) => GetDataPresent(format.FullName!); - - private bool GetDataPresentInner(string format) - { - Com.FORMATETC formatEtc = new() - { - cfFormat = (ushort)(DataFormats.GetFormat(format).Id), - dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, - lindex = -1, - tymed = (uint)AllowedTymeds - }; - - HRESULT hr = OleDataObject->QueryGetData(formatEtc); - return hr.Succeeded; - } - - public bool GetDataPresent(string format, bool autoConvert) - { - bool dataPresent = GetDataPresentInner(format); - - if (dataPresent || !autoConvert || GetMappedFormats(format) is not { } mappedFormats) - { - return dataPresent; - } - - foreach (string mappedFormat in mappedFormats) - { - if (!format.Equals(mappedFormat) && (dataPresent = GetDataPresentInner(mappedFormat))) - { - break; - } - } - - return dataPresent; - } - - public bool GetDataPresent(string format) => GetDataPresent(format, autoConvert: true); - - public string[] GetFormats(bool autoConvert) - { - Debug.Assert(OleDataObject is not null, "You must have an innerData on all DataObjects"); - - using ComScope enumFORMATETC = new(null); - OleDataObject->EnumFormatEtc((uint)DATADIR.DATADIR_GET, enumFORMATETC).AssertSuccess(); - - if (enumFORMATETC.IsNull) - { - return []; - } - - // Since we are only adding elements to the HashSet, the order will be preserved. - HashSet distinctFormats = []; - - enumFORMATETC.Value->Reset(); - - Com.FORMATETC[] formatEtc = [default]; - HRESULT hr; - - fixed (Com.FORMATETC* pFormatEtc = formatEtc) - { - hr = enumFORMATETC.Value->Next(1, pFormatEtc); - } - - if (hr == HRESULT.S_OK) - { - string name = DataFormats.GetFormat(formatEtc[0].cfFormat).Name; - if (autoConvert) - { - string[] mappedFormats = GetMappedFormats(name)!; - for (int i = 0; i < mappedFormats.Length; i++) - { - distinctFormats.Add(mappedFormats[i]); - } - } - else - { - distinctFormats.Add(name); - } - } - - return [.. distinctFormats]; - } - - public string[] GetFormats() => GetFormats(autoConvert: true); - } -} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToRuntimeAdapter.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToRuntimeAdapter.cs new file mode 100644 index 00000000000..f81335b02b9 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToRuntimeAdapter.cs @@ -0,0 +1,116 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using Com = Windows.Win32.System.Com; +using ComTypes = System.Runtime.InteropServices.ComTypes; + +namespace System.Windows.Forms; + +public unsafe partial class DataObject +{ + internal unsafe partial class ComposedDataObject + { + /// + /// Maps native pointer to . + /// + private class NativeDataObjectToRuntimeAdapter : ComTypes.IDataObject + { + private readonly AgileComPointer _nativeDataObject; + + public NativeDataObjectToRuntimeAdapter(Com.IDataObject* dataObject) + { +#if DEBUG + _nativeDataObject = new(dataObject, takeOwnership: true, trackDisposal: false); +#else + _nativeDataObject = new(dataObject, takeOwnership: true); +#endif + } + + int ComTypes.IDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection) + { + using var nativeAdviseSink = ComHelpers.TryGetComScope(adviseSink); + fixed (Com.FORMATETC* nativeFormat = &Unsafe.As(ref pFormatetc)) + fixed (int* pConnection = &connection) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->DAdvise(nativeFormat, (uint)advf, nativeAdviseSink, (uint*)pConnection); + } + } + + void ComTypes.IDataObject.DUnadvise(int connection) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + nativeDataObject.Value->DUnadvise((uint)connection).ThrowOnFailure(); + } + + int ComTypes.IDataObject.EnumDAdvise(out IEnumSTATDATA? enumAdvise) + { + using ComScope nativeStatData = new(null); + using var nativeDataObject = _nativeDataObject.GetInterface(); + HRESULT result = nativeDataObject.Value->EnumDAdvise(nativeStatData); + ComHelpers.TryGetObjectForIUnknown(nativeStatData.AsUnknown, out enumAdvise); + return result; + } + + IEnumFORMATETC ComTypes.IDataObject.EnumFormatEtc(DATADIR direction) + { + using ComScope nativeFormat = new(null); + using var nativeDataObject = _nativeDataObject.GetInterface(); + if (nativeDataObject.Value->EnumFormatEtc((uint)direction, nativeFormat).Failed) + { + throw new ExternalException(SR.ExternalException, (int)HRESULT.E_NOTIMPL); + } + + return (IEnumFORMATETC)ComHelpers.GetObjectForIUnknown(nativeFormat.AsUnknown); + } + + int ComTypes.IDataObject.GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + HRESULT result = nativeDataObject.Value->GetCanonicalFormatEtc(Unsafe.As(ref formatIn), out Com.FORMATETC nativeFormat); + formatOut = Unsafe.As(ref nativeFormat); + return result; + } + + void ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) + { + Com.FORMATETC nativeFormat = Unsafe.As(ref format); + Com.STGMEDIUM nativeMedium = default; + using var nativeDataObject = _nativeDataObject.GetInterface(); + nativeDataObject.Value->GetData(&nativeFormat, &nativeMedium).ThrowOnFailure(); + medium = (STGMEDIUM)nativeMedium; + nativeMedium.ReleaseUnknown(); + } + + void ComTypes.IDataObject.GetDataHere(ref FORMATETC format, ref STGMEDIUM medium) + { + Com.FORMATETC nativeFormat = Unsafe.As(ref format); + Com.STGMEDIUM nativeMedium = (Com.STGMEDIUM)medium; + using var nativeDataObject = _nativeDataObject.GetInterface(); + nativeDataObject.Value->GetDataHere(&nativeFormat, &nativeMedium).ThrowOnFailure(); + medium = (STGMEDIUM)nativeMedium; + nativeMedium.ReleaseUnknown(); + } + + int ComTypes.IDataObject.QueryGetData(ref FORMATETC format) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->QueryGetData(Unsafe.As(ref format)); + } + + void ComTypes.IDataObject.SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release) + { + Com.STGMEDIUM nativeMedium = (Com.STGMEDIUM)medium; + Com.FORMATETC nativeFormat = Unsafe.As(ref formatIn); + using var nativeDataObject = _nativeDataObject.GetInterface(); + HRESULT result = nativeDataObject.Value->SetData(&nativeFormat, &nativeMedium, release); + medium = (STGMEDIUM)nativeMedium; + nativeMedium.ReleaseUnknown(); + result.ThrowOnFailure(); + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToWinFormsAdapter.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToWinFormsAdapter.cs new file mode 100644 index 00000000000..89230e6b789 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.NativeDataObjectToWinFormsAdapter.cs @@ -0,0 +1,556 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization.Formatters; +using System.Text; +using System.Windows.Forms.BinaryFormat; +using Com = Windows.Win32.System.Com; +using System.Drawing; + +namespace System.Windows.Forms; + +public unsafe partial class DataObject +{ + internal unsafe partial class ComposedDataObject + { + /// + /// Maps native pointer to . + /// + private unsafe class NativeDataObjectToWinFormsAdapter : IDataObject, Com.IDataObject.Interface + { + private readonly AgileComPointer _nativeDataObject; + + public NativeDataObjectToWinFormsAdapter(Com.IDataObject* dataObject) + { +#if DEBUG + _nativeDataObject = new(dataObject, takeOwnership: true, trackDisposal: false); +#else + _nativeDataObject = new(dataObject, takeOwnership: true); +#endif + } + + HRESULT Com.IDataObject.Interface.GetData(Com.FORMATETC* pformatetcIn, Com.STGMEDIUM* pmedium) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->GetData(pformatetcIn, pmedium); + } + + HRESULT Com.IDataObject.Interface.GetDataHere(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->GetDataHere(pformatetc, pmedium); + } + + HRESULT Com.IDataObject.Interface.QueryGetData(Com.FORMATETC* pformatetc) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->QueryGetData(pformatetc); + } + + HRESULT Com.IDataObject.Interface.GetCanonicalFormatEtc(Com.FORMATETC* pformatectIn, Com.FORMATETC* pformatetcOut) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->GetCanonicalFormatEtc(pformatectIn, pformatetcOut); + } + + HRESULT Com.IDataObject.Interface.SetData(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium, BOOL fRelease) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->SetData(pformatetc, pmedium, fRelease); + } + + HRESULT Com.IDataObject.Interface.EnumFormatEtc(uint dwDirection, Com.IEnumFORMATETC** ppenumFormatEtc) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->EnumFormatEtc(dwDirection, ppenumFormatEtc); + } + + HRESULT Com.IDataObject.Interface.DAdvise(Com.FORMATETC* pformatetc, uint advf, Com.IAdviseSink* pAdvSink, uint* pdwConnection) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->DAdvise(pformatetc, advf, pAdvSink, pdwConnection); + } + + HRESULT Com.IDataObject.Interface.DUnadvise(uint dwConnection) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->DUnadvise(dwConnection); + } + + HRESULT Com.IDataObject.Interface.EnumDAdvise(Com.IEnumSTATDATA** ppenumAdvise) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + return nativeDataObject.Value->EnumDAdvise(ppenumAdvise); + } + + /// + /// Retrieves the specified format from the specified hglobal. + /// + private static object? GetDataFromHGLOBAL(HGLOBAL hglobal, string format) + { + if (hglobal == 0) + { + return null; + } + + return format switch + { + DataFormats.TextConstant or DataFormats.RtfConstant or DataFormats.OemTextConstant + => ReadStringFromHGLOBAL(hglobal, unicode: false), + DataFormats.HtmlConstant => ReadUtf8StringFromHGLOBAL(hglobal), + DataFormats.UnicodeTextConstant => ReadStringFromHGLOBAL(hglobal, unicode: true), + DataFormats.FileDropConstant => ReadFileListFromHDROP((HDROP)(nint)hglobal), + CF_DEPRECATED_FILENAME => new string[] { ReadStringFromHGLOBAL(hglobal, unicode: false) }, + CF_DEPRECATED_FILENAMEW => new string[] { ReadStringFromHGLOBAL(hglobal, unicode: true) }, + _ => ReadObjectFromHGLOBAL(hglobal, RestrictDeserializationToSafeTypes(format)) + }; + + static unsafe string ReadStringFromHGLOBAL(HGLOBAL hglobal, bool unicode) + { + string? stringData = null; + + void* buffer = PInvokeCore.GlobalLock(hglobal); + try + { + stringData = unicode ? new string((char*)buffer) : new string((sbyte*)buffer); + } + finally + { + PInvokeCore.GlobalUnlock(hglobal); + } + + return stringData; + } + + static unsafe string ReadUtf8StringFromHGLOBAL(HGLOBAL hglobal) + { + void* buffer = PInvokeCore.GlobalLock(hglobal); + try + { + int size = (int)PInvokeCore.GlobalSize(hglobal); + return Encoding.UTF8.GetString((byte*)buffer, size - 1); + } + finally + { + PInvokeCore.GlobalUnlock(hglobal); + } + } + + static unsafe string[]? ReadFileListFromHDROP(HDROP hdrop) + { + uint count = PInvoke.DragQueryFile(hdrop, iFile: 0xFFFFFFFF, lpszFile: null, cch: 0); + if (count == 0) + { + return null; + } + + Span fileName = stackalloc char[PInvoke.MAX_PATH + 1]; + string[] files = new string[count]; + + fixed (char* buffer = fileName) + { + for (uint i = 0; i < count; i++) + { + uint charactersCopied = PInvoke.DragQueryFile(hdrop, i, buffer, (uint)fileName.Length); + if (charactersCopied == 0) + { + continue; + } + + string s = fileName[..(int)charactersCopied].ToString(); + files[i] = s; + } + } + + return files; + } + + static object ReadObjectFromHGLOBAL(HGLOBAL hglobal, bool restrictDeserialization) + { + Stream stream = ReadByteStreamFromHGLOBAL(hglobal, out bool isSerializedObject); + return !isSerializedObject ? stream : ReadObjectFromHandleDeserializer(stream, restrictDeserialization); + + static object ReadObjectFromHandleDeserializer(Stream stream, bool restrictDeserialization) + { + long startPosition = stream.Position; + try + { + if (new BinaryFormattedObject(stream, leaveOpen: true).TryGetObject(out object? value)) + { + return value; + } + } + catch (Exception ex) when (!ex.IsCriticalException()) + { + // Couldn't parse for some reason, let the BinaryFormatter try to handle it. + } + + stream.Position = startPosition; + +#pragma warning disable SYSLIB0011 // Type or member is obsolete +#pragma warning disable SYSLIB0050 // Type or member is obsolete + return new BinaryFormatter() + { + Binder = restrictDeserialization ? new BitmapBinder() : null, + AssemblyFormat = FormatterAssemblyStyle.Simple + }.Deserialize(stream); +#pragma warning restore SYSLIB0050 +#pragma warning restore SYSLIB0011 + } + + static unsafe Stream ReadByteStreamFromHGLOBAL(HGLOBAL hglobal, out bool isSerializedObject) + { + void* buffer = PInvokeCore.GlobalLock(hglobal); + if (buffer is null) + { + throw new ExternalException(SR.ExternalException, (int)HRESULT.E_OUTOFMEMORY); + } + + try + { + int size = (int)PInvokeCore.GlobalSize(hglobal); + byte[] bytes = new byte[size]; + Marshal.Copy((nint)buffer, bytes, 0, size); + int index = 0; + + // The object here can either be a stream or a serialized object. We identify a serialized object + // by writing the bytes for the guid serializedObjectID at the front of the stream. + + if (isSerializedObject = bytes.AsSpan().StartsWith(s_serializedObjectID)) + { + index = s_serializedObjectID.Length; + } + + return new MemoryStream(bytes, index, bytes.Length - index); + } + finally + { + PInvokeCore.GlobalUnlock(hglobal); + } + } + } + } + + /// + /// Extracts a managed object from of the specified format. + /// + /// + /// A restricted type was encountered, do not continue trying to deserialize. + /// + private static object? GetObjectFromDataObject(Com.IDataObject* dataObject, string format, out bool doNotContinue) + { + object? data = null; + doNotContinue = false; + try + { + // Try to get the data as a bitmap first. + data = TryGetBitmapData(dataObject, format); + + // Check for one of our standard data types. + data ??= TryGetHGLOBALData(dataObject, format, out doNotContinue); + + if (data is null && !doNotContinue) + { + // Lastly check to see if the data is an IStream. + data = TryGetIStreamData(dataObject, format); + } + } + catch (Exception e) + { + Debug.Fail(e.ToString()); + } + + return data; + + static object? TryGetBitmapData(Com.IDataObject* dataObject, string format) + { + if (format != DataFormats.BitmapConstant) + { + return null; + } + + Com.FORMATETC formatEtc = new() + { + cfFormat = (ushort)DataFormats.GetFormat(format).Id, + dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, + lindex = -1, + tymed = (uint)Com.TYMED.TYMED_GDI + }; + + Com.STGMEDIUM medium = default; + + if (dataObject->QueryGetData(formatEtc).Succeeded) + { + HRESULT hr = dataObject->GetData(formatEtc, out medium); + // One of the ways this can happen is when we attempt to put binary formatted data onto the + // clipboard, which will succeed as Windows ignores all errors when putting data on the clipboard. + // The data state, however, is not good, and this error will be returned by Windows when asking to + // get the data out. + Debug.WriteLineIf(hr == HRESULT.CLIPBRD_E_BAD_DATA, "CLIPBRD_E_BAD_DATA returned when trying to get clipboard data."); + } + + object? data = null; + + try + { + // GDI+ doesn't own this HBITMAP, but we can't delete it while the object is still around. So we + // have to do the really expensive thing of cloning the image so we can release the HBITMAP. + if ((uint)medium.tymed == (uint)TYMED.TYMED_GDI + && !medium.hGlobal.IsNull + && format.Equals(DataFormats.BitmapConstant) + && Image.FromHbitmap(medium.hGlobal) is Image clipboardImage) + { + data = (Image)clipboardImage.Clone(); + clipboardImage.Dispose(); + } + } + finally + { + PInvoke.ReleaseStgMedium(ref medium); + } + + return data; + } + + static object? TryGetHGLOBALData(Com.IDataObject* dataObject, string format, out bool doNotContinue) + { + doNotContinue = false; + + Com.FORMATETC formatetc = new() + { + cfFormat = (ushort)DataFormats.GetFormat(format).Id, + dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, + lindex = -1, + tymed = (uint)Com.TYMED.TYMED_HGLOBAL + }; + + if (dataObject->QueryGetData(formatetc).Failed) + { + return null; + } + + object? data = null; + HRESULT result = dataObject->GetData(formatetc, out Com.STGMEDIUM medium); + + // One of the ways this can happen is when we attempt to put binary formatted data onto the + // clipboard, which will succeed as Windows ignores all errors when putting data on the clipboard. + // The data state, however, is not good, and this error will be returned by Windows when asking to + // get the data out. + Debug.WriteLineIf(result == HRESULT.CLIPBRD_E_BAD_DATA, "CLIPBRD_E_BAD_DATA returned when trying to get clipboard data."); + + try + { + if (medium.tymed == Com.TYMED.TYMED_HGLOBAL && !medium.hGlobal.IsNull) + { + data = GetDataFromHGLOBAL(medium.hGlobal, format); + } + } + catch (RestrictedTypeDeserializationException) + { + doNotContinue = true; + } + catch + { + } + finally + { + PInvoke.ReleaseStgMedium(ref medium); + } + + return data; + } + + static unsafe object? TryGetIStreamData(Com.IDataObject* dataObject, string format) + { + Com.FORMATETC formatEtc = new() + { + cfFormat = (ushort)DataFormats.GetFormat(format).Id, + dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, + lindex = -1, + tymed = (uint)Com.TYMED.TYMED_ISTREAM + }; + + // Limit the # of exceptions we may throw below. + if (dataObject->QueryGetData(formatEtc).Failed + || dataObject->GetData(formatEtc, out Com.STGMEDIUM medium).Failed) + { + return null; + } + + HGLOBAL hglobal = default; + try + { + if (medium.tymed != Com.TYMED.TYMED_ISTREAM || medium.hGlobal.IsNull) + { + return null; + } + + using ComScope pStream = new((Com.IStream*)medium.hGlobal); + pStream.Value->Stat(out Com.STATSTG sstg, (uint)Com.STATFLAG.STATFLAG_DEFAULT); + + hglobal = PInvokeCore.GlobalAlloc(GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT, (uint)sstg.cbSize); + + // Not throwing here because the other out of memory condition on GlobalAlloc + // happens inside innerData.GetData and gets turned into a null return value. + if (hglobal.IsNull) + { + return null; + } + + void* ptr = PInvokeCore.GlobalLock(hglobal); + pStream.Value->Read((byte*)ptr, (uint)sstg.cbSize, null); + PInvokeCore.GlobalUnlock(hglobal); + + return GetDataFromHGLOBAL(hglobal, format); + } + finally + { + if (!hglobal.IsNull) + { + PInvokeCore.GlobalFree(hglobal); + } + + PInvoke.ReleaseStgMedium(ref medium); + } + } + } + + object? IDataObject.GetData(string format, bool autoConvert) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + object? data = GetObjectFromDataObject(nativeDataObject, format, out bool doNotContinue); + + if (doNotContinue + || !autoConvert + || (data is not null && data is not MemoryStream) + || GetMappedFormats(format) is not { } mappedFormats) + { + return data; + } + + object? originalData = data; + + // Try to find a mapped format that works better. + foreach (string mappedFormat in mappedFormats) + { + if (!format.Equals(mappedFormat)) + { + data = GetObjectFromDataObject(nativeDataObject, mappedFormat, out doNotContinue); + if (doNotContinue) + { + break; + } + + if (data is not null and not MemoryStream) + { + return data; + } + } + } + + return originalData ?? data; + } + + object? IDataObject.GetData(string format) => ((IDataObject)this).GetData(format, autoConvert: true); + + object? IDataObject.GetData(Type format) => ((IDataObject)this).GetData(format.FullName!); + + void IDataObject.SetData(string format, bool autoConvert, object? data) { } + void IDataObject.SetData(string format, object? data) { } + + void IDataObject.SetData(Type format, object? data) { } + + void IDataObject.SetData(object? data) { } + + bool IDataObject.GetDataPresent(Type format) => GetDataPresent(format.FullName!); + + private bool GetDataPresentInner(string format) + { + Com.FORMATETC formatEtc = new() + { + cfFormat = (ushort)(DataFormats.GetFormat(format).Id), + dwAspect = (uint)Com.DVASPECT.DVASPECT_CONTENT, + lindex = -1, + tymed = (uint)AllowedTymeds + }; + + using var nativeDataObject = _nativeDataObject.GetInterface(); + HRESULT hr = nativeDataObject.Value->QueryGetData(formatEtc); + return hr.Succeeded; + } + + public bool GetDataPresent(string format, bool autoConvert) + { + bool dataPresent = GetDataPresentInner(format); + + if (dataPresent || !autoConvert || GetMappedFormats(format) is not { } mappedFormats) + { + return dataPresent; + } + + foreach (string mappedFormat in mappedFormats) + { + if (!format.Equals(mappedFormat) && (dataPresent = GetDataPresentInner(mappedFormat))) + { + break; + } + } + + return dataPresent; + } + + public bool GetDataPresent(string format) => GetDataPresent(format, autoConvert: true); + + public string[] GetFormats(bool autoConvert) + { + using var nativeDataObject = _nativeDataObject.GetInterface(); + Debug.Assert(!nativeDataObject.IsNull, "You must have an innerData on all DataObjects"); + + using ComScope enumFORMATETC = new(null); + nativeDataObject.Value->EnumFormatEtc((uint)DATADIR.DATADIR_GET, enumFORMATETC).AssertSuccess(); + + if (enumFORMATETC.IsNull) + { + return []; + } + + // Since we are only adding elements to the HashSet, the order will be preserved. + HashSet distinctFormats = []; + + enumFORMATETC.Value->Reset(); + + Com.FORMATETC[] formatEtc = [default]; + HRESULT hr; + + fixed (Com.FORMATETC* pFormatEtc = formatEtc) + { + hr = enumFORMATETC.Value->Next(1, pFormatEtc); + } + + if (hr == HRESULT.S_OK) + { + string name = DataFormats.GetFormat(formatEtc[0].cfFormat).Name; + if (autoConvert) + { + string[] mappedFormats = GetMappedFormats(name)!; + for (int i = 0; i < mappedFormats.Length; i++) + { + distinctFormats.Add(mappedFormats[i]); + } + } + else + { + distinctFormats.Add(name); + } + } + + return [.. distinctFormats]; + } + + public string[] GetFormats() => GetFormats(autoConvert: true); + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.RuntimeDataObjectToNativeAdapter.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.RuntimeDataObjectToNativeAdapter.cs new file mode 100644 index 00000000000..51967a5320d --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.RuntimeDataObjectToNativeAdapter.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices.ComTypes; +using Com = Windows.Win32.System.Com; +using ComTypes = System.Runtime.InteropServices.ComTypes; + +namespace System.Windows.Forms; + +public unsafe partial class DataObject +{ + internal unsafe partial class ComposedDataObject + { + /// + /// Maps to . + /// + private class RuntimeDataObjectToNativeAdapter : Com.IDataObject.Interface, ComTypes.IDataObject, Com.IManagedWrapper + { + private readonly ComTypes.IDataObject _runtimeDataObject; + + public RuntimeDataObjectToNativeAdapter(ComTypes.IDataObject dataObject) => _runtimeDataObject = dataObject; + + int ComTypes.IDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection) => _runtimeDataObject.DAdvise(ref pFormatetc, advf, adviseSink, out connection); + void ComTypes.IDataObject.DUnadvise(int connection) => _runtimeDataObject.DUnadvise(connection); + int ComTypes.IDataObject.EnumDAdvise(out IEnumSTATDATA? enumAdvise) => _runtimeDataObject.EnumDAdvise(out enumAdvise); + IEnumFORMATETC ComTypes.IDataObject.EnumFormatEtc(DATADIR direction) => _runtimeDataObject.EnumFormatEtc(direction); + int ComTypes.IDataObject.GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut) => _runtimeDataObject.GetCanonicalFormatEtc(ref formatIn, out formatOut); + void ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) => _runtimeDataObject.GetData(ref format, out medium); + void ComTypes.IDataObject.GetDataHere(ref FORMATETC format, ref STGMEDIUM medium) => _runtimeDataObject.GetDataHere(ref format, ref medium); + int ComTypes.IDataObject.QueryGetData(ref FORMATETC format) => _runtimeDataObject.QueryGetData(ref format); + void ComTypes.IDataObject.SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release) => _runtimeDataObject.SetData(ref formatIn, ref medium, release); + + HRESULT Com.IDataObject.Interface.GetData(Com.FORMATETC* pformatetcIn, Com.STGMEDIUM* pmedium) + { + if (pmedium is null) + { + return HRESULT.E_POINTER; + } + + try + { + ((ComTypes.IDataObject)this).GetData(ref *(FORMATETC*)pformatetcIn, out STGMEDIUM medium); + *pmedium = (Com.STGMEDIUM)medium; + return HRESULT.S_OK; + } + catch (Exception e) + { + return (HRESULT)e.HResult; + } + } + + HRESULT Com.IDataObject.Interface.GetDataHere(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium) + { + if (pmedium is null) + { + return HRESULT.E_POINTER; + } + + STGMEDIUM medium = (STGMEDIUM)(*pmedium); + try + { + ((ComTypes.IDataObject)this).GetDataHere(ref *(FORMATETC*)pformatetc, ref medium); + } + catch (Exception e) + { + return (HRESULT)e.HResult; + } + + *pmedium = (Com.STGMEDIUM)medium; + return HRESULT.S_OK; + } + + HRESULT Com.IDataObject.Interface.QueryGetData(Com.FORMATETC* pformatetc) + => (HRESULT)((ComTypes.IDataObject)this).QueryGetData(ref *(FORMATETC*)pformatetc); + + HRESULT Com.IDataObject.Interface.GetCanonicalFormatEtc(Com.FORMATETC* pformatectIn, Com.FORMATETC* pformatetcOut) + => (HRESULT)((ComTypes.IDataObject)this).GetCanonicalFormatEtc(ref *(FORMATETC*)pformatectIn, out *(FORMATETC*)pformatetcOut); + + HRESULT Com.IDataObject.Interface.SetData(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium, BOOL fRelease) + { + if (pmedium is null) + { + return HRESULT.E_POINTER; + } + + STGMEDIUM medium = (STGMEDIUM)(*pmedium); + try + { + ((ComTypes.IDataObject)this).SetData(ref *(FORMATETC*)pformatetc, ref medium, fRelease); + } + catch (Exception e) + { + return (HRESULT)e.HResult; + } + + return HRESULT.S_OK; + } + + HRESULT Com.IDataObject.Interface.EnumFormatEtc(uint dwDirection, Com.IEnumFORMATETC** ppenumFormatEtc) + { + if (ppenumFormatEtc is null) + { + return HRESULT.E_POINTER; + } + + var comTypeFormatEtc = ((ComTypes.IDataObject)this).EnumFormatEtc((DATADIR)(int)dwDirection); + *ppenumFormatEtc = ComHelpers.TryGetComPointer(comTypeFormatEtc, out HRESULT hr); + return hr.Succeeded ? HRESULT.S_OK : HRESULT.E_NOINTERFACE; + } + + HRESULT Com.IDataObject.Interface.DAdvise(Com.FORMATETC* pformatetc, uint advf, Com.IAdviseSink* pAdvSink, uint* pdwConnection) + { + var adviseSink = (IAdviseSink)ComHelpers.GetObjectForIUnknown((Com.IUnknown*)pAdvSink); + return (HRESULT)((ComTypes.IDataObject)this).DAdvise(ref *(FORMATETC*)pformatetc, (ADVF)advf, adviseSink, out *(int*)pdwConnection); + } + + HRESULT Com.IDataObject.Interface.DUnadvise(uint dwConnection) + { + try + { + ((ComTypes.IDataObject)this).DUnadvise((int)dwConnection); + } + catch (Exception e) + { + return (HRESULT)e.HResult; + } + + return HRESULT.S_OK; + } + + HRESULT Com.IDataObject.Interface.EnumDAdvise(Com.IEnumSTATDATA** ppenumAdvise) + { + if (ppenumAdvise is null) + { + return HRESULT.E_POINTER; + } + + *ppenumAdvise = null; + + HRESULT hr = (HRESULT)((ComTypes.IDataObject)this).EnumDAdvise(out var enumAdvice); + if (hr.Failed) + { + return hr; + } + + *ppenumAdvise = ComHelpers.TryGetComPointer(enumAdvice, out hr); + return hr.Succeeded ? hr : HRESULT.E_NOINTERFACE; + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.WinFormsDataObjectToNativeAdapter.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.WinFormsDataObjectToNativeAdapter.cs new file mode 100644 index 00000000000..97098165da4 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.WinFormsDataObjectToNativeAdapter.cs @@ -0,0 +1,554 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Drawing; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Windows.Forms.BinaryFormat; +using Windows.Win32.System.Com; +using Com = Windows.Win32.System.Com; +using ComTypes = System.Runtime.InteropServices.ComTypes; + +namespace System.Windows.Forms; + +public unsafe partial class DataObject +{ + internal unsafe partial class ComposedDataObject + { + /// + /// Maps to . + /// + private unsafe class WinFormsDataObjectToNativeAdapter : Com.IDataObject.Interface, IManagedWrapper + { + private const int DATA_S_SAMEFORMATETC = 0x00040130; + + private readonly IDataObject _dataObject; + + public WinFormsDataObjectToNativeAdapter(IDataObject dataObject) + { + _dataObject = dataObject; + } + + /// + /// Returns true if the tymed is useable. + /// + private static bool GetTymedUseable(TYMED tymed) => (tymed & AllowedTymeds) != 0; + + HRESULT Com.IDataObject.Interface.GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium) + { + if (pformatetcIn is null) + { + return HRESULT.DV_E_FORMATETC; + } + + if (pmedium is null) + { + return HRESULT.E_POINTER; + } + + if (DragDropHelper.IsInDragLoop(_dataObject)) + { + string formatName = DataFormats.GetFormat(pformatetcIn->cfFormat).Name; + if (!_dataObject.GetDataPresent(formatName)) + { + *pmedium = default; + return HRESULT.S_OK; + } + + if (_dataObject.GetData(formatName) is DragDropFormat dragDropFormat) + { + *pmedium = dragDropFormat.GetData(); + return HRESULT.S_OK; + } + } + + *pmedium = default; + + if (!GetTymedUseable((TYMED)pformatetcIn->tymed)) + { + return HRESULT.DV_E_TYMED; + } + + if (!((TYMED)pformatetcIn->tymed).HasFlag(TYMED.TYMED_HGLOBAL)) + { + pmedium->tymed = (TYMED)pformatetcIn->tymed; + return ((Com.IDataObject.Interface)this).GetDataHere(pformatetcIn, pmedium); + } + + pmedium->tymed = TYMED.TYMED_HGLOBAL; + pmedium->hGlobal = PInvokeCore.GlobalAlloc(GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT, 1); + + if (pmedium->hGlobal.IsNull) + { + return HRESULT.E_OUTOFMEMORY; + } + + HRESULT result = ((Com.IDataObject.Interface)this).GetDataHere(pformatetcIn, pmedium); + if (result.Failed) + { + PInvokeCore.GlobalFree(pmedium->hGlobal); + pmedium->hGlobal = HGLOBAL.Null; + } + + return result; + } + + HRESULT Com.IDataObject.Interface.GetDataHere(FORMATETC* pformatetc, STGMEDIUM* pmedium) + { + if (pformatetc is null) + { + return HRESULT.DV_E_FORMATETC; + } + + if (pmedium is null) + { + return HRESULT.E_POINTER; + } + + if (!GetTymedUseable((TYMED)pformatetc->tymed) || !GetTymedUseable(pmedium->tymed)) + { + return HRESULT.DV_E_TYMED; + } + + string format = DataFormats.GetFormat(pformatetc->cfFormat).Name; + + if (!_dataObject.GetDataPresent(format)) + { + return HRESULT.DV_E_FORMATETC; + } + + object? data = _dataObject.GetData(format); + + if (((TYMED)pformatetc->tymed).HasFlag(TYMED.TYMED_HGLOBAL)) + { + try + { + return SaveDataToHGLOBAL(data!, format, ref *pmedium); + } + catch (NotSupportedException ex) + { + // BinaryFormatter is disabled. As all errors get swallowed by Windows, put the exception on the + // clipboard so consumers can get some indication as to what is wrong. (We handle the binary formatting + // of this exception, so it will always work.) + return SaveDataToHGLOBAL(ex, format, ref *pmedium); + } + } + + if (((TYMED)pformatetc->tymed).HasFlag(TYMED.TYMED_GDI)) + { + if (format.Equals(DataFormats.Bitmap) && data is Bitmap bitmap) + { + // Save bitmap + pmedium->u.hBitmap = GetCompatibleBitmap(bitmap); + } + + return HRESULT.S_OK; + } + + return HRESULT.DV_E_TYMED; + + static HBITMAP GetCompatibleBitmap(Bitmap bitmap) + { + using var screenDC = GetDcScope.ScreenDC; + + // GDI+ returns a DIBSECTION based HBITMAP. The clipboard only deals well with bitmaps created using + // CreateCompatibleBitmap(). So, we convert the DIBSECTION into a compatible bitmap. + HBITMAP hbitmap = bitmap.GetHBITMAP(); + + // Create a compatible DC to render the source bitmap. + using CreateDcScope sourceDC = new(screenDC); + using SelectObjectScope sourceBitmapSelection = new(sourceDC, hbitmap); + + // Create a compatible DC and a new compatible bitmap. + using CreateDcScope destinationDC = new(screenDC); + HBITMAP compatibleBitmap = PInvokeCore.CreateCompatibleBitmap(screenDC, bitmap.Size.Width, bitmap.Size.Height); + + // Select the new bitmap into a compatible DC and render the blt the original bitmap. + using SelectObjectScope destinationBitmapSelection = new(destinationDC, compatibleBitmap); + PInvokeCore.BitBlt( + destinationDC, + 0, + 0, + bitmap.Size.Width, + bitmap.Size.Height, + sourceDC, + 0, + 0, + ROP_CODE.SRCCOPY); + + return compatibleBitmap; + } + } + + HRESULT Com.IDataObject.Interface.QueryGetData(FORMATETC* pformatetc) + { + if (pformatetc is null) + { + return HRESULT.DV_E_FORMATETC; + } + + if (pformatetc->dwAspect != (uint)DVASPECT.DVASPECT_CONTENT) + { + return HRESULT.DV_E_DVASPECT; + } + + if (!GetTymedUseable((TYMED)pformatetc->tymed)) + { + return HRESULT.DV_E_TYMED; + } + + if (pformatetc->cfFormat == 0) + { + return HRESULT.S_FALSE; + } + + if (!_dataObject.GetDataPresent(DataFormats.GetFormat(pformatetc->cfFormat).Name)) + { + return HRESULT.DV_E_FORMATETC; + } + + return HRESULT.S_OK; + } + + HRESULT Com.IDataObject.Interface.GetCanonicalFormatEtc(FORMATETC* pformatectIn, FORMATETC* pformatetcOut) + { + if (pformatetcOut is null) + { + return HRESULT.E_POINTER; + } + + *pformatetcOut = default; + return (HRESULT)DATA_S_SAMEFORMATETC; + } + + HRESULT Com.IDataObject.Interface.SetData(FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease) + { + if (pformatetc is null) + { + return HRESULT.DV_E_FORMATETC; + } + + if (pmedium is null) + { + return HRESULT.E_POINTER; + } + + if (DragDropHelper.IsInDragLoopFormat(*pformatetc) || DragDropHelper.IsInDragLoop(_dataObject)) + { + string formatName = DataFormats.GetFormat(pformatetc->cfFormat).Name; + if (_dataObject.GetDataPresent(formatName) && _dataObject.GetData(formatName) is DragDropFormat dragDropFormat) + { + dragDropFormat.RefreshData(pformatetc->cfFormat, *pmedium, !fRelease); + } + else + { + _dataObject.SetData(formatName, new DragDropFormat(pformatetc->cfFormat, *pmedium, !fRelease)); + } + + return HRESULT.S_OK; + } + + return HRESULT.E_NOTIMPL; + } + + HRESULT Com.IDataObject.Interface.EnumFormatEtc(uint dwDirection, IEnumFORMATETC** ppenumFormatEtc) + { + if (ppenumFormatEtc is null) + { + return HRESULT.E_POINTER; + } + + if (dwDirection == (uint)ComTypes.DATADIR.DATADIR_GET) + { + *ppenumFormatEtc = ComHelpers.GetComPointer(new FormatEnumerator(_dataObject)); + return HRESULT.S_OK; + } + + return HRESULT.E_NOTIMPL; + } + + HRESULT Com.IDataObject.Interface.DAdvise(FORMATETC* pformatetc, uint advf, IAdviseSink* pAdvSink, uint* pdwConnection) + { + if (pdwConnection is null) + { + return HRESULT.E_POINTER; + } + + *pdwConnection = 0; + return HRESULT.E_NOTIMPL; + } + + HRESULT Com.IDataObject.Interface.DUnadvise(uint dwConnection) => HRESULT.E_NOTIMPL; + + HRESULT Com.IDataObject.Interface.EnumDAdvise(IEnumSTATDATA** ppenumAdvise) + { + if (ppenumAdvise is null) + { + return HRESULT.E_POINTER; + } + + *ppenumAdvise = null; + return HRESULT.OLE_E_ADVISENOTSUPPORTED; + } + + private HRESULT SaveDataToHGLOBAL(object data, string format, ref STGMEDIUM medium) => format switch + { + _ when data is Stream dataStream + => SaveStreamToHGLOBAL(ref medium.hGlobal, dataStream), + DataFormats.TextConstant or DataFormats.RtfConstant or DataFormats.OemTextConstant + => SaveStringToHGLOBAL(medium.hGlobal, data.ToString()!, unicode: false), + DataFormats.HtmlConstant + => SaveHtmlToHGLOBAL(medium.hGlobal, data.ToString()!), + DataFormats.UnicodeTextConstant + => SaveStringToHGLOBAL(medium.hGlobal, data.ToString()!, unicode: true), + DataFormats.FileDropConstant + => SaveFileListToHGLOBAL(medium.hGlobal, (string[])data), + CF_DEPRECATED_FILENAME + => SaveStringToHGLOBAL(medium.hGlobal, ((string[])data)[0], unicode: false), + CF_DEPRECATED_FILENAMEW + => SaveStringToHGLOBAL(medium.hGlobal, ((string[])data)[0], unicode: true), + DataFormats.DibConstant when data is Image + // GDI+ does not properly handle saving to DIB images. Since the clipboard will take + // an HBITMAP and publish a Dib, we don't need to support this. + => HRESULT.DV_E_TYMED, +#pragma warning disable SYSLIB0050 // Type or member is obsolete + _ when format == DataFormats.SerializableConstant || data is ISerializable || data.GetType().IsSerializable +#pragma warning restore + => SaveObjectToHGLOBAL(ref medium.hGlobal, data, RestrictDeserializationToSafeTypes(format)), + _ => HRESULT.E_FAIL + }; + + private static HRESULT SaveObjectToHGLOBAL(ref HGLOBAL hglobal, object data, bool restrictSerialization) + { + using MemoryStream stream = new(); + stream.Write(s_serializedObjectID); + long position = stream.Position; + bool success = false; + + try + { + success = WinFormsBinaryFormatWriter.TryWriteObject(stream, data); + } + catch (Exception ex) when (!ex.IsCriticalException()) + { + // Being extra cautious here, but the Try method above should never throw in normal circumstances. + Debug.Fail($"Unexpected exception writing binary formatted data. {ex.Message}"); + } + +#pragma warning disable SYSLIB0011 // Type or member is obsolete + if (!success) + { + new BinaryFormatter() + { + Binder = restrictSerialization ? new BitmapBinder() : null + }.Serialize(stream, data); + } +#pragma warning restore SYSLIB0011 + + return SaveStreamToHGLOBAL(ref hglobal, stream); + } + + private static HRESULT SaveStreamToHGLOBAL(ref HGLOBAL hglobal, Stream stream) + { + if (hglobal != 0) + { + PInvokeCore.GlobalFree(hglobal); + } + + int size = checked((int)stream.Length); + hglobal = PInvokeCore.GlobalAlloc(GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE, (uint)size); + if (hglobal == 0) + { + return HRESULT.E_OUTOFMEMORY; + } + + void* buffer = PInvokeCore.GlobalLock(hglobal); + if (buffer is null) + { + return HRESULT.E_OUTOFMEMORY; + } + + try + { + Span span = new(buffer, size); + stream.Position = 0; + stream.Read(span); + } + finally + { + PInvokeCore.GlobalUnlock(hglobal); + } + + return HRESULT.S_OK; + } + + /// + /// Saves a list of files out to the handle in HDROP format. + /// + private HRESULT SaveFileListToHGLOBAL(HGLOBAL hglobal, string[] files) + { + if (files is null || files.Length == 0) + { + return HRESULT.S_OK; + } + + if (hglobal == 0) + { + return HRESULT.E_INVALIDARG; + } + + // CF_HDROP consists of a DROPFILES struct followed by an list of strings including the terminating null + // character. An additional null character is appended to the final string to terminate the array. + // + // E.g. if the files c:\temp1.txt and c:\temp2.txt are being transferred, the character array is: + // "c:\temp1.txt\0c:\temp2.txt\0\0" + + // Determine the size of the data structure. + uint sizeInBytes = (uint)sizeof(DROPFILES); + foreach (string file in files) + { + sizeInBytes += (uint)(file.Length + 1) * sizeof(char); + } + + sizeInBytes += sizeof(char); + + // Allocate the Win32 memory + HGLOBAL newHandle = PInvokeCore.GlobalReAlloc(hglobal, sizeInBytes, (uint)GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE); + if (newHandle == 0) + { + return HRESULT.E_OUTOFMEMORY; + } + + void* buffer = PInvokeCore.GlobalLock(newHandle); + if (buffer is null) + { + return HRESULT.E_OUTOFMEMORY; + } + + // Write out the DROPFILES struct. + DROPFILES* dropFiles = (DROPFILES*)buffer; + *dropFiles = new DROPFILES() + { + pFiles = (uint)sizeof(DROPFILES), + pt = Point.Empty, + fNC = false, + fWide = true + }; + + Span fileBuffer = new( + (char*)((byte*)buffer + dropFiles->pFiles), + ((int)sizeInBytes - (int)dropFiles->pFiles) / sizeof(char)); + + // Write out the strings. + foreach (string file in files) + { + file.CopyTo(fileBuffer); + fileBuffer[file.Length] = '\0'; + fileBuffer = fileBuffer[(file.Length + 1)..]; + } + + fileBuffer[0] = '\0'; + + PInvokeCore.GlobalUnlock(newHandle); + return HRESULT.S_OK; + } + + /// + /// Save string to handle. If unicode is set to true then the string is saved as Unicode, else it is saves as DBCS. + /// + private HRESULT SaveStringToHGLOBAL(HGLOBAL hglobal, string value, bool unicode) + { + if (hglobal == 0) + { + return HRESULT.E_INVALIDARG; + } + + HGLOBAL newHandle = default; + if (unicode) + { + uint byteSize = (uint)value.Length * sizeof(char) + sizeof(char); + newHandle = PInvokeCore.GlobalReAlloc(hglobal, byteSize, (uint)(GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT)); + if (newHandle == 0) + { + return HRESULT.E_OUTOFMEMORY; + } + + char* buffer = (char*)PInvokeCore.GlobalLock(newHandle); + if (buffer is null) + { + return HRESULT.E_OUTOFMEMORY; + } + + Span data = new(buffer, value.Length + 1); + value.AsSpan().CopyTo(data); + + // Null terminate. + data[value.Length] = '\0'; + } + else + { + fixed (char* c = value) + { + int pinvokeSize = PInvoke.WideCharToMultiByte(PInvoke.CP_ACP, 0, value, value.Length, null, 0, null, null); + newHandle = PInvokeCore.GlobalReAlloc(hglobal, (uint)pinvokeSize + 1, (uint)GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | (uint)GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT); + if (newHandle == 0) + { + return HRESULT.E_OUTOFMEMORY; + } + + byte* buffer = (byte*)PInvokeCore.GlobalLock(newHandle); + if (buffer is null) + { + return HRESULT.E_OUTOFMEMORY; + } + + PInvoke.WideCharToMultiByte(PInvoke.CP_ACP, 0, value, value.Length, buffer, pinvokeSize, null, null); + + // Null terminate + buffer[pinvokeSize] = 0; + } + } + + PInvokeCore.GlobalUnlock(newHandle); + return HRESULT.S_OK; + } + + private static HRESULT SaveHtmlToHGLOBAL(HGLOBAL hglobal, string value) + { + if (hglobal == 0) + { + return HRESULT.E_INVALIDARG; + } + + int byteLength = Encoding.UTF8.GetByteCount(value); + HGLOBAL newHandle = PInvokeCore.GlobalReAlloc(hglobal, (uint)byteLength + 1, (uint)(GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT)); + if (newHandle == 0) + { + return HRESULT.E_OUTOFMEMORY; + } + + byte* buffer = (byte*)PInvokeCore.GlobalLock(newHandle); + if (buffer is null) + { + return HRESULT.E_OUTOFMEMORY; + } + + try + { + Span span = new(buffer, byteLength + 1); + Encoding.UTF8.GetBytes(value, span); + + // Null terminate + span[byteLength] = 0; + } + finally + { + PInvokeCore.GlobalUnlock(newHandle); + } + + return HRESULT.S_OK; + } + } + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.cs new file mode 100644 index 00000000000..69dc37d9267 --- /dev/null +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.ComposedDataObject.cs @@ -0,0 +1,137 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices.ComTypes; +using Com = Windows.Win32.System.Com; +using ComTypes = System.Runtime.InteropServices.ComTypes; + +namespace System.Windows.Forms; + +public unsafe partial class DataObject +{ + /// + /// Contains the logic to move between , , + /// and calls. + /// + internal unsafe partial class ComposedDataObject : IDataObject, Com.IDataObject.Interface, ComTypes.IDataObject + { + private const Com.TYMED AllowedTymeds = Com.TYMED.TYMED_HGLOBAL | Com.TYMED.TYMED_ISTREAM | Com.TYMED.TYMED_GDI; + + // We use this to identify that a stream is actually a serialized object. On read, we don't know if the contents + // of a stream were saved "raw" or if the stream is really pointing to a serialized object. If we saved an object, + // we prefix it with this guid. + private static readonly byte[] s_serializedObjectID = + [ + // FD9EA796-3B13-4370-A679-56106BB288FB + 0x96, 0xa7, 0x9e, 0xfd, + 0x13, 0x3b, + 0x70, 0x43, + 0xa6, 0x79, 0x56, 0x10, 0x6b, 0xb2, 0x88, 0xfb + ]; + + private readonly IDataObject _winFormsDataObject; + private readonly Com.IDataObject.Interface _nativeDataObject; + private readonly ComTypes.IDataObject _runtimeDataObject; + + private ComposedDataObject(IDataObject winFormsDataObject, Com.IDataObject.Interface nativeDataObject, ComTypes.IDataObject runtimeDataObject) + { + _winFormsDataObject = winFormsDataObject; + _nativeDataObject = nativeDataObject; + _runtimeDataObject = runtimeDataObject; + if (winFormsDataObject is not NativeDataObjectToWinFormsAdapter and not DataStore) + { + OriginalIDataObject = winFormsDataObject; + } + } + + public static ComposedDataObject CreateFromWinFormsDataObject(IDataObject winFormsDataObject) + { + WinFormsDataObjectToNativeAdapter winFormsToNative = new(winFormsDataObject); + NativeDataObjectToRuntimeAdapter nativeToRuntime = new(ComHelpers.GetComPointer(winFormsToNative)); + return new(winFormsDataObject, winFormsToNative, nativeToRuntime); + } + + public static ComposedDataObject CreateFromNativeDataObject(Com.IDataObject* nativeDataObject) + { + // Add ref so each adapter can take ownership of the native data object. + nativeDataObject->AddRef(); + nativeDataObject->AddRef(); + NativeDataObjectToWinFormsAdapter nativeToWinForms = new(nativeDataObject); + NativeDataObjectToRuntimeAdapter nativeToRuntime = new(nativeDataObject); + return new(nativeToWinForms, nativeToWinForms, nativeToRuntime); + } + + public static ComposedDataObject CreateFromRuntimeDataObject(ComTypes.IDataObject runtimeDataObject) + { + RuntimeDataObjectToNativeAdapter runtimeToNative = new(runtimeDataObject); + NativeDataObjectToWinFormsAdapter nativeToWinForms = new(ComHelpers.GetComPointer(runtimeToNative)); + return new(nativeToWinForms, runtimeToNative, runtimeDataObject); + } + + /// + /// The the user passed to us, so that it can be passed back out. + /// + public IDataObject? OriginalIDataObject { get; private set; } + + /// + /// We are restricting serialization of formats that represent strings, bitmaps or OLE types. + /// + /// format name + /// true - serialize only safe types, strings or bitmaps. + private static bool RestrictDeserializationToSafeTypes(string format) + => format is DataFormats.StringConstant + or BitmapFullName + or DataFormats.CsvConstant + or DataFormats.DibConstant + or DataFormats.DifConstant + or DataFormats.LocaleConstant + or DataFormats.PenDataConstant + or DataFormats.RiffConstant + or DataFormats.SymbolicLinkConstant + or DataFormats.TiffConstant + or DataFormats.WaveAudioConstant + or DataFormats.BitmapConstant + or DataFormats.EmfConstant + or DataFormats.PaletteConstant + or DataFormats.WmfConstant; + + #region IDataObject + object? IDataObject.GetData(string format, bool autoConvert) => _winFormsDataObject.GetData(format, autoConvert); + object? IDataObject.GetData(string format) => _winFormsDataObject.GetData(format); + object? IDataObject.GetData(Type format) => _winFormsDataObject.GetData(format); + bool IDataObject.GetDataPresent(string format, bool autoConvert) => _winFormsDataObject.GetDataPresent(format, autoConvert); + bool IDataObject.GetDataPresent(string format) => _winFormsDataObject.GetDataPresent(format); + bool IDataObject.GetDataPresent(Type format) => _winFormsDataObject.GetDataPresent(format); + string[] IDataObject.GetFormats(bool autoConvert) => _winFormsDataObject.GetFormats(autoConvert); + string[] IDataObject.GetFormats() => _winFormsDataObject.GetFormats(); + void IDataObject.SetData(string format, bool autoConvert, object? data) => _winFormsDataObject.SetData(format, autoConvert, data); + void IDataObject.SetData(string format, object? data) => _winFormsDataObject.SetData(format, data); + void IDataObject.SetData(Type format, object? data) => _winFormsDataObject.SetData(format, data); + void IDataObject.SetData(object? data) => _winFormsDataObject.SetData(data); + #endregion + + #region Com.IDataObject.Interface + HRESULT Com.IDataObject.Interface.GetData(Com.FORMATETC* pformatetcIn, Com.STGMEDIUM* pmedium) => _nativeDataObject.GetData(pformatetcIn, pmedium); + HRESULT Com.IDataObject.Interface.GetDataHere(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium) => _nativeDataObject.GetDataHere(pformatetc, pmedium); + HRESULT Com.IDataObject.Interface.QueryGetData(Com.FORMATETC* pformatetc) => _nativeDataObject.QueryGetData(pformatetc); + HRESULT Com.IDataObject.Interface.GetCanonicalFormatEtc(Com.FORMATETC* pformatectIn, Com.FORMATETC* pformatetcOut) => _nativeDataObject.GetCanonicalFormatEtc(pformatectIn, pformatetcOut); + HRESULT Com.IDataObject.Interface.SetData(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium, BOOL fRelease) => _nativeDataObject.SetData(pformatetc, pmedium, fRelease); + HRESULT Com.IDataObject.Interface.EnumFormatEtc(uint dwDirection, Com.IEnumFORMATETC** ppenumFormatEtc) => _nativeDataObject.EnumFormatEtc(dwDirection, ppenumFormatEtc); + HRESULT Com.IDataObject.Interface.DAdvise(Com.FORMATETC* pformatetc, uint advf, Com.IAdviseSink* pAdvSink, uint* pdwConnection) => _nativeDataObject.DAdvise(pformatetc, advf, pAdvSink, pdwConnection); + HRESULT Com.IDataObject.Interface.DUnadvise(uint dwConnection) => _nativeDataObject.DUnadvise(dwConnection); + HRESULT Com.IDataObject.Interface.EnumDAdvise(Com.IEnumSTATDATA** ppenumAdvise) => _nativeDataObject.EnumDAdvise(ppenumAdvise); + #endregion + + #region ComTypes.IDataObject + int ComTypes.IDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection) => _runtimeDataObject.DAdvise(ref pFormatetc, advf, adviseSink, out connection); + void ComTypes.IDataObject.DUnadvise(int connection) => _runtimeDataObject.DUnadvise(connection); + int ComTypes.IDataObject.EnumDAdvise(out IEnumSTATDATA? enumAdvise) => _runtimeDataObject.EnumDAdvise(out enumAdvise); + IEnumFORMATETC ComTypes.IDataObject.EnumFormatEtc(DATADIR direction) => _runtimeDataObject.EnumFormatEtc(direction); + int ComTypes.IDataObject.GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut) => _runtimeDataObject.GetCanonicalFormatEtc(ref formatIn, out formatOut); + void ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) => _runtimeDataObject.GetData(ref format, out medium); + void ComTypes.IDataObject.GetDataHere(ref FORMATETC format, ref STGMEDIUM medium) => _runtimeDataObject.GetDataHere(ref format, ref medium); + int ComTypes.IDataObject.QueryGetData(ref FORMATETC format) => _runtimeDataObject.QueryGetData(ref format); + void ComTypes.IDataObject.SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release) => _runtimeDataObject.SetData(ref formatIn, ref medium, release); + #endregion + } +} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumFormatEtcWrapper.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumFormatEtcWrapper.cs deleted file mode 100644 index 58d5475fff8..00000000000 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumFormatEtcWrapper.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.InteropServices.ComTypes; -using Com = Windows.Win32.System.Com; - -namespace System.Windows.Forms; - -public unsafe partial class DataObject -{ - /// - /// A wrapper that responds to calls by - /// forwarding to the underlying native . - /// - private class EnumFormatEtcWrapper : IEnumFORMATETC - { - private readonly AgileComPointer _enumFormatEtc; - - public EnumFormatEtcWrapper(Com.IEnumFORMATETC* enumFormatEtc) - { - _enumFormatEtc = new(enumFormatEtc, takeOwnership: false); - } - - void IEnumFORMATETC.Clone(out IEnumFORMATETC newEnum) - { - using var formatEtc = _enumFormatEtc.GetInterface(); - using ComScope result = new(null); - formatEtc.Value->Clone(result).ThrowOnFailure(); - newEnum = new EnumFormatEtcWrapper(result); - } - - int IEnumFORMATETC.Next(int celt, FORMATETC[] rgelt, int[] pceltFetched) - { - using var formatEtc = _enumFormatEtc.GetInterface(); - fixed (int* ppceltFetched = pceltFetched) - fixed (FORMATETC* pRgelt = rgelt) - { - return formatEtc.Value->Next((uint)celt, (Com.FORMATETC*)pRgelt, (uint*)ppceltFetched); - } - } - - int IEnumFORMATETC.Reset() - { - using var formatEtc = _enumFormatEtc.GetInterface(); - return formatEtc.Value->Reset(); - } - - int IEnumFORMATETC.Skip(int celt) - { - using var formatEtc = _enumFormatEtc.GetInterface(); - return formatEtc.Value->Skip((uint)celt); - } - } -} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumStatDataWrapper.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumStatDataWrapper.cs deleted file mode 100644 index d3027053013..00000000000 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.EnumStatDataWrapper.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.InteropServices.ComTypes; -using Com = Windows.Win32.System.Com; - -namespace System.Windows.Forms; - -public unsafe partial class DataObject -{ - /// - /// A wrapper that responds to calls by - /// forwarding to the underlying native . - /// - private class EnumStatDataWrapper : IEnumSTATDATA - { - private readonly AgileComPointer _enumStatData; - - public EnumStatDataWrapper(Com.IEnumSTATDATA* enumStatData) - { - _enumStatData = new(enumStatData, takeOwnership: false); - } - - void IEnumSTATDATA.Clone(out IEnumSTATDATA newEnum) - { - using var enumStatData = _enumStatData.GetInterface(); - using ComScope result = new(null); - enumStatData.Value->Clone(result).ThrowOnFailure(); - newEnum = new EnumStatDataWrapper(result); - } - - unsafe int IEnumSTATDATA.Next(int celt, STATDATA[] rgelt, int[] pceltFetched) - { - if (rgelt is null || (pceltFetched is not null && pceltFetched.Length == 0)) - { - return HRESULT.E_POINTER; - } - - if (celt > 1 && pceltFetched is null) - { - return HRESULT.E_INVALIDARG; - } - - if (celt > rgelt.Length) - { - if (pceltFetched is not null) - { - pceltFetched[0] = 0; - } - - return HRESULT.E_INVALIDARG; - } - - using var enumStataData = _enumStatData.GetInterface(); - Com.STATDATA[] nativeStatData = new Com.STATDATA[rgelt.Length]; - HRESULT result; - fixed (int* ppceltFetched = pceltFetched) - fixed (Com.STATDATA* pNativeStatData = nativeStatData) - { - result = enumStataData.Value->Next((uint)celt, pNativeStatData, (uint*)ppceltFetched); - - for (int i = 0; i < *ppceltFetched; i++) - { - rgelt[i] = Com.STATDATA.ConvertToRuntimeStatData(nativeStatData[i]); - } - } - - return result; - } - - int IEnumSTATDATA.Reset() - { - using var enumStatData = _enumStatData.GetInterface(); - return enumStatData.Value->Reset(); - } - - int IEnumSTATDATA.Skip(int celt) - { - using var enumStatData = _enumStatData.GetInterface(); - return enumStatData.Value->Skip((uint)celt); - } - } -} diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.cs index 996e7ac3504..27b94024fbb 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DataObject.cs @@ -4,14 +4,8 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Drawing; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using System.Windows.Forms.BinaryFormat; -using static Windows.Win32.System.Memory.GLOBAL_ALLOC_FLAGS; using Com = Windows.Win32.System.Com; using ComTypes = System.Runtime.InteropServices.ComTypes; @@ -23,80 +17,24 @@ namespace System.Windows.Forms; [ClassInterface(ClassInterfaceType.None)] public unsafe partial class DataObject : IDataObject, - ComTypes.IDataObject, Com.IDataObject.Interface, + ComTypes.IDataObject, Com.IManagedWrapper { private const string CF_DEPRECATED_FILENAME = "FileName"; private const string CF_DEPRECATED_FILENAMEW = "FileNameW"; private const string BitmapFullName = "System.Drawing.Bitmap"; - private const int DATA_S_SAMEFORMATETC = 0x00040130; - - private const TYMED AllowedTymeds = TYMED.TYMED_HGLOBAL | TYMED.TYMED_ISTREAM | TYMED.TYMED_GDI; - - private readonly IDataObject _innerData; - - // We use this to identify that a stream is actually a serialized object. On read, we don't know if the contents - // of a stream were saved "raw" or if the stream is really pointing to a serialized object. If we saved an object, - // we prefix it with this guid. - private static readonly byte[] s_serializedObjectID = - [ - // FD9EA796-3B13-4370-A679-56106BB288FB - 0x96, 0xa7, 0x9e, 0xfd, - 0x13, 0x3b, - 0x70, 0x43, - 0xa6, 0x79, 0x56, 0x10, 0x6b, 0xb2, 0x88, 0xfb - ]; - - /// - /// Initializes a new instance of the class, with the specified . - /// - internal DataObject(IDataObject data) - { - CompModSwitches.DataObject.TraceVerbose("Constructed DataObject based on IDataObject"); - _innerData = data; - } - - /// - /// Create a from a raw interface pointer. - /// - internal static DataObject FromComPointer(Com.IDataObject* data) - { - // Get the RCW for the pointer and continue. - bool success = ComHelpers.TryGetObjectForIUnknown( - (Com.IUnknown*)data, - takeOwnership: false, - out ComTypes.IDataObject? comTypesData); - - Debug.Assert(success && comTypesData is not null); - return new(comTypesData!); - } - - /// - /// Initializes a new instance of the class, with the specified . - /// - internal DataObject(ComTypes.IDataObject data) - { - if (data is DataObject dataObject) - { - _innerData = dataObject; - } - else - { - CompModSwitches.DataObject.TraceVerbose("Constructed DataObject based on IComDataObject"); - _innerData = new ComDataObjectAdapter(data); - } - } + private readonly ComposedDataObject _innerData; /// /// Initializes a new instance of the class, with the raw /// and the managed data object the raw pointer is associated with. /// - internal DataObject(Com.IDataObject* data, object managedDataObject) + internal DataObject(Com.IDataObject* data) { CompModSwitches.DataObject.TraceVerbose("Constructed DataObject based on IComDataObject"); - _innerData = new ComDataObjectAdapter(data, managedDataObject); + _innerData = ComposedDataObject.CreateFromNativeDataObject(data); } /// @@ -105,7 +43,7 @@ internal DataObject(Com.IDataObject* data, object managedDataObject) public DataObject() { CompModSwitches.DataObject.TraceVerbose("Constructed DataObject standalone"); - _innerData = new DataStore(); + _innerData = ComposedDataObject.CreateFromWinFormsDataObject(new DataStore()); } /// @@ -114,17 +52,21 @@ public DataObject() public DataObject(object data) { CompModSwitches.DataObject.TraceVerbose($"Constructed DataObject base on Object: {data}"); - if (data is IDataObject dataObject && !Marshal.IsComObject(data)) + if (data is DataObject dataObject) { - _innerData = dataObject; + _innerData = dataObject._innerData; + } + else if (data is IDataObject iDataObject) + { + _innerData = ComposedDataObject.CreateFromWinFormsDataObject(iDataObject); } else if (data is ComTypes.IDataObject comDataObject) { - _innerData = new ComDataObjectAdapter(comDataObject); + _innerData = ComposedDataObject.CreateFromRuntimeDataObject(comDataObject); } else { - _innerData = new DataStore(); + _innerData = ComposedDataObject.CreateFromWinFormsDataObject(new DataStore()); SetData(data); } } @@ -150,12 +92,12 @@ public DataObject(object data) internal IDataObject TryUnwrapInnerIDataObject() { Debug.Assert(IsWrappedForClipboard, "This method should only be used for clipboard purposes."); - - return _innerData is DataStore or ComDataObjectAdapter - ? this - : _innerData; + return _innerData.OriginalIDataObject is { } original ? original : this; } + /// + internal IDataObject? OriginalIDataObject => _innerData.OriginalIDataObject; + /// /// Retrieves the data associated with the specified data format, using an automated conversion parameter to /// determine whether to convert the data to the format. @@ -163,7 +105,7 @@ internal IDataObject TryUnwrapInnerIDataObject() public virtual object? GetData(string format, bool autoConvert) { CompModSwitches.DataObject.TraceVerbose($"Request data: {format}, {autoConvert}"); - return _innerData.GetData(format, autoConvert); + return ((IDataObject)_innerData).GetData(format, autoConvert); } /// @@ -208,7 +150,7 @@ public virtual bool GetDataPresent(Type format) public virtual bool GetDataPresent(string format, bool autoConvert) { CompModSwitches.DataObject.TraceVerbose($"Check data: {format}, {autoConvert}"); - bool present = _innerData.GetDataPresent(format, autoConvert); + bool present = ((IDataObject)_innerData).GetDataPresent(format, autoConvert); CompModSwitches.DataObject.TraceVerbose($" ret: {present}"); return present; } @@ -233,7 +175,7 @@ public virtual bool GetDataPresent(string format) public virtual string[] GetFormats(bool autoConvert) { CompModSwitches.DataObject.TraceVerbose($"Check formats: {autoConvert}"); - return _innerData.GetFormats(autoConvert); + return ((IDataObject)_innerData).GetFormats(autoConvert); } /// @@ -345,597 +287,31 @@ public virtual void SetText(string textData, TextDataFormat format) _ => new string[] { format } }; - /// - /// Returns true if the tymed is useable. - /// - private static bool GetTymedUseable(TYMED tymed) => (tymed & AllowedTymeds) != 0; - int ComTypes.IDataObject.DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink pAdvSink, out int pdwConnection) - { - CompModSwitches.DataObject.TraceVerbose("DAdvise"); - if (_innerData is ComDataObjectAdapter converter) - { - using var comAdviseSink = ComHelpers.TryGetComScope(pAdvSink); - HRESULT result = converter.OleDataObject->DAdvise( - Unsafe.As(ref pFormatetc), - (uint)advf, - comAdviseSink, - out uint connection); - pdwConnection = (int)connection; - return result; - } + => ((ComTypes.IDataObject)_innerData).DAdvise(ref pFormatetc, advf, pAdvSink, out pdwConnection); - pdwConnection = 0; - return (int)HRESULT.E_NOTIMPL; - } - - void ComTypes.IDataObject.DUnadvise(int dwConnection) - { - CompModSwitches.DataObject.TraceVerbose("DUnadvise"); - if (_innerData is ComDataObjectAdapter converter) - { - converter.OleDataObject->DUnadvise((uint)dwConnection).ThrowOnFailure(); - return; - } - - Marshal.ThrowExceptionForHR((int)HRESULT.E_NOTIMPL); - } + void ComTypes.IDataObject.DUnadvise(int dwConnection) => ((ComTypes.IDataObject)_innerData).DUnadvise(dwConnection); int ComTypes.IDataObject.EnumDAdvise(out IEnumSTATDATA? enumAdvise) - { - CompModSwitches.DataObject.TraceVerbose("EnumDAdvise"); - if (_innerData is ComDataObjectAdapter converter) - { - using ComScope statData = new(null); - HRESULT result = converter.OleDataObject->EnumDAdvise(statData); - enumAdvise = statData.IsNull - ? null - : ComHelpers.TryGetObjectForIUnknown( - statData.Query(), - out IEnumSTATDATA? managedStatData) - ? managedStatData - : new EnumStatDataWrapper(statData); - - return result; - } - - enumAdvise = null; - return (int)HRESULT.OLE_E_ADVISENOTSUPPORTED; - } + => ((ComTypes.IDataObject)_innerData).EnumDAdvise(out enumAdvise); IEnumFORMATETC ComTypes.IDataObject.EnumFormatEtc(DATADIR dwDirection) - { - CompModSwitches.DataObject.TraceVerbose($"EnumFormatEtc: {dwDirection}"); - if (_innerData is ComDataObjectAdapter converter) - { - using ComScope formatEtc = new(null); - converter.OleDataObject->EnumFormatEtc((uint)dwDirection, formatEtc).ThrowOnFailure(); - IEnumFORMATETC result = ComHelpers.TryGetObjectForIUnknown( - formatEtc.Query(), - out IEnumFORMATETC? managedEnumFormat) - ? managedEnumFormat - : new EnumFormatEtcWrapper(formatEtc); - - return result; - } - - if (dwDirection == DATADIR.DATADIR_GET) - { - return new FormatEnumerator(this); - } - - throw new ExternalException(SR.ExternalException, (int)HRESULT.E_NOTIMPL); - } + => ((ComTypes.IDataObject)_innerData).EnumFormatEtc(dwDirection); int ComTypes.IDataObject.GetCanonicalFormatEtc(ref FORMATETC pformatetcIn, out FORMATETC pformatetcOut) - { - CompModSwitches.DataObject.TraceVerbose("GetCanonicalFormatEtc"); - if (_innerData is ComDataObjectAdapter converter) - { - HRESULT result = converter.OleDataObject->GetCanonicalFormatEtc( - Unsafe.As(ref pformatetcIn), - out Com.FORMATETC formatEtcOut); - pformatetcOut = Unsafe.As(ref formatEtcOut); - return result; - } - - pformatetcOut = default; - return DATA_S_SAMEFORMATETC; - } + => ((ComTypes.IDataObject)_innerData).GetCanonicalFormatEtc(ref pformatetcIn, out pformatetcOut); void ComTypes.IDataObject.GetData(ref FORMATETC formatetc, out STGMEDIUM medium) - { - CompModSwitches.DataObject.TraceVerbose("GetData"); - if (_innerData is ComDataObjectAdapter converter) - { - converter.OleDataObject->GetData(Unsafe.As(ref formatetc), out Com.STGMEDIUM comMedium).ThrowOnFailure(); - medium = (STGMEDIUM)comMedium; - return; - } - - if (DragDropHelper.IsInDragLoop(_innerData)) - { - string formatName = DataFormats.GetFormat(formatetc.cfFormat).Name; - if (!_innerData.GetDataPresent(formatName)) - { - medium = default; - CompModSwitches.DataObject.TraceVerbose($" drag-and-drop private format requested '{formatName}' not present"); - return; - } - - if (_innerData.GetData(formatName) is DragDropFormat dragDropFormat) - { - medium = dragDropFormat.GetData(); - CompModSwitches.DataObject.TraceVerbose($" drag-and-drop private format retrieved '{formatName}'"); - return; - } - } - - medium = default; - - if (!GetTymedUseable(formatetc.tymed)) - { - Marshal.ThrowExceptionForHR((int)HRESULT.DV_E_TYMED); - } - - if (!formatetc.tymed.HasFlag(TYMED.TYMED_HGLOBAL)) - { - medium.tymed = formatetc.tymed; - ((ComTypes.IDataObject)this).GetDataHere(ref formatetc, ref medium); - return; - } - - medium.tymed = TYMED.TYMED_HGLOBAL; - medium.unionmember = PInvokeCore.GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 1); - - if (medium.unionmember == 0) - { - throw new OutOfMemoryException(); - } - - try - { - ((ComTypes.IDataObject)this).GetDataHere(ref formatetc, ref medium); - } - catch - { - PInvokeCore.GlobalFree((HGLOBAL)medium.unionmember); - medium.unionmember = 0; - throw; - } - } + => ((ComTypes.IDataObject)_innerData).GetData(ref formatetc, out medium); void ComTypes.IDataObject.GetDataHere(ref FORMATETC formatetc, ref STGMEDIUM medium) - { - CompModSwitches.DataObject.TraceVerbose("GetDataHere"); - if (_innerData is ComDataObjectAdapter converter) - { - Com.STGMEDIUM comMedium = default; - converter.OleDataObject->GetDataHere(Unsafe.As(ref formatetc), ref comMedium).ThrowOnFailure(); - medium = (STGMEDIUM)comMedium; - return; - } - - if (!GetTymedUseable(formatetc.tymed) || !GetTymedUseable(medium.tymed)) - { - Marshal.ThrowExceptionForHR((int)HRESULT.DV_E_TYMED); - } - - string format = DataFormats.GetFormat(formatetc.cfFormat).Name; - - if (!GetDataPresent(format)) - { - Marshal.ThrowExceptionForHR((int)HRESULT.DV_E_FORMATETC); - } - - object? data = GetData(format); - - if (formatetc.tymed.HasFlag(TYMED.TYMED_HGLOBAL)) - { - try - { - SaveDataToHGLOBAL(data!, format, ref medium).ThrowOnFailure(); - } - catch (NotSupportedException ex) - { - // BinaryFormatter is disabled. As all errors get swallowed by Windows, put the exception on the - // clipboard so consumers can get some indication as to what is wrong. (We handle the binary formatting - // of this exception, so it will always work.) - SaveDataToHGLOBAL(ex, format, ref medium).ThrowOnFailure(); - } - - return; - } - - if (formatetc.tymed.HasFlag(TYMED.TYMED_GDI)) - { - if (format.Equals(DataFormats.Bitmap) && data is Bitmap bitmap) - { - // Save bitmap - medium.unionmember = (nint)GetCompatibleBitmap(bitmap); - } - - return; - } - - Marshal.ThrowExceptionForHR((int)HRESULT.DV_E_TYMED); - - static HBITMAP GetCompatibleBitmap(Bitmap bitmap) - { - using var screenDC = GetDcScope.ScreenDC; - - // GDI+ returns a DIBSECTION based HBITMAP. The clipboard only deals well with bitmaps created using - // CreateCompatibleBitmap(). So, we convert the DIBSECTION into a compatible bitmap. - HBITMAP hbitmap = bitmap.GetHBITMAP(); - - // Create a compatible DC to render the source bitmap. - using CreateDcScope sourceDC = new(screenDC); - using SelectObjectScope sourceBitmapSelection = new(sourceDC, hbitmap); - - // Create a compatible DC and a new compatible bitmap. - using CreateDcScope destinationDC = new(screenDC); - HBITMAP compatibleBitmap = PInvokeCore.CreateCompatibleBitmap(screenDC, bitmap.Size.Width, bitmap.Size.Height); - - // Select the new bitmap into a compatible DC and render the blt the original bitmap. - using SelectObjectScope destinationBitmapSelection = new(destinationDC, compatibleBitmap); - PInvokeCore.BitBlt( - destinationDC, - 0, - 0, - bitmap.Size.Width, - bitmap.Size.Height, - sourceDC, - 0, - 0, - ROP_CODE.SRCCOPY); - - return compatibleBitmap; - } - } + => ((ComTypes.IDataObject)_innerData).GetDataHere(ref formatetc, ref medium); int ComTypes.IDataObject.QueryGetData(ref FORMATETC formatetc) - { - CompModSwitches.DataObject.TraceVerbose("QueryGetData"); - if (_innerData is ComDataObjectAdapter converter) - { - return converter.OleDataObject->QueryGetData(Unsafe.As(ref formatetc)); - } - - if (formatetc.dwAspect != DVASPECT.DVASPECT_CONTENT) - { - return (int)HRESULT.DV_E_DVASPECT; - } - - if (!GetTymedUseable(formatetc.tymed)) - { - return (int)HRESULT.DV_E_TYMED; - } - - if (formatetc.cfFormat == 0) - { - CompModSwitches.DataObject.TraceVerbose("QueryGetData::returning S_FALSE because cfFormat == 0"); - return (int)HRESULT.S_FALSE; - } - - if (!GetDataPresent(DataFormats.GetFormat(formatetc.cfFormat).Name)) - { - return (int)HRESULT.DV_E_FORMATETC; - } - - CompModSwitches.DataObject.TraceVerbose($"QueryGetData::cfFormat {(ushort)formatetc.cfFormat} found"); - return (int)HRESULT.S_OK; - } + => ((ComTypes.IDataObject)_innerData).QueryGetData(ref formatetc); void ComTypes.IDataObject.SetData(ref FORMATETC pFormatetcIn, ref STGMEDIUM pmedium, bool fRelease) - { - CompModSwitches.DataObject.TraceVerbose("SetData"); - if (_innerData is ComDataObjectAdapter converter) - { - Com.STGMEDIUM comMedium = default; - converter.OleDataObject->SetData(Unsafe.As(ref pFormatetcIn), comMedium, fRelease).ThrowOnFailure(); - pmedium = (STGMEDIUM)comMedium; - return; - } - - if (DragDropHelper.IsInDragLoopFormat(Unsafe.As(ref pFormatetcIn)) || DragDropHelper.IsInDragLoop(_innerData)) - { - string formatName = DataFormats.GetFormat(pFormatetcIn.cfFormat).Name; - if (_innerData.GetDataPresent(formatName) && _innerData.GetData(formatName) is DragDropFormat dragDropFormat) - { - dragDropFormat.RefreshData(pFormatetcIn.cfFormat, pmedium, !fRelease); - CompModSwitches.DataObject.TraceVerbose($" drag-and-drop private format refreshed '{formatName}'"); - } - else - { - _innerData.SetData(formatName, new DragDropFormat(pFormatetcIn.cfFormat, pmedium, !fRelease)); - CompModSwitches.DataObject.TraceVerbose($" drag-and-drop private format loaded '{formatName}'"); - } - - return; - } - - throw new NotImplementedException(); - } - - /// - /// We are restricting serialization of formats that represent strings, bitmaps or OLE types. - /// - /// format name - /// true - serialize only safe types, strings or bitmaps. - private static bool RestrictDeserializationToSafeTypes(string format) - => format is DataFormats.StringConstant - or BitmapFullName - or DataFormats.CsvConstant - or DataFormats.DibConstant - or DataFormats.DifConstant - or DataFormats.LocaleConstant - or DataFormats.PenDataConstant - or DataFormats.RiffConstant - or DataFormats.SymbolicLinkConstant - or DataFormats.TiffConstant - or DataFormats.WaveAudioConstant - or DataFormats.BitmapConstant - or DataFormats.EmfConstant - or DataFormats.PaletteConstant - or DataFormats.WmfConstant; - - private HRESULT SaveDataToHGLOBAL(object data, string format, ref STGMEDIUM medium) => format switch - { - _ when data is Stream dataStream - => SaveStreamToHGLOBAL(ref Unsafe.As(ref medium.unionmember), dataStream), - DataFormats.TextConstant or DataFormats.RtfConstant or DataFormats.OemTextConstant - => SaveStringToHGLOBAL((HGLOBAL)medium.unionmember, data.ToString()!, unicode: false), - DataFormats.HtmlConstant - => SaveHtmlToHGLOBAL((HGLOBAL)medium.unionmember, data.ToString()!), - DataFormats.UnicodeTextConstant - => SaveStringToHGLOBAL((HGLOBAL)medium.unionmember, data.ToString()!, unicode: true), - DataFormats.FileDropConstant - => SaveFileListToHGLOBAL((HGLOBAL)medium.unionmember, (string[])data), - CF_DEPRECATED_FILENAME - => SaveStringToHGLOBAL((HGLOBAL)medium.unionmember, ((string[])data)[0], unicode: false), - CF_DEPRECATED_FILENAMEW - => SaveStringToHGLOBAL((HGLOBAL)medium.unionmember, ((string[])data)[0], unicode: true), - DataFormats.DibConstant when data is Image - // GDI+ does not properly handle saving to DIB images. Since the clipboard will take - // an HBITMAP and publish a Dib, we don't need to support this. - => HRESULT.DV_E_TYMED, -#pragma warning disable SYSLIB0050 // Type or member is obsolete - _ when format == DataFormats.SerializableConstant || data is ISerializable || data.GetType().IsSerializable -#pragma warning restore - => SaveObjectToHGLOBAL(ref Unsafe.As(ref medium.unionmember), data, RestrictDeserializationToSafeTypes(format)), - _ => HRESULT.E_FAIL - }; - - private static HRESULT SaveObjectToHGLOBAL(ref HGLOBAL hglobal, object data, bool restrictSerialization) - { - using MemoryStream stream = new(); - stream.Write(s_serializedObjectID); - long position = stream.Position; - bool success = false; - - try - { - success = WinFormsBinaryFormatWriter.TryWriteObject(stream, data); - } - catch (Exception ex) when (!ex.IsCriticalException()) - { - // Being extra cautious here, but the Try method above should never throw in normal circumstances. - Debug.Fail($"Unexpected exception writing binary formatted data. {ex.Message}"); - } - -#pragma warning disable SYSLIB0011 // Type or member is obsolete - if (!success) - { - new BinaryFormatter() - { - Binder = restrictSerialization ? new BitmapBinder() : null - }.Serialize(stream, data); - } -#pragma warning restore SYSLIB0011 - - return SaveStreamToHGLOBAL(ref hglobal, stream); - } - - private static HRESULT SaveStreamToHGLOBAL(ref HGLOBAL hglobal, Stream stream) - { - if (hglobal != 0) - { - PInvokeCore.GlobalFree(hglobal); - } - - int size = checked((int)stream.Length); - hglobal = PInvokeCore.GlobalAlloc(GMEM_MOVEABLE, (uint)size); - if (hglobal == 0) - { - return HRESULT.E_OUTOFMEMORY; - } - - void* buffer = PInvokeCore.GlobalLock(hglobal); - if (buffer is null) - { - return HRESULT.E_OUTOFMEMORY; - } - - try - { - Span span = new(buffer, size); - stream.Position = 0; - stream.Read(span); - } - finally - { - PInvokeCore.GlobalUnlock(hglobal); - } - - return HRESULT.S_OK; - } - - /// - /// Saves a list of files out to the handle in HDROP format. - /// - private HRESULT SaveFileListToHGLOBAL(HGLOBAL hglobal, string[] files) - { - if (files is null || files.Length == 0) - { - return HRESULT.S_OK; - } - - if (hglobal == 0) - { - return HRESULT.E_INVALIDARG; - } - - // CF_HDROP consists of a DROPFILES struct followed by an list of strings including the terminating null - // character. An additional null character is appended to the final string to terminate the array. - // - // E.g. if the files c:\temp1.txt and c:\temp2.txt are being transferred, the character array is: - // "c:\temp1.txt\0c:\temp2.txt\0\0" - - // Determine the size of the data structure. - uint sizeInBytes = (uint)sizeof(DROPFILES); - foreach (string file in files) - { - sizeInBytes += (uint)(file.Length + 1) * sizeof(char); - } - - sizeInBytes += sizeof(char); - - // Allocate the Win32 memory - HGLOBAL newHandle = PInvokeCore.GlobalReAlloc(hglobal, sizeInBytes, (uint)GMEM_MOVEABLE); - if (newHandle == 0) - { - return HRESULT.E_OUTOFMEMORY; - } - - void* buffer = PInvokeCore.GlobalLock(newHandle); - if (buffer is null) - { - return HRESULT.E_OUTOFMEMORY; - } - - // Write out the DROPFILES struct. - DROPFILES* dropFiles = (DROPFILES*)buffer; - *dropFiles = new DROPFILES() - { - pFiles = (uint)sizeof(DROPFILES), - pt = Point.Empty, - fNC = false, - fWide = true - }; - - Span fileBuffer = new( - (char*)((byte*)buffer + dropFiles->pFiles), - ((int)sizeInBytes - (int)dropFiles->pFiles) / sizeof(char)); - - // Write out the strings. - foreach (string file in files) - { - file.CopyTo(fileBuffer); - fileBuffer[file.Length] = '\0'; - fileBuffer = fileBuffer[(file.Length + 1)..]; - } - - fileBuffer[0] = '\0'; - - PInvokeCore.GlobalUnlock(newHandle); - return HRESULT.S_OK; - } - - /// - /// Save string to handle. If unicode is set to true then the string is saved as Unicode, else it is saves as DBCS. - /// - private HRESULT SaveStringToHGLOBAL(HGLOBAL hglobal, string value, bool unicode) - { - if (hglobal == 0) - { - return HRESULT.E_INVALIDARG; - } - - HGLOBAL newHandle = default; - if (unicode) - { - uint byteSize = (uint)value.Length * sizeof(char) + sizeof(char); - newHandle = PInvokeCore.GlobalReAlloc(hglobal, byteSize, (uint)(GMEM_MOVEABLE | GMEM_ZEROINIT)); - if (newHandle == 0) - { - return HRESULT.E_OUTOFMEMORY; - } - - char* buffer = (char*)PInvokeCore.GlobalLock(newHandle); - if (buffer is null) - { - return HRESULT.E_OUTOFMEMORY; - } - - Span data = new(buffer, value.Length + 1); - value.AsSpan().CopyTo(data); - - // Null terminate. - data[value.Length] = '\0'; - } - else - { - fixed (char* c = value) - { - int pinvokeSize = PInvoke.WideCharToMultiByte(PInvoke.CP_ACP, 0, value, value.Length, null, 0, null, null); - newHandle = PInvokeCore.GlobalReAlloc(hglobal, (uint)pinvokeSize + 1, (uint)GMEM_MOVEABLE | (uint)GMEM_ZEROINIT); - if (newHandle == 0) - { - return HRESULT.E_OUTOFMEMORY; - } - - byte* buffer = (byte*)PInvokeCore.GlobalLock(newHandle); - if (buffer is null) - { - return HRESULT.E_OUTOFMEMORY; - } - - PInvoke.WideCharToMultiByte(PInvoke.CP_ACP, 0, value, value.Length, buffer, pinvokeSize, null, null); - - // Null terminate - buffer[pinvokeSize] = 0; - } - } - - PInvokeCore.GlobalUnlock(newHandle); - return HRESULT.S_OK; - } - - private static HRESULT SaveHtmlToHGLOBAL(HGLOBAL hglobal, string value) - { - if (hglobal == 0) - { - return HRESULT.E_INVALIDARG; - } - - int byteLength = Encoding.UTF8.GetByteCount(value); - HGLOBAL newHandle = PInvokeCore.GlobalReAlloc(hglobal, (uint)byteLength + 1, (uint)(GMEM_MOVEABLE | GMEM_ZEROINIT)); - if (newHandle == 0) - { - return HRESULT.E_OUTOFMEMORY; - } - - byte* buffer = (byte*)PInvokeCore.GlobalLock(newHandle); - if (buffer is null) - { - return HRESULT.E_OUTOFMEMORY; - } - - try - { - Span span = new(buffer, byteLength + 1); - Encoding.UTF8.GetBytes(value, span); - - // Null terminate - span[byteLength] = 0; - } - finally - { - PInvokeCore.GlobalUnlock(newHandle); - } - - return HRESULT.S_OK; - } + => ((ComTypes.IDataObject)_innerData).SetData(ref pFormatetcIn, ref pmedium, fRelease); /// /// Stores the specified data and its associated format in this instance, using the automatic conversion @@ -944,7 +320,7 @@ private static HRESULT SaveHtmlToHGLOBAL(HGLOBAL hglobal, string value) public virtual void SetData(string format, bool autoConvert, object? data) { CompModSwitches.DataObject.TraceVerbose($"Set data: {format}, {autoConvert}, {data ?? "(null)"}"); - _innerData.SetData(format, autoConvert, data); + ((IDataObject)_innerData).SetData(format, autoConvert, data); } /// @@ -953,7 +329,7 @@ public virtual void SetData(string format, bool autoConvert, object? data) public virtual void SetData(string format, object? data) { CompModSwitches.DataObject.TraceVerbose($"Set data: {format}, {data ?? "(null)"}"); - _innerData.SetData(format, data); + ((IDataObject)_innerData).SetData(format, data); } /// @@ -962,7 +338,7 @@ public virtual void SetData(string format, object? data) public virtual void SetData(Type format, object? data) { CompModSwitches.DataObject.TraceVerbose($"Set data: {format?.FullName ?? "(null)"}, {data ?? "(null)"}"); - _innerData.SetData(format!, data); + ((IDataObject)_innerData).SetData(format!, data); } /// @@ -971,92 +347,33 @@ public virtual void SetData(Type format, object? data) public virtual void SetData(object? data) { CompModSwitches.DataObject.TraceVerbose($"Set data: {data ?? "(null)"}"); - _innerData.SetData(data); + ((IDataObject)_innerData).SetData(data); } HRESULT Com.IDataObject.Interface.GetData(Com.FORMATETC* pformatetcIn, Com.STGMEDIUM* pmedium) - { - if (pmedium is null) - { - return HRESULT.E_POINTER; - } - - ((ComTypes.IDataObject)this).GetData(ref *(FORMATETC*)pformatetcIn, out STGMEDIUM medium); - *pmedium = (Com.STGMEDIUM)medium; - return HRESULT.S_OK; - } + => ((Com.IDataObject.Interface)_innerData).GetData(pformatetcIn, pmedium); HRESULT Com.IDataObject.Interface.GetDataHere(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium) - { - if (pmedium is null) - { - return HRESULT.E_POINTER; - } - - STGMEDIUM medium = (STGMEDIUM)(*pmedium); - ((ComTypes.IDataObject)this).GetDataHere(ref *(FORMATETC*)pformatetc, ref medium); - *pmedium = (Com.STGMEDIUM)medium; - return HRESULT.S_OK; - } + => ((Com.IDataObject.Interface)_innerData).GetDataHere(pformatetc, pmedium); HRESULT Com.IDataObject.Interface.QueryGetData(Com.FORMATETC* pformatetc) - => (HRESULT)((ComTypes.IDataObject)this).QueryGetData(ref *(FORMATETC*)pformatetc); + => ((Com.IDataObject.Interface)_innerData).QueryGetData(pformatetc); HRESULT Com.IDataObject.Interface.GetCanonicalFormatEtc(Com.FORMATETC* pformatectIn, Com.FORMATETC* pformatetcOut) - => (HRESULT)((ComTypes.IDataObject)this).GetCanonicalFormatEtc(ref *(FORMATETC*)pformatectIn, out *(FORMATETC*)pformatetcOut); + => ((Com.IDataObject.Interface)_innerData).GetCanonicalFormatEtc(pformatectIn, pformatetcOut); HRESULT Com.IDataObject.Interface.SetData(Com.FORMATETC* pformatetc, Com.STGMEDIUM* pmedium, BOOL fRelease) - { - if (pmedium is null) - { - return HRESULT.E_POINTER; - } - - STGMEDIUM medium = (STGMEDIUM)(*pmedium); - ((ComTypes.IDataObject)this).SetData(ref *(FORMATETC*)pformatetc, ref medium, fRelease); - return HRESULT.S_OK; - } + => ((Com.IDataObject.Interface)_innerData).SetData(pformatetc, pmedium, fRelease); HRESULT Com.IDataObject.Interface.EnumFormatEtc(uint dwDirection, Com.IEnumFORMATETC** ppenumFormatEtc) - { - if (ppenumFormatEtc is null) - { - return HRESULT.E_POINTER; - } - - var comTypeFormatEtc = ((ComTypes.IDataObject)this).EnumFormatEtc((DATADIR)(int)dwDirection); - *ppenumFormatEtc = ComHelpers.TryGetComPointer(comTypeFormatEtc, out HRESULT hr); - return hr.Succeeded ? HRESULT.S_OK : HRESULT.E_NOINTERFACE; - } + => ((Com.IDataObject.Interface)_innerData).EnumFormatEtc(dwDirection, ppenumFormatEtc); HRESULT Com.IDataObject.Interface.DAdvise(Com.FORMATETC* pformatetc, uint advf, Com.IAdviseSink* pAdvSink, uint* pdwConnection) - { - var adviseSink = (IAdviseSink)ComHelpers.GetObjectForIUnknown((Com.IUnknown*)pAdvSink); - return (HRESULT)((ComTypes.IDataObject)this).DAdvise(ref *(FORMATETC*)pformatetc, (ADVF)advf, adviseSink, out *(int*)pdwConnection); - } + => ((Com.IDataObject.Interface)_innerData).DAdvise(pformatetc, advf, pAdvSink, pdwConnection); HRESULT Com.IDataObject.Interface.DUnadvise(uint dwConnection) - { - ((ComTypes.IDataObject)this).DUnadvise((int)dwConnection); - return HRESULT.S_OK; - } + => ((Com.IDataObject.Interface)_innerData).DUnadvise(dwConnection); HRESULT Com.IDataObject.Interface.EnumDAdvise(Com.IEnumSTATDATA** ppenumAdvise) - { - if (ppenumAdvise is null) - { - return HRESULT.E_POINTER; - } - - *ppenumAdvise = null; - - HRESULT hr = (HRESULT)((ComTypes.IDataObject)this).EnumDAdvise(out var enumAdvice); - if (hr.Failed) - { - return hr; - } - - *ppenumAdvise = ComHelpers.TryGetComPointer(enumAdvice, out hr); - return hr.Succeeded ? hr : HRESULT.E_NOINTERFACE; - } + => ((Com.IDataObject.Interface)_innerData).EnumDAdvise(ppenumAdvise); } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropFormat.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropFormat.cs index 61163f3400e..e6818b7df16 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropFormat.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropFormat.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; using Windows.Win32.System.Ole; -using Com = Windows.Win32.System.Com; +using Windows.Win32.System.Com; namespace System.Windows.Forms; @@ -13,7 +12,7 @@ namespace System.Windows.Forms; /// internal class DragDropFormat : IDisposable { - private short _format; + private ushort _format; private STGMEDIUM _medium; public STGMEDIUM Medium => _medium; @@ -21,7 +20,7 @@ internal class DragDropFormat : IDisposable /// /// Initializes a new instance of the class using the specified format, storage medium, and owner. /// - public DragDropFormat(short format, STGMEDIUM medium, bool copyData) + public DragDropFormat(ushort format, STGMEDIUM medium, bool copyData) { _format = format; @@ -32,15 +31,12 @@ public DragDropFormat(short format, STGMEDIUM medium, bool copyData) /// /// Returns a copy of the storage mediumn in this instance. /// - public STGMEDIUM GetData() - { - return CopyData(_format, _medium); - } + public STGMEDIUM GetData() => CopyData(_format, _medium); /// /// Refreshes the storage medium in this instance. /// - public void RefreshData(short format, STGMEDIUM medium, bool copyData) + public void RefreshData(ushort format, STGMEDIUM medium, bool copyData) { ReleaseData(); _format = format; @@ -55,7 +51,7 @@ public void RefreshData(short format, STGMEDIUM medium, bool copyData) /// /// A copy of . /// - private static STGMEDIUM CopyData(short format, STGMEDIUM mediumSource) + private static unsafe STGMEDIUM CopyData(ushort format, STGMEDIUM mediumSource) { STGMEDIUM mediumDestination = default; @@ -69,13 +65,13 @@ private static STGMEDIUM CopyData(short format, STGMEDIUM mediumSource) case TYMED.TYMED_GDI: case TYMED.TYMED_MFPICT: - mediumDestination.unionmember = PInvoke.OleDuplicateData( - (HANDLE)mediumSource.unionmember, + mediumDestination.hGlobal = (HGLOBAL)(nint)PInvoke.OleDuplicateData( + (HANDLE)(nint)mediumSource.hGlobal, (CLIPBOARD_FORMAT)format, // Note that GMEM_DDESHARE is ignored GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT); - if (mediumDestination.unionmember == IntPtr.Zero) + if (mediumDestination.hGlobal.IsNull) { return default; } @@ -85,32 +81,30 @@ private static STGMEDIUM CopyData(short format, STGMEDIUM mediumSource) case TYMED.TYMED_ISTORAGE: case TYMED.TYMED_ISTREAM: - mediumDestination.unionmember = mediumSource.unionmember; - Marshal.AddRef(mediumSource.unionmember); + mediumDestination.hGlobal = mediumSource.hGlobal; + Marshal.AddRef(mediumSource.hGlobal); break; case TYMED.TYMED_NULL: default: - mediumDestination.unionmember = IntPtr.Zero; + mediumDestination.hGlobal = HGLOBAL.Null; break; } mediumDestination.tymed = mediumSource.tymed; mediumDestination.pUnkForRelease = mediumSource.pUnkForRelease; - // If the object is non-null, perform an indirect AddRef() by requesting the IUnknown. if (mediumSource.pUnkForRelease is not null) { - Marshal.GetIUnknownForObject(mediumSource.pUnkForRelease); + mediumSource.pUnkForRelease->AddRef(); } return mediumDestination; } catch { - var comMedium = (Com.STGMEDIUM)mediumDestination; - PInvoke.ReleaseStgMedium(ref comMedium); + PInvoke.ReleaseStgMedium(ref mediumDestination); return default; } } @@ -118,13 +112,12 @@ private static STGMEDIUM CopyData(short format, STGMEDIUM mediumSource) /// /// Frees the storage medium in this instance. /// - private void ReleaseData() + private unsafe void ReleaseData() { - var comMedium = (Com.STGMEDIUM)_medium; - PInvoke.ReleaseStgMedium(ref comMedium); + PInvoke.ReleaseStgMedium(ref _medium); _medium.pUnkForRelease = null; _medium.tymed = TYMED.TYMED_NULL; - _medium.unionmember = IntPtr.Zero; + _medium.hGlobal = HGLOBAL.Null; } public void Dispose() diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropHelper.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropHelper.cs index bc698519a31..42790b0e1d8 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropHelper.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DragDropHelper.cs @@ -200,12 +200,12 @@ public static unsafe bool IsInDragLoop(IDataObject dataObject) { try { - void* basePtr = PInvokeCore.GlobalLock((HGLOBAL)dragDropFormat.Medium.unionmember); + void* basePtr = PInvokeCore.GlobalLock(dragDropFormat.Medium.hGlobal); return (basePtr is not null) && (*(BOOL*)basePtr == true); } finally { - PInvokeCore.GlobalUnlock((HGLOBAL)dragDropFormat.Medium.unionmember); + PInvokeCore.GlobalUnlock(dragDropFormat.Medium.hGlobal); } } else diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DropTarget.cs b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DropTarget.cs index c2440e3f828..544e556dbce 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DropTarget.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/OLE/DropTarget.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; +using System.Runtime.InteropServices; using Windows.Win32.System.Com; using Windows.Win32.System.SystemServices; using Com = Windows.Win32.System.Com; @@ -48,24 +49,22 @@ private void ClearDropDescription() } /// - /// Prepares the drag data to be passed out. - /// should implement to be passed out as is. - /// Otherwise, the data will be wrapped in a . + /// Creates to be passed out as data for drag/drop operation + /// should have associated ComWrappers created wrapper that implements + /// to be passed out as is. Otherwise, the data will be wrapped in a . /// - private static IDataObject? PrepareOutgoingDropData(object managedDataObject) + private static IDataObject? CreateWinFormsDataObjectForOutgoingDropData(Com.IDataObject* nativeDataObject) { - if (managedDataObject is IDataObject dataObject) + using var unknown = ComScope.QueryFrom(nativeDataObject); + if (ComWrappers.TryGetObject(unknown, out object? obj) && obj is IDataObject dataObject) { - return dataObject; + // If the original data object implemented IDataObject, we might've wrapped it. We need to give the original back out. + return dataObject is DataObject winFormsDataObject && winFormsDataObject.OriginalIDataObject is { } originalDataObject + ? originalDataObject + : dataObject; } - var comDataObjectPtr = ComHelpers.TryGetComPointer(managedDataObject, out HRESULT hr); - if (hr.Succeeded) - { - return new DataObject(comDataObjectPtr, managedDataObject); - } - - return null; // Unknown data object interface; we can't work with this so return null + return new DataObject(nativeDataObject); } private DragEventArgs? CreateDragEventArgs(Com.IDataObject* pDataObj, MODIFIERKEYS_FLAGS grfKeyState, POINTL pt, Ole.DROPEFFECT pdwEffect) @@ -78,7 +77,7 @@ private void ClearDropDescription() } else { - data = PrepareOutgoingDropData(ComHelpers.GetObjectForIUnknown((IUnknown*)pDataObj)); + data = CreateWinFormsDataObjectForOutgoingDropData(pDataObj); if (data is null) { return null; diff --git a/src/System.Windows.Forms/tests/ComDisabledTests/ClipboardComTests.cs b/src/System.Windows.Forms/tests/ComDisabledTests/ClipboardComTests.cs new file mode 100644 index 00000000000..381ee7a2741 --- /dev/null +++ b/src/System.Windows.Forms/tests/ComDisabledTests/ClipboardComTests.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Windows.Forms.Tests; + +public partial class ClipboardTests +{ + [WinFormsFact] + public void Clipboard_SetText_InvokeString_GetReturnsExpected() + { + Clipboard.SetText("text"); + Assert.Equal("text", Clipboard.GetText()); + Assert.True(Clipboard.ContainsText()); + } +} diff --git a/src/System.Windows.Forms/tests/ComDisabledTests/ComDisabled.Tests.csproj b/src/System.Windows.Forms/tests/ComDisabledTests/ComDisabled.Tests.csproj new file mode 100644 index 00000000000..2c2b2b22f61 --- /dev/null +++ b/src/System.Windows.Forms/tests/ComDisabledTests/ComDisabled.Tests.csproj @@ -0,0 +1,54 @@ + + + + $(TargetFramework) + $(TargetFramework)-windows7.0 + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + $(ArtifactsBinDir)\AxHosts\$(Configuration)\net472\AxInterop.WMPLib.dll + + + $(ArtifactsBinDir)\AxHosts\$(Configuration)\net472\Interop.WMPLib.dll + + + + + + $(ArtifactsBinDir)\AxHosts\$(Configuration)\net472\AxInterop.SystemMonitor.dll + + + $(ArtifactsBinDir)\AxHosts\$(Configuration)\net472\Interop.SystemMonitor.dll + + + + + + PreserveNewest + + + diff --git a/src/System.Windows.Forms/tests/ComDisabledTests/DataObjectComTests.cs b/src/System.Windows.Forms/tests/ComDisabledTests/DataObjectComTests.cs new file mode 100644 index 00000000000..58923843eda --- /dev/null +++ b/src/System.Windows.Forms/tests/ComDisabledTests/DataObjectComTests.cs @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices.ComTypes; +using Com = Windows.Win32.System.Com; +using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; + +namespace System.Windows.Forms.Tests; + +public unsafe partial class DataObjectTests +{ + private delegate IDataObject CreateWinFormsDataObjectForOutgoingDropData(Com.IDataObject* dataObject); + + [WinFormsFact] + public void DataObject_CustomIDataObject_MockRoundTrip() + { + CustomIDataObject data = new(); + dynamic accessor = typeof(Control).TestAccessor().Dynamic; + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); + + DataObject inData = accessor.CreateRuntimeDataObjectForDrag(data); + inData.Should().NotBeSameAs(data); + + // Simulate COM call. The COM call will eventually hit CreateWinFormsDataObjectForOutgoingDropData. + // Note that this will be a ComWrappers created object since data has been wrapped in our DataObject. + var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); + + outData.Should().BeSameAs(data); + } + + [WinFormsFact] + public void DataObject_ComTypesIDataObject_MockRoundTrip() + { + CustomComTypesDataObject data = new(); + dynamic accessor = typeof(Control).TestAccessor().Dynamic; + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); + + DataObject inData = accessor.CreateRuntimeDataObjectForDrag(data); + inData.Should().NotBeSameAs(data); + + // Simulate COM call. The COM call will eventually hit CreateWinFormsDataObjectForOutgoingDropData. + // Note that this will not be a ComWrappers created object since IComDataObject does not get wrapped in our DataObject. + var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); + + outData.Should().BeSameAs(inData); + } + + private class CustomIDataObject : IDataObject + { + public object GetData(string format, bool autoConvert) => throw new NotImplementedException(); + public object GetData(string format) => throw new NotImplementedException(); + public object GetData(Type format) => throw new NotImplementedException(); + public bool GetDataPresent(string format, bool autoConvert) => throw new NotImplementedException(); + public bool GetDataPresent(string format) => throw new NotImplementedException(); + public bool GetDataPresent(Type format) => throw new NotImplementedException(); + public string[] GetFormats(bool autoConvert) => throw new NotImplementedException(); + public string[] GetFormats() => throw new NotImplementedException(); + public void SetData(string format, bool autoConvert, object data) => throw new NotImplementedException(); + public void SetData(string format, object data) => throw new NotImplementedException(); + public void SetData(Type format, object data) => throw new NotImplementedException(); + public void SetData(object data) => throw new NotImplementedException(); + } + + private class CustomComTypesDataObject : IComDataObject + { + public int DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection) => throw new NotImplementedException(); + public void DUnadvise(int connection) => throw new NotImplementedException(); + public int EnumDAdvise(out IEnumSTATDATA enumAdvise) => throw new NotImplementedException(); + public IEnumFORMATETC EnumFormatEtc(DATADIR direction) => throw new NotImplementedException(); + public int GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut) => throw new NotImplementedException(); + public void GetData(ref FORMATETC format, out STGMEDIUM medium) => throw new NotImplementedException(); + public void GetDataHere(ref FORMATETC format, ref STGMEDIUM medium) => throw new NotImplementedException(); + public int QueryGetData(ref FORMATETC format) => throw new NotImplementedException(); + public void SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release) => throw new NotImplementedException(); + } +} diff --git a/src/System.Windows.Forms/tests/ComDisabledTests/GlobalUsings.cs b/src/System.Windows.Forms/tests/ComDisabledTests/GlobalUsings.cs new file mode 100644 index 00000000000..f058bfc2541 --- /dev/null +++ b/src/System.Windows.Forms/tests/ComDisabledTests/GlobalUsings.cs @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +global using FluentAssertions; +global using Windows.Win32; +global using Xunit; diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardComTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardComTests.cs new file mode 100644 index 00000000000..381ee7a2741 --- /dev/null +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardComTests.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Windows.Forms.Tests; + +public partial class ClipboardTests +{ + [WinFormsFact] + public void Clipboard_SetText_InvokeString_GetReturnsExpected() + { + Clipboard.SetText("text"); + Assert.Equal("text", Clipboard.GetText()); + Assert.True(Clipboard.ContainsText()); + } +} diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardTests.cs index 4fab0b1c72b..0418f26e1f1 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardTests.cs @@ -12,7 +12,7 @@ namespace System.Windows.Forms.Tests; -public class ClipboardTests +public partial class ClipboardTests { [WinFormsFact] public void Clipboard_Clear_InvokeMultipleTimes_Success() @@ -596,30 +596,4 @@ ComTypes.IEnumFORMATETC ComTypes.IDataObject.EnumFormatEtc(ComTypes.DATADIR dire void IDataObject.SetData(object data) => throw new NotImplementedException(); void ComTypes.IDataObject.SetData(ref ComTypes.FORMATETC formatIn, ref ComTypes.STGMEDIUM medium, bool release) => throw new NotImplementedException(); } - - [Collection("Sequential")] - public class ClipboardSequentialTests() - { - [WinFormsTheory] - [BoolData] - public void Clipboard_SetText_InvokeString_GetReturnsExpected(bool builtInComSupported) - { - string builtInComInteropSwitch = "System.Runtime.InteropServices.BuiltInComInterop.IsSupported"; - AppContext.TryGetSwitch(builtInComInteropSwitch, out bool original); - try - { - AppContext.SetSwitch(builtInComInteropSwitch, builtInComSupported); - AppContext.TryGetSwitch(builtInComInteropSwitch, out bool isEnabled).Should().BeTrue(); - isEnabled.Should().Be(builtInComSupported); - - Clipboard.SetText("text"); - Assert.Equal("text", Clipboard.GetText()); - Assert.True(Clipboard.ContainsText()); - } - finally - { - AppContext.SetSwitch(builtInComInteropSwitch, original); - } - } - } } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectComTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectComTests.cs new file mode 100644 index 00000000000..02c4b3a92d6 --- /dev/null +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectComTests.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices.ComTypes; +using Com = Windows.Win32.System.Com; +using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; + +namespace System.Windows.Forms.Tests; + +public unsafe partial class DataObjectTests +{ + private delegate IDataObject CreateWinFormsDataObjectForOutgoingDropData(Com.IDataObject* dataObject); + + [WinFormsFact] + public void DataObject_CustomIDataObject_MockRoundTrip() + { + CustomIDataObject data = new(); + dynamic accessor = typeof(Control).TestAccessor().Dynamic; + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); + + IComDataObject inData = accessor.CreateRuntimeDataObjectForDrag(data); + inData.Should().BeAssignableTo(); + inData.Should().NotBeSameAs(data); + + // Simulate COM call. The COM call will eventually hit CreateWinFormsDataObjectForOutgoingDropData. + // Note that this will be a ComWrappers created object since data has been wrapped in our DataObject. + var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); + + outData.Should().BeSameAs(data); + } + + [WinFormsFact] + public void DataObject_ComTypesIDataObject_MockRoundTrip() + { + CustomComTypesDataObject data = new(); + dynamic accessor = typeof(Control).TestAccessor().Dynamic; + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); + + DataObject inData = accessor.CreateRuntimeDataObjectForDrag(data); + inData.Should().NotBeSameAs(data); + + // Simulate COM call. The COM call will eventually hit CreateWinFormsDataObjectForOutgoingDropData. + // Note that this will not be a ComWrappers created object since IComDataObject does not get wrapped in our DataObject. + var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); + + outData.Should().BeSameAs(inData); + } + + private class CustomIDataObject : IDataObject + { + public object GetData(string format, bool autoConvert) => throw new NotImplementedException(); + public object GetData(string format) => throw new NotImplementedException(); + public object GetData(Type format) => throw new NotImplementedException(); + public bool GetDataPresent(string format, bool autoConvert) => throw new NotImplementedException(); + public bool GetDataPresent(string format) => throw new NotImplementedException(); + public bool GetDataPresent(Type format) => throw new NotImplementedException(); + public string[] GetFormats(bool autoConvert) => throw new NotImplementedException(); + public string[] GetFormats() => throw new NotImplementedException(); + public void SetData(string format, bool autoConvert, object data) => throw new NotImplementedException(); + public void SetData(string format, object data) => throw new NotImplementedException(); + public void SetData(Type format, object data) => throw new NotImplementedException(); + public void SetData(object data) => throw new NotImplementedException(); + } + + private class CustomComTypesDataObject : IComDataObject + { + public int DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection) => throw new NotImplementedException(); + public void DUnadvise(int connection) => throw new NotImplementedException(); + public int EnumDAdvise(out IEnumSTATDATA enumAdvise) => throw new NotImplementedException(); + public IEnumFORMATETC EnumFormatEtc(DATADIR direction) => throw new NotImplementedException(); + public int GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut) => throw new NotImplementedException(); + public void GetData(ref FORMATETC format, out STGMEDIUM medium) => throw new NotImplementedException(); + public void GetDataHere(ref FORMATETC format, ref STGMEDIUM medium) => throw new NotImplementedException(); + public int QueryGetData(ref FORMATETC format) => throw new NotImplementedException(); + public void SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release) => throw new NotImplementedException(); + } +} diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectTests.cs index f493810bc17..986a02e7e9f 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DataObjectTests.cs @@ -16,7 +16,7 @@ namespace System.Windows.Forms.Tests; // NB: doesn't require thread affinity -public class DataObjectTests +public partial class DataObjectTests { private static readonly string[] s_clipboardFormats = { @@ -1820,8 +1820,8 @@ public void DataObject_EnumFormatEtc_InvokeWithValues_Success(string format1, TY { Mock mockDataObject = new(MockBehavior.Strict); mockDataObject - .Setup(o => o.GetFormats(true)) - .Returns(new string[] { format1, "Format2" }); + .Setup(o => o.GetFormats()) + .Returns([format1, "Format2"]); DataObject dataObject = new(mockDataObject.Object); IComDataObject comDataObject = dataObject; IEnumFORMATETC enumerator = comDataObject.EnumFormatEtc(DATADIR.DATADIR_GET); @@ -1882,7 +1882,7 @@ public void DataObject_EnumFormatEtc_InvokeNullFormats_Success(int celt) { Mock mockDataObject = new(MockBehavior.Strict); mockDataObject - .Setup(o => o.GetFormats(true)) + .Setup(o => o.GetFormats()) .Returns((string[])null); DataObject dataObject = new(mockDataObject.Object); IComDataObject comDataObject = dataObject; @@ -1929,8 +1929,8 @@ public void DataObject_EnumFormatEtc_SkipCustom_Success() { Mock mockDataObject = new(MockBehavior.Strict); mockDataObject - .Setup(o => o.GetFormats(true)) - .Returns(new string[] { "Format1", DataFormats.Bitmap, "Format2" }); + .Setup(o => o.GetFormats()) + .Returns(["Format1", DataFormats.Bitmap, "Format2"]); DataObject dataObject = new(mockDataObject.Object); IComDataObject comDataObject = dataObject; IEnumFORMATETC enumerator = comDataObject.EnumFormatEtc(DATADIR.DATADIR_GET); @@ -2006,8 +2006,8 @@ public void DataObject_EnumFormatEtc_CloneWithValues_Success(string format1, TYM { Mock mockDataObject = new(MockBehavior.Strict); mockDataObject - .Setup(o => o.GetFormats(true)) - .Returns(new string[] { format1, "Format2" }); + .Setup(o => o.GetFormats()) + .Returns([format1, "Format2"]); DataObject dataObject = new(mockDataObject.Object); IComDataObject comDataObject = dataObject; IEnumFORMATETC source = comDataObject.EnumFormatEtc(DATADIR.DATADIR_GET); @@ -2069,7 +2069,7 @@ public void DataObject_EnumFormatEtc_CloneNullFormats_Success(int celt) { Mock mockDataObject = new(MockBehavior.Strict); mockDataObject - .Setup(o => o.GetFormats(true)) + .Setup(o => o.GetFormats()) .Returns((string[])null); DataObject dataObject = new(mockDataObject.Object); IComDataObject comDataObject = dataObject; @@ -2459,165 +2459,71 @@ public static IEnumerable DataObjectMockRoundTripData() [WinFormsTheory] [MemberData(nameof(DataObjectMockRoundTripData))] - public void DataObject_MockRoundTrip_IsSame(object data) + public unsafe void DataObject_MockRoundTrip_OutData_IsSame(object data) { dynamic controlAccessor = typeof(Control).TestAccessor().Dynamic; - dynamic dropTargetAccessor = typeof(DropTarget).TestAccessor().Dynamic; + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); - IComDataObject inData = controlAccessor.PrepareIncomingDragData(data); - inData.Should().BeSameAs(data); + IComDataObject inData = controlAccessor.CreateRuntimeDataObjectForDrag(data); + if (data is DataObject) + { + inData.Should().BeSameAs(data); + } + else + { + inData.Should().NotBeSameAs(data); + } - IDataObject outData = dropTargetAccessor.PrepareOutgoingDropData(inData); + using var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); outData.Should().BeSameAs(data); } [WinFormsFact] - public void DataObject_StringData_MockRoundTrip_IsWrapped() + public unsafe void DataObject_StringData_MockRoundTrip_IsWrapped() { string testString = "Test"; dynamic accessor = typeof(Control).TestAccessor().Dynamic; - dynamic dropTargetAccessor = typeof(DropTarget).TestAccessor().Dynamic; + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); - IComDataObject inData = accessor.PrepareIncomingDragData(testString); + IComDataObject inData = accessor.CreateRuntimeDataObjectForDrag(testString); inData.Should().BeAssignableTo(); - IDataObject outData = dropTargetAccessor.PrepareOutgoingDropData(inData); + using var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); outData.Should().BeSameAs(inData); outData.GetData(typeof(string)).Should().Be(testString); } [WinFormsFact] - public void DataObject_IDataObject_MockRoundTrip_IsWrapped() + public unsafe void DataObject_IDataObject_MockRoundTrip_IsWrapped() { CustomIDataObject data = new(); dynamic accessor = typeof(Control).TestAccessor().Dynamic; - dynamic dropTargetAccessor = typeof(DropTarget).TestAccessor().Dynamic; + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); - IComDataObject inData = accessor.PrepareIncomingDragData(data); + IComDataObject inData = accessor.CreateRuntimeDataObjectForDrag(data); inData.Should().BeAssignableTo(); inData.Should().NotBeSameAs(data); - IDataObject outData = dropTargetAccessor.PrepareOutgoingDropData(inData); - outData.Should().BeSameAs(inData); - } - - private class CustomIDataObject : IDataObject - { - public object GetData(string format, bool autoConvert) => throw new NotImplementedException(); - public object GetData(string format) => throw new NotImplementedException(); - public object GetData(Type format) => throw new NotImplementedException(); - public bool GetDataPresent(string format, bool autoConvert) => throw new NotImplementedException(); - public bool GetDataPresent(string format) => throw new NotImplementedException(); - public bool GetDataPresent(Type format) => throw new NotImplementedException(); - public string[] GetFormats(bool autoConvert) => throw new NotImplementedException(); - public string[] GetFormats() => throw new NotImplementedException(); - public void SetData(string format, bool autoConvert, object data) => throw new NotImplementedException(); - public void SetData(string format, object data) => throw new NotImplementedException(); - public void SetData(Type format, object data) => throw new NotImplementedException(); - public void SetData(object data) => throw new NotImplementedException(); + using var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); + outData.Should().BeSameAs(data); } [WinFormsFact] - public void DataObject_ComTypesIDataObject_MockRoundTrip_IsWrapped() + public unsafe void DataObject_ComTypesIDataObject_MockRoundTrip_IsWrapped() { CustomComTypesDataObject data = new(); dynamic accessor = typeof(Control).TestAccessor().Dynamic; - dynamic dropTargetAccessor = typeof(DropTarget).TestAccessor().Dynamic; - - IComDataObject inData = accessor.PrepareIncomingDragData(data); - inData.Should().BeSameAs(data); - - IDataObject outData = dropTargetAccessor.PrepareOutgoingDropData(inData); - outData.Should().BeAssignableTo(); - outData.Should().NotBeSameAs(inData); - } - - private class CustomComTypesDataObject : IComDataObject - { - public int DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection) => throw new NotImplementedException(); - public void DUnadvise(int connection) => throw new NotImplementedException(); - public int EnumDAdvise(out IEnumSTATDATA enumAdvise) => throw new NotImplementedException(); - public IEnumFORMATETC EnumFormatEtc(DATADIR direction) => throw new NotImplementedException(); - public int GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut) => throw new NotImplementedException(); - public void GetData(ref FORMATETC format, out STGMEDIUM medium) => throw new NotImplementedException(); - public void GetDataHere(ref FORMATETC format, ref STGMEDIUM medium) => throw new NotImplementedException(); - public int QueryGetData(ref FORMATETC format) => throw new NotImplementedException(); - public void SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release) => throw new NotImplementedException(); - } + var dropTargetAccessor = typeof(DropTarget).TestAccessor(); - [Collection("Sequential")] - public class DataObjectSequentialTests() - { - [WinFormsTheory] - [BoolData] - public unsafe void DataObject_IDataObject_MockRoundTrip_ToggleBuiltInCom(bool builtInComSupported) - { - string builtInComInteropSwitch = "System.Runtime.InteropServices.BuiltInComInterop.IsSupported"; - AppContext.TryGetSwitch(builtInComInteropSwitch, out bool original); - - try - { - AppContext.SetSwitch(builtInComInteropSwitch, builtInComSupported); - AppContext.TryGetSwitch(builtInComInteropSwitch, out bool isEnabled).Should().BeTrue(); - isEnabled.Should().Be(builtInComSupported); - - CustomIDataObject data = new(); - dynamic accessor = typeof(Control).TestAccessor().Dynamic; - dynamic dropTargetAccessor = typeof(DropTarget).TestAccessor().Dynamic; - - IComDataObject inData = accessor.PrepareIncomingDragData(data); - inData.Should().BeAssignableTo(); - inData.Should().NotBeSameAs(data); - - // Simulate COM call. The COM call will eventually hit PrepareOutgoingDropData. - // Note that this will be a ComWrappers created object since data has been wrapped in our DataObject. - var inDataPtr = ComHelpers.GetComScope(inData); - object managedDataObject = ComHelpers.GetObjectForIUnknown(inDataPtr.AsUnknown); - - IDataObject outData = dropTargetAccessor.PrepareOutgoingDropData(managedDataObject); - - outData.Should().BeSameAs(inData); - } - finally - { - AppContext.SetSwitch(builtInComInteropSwitch, original); - } - } - - [WinFormsTheory] - [BoolData] - public unsafe void DataObject_ComTypesIDataObject_MockRoundTrip_ToggleBuiltInCom(bool builtInComSupported) - { - string builtInComInteropSwitch = "System.Runtime.InteropServices.BuiltInComInterop.IsSupported"; - AppContext.TryGetSwitch(builtInComInteropSwitch, out bool original); - - try - { - AppContext.SetSwitch(builtInComInteropSwitch, builtInComSupported); - AppContext.TryGetSwitch(builtInComInteropSwitch, out bool isEnabled).Should().BeTrue(); - isEnabled.Should().Be(builtInComSupported); - - CustomComTypesDataObject data = new(); - dynamic accessor = typeof(Control).TestAccessor().Dynamic; - dynamic dropTargetAccessor = typeof(DropTarget).TestAccessor().Dynamic; - - IComDataObject inData = accessor.PrepareIncomingDragData(data); - inData.Should().BeSameAs(data); - - // Simulate COM call. The COM call will eventually hit PrepareOutgoingDropData. - // Note that this will not be a ComWrappers created object since IComDataObject does not get wrapped in our DataObject. - var inDataPtr = ComHelpers.GetComScope(inData); - object managedDataObject = ComHelpers.GetObjectForIUnknown(inDataPtr.AsUnknown); - - IDataObject outData = dropTargetAccessor.PrepareOutgoingDropData(ComHelpers.GetObjectForIUnknown(inDataPtr.AsUnknown)); + IComDataObject inData = accessor.CreateRuntimeDataObjectForDrag(data); + inData.Should().NotBeSameAs(data); + inData.Should().BeAssignableTo(); - outData.Should().BeAssignableTo(); - outData.Should().NotBeSameAs(inData); - } - finally - { - AppContext.SetSwitch(builtInComInteropSwitch, original); - } - } + using var inDataPtr = ComHelpers.GetComScope(inData); + IDataObject outData = dropTargetAccessor.CreateDelegate()(inDataPtr); + outData.Should().BeSameAs(inData); } } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropFormatTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropFormatTests.cs index 21fbec6cce2..f837d0c16e5 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropFormatTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropFormatTests.cs @@ -9,10 +9,11 @@ using IStream = Windows.Win32.System.Com.IStream; using STGMEDIUM = System.Runtime.InteropServices.ComTypes.STGMEDIUM; using TYMED = System.Runtime.InteropServices.ComTypes.TYMED; +using Com = Windows.Win32.System.Com; namespace System.Windows.Forms.Tests; -public class DragDropFormatTests +public unsafe class DragDropFormatTests { public static IEnumerable DragDropFormat_TestData() { @@ -21,7 +22,7 @@ public static IEnumerable DragDropFormat_TestData() cfFormat = (short)PInvoke.RegisterClipboardFormat("InShellDragLoop"), dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, - ptd = IntPtr.Zero, + ptd = nint.Zero, tymed = TYMED.TYMED_HGLOBAL }; @@ -44,7 +45,7 @@ public static IEnumerable DragDropFormat_TestData() cfFormat = (short)PInvoke.RegisterClipboardFormat("DragContext"), dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, - ptd = IntPtr.Zero, + ptd = nint.Zero, tymed = TYMED.TYMED_ISTREAM }; @@ -66,13 +67,13 @@ public void DragDropFormat_Set_Dispose_ReturnsExpected(FORMATETC formatEtc, STGM try { - dragDropFormat = new DragDropFormat(formatEtc.cfFormat, medium, copyData: false); + dragDropFormat = new DragDropFormat((ushort)formatEtc.cfFormat, (Com.STGMEDIUM)medium, copyData: false); dragDropFormat.Dispose(); - int handleSize = (int)PInvokeCore.GlobalSize((HGLOBAL)dragDropFormat.Medium.unionmember); + int handleSize = (int)PInvokeCore.GlobalSize(dragDropFormat.Medium.hGlobal); Assert.Equal(0, handleSize); - Assert.Null(dragDropFormat.Medium.pUnkForRelease); - Assert.Equal(TYMED.TYMED_NULL, dragDropFormat.Medium.tymed); - Assert.Equal(IntPtr.Zero, dragDropFormat.Medium.unionmember); + Assert.Equal(nint.Zero, (nint)dragDropFormat.Medium.pUnkForRelease); + Assert.Equal(Com.TYMED.TYMED_NULL, dragDropFormat.Medium.tymed); + Assert.True(dragDropFormat.Medium.hGlobal.IsNull); } finally { @@ -88,28 +89,28 @@ public void DragDropFormat_Set_GetData_ReturnsExpected(FORMATETC formatEtc, STGM try { - dragDropFormat = new DragDropFormat(formatEtc.cfFormat, medium, copyData: false); - STGMEDIUM data = dragDropFormat.GetData(); - Assert.Equal(medium.pUnkForRelease, data.pUnkForRelease); - Assert.Equal(medium.tymed, data.tymed); + dragDropFormat = new DragDropFormat((ushort)formatEtc.cfFormat, (Com.STGMEDIUM)medium, copyData: false); + Com.STGMEDIUM data = dragDropFormat.GetData(); + Assert.Equal(medium.pUnkForRelease ?? nint.Zero, (nint)data.pUnkForRelease); + Assert.Equal((uint)medium.tymed, (uint)data.tymed); switch (data.tymed) { - case TYMED.TYMED_HGLOBAL: - case TYMED.TYMED_FILE: - case TYMED.TYMED_ENHMF: - case TYMED.TYMED_GDI: - case TYMED.TYMED_MFPICT: + case Com.TYMED.TYMED_HGLOBAL: + case Com.TYMED.TYMED_FILE: + case Com.TYMED.TYMED_ENHMF: + case Com.TYMED.TYMED_GDI: + case Com.TYMED.TYMED_MFPICT: - Assert.NotEqual(medium.unionmember, data.unionmember); + Assert.NotEqual(medium.unionmember, data.hGlobal); break; - case TYMED.TYMED_ISTORAGE: - case TYMED.TYMED_ISTREAM: - case TYMED.TYMED_NULL: + case Com.TYMED.TYMED_ISTORAGE: + case Com.TYMED.TYMED_ISTREAM: + case Com.TYMED.TYMED_NULL: default: - Assert.Equal(medium.unionmember, data.unionmember); + Assert.Equal(medium.unionmember, (nint)data.hGlobal); break; } } @@ -127,42 +128,45 @@ public void DragDropFormat_Set_RefreshData_ReturnsExpected(FORMATETC formatEtc, try { - dragDropFormat = new DragDropFormat(formatEtc.cfFormat, medium, copyData: false); - STGMEDIUM dataRefresh = new() + dragDropFormat = new DragDropFormat((ushort)formatEtc.cfFormat, (Com.STGMEDIUM)medium, copyData: false); + Com.STGMEDIUM dataRefresh = new() { pUnkForRelease = dragDropFormat.Medium.pUnkForRelease, tymed = dragDropFormat.Medium.tymed, - unionmember = dragDropFormat.Medium.tymed switch + u = new() { - TYMED.TYMED_HGLOBAL or TYMED.TYMED_FILE or TYMED.TYMED_ENHMF or TYMED.TYMED_GDI or TYMED.TYMED_MFPICT - => PInvoke.OleDuplicateData( - (HANDLE)dragDropFormat.Medium.unionmember, - (CLIPBOARD_FORMAT)formatEtc.cfFormat, - GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT), - _ => dragDropFormat.Medium.unionmember, + hGlobal = dragDropFormat.Medium.tymed switch + { + Com.TYMED.TYMED_HGLOBAL or Com.TYMED.TYMED_FILE or Com.TYMED.TYMED_ENHMF or Com.TYMED.TYMED_GDI or Com.TYMED.TYMED_MFPICT + => (HGLOBAL)(nint)PInvoke.OleDuplicateData( + (HANDLE)(nint)dragDropFormat.Medium.hGlobal, + (CLIPBOARD_FORMAT)formatEtc.cfFormat, + GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT), + _ => dragDropFormat.Medium.hGlobal, + } } }; - dragDropFormat.RefreshData(formatEtc.cfFormat, dataRefresh, copyData: false); - STGMEDIUM data = dragDropFormat.GetData(); + dragDropFormat.RefreshData((ushort)formatEtc.cfFormat, dataRefresh, copyData: false); + Com.STGMEDIUM data = dragDropFormat.GetData(); switch (dragDropFormat.Medium.tymed) { - case TYMED.TYMED_HGLOBAL: - case TYMED.TYMED_FILE: - case TYMED.TYMED_ENHMF: - case TYMED.TYMED_GDI: - case TYMED.TYMED_MFPICT: + case Com.TYMED.TYMED_HGLOBAL: + case Com.TYMED.TYMED_FILE: + case Com.TYMED.TYMED_ENHMF: + case Com.TYMED.TYMED_GDI: + case Com.TYMED.TYMED_MFPICT: - Assert.NotEqual(dragDropFormat.Medium.unionmember, data.unionmember); + Assert.NotEqual(dragDropFormat.Medium.u, data.u); break; - case TYMED.TYMED_ISTORAGE: - case TYMED.TYMED_ISTREAM: - case TYMED.TYMED_NULL: + case Com.TYMED.TYMED_ISTORAGE: + case Com.TYMED.TYMED_ISTREAM: + case Com.TYMED.TYMED_NULL: default: - Assert.Equal(dragDropFormat.Medium.unionmember, data.unionmember); + Assert.Equal(dragDropFormat.Medium.u, data.u); break; } } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropHelperTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropHelperTests.cs index 598eed34e4d..a156678b318 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropHelperTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/DragDropHelperTests.cs @@ -109,12 +109,12 @@ public unsafe void SetDragImage_DataObject_Bitmap_Point_bool_ReturnsExpected(Dat { DragDropHelper.SetDragImage(dataObject, dragImage, cursorOffset, useDefaultDragImage); DragDropFormat dragDropFormat = (DragDropFormat)dataObject.GetData(DragDropHelper.DRAGIMAGEBITS); - void* basePtr = PInvokeCore.GlobalLock((HGLOBAL)dragDropFormat.Medium.unionmember); + void* basePtr = PInvokeCore.GlobalLock(dragDropFormat.Medium.hGlobal); SHDRAGIMAGE* pDragImage = (SHDRAGIMAGE*)basePtr; bool isDragImageNull = BitOperations.LeadingZeroCount((uint)(nint)pDragImage->hbmpDragImage).Equals(32); Size dragImageSize = pDragImage->sizeDragImage; Point offset = pDragImage->ptOffset; - PInvokeCore.GlobalUnlock((HGLOBAL)dragDropFormat.Medium.unionmember); + PInvokeCore.GlobalUnlock(dragDropFormat.Medium.hGlobal); Assert.Equal(dragImage is null, isDragImageNull); Assert.Equal(dragImage is null ? new Size(0, 0) : dragImage.Size, dragImageSize); Assert.Equal(cursorOffset, offset); @@ -133,12 +133,12 @@ public unsafe void SetDragImage_DataObject_GiveFeedbackEventArgs_ReturnsExpected { DragDropHelper.SetDragImage(dataObject, e); DragDropFormat dragDropFormat = (DragDropFormat)dataObject.GetData(DragDropHelper.DRAGIMAGEBITS); - void* basePtr = PInvokeCore.GlobalLock((HGLOBAL)dragDropFormat.Medium.unionmember); + void* basePtr = PInvokeCore.GlobalLock(dragDropFormat.Medium.hGlobal); SHDRAGIMAGE* pDragImage = (SHDRAGIMAGE*)basePtr; bool isDragImageNull = BitOperations.LeadingZeroCount((uint)(nint)pDragImage->hbmpDragImage).Equals(32); Size dragImageSize = pDragImage->sizeDragImage; Point offset = pDragImage->ptOffset; - PInvokeCore.GlobalUnlock((HGLOBAL)dragDropFormat.Medium.unionmember); + PInvokeCore.GlobalUnlock(dragDropFormat.Medium.hGlobal); Assert.Equal(e.DragImage is null, isDragImageNull); Assert.Equal(e.DragImage is null ? new Size(0, 0) : e.DragImage.Size, dragImageSize); Assert.Equal(e.CursorOffset, offset); @@ -180,12 +180,12 @@ public unsafe void SetDropDescription_ClearDropDescription_ReturnsExpected(DataO DragDropHelper.SetDropDescription(dataObject, dropImageType, message, messageReplacementToken); DragDropHelper.ClearDropDescription(dataObject); DragDropFormat dragDropFormat = (DragDropFormat)dataObject.GetData(PInvoke.CFSTR_DROPDESCRIPTION); - void* basePtr = PInvokeCore.GlobalLock((HGLOBAL)dragDropFormat.Medium.unionmember); + void* basePtr = PInvokeCore.GlobalLock(dragDropFormat.Medium.hGlobal); DROPDESCRIPTION* pDropDescription = (DROPDESCRIPTION*)basePtr; DROPIMAGETYPE type = pDropDescription->type; string szMessage = pDropDescription->szMessage.ToString(); string szInsert = pDropDescription->szInsert.ToString(); - PInvokeCore.GlobalUnlock((HGLOBAL)dragDropFormat.Medium.unionmember); + PInvokeCore.GlobalUnlock(dragDropFormat.Medium.hGlobal); Assert.Equal(DROPIMAGETYPE.DROPIMAGE_INVALID, type); Assert.Equal(string.Empty, szMessage); Assert.Equal(string.Empty, szInsert); @@ -238,7 +238,7 @@ public void SetDropDescription_NullDataObject_ThrowsArgumentNullException() [Theory] [MemberData(nameof(DropDescription_DataObject_DropImageType_string_string_TestData))] - public void SetDropDescription_ReleaseDragDropFormats_ReturnsExpected(DataObject dataObject, DropImageType dropImageType, string message, string messageReplacementToken) + public unsafe void SetDropDescription_ReleaseDragDropFormats_ReturnsExpected(DataObject dataObject, DropImageType dropImageType, string message, string messageReplacementToken) { DragDropHelper.SetDropDescription(dataObject, dropImageType, message, messageReplacementToken); DragDropHelper.ReleaseDragDropFormats(dataObject); @@ -247,10 +247,10 @@ public void SetDropDescription_ReleaseDragDropFormats_ReturnsExpected(DataObject { if (dataObject.GetData(format) is DragDropFormat dragDropFormat) { - Assert.Equal(0, (int)PInvokeCore.GlobalSize((HGLOBAL)dragDropFormat.Medium.unionmember)); - Assert.Null(dragDropFormat.Medium.pUnkForRelease); - Assert.Equal(TYMED.TYMED_NULL, dragDropFormat.Medium.tymed); - Assert.Equal(IntPtr.Zero, dragDropFormat.Medium.unionmember); + Assert.Equal(0, (int)PInvokeCore.GlobalSize(dragDropFormat.Medium.hGlobal)); + Assert.Equal(nint.Zero, (nint)dragDropFormat.Medium.pUnkForRelease); + Assert.Equal(Com.TYMED.TYMED_NULL, dragDropFormat.Medium.tymed); + Assert.Equal(nint.Zero, (nint)dragDropFormat.Medium.hGlobal); } } } @@ -263,12 +263,12 @@ public unsafe void SetDropDescription_DragEventArgs_ReturnsExpected(DragEventArg { DragDropHelper.SetDropDescription(e); DragDropFormat dragDropFormat = (DragDropFormat)e.Data.GetData(PInvoke.CFSTR_DROPDESCRIPTION); - void* basePtr = PInvokeCore.GlobalLock((HGLOBAL)dragDropFormat.Medium.unionmember); + void* basePtr = PInvokeCore.GlobalLock(dragDropFormat.Medium.hGlobal); DROPDESCRIPTION* pDropDescription = (DROPDESCRIPTION*)basePtr; DROPIMAGETYPE type = pDropDescription->type; string szMessage = pDropDescription->szMessage.ToString(); string szInsert = pDropDescription->szInsert.ToString(); - PInvokeCore.GlobalUnlock((HGLOBAL)dragDropFormat.Medium.unionmember); + PInvokeCore.GlobalUnlock(dragDropFormat.Medium.hGlobal); Assert.Equal((DROPIMAGETYPE)e.DropImageType, type); Assert.Equal(e.Message, szMessage); Assert.Equal(e.MessageReplacementToken, szInsert); @@ -290,12 +290,12 @@ public unsafe void SetDropDescription_DataObject_DropImageType_string_string_Ret { DragDropHelper.SetDropDescription(dataObject, dropImageType, message, messageReplacementToken); DragDropFormat dragDropFormat = (DragDropFormat)dataObject.GetData(PInvoke.CFSTR_DROPDESCRIPTION); - void* basePtr = PInvokeCore.GlobalLock((HGLOBAL)dragDropFormat.Medium.unionmember); + void* basePtr = PInvokeCore.GlobalLock(dragDropFormat.Medium.hGlobal); DROPDESCRIPTION* pDropDescription = (DROPDESCRIPTION*)basePtr; DROPIMAGETYPE type = pDropDescription->type; string szMessage = pDropDescription->szMessage.ToString(); string szInsert = pDropDescription->szInsert.ToString(); - PInvokeCore.GlobalUnlock((HGLOBAL)dragDropFormat.Medium.unionmember); + PInvokeCore.GlobalUnlock(dragDropFormat.Medium.hGlobal); Assert.Equal((DROPIMAGETYPE)dropImageType, type); Assert.Equal(message, szMessage); Assert.Equal(messageReplacementToken, szInsert); @@ -321,9 +321,9 @@ public unsafe void SetInDragLoop_ReturnsExpected(DataObject dataObject, bool inD { DragDropHelper.SetInDragLoop(dataObject, inDragLoop); DragDropFormat dragDropFormat = (DragDropFormat)dataObject.GetData(PInvoke.CFSTR_INDRAGLOOP); - void* basePtr = PInvokeCore.GlobalLock((HGLOBAL)dragDropFormat.Medium.unionmember); + void* basePtr = PInvokeCore.GlobalLock(dragDropFormat.Medium.hGlobal); bool inShellDragLoop = (basePtr is not null) && (*(BOOL*)basePtr == true); - PInvokeCore.GlobalUnlock((HGLOBAL)dragDropFormat.Medium.unionmember); + PInvokeCore.GlobalUnlock(dragDropFormat.Medium.hGlobal); Assert.Equal(inDragLoop, inShellDragLoop); } finally From 1864d7a3cfeaeee69d732a1826ad8e2688d91ae2 Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Thu, 22 Feb 2024 09:31:06 -0800 Subject: [PATCH 22/30] Add span overloads to Graphics (#10929) Add span overloads to Graphics This adds new span APIs to Graphics and GraphicsPath and adds params where applicable. Also move ArgumentValidation. --- src/System.Drawing.Common/src/GlobalUsings.cs | 1 + .../src/NativeMethods.txt | 1 + .../System/Drawing/Drawing2D/GraphicsPath.cs | 379 +++++++++++--- .../System/Drawing/Drawing2D/PathPointType.cs | 49 +- .../src/System/Drawing/Graphics.cs | 467 +++++++++++++----- .../src/System}/ArgumentValidation.cs | 2 +- .../Design/DesignSurfaceEvent.cs | 2 - .../DesignerSerializationManager.cs | 1 - .../Design/Serialization/ExpressionContext.cs | 1 - .../Design/Serialization/RootContext.cs | 1 - .../Design/UndoEngine.UndoUnit.cs | 1 - .../ComponentModel/Design/UndoEngine.cs | 1 - .../Drawing/Design/PaintValueEventArgs.cs | 1 - .../Drawing/Design/PropertyValueUIItem.cs | 2 - .../src/System/Resources/ResXDataNode.cs | 1 - .../src/System/Resources/ResXFileRef.cs | 1 - .../Forms/Controls/ToolStrips/ToolStrip.cs | 82 ++- 17 files changed, 754 insertions(+), 239 deletions(-) rename src/{System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals => System.Private.Windows.Core/src/System}/ArgumentValidation.cs (98%) diff --git a/src/System.Drawing.Common/src/GlobalUsings.cs b/src/System.Drawing.Common/src/GlobalUsings.cs index a9c3f798d7a..c7e6245d339 100644 --- a/src/System.Drawing.Common/src/GlobalUsings.cs +++ b/src/System.Drawing.Common/src/GlobalUsings.cs @@ -18,6 +18,7 @@ global using DashCap = System.Drawing.Drawing2D.DashCap; global using DashStyle = System.Drawing.Drawing2D.DashStyle; global using EmfPlusRecordType = System.Drawing.Imaging.EmfPlusRecordType; +global using FillMode = System.Drawing.Drawing2D.FillMode; global using ImageCodecInfo = System.Drawing.Imaging.ImageCodecInfo; global using ImageLockMode = System.Drawing.Imaging.ImageLockMode; global using LineCap = System.Drawing.Drawing2D.LineCap; diff --git a/src/System.Drawing.Common/src/NativeMethods.txt b/src/System.Drawing.Common/src/NativeMethods.txt index c229f74b43a..edb7b1421e7 100644 --- a/src/System.Drawing.Common/src/NativeMethods.txt +++ b/src/System.Drawing.Common/src/NativeMethods.txt @@ -554,6 +554,7 @@ LevelsParams PALETTEENTRY PaletteFlags PaletteType +PathPointType PRINTER_ENUM_CONNECTIONS PRINTER_ENUM_LOCAL PRINTER_INFO_4W diff --git a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs index d2bfb7b427c..4878f15c08c 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs @@ -12,8 +12,10 @@ public sealed unsafe class GraphicsPath : MarshalByRefObject, ICloneable, IDispo private const float Flatness = (float)2.0 / (float)3.0; + /// public GraphicsPath() : this(FillMode.Alternate) { } + /// public GraphicsPath(FillMode fillMode) { GpPath* path; @@ -21,15 +23,27 @@ public GraphicsPath(FillMode fillMode) _nativePath = path; } + /// public GraphicsPath(PointF[] pts, byte[] types) : this(pts, types, FillMode.Alternate) { } + /// public GraphicsPath(PointF[] pts, byte[] types, FillMode fillMode) + : this(pts.OrThrowIfNull().AsSpan(), types.OrThrowIfNull().AsSpan(), fillMode) { - ArgumentNullException.ThrowIfNull(pts); - ArgumentNullException.ThrowIfNull(types); + } + /// +#if NET9_0_OR_GREATER + public +#else + internal +#endif + GraphicsPath(ReadOnlySpan pts, ReadOnlySpan types, FillMode fillMode = FillMode.Alternate) + { if (pts.Length != types.Length) + { throw Status.InvalidParameter.GetException(); + } fixed (PointF* p = pts) fixed (byte* t = types) @@ -40,14 +54,32 @@ public GraphicsPath(PointF[] pts, byte[] types, FillMode fillMode) } } + /// public GraphicsPath(Point[] pts, byte[] types) : this(pts, types, FillMode.Alternate) { } + /// + /// Initializes a new instance of the class. + /// + /// Array of points that define the path. + /// Array of values that specify the type of + /// + /// A enumeration that specifies how the interiors of shapes in this + /// public GraphicsPath(Point[] pts, byte[] types, FillMode fillMode) - { - ArgumentNullException.ThrowIfNull(pts); + : this(pts.OrThrowIfNull().AsSpan(), types.OrThrowIfNull().AsSpan(), fillMode) { } + /// +#if NET9_0_OR_GREATER + public +#else + internal +#endif + GraphicsPath(ReadOnlySpan pts, ReadOnlySpan types, FillMode fillMode = FillMode.Alternate) + { if (pts.Length != types.Length) + { throw Status.InvalidParameter.GetException(); + } fixed (byte* t = types) fixed (Point* p = pts) @@ -276,12 +308,33 @@ public void AddLine(float x1, float y1, float x2, float y2) GC.KeepAlive(this); } - public void AddLines(PointF[] points) + /// + /// Appends a series of connected line segments to the end of this . + /// + /// An array of points that define the line segments to add. + /// + /// + /// + /// If there are previous lines or curves in the figure, a line is added to connect the endpoint + /// of the previous segment the starting point of the line. The parameter + /// specifies an array of endpoints. The first two specify the first line. Each additional point + /// specifies the endpoint of a line segment whose starting point is the endpoint of the previous line. + /// + /// + public void AddLines(params PointF[] points) => AddLines(points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddLines(ReadOnlySpan points) { - ArgumentNullException.ThrowIfNull(points); - if (points.Length == 0) + { throw new ArgumentException(null, nameof(points)); + } fixed (PointF* p = points) { @@ -294,12 +347,21 @@ public void AddLines(PointF[] points) public void AddLine(int x1, int y1, int x2, int y2) => AddLine((float)x1, y1, x2, y2); - public void AddLines(Point[] points) - { - ArgumentNullException.ThrowIfNull(points); + /// + public void AddLines(params Point[] points) => AddLines(points.OrThrowIfNull().AsSpan()); + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddLines(ReadOnlySpan points) + { if (points.Length == 0) + { throw new ArgumentException(null, nameof(points)); + } fixed (Point* p = points) { @@ -332,10 +394,20 @@ public void AddBezier(float x1, float y1, float x2, float y2, float x3, float y3 GC.KeepAlive(this); } - public void AddBeziers(PointF[] points) - { - ArgumentNullException.ThrowIfNull(points); + /// + /// Adds a sequence of connected cubic Bézier curves to the current figure. + /// + /// An array of points that define the curves. + public void AddBeziers(params PointF[] points) => AddBeziers(points.OrThrowIfNull().AsSpan()); + /// +#if NET9_0_OR_GREATER + public +#else + internal +#endif + void AddBeziers(ReadOnlySpan points) + { fixed (PointF* p = points) { PInvoke.GdipAddPathBeziers(_nativePath, (GdiPlus.PointF*)p, points.Length).ThrowIfFailed(); @@ -349,10 +421,17 @@ public void AddBezier(Point pt1, Point pt2, Point pt3, Point pt4) => public void AddBezier(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) => AddBezier((float)x1, y1, x2, y2, x3, y3, x4, y4); - public void AddBeziers(params Point[] points) - { - ArgumentNullException.ThrowIfNull(points); + /// + public void AddBeziers(params Point[] points) => AddBeziers(points.OrThrowIfNull().AsSpan()); + /// +#if NET9_0_OR_GREATER + public +#else + internal +#endif + void AddBeziers(ReadOnlySpan points) + { if (points.Length == 0) return; @@ -363,13 +442,26 @@ public void AddBeziers(params Point[] points) } } - /// - /// Add cardinal splines to the path object - /// - public void AddCurve(PointF[] points) => AddCurve(points.AsSpan(), 0.5f); + /// + public void AddCurve(params PointF[] points) => AddCurve(points.AsSpan(), 0.5f); + /// public void AddCurve(PointF[] points, float tension) => AddCurve(points.AsSpan(), tension); + /// + /// Adds a spline curve to the current figure. A cardinal spline curve is used because the + /// curve travels through each of the points in the array. + /// + /// An array points that define the curve. + /// The index of the first point in the array to use. + /// + /// The number of segments to use when creating the curve. A segment can be thought of as + /// a line connecting two points. + /// + /// + /// A value that specifies the amount that the curve bends between control points. + /// Values greater than 1 produce unpredictable results. + /// public void AddCurve(PointF[] points, int offset, int numberOfSegments, float tension) { fixed (PointF* p = points) @@ -386,7 +478,18 @@ public void AddCurve(PointF[] points, int offset, int numberOfSegments, float te } } - private void AddCurve(Span points, float tension) +#if NET9_0_OR_GREATER + /// + public void AddCurve(ReadOnlySpan points) => AddCurve(points, 0.5f); +#endif + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddCurve(ReadOnlySpan points, float tension) { fixed (PointF* p = points) { @@ -400,10 +503,13 @@ private void AddCurve(Span points, float tension) } } - public void AddCurve(Point[] points) => AddCurve(points.AsSpan(), 0.5f); + /// + public void AddCurve(params Point[] points) => AddCurve(points.AsSpan(), 0.5f); + /// public void AddCurve(Point[] points, float tension) => AddCurve(points.AsSpan(), tension); + /// public void AddCurve(Point[] points, int offset, int numberOfSegments, float tension) { fixed (Point* p = points) @@ -420,7 +526,18 @@ public void AddCurve(Point[] points, int offset, int numberOfSegments, float ten } } - private void AddCurve(Span points, float tension) +#if NET9_0_OR_GREATER + /// + public void AddCurve(ReadOnlySpan points) => AddCurve(points, 0.5f); +#endif + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddCurve(ReadOnlySpan points, float tension) { fixed (Point* p = points) { @@ -434,12 +551,25 @@ private void AddCurve(Span points, float tension) } } - public void AddClosedCurve(PointF[] points) => AddClosedCurve(points, 0.5f); + /// + public void AddClosedCurve(params PointF[] points) => AddClosedCurve(points, 0.5f); - public void AddClosedCurve(PointF[] points, float tension) - { - ArgumentNullException.ThrowIfNull(points); + /// + public void AddClosedCurve(PointF[] points, float tension) => AddClosedCurve(points.OrThrowIfNull().AsSpan(), tension); + +#if NET9_0_OR_GREATER + /// + public void AddClosedCurve(ReadOnlySpan points) => AddClosedCurve(points, 0.5f); +#endif + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddClosedCurve(ReadOnlySpan points, float tension) + { fixed (PointF* p = points) { PInvoke.GdipAddPathClosedCurve2(_nativePath, (GdiPlus.PointF*)p, points.Length, tension).ThrowIfFailed(); @@ -447,12 +577,29 @@ public void AddClosedCurve(PointF[] points, float tension) } } - public void AddClosedCurve(Point[] points) => AddClosedCurve(points, 0.5f); + /// + public void AddClosedCurve(params Point[] points) => AddClosedCurve(points, 0.5f); - public void AddClosedCurve(Point[] points, float tension) - { - ArgumentNullException.ThrowIfNull(points); + /// + /// Adds a closed spline curve to the current figure. A cardinal spline curve is used because the + /// curve travels through each of the points in the array. + /// + /// + public void AddClosedCurve(Point[] points, float tension) => AddClosedCurve(points.OrThrowIfNull().AsSpan(), tension); +#if NET9_0_OR_GREATER + /// + public void AddClosedCurve(ReadOnlySpan points) => AddClosedCurve(points, 0.5f); +#endif + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddClosedCurve(ReadOnlySpan points, float tension) + { fixed (Point* p = points) { PInvoke.GdipAddPathClosedCurve2I(_nativePath, (GdiPlus.Point*)p, points.Length, tension).ThrowIfFailed(); @@ -468,10 +615,20 @@ public void AddRectangle(RectangleF rect) GC.KeepAlive(this); } - public void AddRectangles(RectangleF[] rects) - { - ArgumentNullException.ThrowIfNull(rects); + /// + /// Adds a series of rectangles to this path. + /// + /// Array of rectangles to add. + public void AddRectangles(params RectangleF[] rects) => AddRectangles(rects.OrThrowIfNull().AsSpan()); + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddRectangles(ReadOnlySpan rects) + { fixed (RectangleF* r = rects) { PInvoke.GdipAddPathRectangles(_nativePath, (RectF*)r, rects.Length).ThrowIfFailed(); @@ -481,10 +638,17 @@ public void AddRectangles(RectangleF[] rects) public void AddRectangle(Rectangle rect) => AddRectangle((RectangleF)rect); - public void AddRectangles(Rectangle[] rects) - { - ArgumentNullException.ThrowIfNull(rects); + /// + public void AddRectangles(Rectangle[] rects) => AddRectangles(rects.OrThrowIfNull().AsSpan()); + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddRectangles(ReadOnlySpan rects) + { fixed (Rectangle* r = rects) { PInvoke.GdipAddPathRectanglesI(_nativePath, (Rect*)r, rects.Length).ThrowIfFailed(); @@ -563,10 +727,17 @@ public void AddPie(float x, float y, float width, float height, float startAngle public void AddPie(int x, int y, int width, int height, float startAngle, float sweepAngle) => AddPie((float)x, y, width, height, startAngle, sweepAngle); - public void AddPolygon(PointF[] points) - { - ArgumentNullException.ThrowIfNull(points); + /// + public void AddPolygon(PointF[] points) => AddPolygon(points.OrThrowIfNull().AsSpan()); + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddPolygon(ReadOnlySpan points) + { fixed (PointF* p = points) { PInvoke.GdipAddPathPolygon(_nativePath, (GdiPlus.PointF*)p, points.Length).ThrowIfFailed(); @@ -575,12 +746,19 @@ public void AddPolygon(PointF[] points) } /// - /// Adds a polygon to the current figure. + /// Adds a polygon to this path. /// - public void AddPolygon(Point[] points) - { - ArgumentNullException.ThrowIfNull(points); + /// The points that define the polygon. + public void AddPolygon(Point[] points) => AddPolygon(points.OrThrowIfNull().AsSpan()); + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void AddPolygon(ReadOnlySpan points) + { fixed (Point* p = points) { PInvoke.GdipAddPathPolygonI(_nativePath, (GdiPlus.Point*)p, points.Length).ThrowIfFailed(); @@ -683,18 +861,51 @@ public void Widen(Pen pen, Matrix? matrix, float flatness) GC.KeepAlive(this); } + /// public void Warp(PointF[] destPoints, RectangleF srcRect) => Warp(destPoints, srcRect, null); + /// public void Warp(PointF[] destPoints, RectangleF srcRect, Matrix? matrix) => Warp(destPoints, srcRect, matrix, WarpMode.Perspective); + /// public void Warp(PointF[] destPoints, RectangleF srcRect, Matrix? matrix, WarpMode warpMode) => Warp(destPoints, srcRect, matrix, warpMode, 0.25f); - public void Warp(PointF[] destPoints, RectangleF srcRect, Matrix? matrix, WarpMode warpMode, float flatness) - { - ArgumentNullException.ThrowIfNull(destPoints); + /// + public void Warp(PointF[] destPoints, RectangleF srcRect, Matrix? matrix, WarpMode warpMode, float flatness) => + Warp(destPoints.OrThrowIfNull().AsSpan(), srcRect, matrix, warpMode, flatness); + /// + /// Applies a warp transform, defined by a rectangle and a parallelogram, to this . + /// + /// + /// An array of points that define a parallelogram to which the rectangle defined by + /// is transformed. The array can contain either three or four elements. If the array contains three elements, + /// the lower-right corner of the parallelogram is implied by the first three points. + /// + /// + /// A rectangle that represents the rectangle that is transformed to the parallelogram defined by + /// . + /// + /// A matrix that specifies a geometric transform to apply to the path. + /// Specifies whether this warp operation uses perspective or bilinear mode. + /// + /// A value from 0 through 1 that specifies how flat the resulting path is. For more information, see the + /// methods. + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void Warp( + ReadOnlySpan destPoints, + RectangleF srcRect, + Matrix? matrix = default, + WarpMode warpMode = WarpMode.Perspective, + float flatness = 0.25f) + { fixed (PointF* p = destPoints) { PInvoke.GdipWarpPath( @@ -732,12 +943,37 @@ public byte[] PathTypes } byte[] types = new byte[count]; - fixed (byte* t = types) - { - PInvoke.GdipGetPathTypes(_nativePath, t, types.Length).ThrowIfFailed(); - GC.KeepAlive(this); - return types; - } + GetPathTypes(types); + return types; + } + } + + /// + /// Gets the types for the points in the path. + /// + /// + /// Span to copy the types into. This should be at least as long as the . + /// + /// + /// The count of types copied into the . + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + int GetPathTypes(Span destination) + { + if (destination.IsEmpty) + { + return 0; + } + + fixed (byte* t = destination) + { + PInvoke.GdipGetPathTypes(_nativePath, t, destination.Length).ThrowIfFailed(); + GC.KeepAlive(this); + return PointCount; } } @@ -752,12 +988,37 @@ public PointF[] PathPoints } PointF[] points = new PointF[count]; - fixed (PointF* p = points) - { - PInvoke.GdipGetPathPoints(_nativePath, (GdiPlus.PointF*)p, points.Length).ThrowIfFailed(); - GC.KeepAlive(this); - return points; - } + GetPathPoints(points); + return points; + } + } + + /// + /// Gets the points in the path. + /// + /// + /// Span to copy the points into. This should be at least as long as the . + /// + /// + /// The count of points copied into the . + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + int GetPathPoints(Span destination) + { + if (destination.IsEmpty) + { + return 0; + } + + fixed (PointF* p = destination) + { + PInvoke.GdipGetPathPoints(_nativePath, (GdiPlus.PointF*)p, destination.Length).ThrowIfFailed(); + GC.KeepAlive(this); + return PointCount; } } } diff --git a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/PathPointType.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/PathPointType.cs index 1c761f0c8a4..ad1d21f45dd 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/PathPointType.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/PathPointType.cs @@ -1,18 +1,45 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Drawing.Drawing2D; public enum PathPointType { - Start = 0, // move - Line = 1, // line - Bezier = 3, // default Beizer (= cubic Bezier) - PathTypeMask = 0x07, // type mask (lowest 3 bits). - DashMode = 0x10, // currently in dash mode. - PathMarker = 0x20, // a marker for the path. - CloseSubpath = 0x80, // closed flag - - // Path types used for advanced path. - Bezier3 = 3, // cubic Bezier + /// + /// Indicates that the point is the start of a figure. + /// + Start = GdiPlus.PathPointType.PathPointTypeStart, + + /// + /// Indicates that the point is an endpoint of a line. + /// + Line = GdiPlus.PathPointType.PathPointTypeLine, + + /// + /// Indicates that the point is an endpoint or a control point of a cubic Bézier spline. + /// + Bezier = GdiPlus.PathPointType.PathPointTypeBezier, + + /// + /// Masks all bits except for the three low-order bits, which indicate the point type. + /// + PathTypeMask = GdiPlus.PathPointType.PathPointTypePathTypeMask, + + /// + /// Not used. + /// + DashMode = GdiPlus.PathPointType.PathPointTypeDashMode, + + /// + /// Specifies that the point is a marker. + /// + PathMarker = GdiPlus.PathPointType.PathPointTypePathMarker, + + /// + /// Specifies that the point is the last point in a closed subpath (figure). + /// + CloseSubpath = GdiPlus.PathPointType.PathPointTypeCloseSubpath, + + /// + Bezier3 = GdiPlus.PathPointType.PathPointTypeBezier3 } diff --git a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs index 8b2d58f785b..a90946bac8b 100644 --- a/src/System.Drawing.Common/src/System/Drawing/Graphics.cs +++ b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs @@ -779,13 +779,18 @@ public void DrawRectangle(Pen pen, float x, float y, float width, float height) public void DrawRectangle(Pen pen, int x, int y, int width, int height) => DrawRectangle(pen, (float)x, y, width, height); - /// - /// Draws the outlines of a series of rectangles. - /// - public void DrawRectangles(Pen pen, RectangleF[] rects) + /// + public void DrawRectangles(Pen pen, params RectangleF[] rects) => DrawRectangles(pen, rects.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawRectangles(Pen pen, ReadOnlySpan rects) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(rects); fixed (RectangleF* r = rects) { @@ -798,10 +803,19 @@ public void DrawRectangles(Pen pen, RectangleF[] rects) /// /// Draws the outlines of a series of rectangles. /// - public void DrawRectangles(Pen pen, Rectangle[] rects) + /// that determines the color, width, and style of the outlines of the rectangles. + /// An array of structures that represents the rectangles to draw. + public void DrawRectangles(Pen pen, params Rectangle[] rects) => DrawRectangles(pen, rects.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawRectangles(Pen pen, ReadOnlySpan rects) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(rects); fixed (Rectangle* r = rects) { @@ -864,13 +878,18 @@ public void DrawPie(Pen pen, Rectangle rect, float startAngle, float sweepAngle) public void DrawPie(Pen pen, int x, int y, int width, int height, int startAngle, int sweepAngle) => DrawPie(pen, (float)x, y, width, height, startAngle, sweepAngle); - /// - /// Draws the outline of a polygon defined by an array of points. - /// - public void DrawPolygon(Pen pen, PointF[] points) + /// + public void DrawPolygon(Pen pen, params PointF[] points) => DrawPolygon(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawPolygon(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -883,10 +902,19 @@ public void DrawPolygon(Pen pen, PointF[] points) /// /// Draws the outline of a polygon defined by an array of points. /// - public void DrawPolygon(Pen pen, Point[] points) + /// The to draw the outline with. + /// An array of structures that represent the vertices of the polygon. + public void DrawPolygon(Pen pen, params Point[] points) => DrawPolygon(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawPolygon(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -910,13 +938,18 @@ public void DrawPath(Pen pen, GraphicsPath path) GC.KeepAlive(path); } - /// - /// Draws a curve defined by an array of points. - /// - public void DrawCurve(Pen pen, PointF[] points) + /// + public void DrawCurve(Pen pen, params PointF[] points) => DrawCurve(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawCurve(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -926,13 +959,19 @@ public void DrawCurve(Pen pen, PointF[] points) GC.KeepAlive(pen); } - /// - /// Draws a curve defined by an array of points. - /// - public void DrawCurve(Pen pen, PointF[] points, float tension) + /// + public void DrawCurve(Pen pen, PointF[] points, float tension) => + DrawCurve(pen, points.OrThrowIfNull().AsSpan(), tension); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawCurve(Pen pen, ReadOnlySpan points, float tension) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -946,16 +985,29 @@ public void DrawCurve(Pen pen, PointF[] points, float tension) GC.KeepAlive(pen); } + /// public void DrawCurve(Pen pen, PointF[] points, int offset, int numberOfSegments) => DrawCurve(pen, points, offset, numberOfSegments, 0.5f); - /// - /// Draws a curve defined by an array of points. - /// - public void DrawCurve(Pen pen, PointF[] points, int offset, int numberOfSegments, float tension) +#if NET9_0_OR_GREATER + /// + public void DrawCurve(Pen pen, ReadOnlySpan points, int offset, int numberOfSegments) => + DrawCurve(pen, points, offset, numberOfSegments, 0.5f); +#endif + + /// + public void DrawCurve(Pen pen, PointF[] points, int offset, int numberOfSegments, float tension) => + DrawCurve(pen, points.OrThrowIfNull().AsSpan(), offset, numberOfSegments, tension); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawCurve(Pen pen, ReadOnlySpan points, int offset, int numberOfSegments, float tension) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -971,13 +1023,18 @@ public void DrawCurve(Pen pen, PointF[] points, int offset, int numberOfSegments GC.KeepAlive(pen); } - /// - /// Draws a curve defined by an array of points. - /// - public void DrawCurve(Pen pen, Point[] points) + /// + public void DrawCurve(Pen pen, params Point[] points) => DrawCurve(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawCurve(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -987,13 +1044,19 @@ public void DrawCurve(Pen pen, Point[] points) GC.KeepAlive(pen); } - /// - /// Draws a curve defined by an array of points. - /// - public void DrawCurve(Pen pen, Point[] points, float tension) + /// + public void DrawCurve(Pen pen, Point[] points, float tension) => + DrawCurve(pen, points.OrThrowIfNull().AsSpan(), tension); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawCurve(Pen pen, ReadOnlySpan points, float tension) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -1010,10 +1073,23 @@ public void DrawCurve(Pen pen, Point[] points, float tension) /// /// Draws a curve defined by an array of points. /// - public void DrawCurve(Pen pen, Point[] points, int offset, int numberOfSegments, float tension) + /// The to draw the curve with. + /// An array of points that define the curve. + /// The index of the first point in the array to draw. + /// The number of segments to draw. + /// A value greater than, or equal to zero that specifies the tension of the curve. + public void DrawCurve(Pen pen, Point[] points, int offset, int numberOfSegments, float tension) => + DrawCurve(pen, points.OrThrowIfNull().AsSpan(), offset, numberOfSegments, tension); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawCurve(Pen pen, ReadOnlySpan points, int offset, int numberOfSegments, float tension) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -1029,13 +1105,19 @@ public void DrawCurve(Pen pen, Point[] points, int offset, int numberOfSegments, GC.KeepAlive(pen); } - /// - /// Draws a closed curve defined by an array of points. - /// - public void DrawClosedCurve(Pen pen, PointF[] points) + /// + public void DrawClosedCurve(Pen pen, params PointF[] points) => + DrawClosedCurve(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawClosedCurve(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -1051,10 +1133,22 @@ public void DrawClosedCurve(Pen pen, PointF[] points) /// /// Draws a closed curve defined by an array of points. /// - public void DrawClosedCurve(Pen pen, PointF[] points, float tension, Drawing2D.FillMode fillmode) + /// The to draw the closed curve with. + /// An array of points that define the closed curve. + /// A value greater than, or equal to zero that specifies the tension of the curve. + /// A enumeration that specifies the fill mode of the curve. + public void DrawClosedCurve(Pen pen, PointF[] points, float tension, FillMode fillmode) => + DrawClosedCurve(pen, points.OrThrowIfNull().AsSpan(), tension, fillmode); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawClosedCurve(Pen pen, ReadOnlySpan points, float tension, FillMode fillmode) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -1068,13 +1162,18 @@ public void DrawClosedCurve(Pen pen, PointF[] points, float tension, Drawing2D.F GC.KeepAlive(pen); } - /// - /// Draws a closed curve defined by an array of points. - /// - public void DrawClosedCurve(Pen pen, Point[] points) + /// + public void DrawClosedCurve(Pen pen, Point[] points) => DrawClosedCurve(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawClosedCurve(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -1087,13 +1186,20 @@ public void DrawClosedCurve(Pen pen, Point[] points) GC.KeepAlive(pen); } - /// - /// Draws a closed curve defined by an array of points. - /// - public void DrawClosedCurve(Pen pen, Point[] points, float tension, Drawing2D.FillMode fillmode) + /// + + public void DrawClosedCurve(Pen pen, Point[] points, float tension, FillMode fillmode) => + DrawClosedCurve(pen, points.OrThrowIfNull().AsSpan(), tension, fillmode); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawClosedCurve(Pen pen, ReadOnlySpan points, float tension, FillMode fillmode) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -1164,10 +1270,23 @@ public void FillRectangle(Brush brush, float x, float y, float width, float heig /// /// Fills the interiors of a series of rectangles with a . /// - public void FillRectangles(Brush brush, RectangleF[] rects) + /// The to fill the rectangles with. + /// An array of rectangles to fill. + public void FillRectangles(Brush brush, params RectangleF[] rects) { - ArgumentNullException.ThrowIfNull(brush); ArgumentNullException.ThrowIfNull(rects); + FillRectangles(brush, rects.AsSpan()); + } + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillRectangles(Brush brush, ReadOnlySpan rects) + { + ArgumentNullException.ThrowIfNull(brush); fixed (RectangleF* r = rects) { @@ -1177,13 +1296,19 @@ public void FillRectangles(Brush brush, RectangleF[] rects) GC.KeepAlive(brush); } - /// - /// Fills the interiors of a series of rectangles with a . - /// - public void FillRectangles(Brush brush, Rectangle[] rects) + /// + public void FillRectangles(Brush brush, params Rectangle[] rects) => + FillRectangles(brush, rects.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillRectangles(Brush brush, ReadOnlySpan rects) { ArgumentNullException.ThrowIfNull(brush); - ArgumentNullException.ThrowIfNull(rects); fixed (Rectangle* r = rects) { @@ -1193,18 +1318,27 @@ public void FillRectangles(Brush brush, Rectangle[] rects) GC.KeepAlive(brush); } - /// - /// Fills the interior of a polygon defined by an array of points. - /// - public void FillPolygon(Brush brush, PointF[] points) => FillPolygon(brush, points, Drawing2D.FillMode.Alternate); + /// + public void FillPolygon(Brush brush, params PointF[] points) => FillPolygon(brush, points, FillMode.Alternate); - /// - /// Fills the interior of a polygon defined by an array of points. - /// - public void FillPolygon(Brush brush, PointF[] points, Drawing2D.FillMode fillMode) +#if NET9_0_OR_GREATER + /// + public void FillPolygon(Brush brush, ReadOnlySpan points) => FillPolygon(brush, points, FillMode.Alternate); +#endif + + /// + public void FillPolygon(Brush brush, PointF[] points, FillMode fillMode) => + FillPolygon(brush, points.OrThrowIfNull().AsSpan(), fillMode); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillPolygon(Brush brush, ReadOnlySpan points, FillMode fillMode) { ArgumentNullException.ThrowIfNull(brush); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -1218,18 +1352,32 @@ public void FillPolygon(Brush brush, PointF[] points, Drawing2D.FillMode fillMod GC.KeepAlive(brush); } - /// - /// Fills the interior of a polygon defined by an array of points. - /// - public void FillPolygon(Brush brush, Point[] points) => FillPolygon(brush, points, Drawing2D.FillMode.Alternate); + /// + public void FillPolygon(Brush brush, Point[] points) => FillPolygon(brush, points, FillMode.Alternate); + +#if NET9_0_OR_GREATER + /// + public void FillPolygon(Brush brush, ReadOnlySpan points) => FillPolygon(brush, points, FillMode.Alternate); +#endif /// /// Fills the interior of a polygon defined by an array of points. /// - public void FillPolygon(Brush brush, Point[] points, Drawing2D.FillMode fillMode) + /// The to fill the polygon with. + /// An array points that represent the vertices of the polygon. + /// A enumeration that specifies the fill mode of the polygon. + public void FillPolygon(Brush brush, Point[] points, FillMode fillMode) => + FillPolygon(brush, points.OrThrowIfNull().AsSpan(), fillMode); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillPolygon(Brush brush, ReadOnlySpan points, FillMode fillMode) { ArgumentNullException.ThrowIfNull(brush); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -1312,13 +1460,19 @@ public void FillPie(Brush brush, float x, float y, float width, float height, fl public void FillPie(Brush brush, int x, int y, int width, int height, int startAngle, int sweepAngle) => FillPie(brush, (float)x, y, width, height, startAngle, sweepAngle); - /// - /// Fills the interior a closed curve defined by an array of points. - /// - public void FillClosedCurve(Brush brush, PointF[] points) + /// + public void FillClosedCurve(Brush brush, params PointF[] points) => + FillClosedCurve(brush, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillClosedCurve(Brush brush, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(brush); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -1331,16 +1485,35 @@ public void FillClosedCurve(Brush brush, PointF[] points) GC.KeepAlive(brush); } + /// + public void FillClosedCurve(Brush brush, PointF[] points, FillMode fillmode) => + FillClosedCurve(brush, points, fillmode, 0.5f); + +#if NET9_0_OR_GREATER + /// + public void FillClosedCurve(Brush brush, ReadOnlySpan points, FillMode fillmode) => + FillClosedCurve(brush, points, fillmode, 0.5f); +#endif + /// /// Fills the interior of a closed curve defined by an array of points. /// - public void FillClosedCurve(Brush brush, PointF[] points, Drawing2D.FillMode fillmode) => - FillClosedCurve(brush, points, fillmode, 0.5f); + /// The to fill the closed curve with. + /// An array of points that make up the closed curve. + /// A enumeration that specifies the fill mode of the closed curve. + /// A value greater than, or equal to zero that specifies the tension of the curve. + public void FillClosedCurve(Brush brush, PointF[] points, FillMode fillmode, float tension) => + FillClosedCurve(brush, points.OrThrowIfNull().AsSpan(), fillmode, tension); - public void FillClosedCurve(Brush brush, PointF[] points, Drawing2D.FillMode fillmode, float tension) + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillClosedCurve(Brush brush, ReadOnlySpan points, FillMode fillmode, float tension) { ArgumentNullException.ThrowIfNull(brush); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -1355,13 +1528,19 @@ public void FillClosedCurve(Brush brush, PointF[] points, Drawing2D.FillMode fil GC.KeepAlive(brush); } - /// - /// Fills the interior a closed curve defined by an array of points. - /// - public void FillClosedCurve(Brush brush, Point[] points) + /// + public void FillClosedCurve(Brush brush, params Point[] points) => + FillClosedCurve(brush, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillClosedCurve(Brush brush, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(brush); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -1374,13 +1553,30 @@ public void FillClosedCurve(Brush brush, Point[] points) GC.KeepAlive(brush); } - public void FillClosedCurve(Brush brush, Point[] points, Drawing2D.FillMode fillmode) => + /// + public void FillClosedCurve(Brush brush, Point[] points, FillMode fillmode) => + FillClosedCurve(brush, points, fillmode, 0.5f); + +#if NET9_0_OR_GREATER + /// + public void FillClosedCurve(Brush brush, ReadOnlySpan points, FillMode fillmode) => FillClosedCurve(brush, points, fillmode, 0.5f); - public void FillClosedCurve(Brush brush, Point[] points, Drawing2D.FillMode fillmode, float tension) +#endif + + /// + public void FillClosedCurve(Brush brush, Point[] points, FillMode fillmode, float tension) => + FillClosedCurve(brush, points.OrThrowIfNull().AsSpan(), fillmode, tension); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void FillClosedCurve(Brush brush, ReadOnlySpan points, FillMode fillmode, float tension) { ArgumentNullException.ThrowIfNull(brush); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { @@ -1570,7 +1766,7 @@ private void DrawStringInternal(ReadOnlySpan s, Font font, Brush brush, Re CheckErrorStatus(PInvoke.GdipDrawString( NativeGraphics, c, s.Length, - (GpFont*)font.NativeFont, + font.NativeFont, (RectF*)&layoutRectangle, format.Pointer(), brush.NativeBrush)); @@ -1632,7 +1828,7 @@ public SizeF MeasureStringInternal( NativeGraphics, c, text.Length, - (GpFont*)font.NativeFont, + font.NativeFont, (RectF*)&layoutArea, stringFormat.Pointer(), &boundingBox, @@ -1792,7 +1988,7 @@ private Region[] MeasureCharacterRangesInternal( NativeGraphics, c, text.Length, - (GpFont*)font.NativeFont, + font.NativeFont, &layoutRect, stringFormat.Pointer(), count, @@ -2174,13 +2370,18 @@ public void DrawImage( /// public void DrawLine(Pen pen, PointF pt1, PointF pt2) => DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y); - /// - /// Draws a series of line segments that connect an array of points. - /// - public void DrawLines(Pen pen, PointF[] points) + /// + public void DrawLines(Pen pen, PointF[] points) => DrawLines(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawLines(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -2204,7 +2405,9 @@ public void DrawLine(Pen pen, int x1, int y1, int x2, int y2) => /// /// Draws a series of line segments that connect an array of points. /// - public void DrawLines(Pen pen, Point[] points) + /// The that determines the color, width, and style of the line segments. + /// An array of points to connect. + public void DrawLines(Pen pen, params Point[] points) { ArgumentNullException.ThrowIfNull(pen); ArgumentNullException.ThrowIfNull(points); @@ -2217,6 +2420,24 @@ public void DrawLines(Pen pen, Point[] points) GC.KeepAlive(pen); } + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawLines(Pen pen, ReadOnlySpan points) + { + ArgumentNullException.ThrowIfNull(pen); + + fixed (Point* p = points) + { + CheckErrorStatus(PInvoke.GdipDrawLinesI(NativeGraphics, pen.NativePen, (GdiPlus.Point*)p, points.Length)); + } + + GC.KeepAlive(pen); + } + /// /// CopyPixels will perform a gdi "bitblt" operation to the source from the destination with the given size. /// @@ -2547,13 +2768,19 @@ public void DrawLine(Pen pen, float x1, float y1, float x2, float y2) GC.KeepAlive(pen); } - /// - /// Draws a series of cubic Bezier curves from an array of points. - /// - public void DrawBeziers(Pen pen, PointF[] points) + /// + public void DrawBeziers(Pen pen, params PointF[] points) => + DrawBeziers(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawBeziers(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (PointF* p = points) { @@ -2567,12 +2794,24 @@ public void DrawBeziers(Pen pen, PointF[] points) } /// - /// Draws a series of cubic Bezier curves from an array of points. + /// Draws a series of cubic Bézier curves from an array of points. /// - public void DrawBeziers(Pen pen, Point[] points) + /// The to draw the Bézier with. + /// + /// Points that represent the points that determine the curve. The number of points in the array + /// should be a multiple of 3 plus 1, such as 4, 7, or 10. + /// + public void DrawBeziers(Pen pen, params Point[] points) => DrawBeziers(pen, points.OrThrowIfNull().AsSpan()); + + /// +#if NET9_0_OR_GREATER + public +#else + private +#endif + void DrawBeziers(Pen pen, ReadOnlySpan points) { ArgumentNullException.ThrowIfNull(pen); - ArgumentNullException.ThrowIfNull(points); fixed (Point* p = points) { diff --git a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/ArgumentValidation.cs b/src/System.Private.Windows.Core/src/System/ArgumentValidation.cs similarity index 98% rename from src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/ArgumentValidation.cs rename to src/System.Private.Windows.Core/src/System/ArgumentValidation.cs index 13253db3fd6..02a9ce63c4e 100644 --- a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/ArgumentValidation.cs +++ b/src/System.Private.Windows.Core/src/System/ArgumentValidation.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; -namespace System.Windows.Forms; +namespace System; internal static class ArgumentValidation { diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignSurfaceEvent.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignSurfaceEvent.cs index 1661d24a9e5..70f8cfde29f 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignSurfaceEvent.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignSurfaceEvent.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Windows.Forms; - namespace System.ComponentModel.Design; /// diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/DesignerSerializationManager.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/DesignerSerializationManager.cs index c94b187bc0d..23014ad295a 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/DesignerSerializationManager.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/DesignerSerializationManager.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Reflection; using System.Runtime.Serialization; -using System.Windows.Forms; namespace System.ComponentModel.Design.Serialization; diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ExpressionContext.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ExpressionContext.cs index 18eea4247eb..e2107a3d0f5 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ExpressionContext.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ExpressionContext.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.CodeDom; -using System.Windows.Forms; namespace System.ComponentModel.Design.Serialization; diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/RootContext.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/RootContext.cs index 57982b68d13..5894189b87f 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/RootContext.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/RootContext.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.CodeDom; -using System.Windows.Forms; namespace System.ComponentModel.Design.Serialization; diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.UndoUnit.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.UndoUnit.cs index daf292a94dc..069fb6f35c7 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.UndoUnit.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.UndoUnit.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Reflection; -using System.Windows.Forms; namespace System.ComponentModel.Design; diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.cs index c6f18c3e4c0..1e6bde234f3 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/UndoEngine.cs @@ -3,7 +3,6 @@ using System.ComponentModel.Design.Serialization; using System.Reflection; -using System.Windows.Forms; namespace System.ComponentModel.Design; diff --git a/src/System.Windows.Forms/src/System/Drawing/Design/PaintValueEventArgs.cs b/src/System.Windows.Forms/src/System/Drawing/Design/PaintValueEventArgs.cs index a17b3024acc..b9f5b119297 100644 --- a/src/System.Windows.Forms/src/System/Drawing/Design/PaintValueEventArgs.cs +++ b/src/System.Windows.Forms/src/System/Drawing/Design/PaintValueEventArgs.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using System.Windows.Forms; namespace System.Drawing.Design; diff --git a/src/System.Windows.Forms/src/System/Drawing/Design/PropertyValueUIItem.cs b/src/System.Windows.Forms/src/System/Drawing/Design/PropertyValueUIItem.cs index 6ae16f0edf4..fa681f139c5 100644 --- a/src/System.Windows.Forms/src/System/Drawing/Design/PropertyValueUIItem.cs +++ b/src/System.Windows.Forms/src/System/Drawing/Design/PropertyValueUIItem.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Windows.Forms; - namespace System.Drawing.Design; /// diff --git a/src/System.Windows.Forms/src/System/Resources/ResXDataNode.cs b/src/System.Windows.Forms/src/System/Resources/ResXDataNode.cs index a95e2061fb5..7f1d8008e71 100644 --- a/src/System.Windows.Forms/src/System/Resources/ResXDataNode.cs +++ b/src/System.Windows.Forms/src/System/Resources/ResXDataNode.cs @@ -9,7 +9,6 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; -using System.Windows.Forms; using System.Windows.Forms.BinaryFormat; using System.Xml; diff --git a/src/System.Windows.Forms/src/System/Resources/ResXFileRef.cs b/src/System.Windows.Forms/src/System/Resources/ResXFileRef.cs index 0c796b82037..ec155f6ca4a 100644 --- a/src/System.Windows.Forms/src/System/Resources/ResXFileRef.cs +++ b/src/System.Windows.Forms/src/System/Resources/ResXFileRef.cs @@ -4,7 +4,6 @@ using System.ComponentModel; using System.Globalization; using System.Text; -using System.Windows.Forms; namespace System.Resources; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStrip.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStrip.cs index 23abca95b0f..419b0e449fe 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStrip.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ToolStrips/ToolStrip.cs @@ -3974,27 +3974,26 @@ internal void PaintInsertionMark(Graphics g) int start = _lastInsertionMarkRect.X; int verticalBeamStart = start + 2; - // draw two vertical lines - g.DrawLines(SystemPens.ControlText, - new Point[] - { - new(verticalBeamStart, _lastInsertionMarkRect.Y), new(verticalBeamStart, _lastInsertionMarkRect.Bottom - 1), // first vertical line - new(verticalBeamStart + 1, _lastInsertionMarkRect.Y), new(verticalBeamStart + 1, _lastInsertionMarkRect.Bottom - 1), // second vertical line - }); - // then two top horizontal - g.DrawLines(SystemPens.ControlText, - new Point[] - { - new(start, _lastInsertionMarkRect.Bottom - 1), new(start + widthOfBeam - 1, _lastInsertionMarkRect.Bottom - 1), // bottom line - new(start + 1, _lastInsertionMarkRect.Bottom - 2), new(start + widthOfBeam - 2, _lastInsertionMarkRect.Bottom - 2), // bottom second line - }); - // then two bottom horizontal - g.DrawLines(SystemPens.ControlText, - new Point[] - { - new(start, _lastInsertionMarkRect.Y), new(start + widthOfBeam - 1, _lastInsertionMarkRect.Y), // top line - new(start + 1, _lastInsertionMarkRect.Y + 1), new(start + widthOfBeam - 2, _lastInsertionMarkRect.Y + 1) // top second line - }); + // Draw vertical lines. + g.DrawLines(SystemPens.ControlText, (ReadOnlySpan) + [ + new(verticalBeamStart, _lastInsertionMarkRect.Y), new(verticalBeamStart, _lastInsertionMarkRect.Bottom - 1), + new(verticalBeamStart + 1, _lastInsertionMarkRect.Y), new(verticalBeamStart + 1, _lastInsertionMarkRect.Bottom - 1) + ]); + + // Draw top horizontal lines. + g.DrawLines(SystemPens.ControlText, (ReadOnlySpan) + [ + new(start, _lastInsertionMarkRect.Bottom - 1), new(start + widthOfBeam - 1, _lastInsertionMarkRect.Bottom - 1), + new(start + 1, _lastInsertionMarkRect.Bottom - 2), new(start + widthOfBeam - 2, _lastInsertionMarkRect.Bottom - 2) + ]); + + // Draw bottom horizontal lines. + g.DrawLines(SystemPens.ControlText, (ReadOnlySpan) + [ + new(start, _lastInsertionMarkRect.Y), new(start + widthOfBeam - 1, _lastInsertionMarkRect.Y), + new(start + 1, _lastInsertionMarkRect.Y + 1), new(start + widthOfBeam - 2, _lastInsertionMarkRect.Y + 1) + ]); } else { @@ -4002,27 +4001,26 @@ internal void PaintInsertionMark(Graphics g) int start = _lastInsertionMarkRect.Y; int horizontalBeamStart = start + 2; - // draw two horizontal lines - g.DrawLines(SystemPens.ControlText, - new Point[] - { - new(_lastInsertionMarkRect.X, horizontalBeamStart), new(_lastInsertionMarkRect.Right - 1, horizontalBeamStart), // first vertical line - new(_lastInsertionMarkRect.X, horizontalBeamStart + 1), new(_lastInsertionMarkRect.Right - 1, horizontalBeamStart + 1), // second vertical line - }); - // then two left vertical - g.DrawLines(SystemPens.ControlText, - new Point[] - { - new(_lastInsertionMarkRect.X, start), new(_lastInsertionMarkRect.X, start + widthOfBeam - 1), // left line - new(_lastInsertionMarkRect.X + 1, start + 1), new(_lastInsertionMarkRect.X + 1, start + widthOfBeam - 2), // second left line - }); - // then two right vertical - g.DrawLines(SystemPens.ControlText, - new Point[] - { - new(_lastInsertionMarkRect.Right - 1, start), new(_lastInsertionMarkRect.Right - 1, start + widthOfBeam - 1), // right line - new(_lastInsertionMarkRect.Right - 2, start + 1), new(_lastInsertionMarkRect.Right - 2, start + widthOfBeam - 2), // second right line - }); + // Draw horizontal lines. + g.DrawLines(SystemPens.ControlText, (ReadOnlySpan) + [ + new(_lastInsertionMarkRect.X, horizontalBeamStart), new(_lastInsertionMarkRect.Right - 1, horizontalBeamStart), + new(_lastInsertionMarkRect.X, horizontalBeamStart + 1), new(_lastInsertionMarkRect.Right - 1, horizontalBeamStart + 1) + ]); + + // Draw left vertical lines. + g.DrawLines(SystemPens.ControlText, (ReadOnlySpan) + [ + new(_lastInsertionMarkRect.X, start), new(_lastInsertionMarkRect.X, start + widthOfBeam - 1), + new(_lastInsertionMarkRect.X + 1, start + 1), new(_lastInsertionMarkRect.X + 1, start + widthOfBeam - 2) + ]); + + // Draw right vertical lines. + g.DrawLines(SystemPens.ControlText, (ReadOnlySpan) + [ + new(_lastInsertionMarkRect.Right - 1, start), new(_lastInsertionMarkRect.Right - 1, start + widthOfBeam - 1), + new(_lastInsertionMarkRect.Right - 2, start + 1), new(_lastInsertionMarkRect.Right - 2, start + widthOfBeam - 2) + ]); } } } From 01d2b63b20bf918fda7f99bc5f24e17fedc033a8 Mon Sep 17 00:00:00 2001 From: v-zhgl <38325459+Zheng-Li01@users.noreply.github.com> Date: Thu, 22 Feb 2024 17:36:32 +0000 Subject: [PATCH 23/30] Add code coverage for RichTextBox (#10921) * Add unit test for RichTextBox control Co-authored-by: Tanya Solyanik --- .../System/Windows/Forms/RichTextBoxTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs index 01ba95d3d80..f7946a9dc3d 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/RichTextBoxTests.cs @@ -10646,6 +10646,33 @@ public void RichTextBox_OnGotFocus_RaisesAutomationNotification_WithText(EventAr Times.Once); } + [WinFormsTheory] + [InlineData(-1, -1, 0)] + [InlineData(0, 0, 0)] + [InlineData(10, 10, 1)] + public void RichTextBox_GetCharIndexFromPosition_Invoke_ReturnsExpected(int x, int y, int expectedIndex) + { + using RichTextBox richTextBox1 = new(); + richTextBox1.Text = "Hello, World!"; + + Assert.NotEqual(0, richTextBox1.Handle); + int invalidatedCallCount = 0; + richTextBox1.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + richTextBox1.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + richTextBox1.HandleCreated += (sender, e) => createdCallCount++; + + Point pt = new(x, y); + int index = richTextBox1.GetCharIndexFromPosition(pt); + + Assert.Equal(expectedIndex, index); + Assert.True(richTextBox1.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + private class CustomGetParaFormatRichTextBox : RichTextBox { public bool MakeCustom { get; set; } From b4c9c031e5451208ac12ad2b21ed3196a5c100e6 Mon Sep 17 00:00:00 2001 From: Leaf Shi <132890443+LeafShi1@users.noreply.github.com> Date: Fri, 23 Feb 2024 10:29:22 +0800 Subject: [PATCH 24/30] Suppress codeQL warnings in tests "BitmapTests" and "ImageListTests" (#10922) * Suppress codeQL warnings in tests "BitmapTests" and "ImageListTests" * Update the comment --- .../tests/mono/System.Drawing/BitmapTests.cs | 3 ++- .../tests/UnitTests/System/Windows/Forms/ImageListTests.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs b/src/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs index 4b6cfde2307..c584e4413ee 100644 --- a/src/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs +++ b/src/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs @@ -389,7 +389,8 @@ public string RotateBmp(Bitmap src, RotateFlipType rotate) } } - hash = MD5.Create().ComputeHash(pixels); + // cs/weak-crypto + hash = MD5.Create().ComputeHash(pixels); // CodeQL [SM02196] This hash is used in test to compare two bitmaps. return ByteArrayToString(hash); } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ImageListTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ImageListTests.cs index 06dd57521f9..d42cf44e6d1 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ImageListTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ImageListTests.cs @@ -444,7 +444,8 @@ private static T RoundtripSerialize(T source) BinaryFormatter formatter = new(); formatter.Serialize(stream, source); stream.Position = 0; - return (T)formatter.Deserialize(stream); + // cs/deserialization-unexpected-subtypes + return (T)formatter.Deserialize(stream); // CodeQL [SM02229] Testing legacy features: we are deserializing stream with controlled content. #pragma warning restore SYSLIB0011 // Type or member is obsolete } From cd2721637f3fbbcacd46f58c2b1f44951468a506 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:36:22 +0000 Subject: [PATCH 25/30] [main] Update dependencies from dotnet/runtime (#10940) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 172 ++++++++++++++++++++-------------------- eng/Versions.props | 54 ++++++------- global.json | 2 +- 3 files changed, 114 insertions(+), 114 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9f5a4c95674..ca1252f2ce7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,178 +7,178 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 - + https://github.com/dotnet/runtime - d908f00305588dcf577cd5f9c99ff0464000efdc + 52c14fb8d01ddd293a0710642aa1e7ef3a438687 diff --git a/eng/Versions.props b/eng/Versions.props index 023e5262cbb..3753a3c6ba3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,35 +15,35 @@ - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 5.0.0-preview.7.20320.5 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 6.0.0 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 - 9.0.0-preview.2.24122.1 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 + 9.0.0-preview.2.24122.9 diff --git a/global.json b/global.json index 0403448c220..30cfd572afe 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24122.1" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24122.9" }, "native-tools": { "cmake": "latest" From 6bd932c0067c48808fd6d7f733812e46a4ea18f2 Mon Sep 17 00:00:00 2001 From: Lachlan Ennis <2433737+elachlan@users.noreply.github.com> Date: Sat, 24 Feb 2024 03:31:34 +1000 Subject: [PATCH 26/30] Fix `null` values in `AutoCompleteCustomSource` (#10905) * Refactoring to add ArgumentNullException/InvalidOperationException to AutoCompleteCustomSource and add tests to verify Cleanup/Refactor of StringSource * Moved tests to AutoCompleteStringCollectionTests * Changes from review * change from review * Use Items property instead of private backing field --- .../Forms/AutoCompleteStringCollection.cs | 39 +++++++++++++++++-- .../Forms/Controls/ComboBox/ComboBox.cs | 30 +++++--------- .../Windows/Forms/Controls/TextBox/TextBox.cs | 15 +------ .../src/System/Windows/Forms/StringSource.cs | 37 ++++++++---------- .../AutoCompleteStringCollectionTests.cs | 27 +++++++++++++ 5 files changed, 91 insertions(+), 57 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/AutoCompleteStringCollection.cs b/src/System.Windows.Forms/src/System/Windows/Forms/AutoCompleteStringCollection.cs index 3c8fea30ddd..0562e5f9138 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/AutoCompleteStringCollection.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/AutoCompleteStringCollection.cs @@ -12,7 +12,7 @@ namespace System.Windows.Forms; public class AutoCompleteStringCollection : IList { private CollectionChangeEventHandler? _onCollectionChanged; - private readonly List _data = new(); + private readonly List _data = []; public AutoCompleteStringCollection() { @@ -57,8 +57,17 @@ public event CollectionChangeEventHandler? CollectionChanged /// Adds a string with the specified value to the /// . /// + /// + /// The position into which the new element was inserted, or -1 to indicate that + /// the item was not inserted into the collection. + /// public int Add(string value) { + if (value is null) + { + return -1; + } + int index = ((IList)_data).Add(value); OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, value)); return index; @@ -71,7 +80,21 @@ public void AddRange(params string[] value) { ArgumentNullException.ThrowIfNull(value); - _data.AddRange(value); + List nonNullItems = []; + foreach (string item in value) + { + if (item is not null) + { + nonNullItems.Add(item); + } + } + + if (nonNullItems.Count <= 0) + { + return; + } + + _data.AddRange(nonNullItems); OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, null)); } @@ -110,8 +133,14 @@ public void Clear() /// public void Insert(int index, string value) { - _data.Insert(index, value); - OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, value)); + ArgumentOutOfRangeException.ThrowIfNegative(index); + ArgumentOutOfRangeException.ThrowIfGreaterThan(index, _data.Count); + + if (value is not null) + { + _data.Insert(index, value); + OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, value)); + } } /// @@ -168,4 +197,6 @@ public void RemoveAt(int index) void ICollection.CopyTo(Array array, int index) => ((ICollection)_data).CopyTo(array, index); public IEnumerator GetEnumerator() => _data.GetEnumerator(); + + internal string[] ToArray() => [.. _data]; } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBox.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBox.cs index 47c4b708544..26e2000c1db 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBox.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBox.cs @@ -915,30 +915,20 @@ private int GetComboHeight() return cyCombo; } - private string[] GetStringsForAutoComplete(IList collection) + private string[] GetStringsForAutoComplete() { - if (collection is AutoCompleteStringCollection) + if (Items is not null) { - string[] strings = new string[AutoCompleteCustomSource.Count]; - for (int i = 0; i < AutoCompleteCustomSource.Count; i++) - { - strings[i] = AutoCompleteCustomSource[i]; - } - - return strings; - } - else if (collection is ObjectCollection && _itemsCollection is not null) - { - string[] strings = new string[_itemsCollection.Count]; - for (int i = 0; i < _itemsCollection.Count; i++) + string[] strings = new string[Items.Count]; + for (int i = 0; i < Items.Count; i++) { - strings[i] = GetItemText(_itemsCollection[i])!; + strings[i] = GetItemText(Items[i])!; } return strings; } - return Array.Empty(); + return []; } /// @@ -3283,7 +3273,7 @@ private void SetAutoComplete(bool reset, bool recreate) if (_stringSource is null) { - _stringSource = new StringSource(GetStringsForAutoComplete(AutoCompleteCustomSource)); + _stringSource = new StringSource(AutoCompleteCustomSource.ToArray()); if (!_stringSource.Bind(_childEdit, (AUTOCOMPLETEOPTIONS)AutoCompleteMode)) { throw new ArgumentException(SR.AutoCompleteFailure); @@ -3291,7 +3281,7 @@ private void SetAutoComplete(bool reset, bool recreate) } else { - _stringSource.RefreshList(GetStringsForAutoComplete(AutoCompleteCustomSource)); + _stringSource.RefreshList(AutoCompleteCustomSource.ToArray()); } return; @@ -3326,7 +3316,7 @@ private void SetAutoComplete(bool reset, bool recreate) if (_stringSource is null) { - _stringSource = new StringSource(GetStringsForAutoComplete(Items)); + _stringSource = new StringSource(GetStringsForAutoComplete()); if (!_stringSource.Bind(_childEdit, (AUTOCOMPLETEOPTIONS)AutoCompleteMode)) { throw new ArgumentException(SR.AutoCompleteFailureListItems); @@ -3334,7 +3324,7 @@ private void SetAutoComplete(bool reset, bool recreate) } else { - _stringSource.RefreshList(GetStringsForAutoComplete(Items)); + _stringSource.RefreshList(GetStringsForAutoComplete()); } return; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TextBox/TextBox.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TextBox/TextBox.cs index 82149a87784..2973820e324 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TextBox/TextBox.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TextBox/TextBox.cs @@ -721,17 +721,6 @@ private protected override void SelectInternal(int start, int length, int textLe base.SelectInternal(start, length, textLen); } - private string[] GetStringsForAutoComplete() - { - string[] strings = new string[AutoCompleteCustomSource.Count]; - for (int i = 0; i < AutoCompleteCustomSource.Count; i++) - { - strings[i] = AutoCompleteCustomSource[i]; - } - - return strings; - } - /// /// Sets the AutoComplete mode in TextBox. /// @@ -767,7 +756,7 @@ private unsafe void SetAutoComplete(bool reset) { if (_stringSource is null) { - _stringSource = new StringSource(GetStringsForAutoComplete()); + _stringSource = new StringSource(AutoCompleteCustomSource.ToArray()); if (!_stringSource.Bind(this, (AUTOCOMPLETEOPTIONS)AutoCompleteMode)) { throw new ArgumentException(SR.AutoCompleteFailure); @@ -775,7 +764,7 @@ private unsafe void SetAutoComplete(bool reset) } else { - _stringSource.RefreshList(GetStringsForAutoComplete()); + _stringSource.RefreshList(AutoCompleteCustomSource.ToArray()); } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/StringSource.cs b/src/System.Windows.Forms/src/System/Windows/Forms/StringSource.cs index 936ab654470..1e32739c3cf 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/StringSource.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/StringSource.cs @@ -13,9 +13,9 @@ namespace System.Windows.Forms; /// internal unsafe class StringSource : IEnumString.Interface, IManagedWrapper { - private string[] strings; - private int current; - private int size; + private string[] _strings; + private int _current; + private int _size; private IAutoComplete2* _autoComplete2; /// @@ -23,11 +23,8 @@ internal unsafe class StringSource : IEnumString.Interface, IManagedWrapper public StringSource(string[] strings) { - Array.Clear(strings, 0, size); - this.strings = strings; - - current = 0; - size = strings.Length; + _strings = strings; + _size = strings.Length; PInvokeCore.CoCreateInstance( in CLSID.AutoComplete, @@ -68,10 +65,10 @@ public void ReleaseAutoComplete() public void RefreshList(string[] newSource) { - Array.Clear(strings, 0, size); - strings = newSource; - current = 0; - size = strings.Length; + Array.Clear(_strings, 0, _size); + _strings = newSource; + _current = 0; + _size = _strings.Length; } public unsafe HRESULT Clone(IEnumString** ppenum) @@ -81,7 +78,7 @@ public unsafe HRESULT Clone(IEnumString** ppenum) return HRESULT.E_POINTER; } - *ppenum = ComHelpers.GetComPointer(new StringSource(strings) { current = current }); + *ppenum = ComHelpers.GetComPointer(new StringSource(_strings) { _current = _current }); return HRESULT.S_OK; } @@ -94,10 +91,10 @@ public unsafe HRESULT Next(uint celt, PWSTR* rgelt, [Optional] uint* pceltFetche uint fetched = 0; - while (current < size && celt > 0) + while (_current < _size && celt > 0) { - rgelt[fetched] = (char*)Marshal.StringToCoTaskMemUni(strings[current]); - current++; + rgelt[fetched] = (char*)Marshal.StringToCoTaskMemUni(_strings[_current]); + _current++; fetched++; celt--; } @@ -112,19 +109,19 @@ public unsafe HRESULT Next(uint celt, PWSTR* rgelt, [Optional] uint* pceltFetche public HRESULT Skip(uint celt) { - int newCurrent = current + (int)celt; - if (newCurrent >= size) + int newCurrent = _current + (int)celt; + if (newCurrent >= _size) { return HRESULT.S_FALSE; } - current = newCurrent; + _current = newCurrent; return HRESULT.S_OK; } public HRESULT Reset() { - current = 0; + _current = 0; return HRESULT.S_OK; } } diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/AutoCompleteStringCollectionTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/AutoCompleteStringCollectionTests.cs index dcab87e1a92..e030dfa9118 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/AutoCompleteStringCollectionTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/AutoCompleteStringCollectionTests.cs @@ -35,6 +35,23 @@ public void AutoCompleteStringCollection_AddRange_NullValue_ThrowsArgumentNullEx Assert.Throws("value", () => collection.AddRange(null)); } +#nullable enable + [WinFormsFact] + public void AutoCompleteStringCollection_AddRange_NullValues_Nop() + { + AutoCompleteStringCollection collection = new(); + collection.AddRange([null!]); + Assert.Empty(collection); + } + + [WinFormsFact] + public void AutoCompleteStringCollection_Add_NullValue_ThrowsArgumentNullException() + { + AutoCompleteStringCollection collection = new(); + Assert.Throws("value", () => collection.AddRange(null!)); + } +#nullable disable + [WinFormsFact] public void AutoCompleteStringCollection_Contains_Invoke_ReturnsExpected() { @@ -181,6 +198,16 @@ public void AutoCompleteStringCollection_IListInsert_InvalidIndex_ThrowsArgument Assert.Throws("index", () => collection.Insert(index, "value")); } +#nullable enable + [WinFormsFact] + public void AutoCompleteStringCollection_IListInsert_NullItem_Nop() + { + IList collection = new AutoCompleteStringCollection(); + collection.Insert(0, null); + Assert.Empty(collection); + } +#nullable disable + [WinFormsFact] public void AutoCompleteStringCollection_Remove_String_Success() { From d4fc8f8243289e64d3fae18fae4b28fba326765f Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Fri, 23 Feb 2024 10:43:31 -0800 Subject: [PATCH 27/30] Publish APIs for .NET 9 Preview 2 (#10941) Sort PublicAPI.Shipped --- .../src/PublicAPI.Shipped.txt | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/System.Windows.Forms/src/PublicAPI.Shipped.txt b/src/System.Windows.Forms/src/PublicAPI.Shipped.txt index 1e956ae0f3e..d3244777ad7 100644 --- a/src/System.Windows.Forms/src/PublicAPI.Shipped.txt +++ b/src/System.Windows.Forms/src/PublicAPI.Shipped.txt @@ -1,30 +1,6 @@ #nullable enable -override System.Windows.Forms.PropertyGrid.CreateAccessibilityInstance() -> System.Windows.Forms.AccessibleObject! -override System.Windows.Forms.PropertyGrid.OnEnabledChanged(System.EventArgs! e) -> void -override System.Windows.Forms.PropertyGrid.OnFontChanged(System.EventArgs! e) -> void -override System.Windows.Forms.PropertyGrid.OnGotFocus(System.EventArgs! e) -> void -override System.Windows.Forms.PropertyGrid.OnHandleCreated(System.EventArgs! e) -> void -override System.Windows.Forms.PropertyGrid.OnHandleDestroyed(System.EventArgs! e) -> void -override System.Windows.Forms.PropertyGrid.OnMouseDown(System.Windows.Forms.MouseEventArgs! me) -> void -override System.Windows.Forms.PropertyGrid.OnMouseMove(System.Windows.Forms.MouseEventArgs! me) -> void -override System.Windows.Forms.PropertyGrid.OnMouseUp(System.Windows.Forms.MouseEventArgs! me) -> void -override System.Windows.Forms.PropertyGrid.OnPaint(System.Windows.Forms.PaintEventArgs! pevent) -> void -override System.Windows.Forms.PropertyGrid.OnResize(System.EventArgs! e) -> void -override System.Windows.Forms.PropertyGrid.OnSystemColorsChanged(System.EventArgs! e) -> void -override System.Windows.Forms.PropertyGrid.OnVisibleChanged(System.EventArgs! e) -> void ~static System.Windows.Forms.Control.FromChildHandle(nint handle) -> System.Windows.Forms.Control ~static System.Windows.Forms.Control.FromHandle(nint handle) -> System.Windows.Forms.Control -System.Windows.Forms.PropertyGrid.OnComComponentNameChanged(System.ComponentModel.Design.ComponentRenameEventArgs! e) -> void -System.Windows.Forms.PropertyGrid.OnNotifyPropertyValueUIItemsChanged(object? sender, System.EventArgs! e) -> void -virtual System.Windows.Forms.PropertyGrid.CreatePropertyTab(System.Type! tabType) -> System.Windows.Forms.Design.PropertyTab? -virtual System.Windows.Forms.PropertyGrid.OnPropertySortChanged(System.EventArgs! e) -> void -virtual System.Windows.Forms.PropertyGrid.OnPropertyTabChanged(System.Windows.Forms.PropertyTabChangedEventArgs! e) -> void -virtual System.Windows.Forms.PropertyGrid.OnPropertyValueChanged(System.Windows.Forms.PropertyValueChangedEventArgs! e) -> void -virtual System.Windows.Forms.PropertyGrid.OnSelectedGridItemChanged(System.Windows.Forms.SelectedGridItemChangedEventArgs! e) -> void -virtual System.Windows.Forms.PropertyGrid.OnSelectedObjectsChanged(System.EventArgs! e) -> void -virtual System.Windows.Forms.PropertyGrid.ShowPropertyPageImage.get -> System.Drawing.Bitmap! -virtual System.Windows.Forms.PropertyGrid.SortByCategoryImage.get -> System.Drawing.Bitmap! -virtual System.Windows.Forms.PropertyGrid.SortByPropertyImage.get -> System.Drawing.Bitmap! abstract System.Windows.Forms.BindingManagerBase.AddNew() -> void abstract System.Windows.Forms.BindingManagerBase.CancelCurrentEdit() -> void abstract System.Windows.Forms.BindingManagerBase.Count.get -> int @@ -1310,10 +1286,23 @@ override System.Windows.Forms.PropertyGrid.BackgroundImage.get -> System.Drawing override System.Windows.Forms.PropertyGrid.BackgroundImage.set -> void override System.Windows.Forms.PropertyGrid.BackgroundImageLayout.get -> System.Windows.Forms.ImageLayout override System.Windows.Forms.PropertyGrid.BackgroundImageLayout.set -> void +override System.Windows.Forms.PropertyGrid.CreateAccessibilityInstance() -> System.Windows.Forms.AccessibleObject! override System.Windows.Forms.PropertyGrid.DefaultSize.get -> System.Drawing.Size override System.Windows.Forms.PropertyGrid.Dispose(bool disposing) -> void override System.Windows.Forms.PropertyGrid.ForeColor.get -> System.Drawing.Color override System.Windows.Forms.PropertyGrid.ForeColor.set -> void +override System.Windows.Forms.PropertyGrid.OnEnabledChanged(System.EventArgs! e) -> void +override System.Windows.Forms.PropertyGrid.OnFontChanged(System.EventArgs! e) -> void +override System.Windows.Forms.PropertyGrid.OnGotFocus(System.EventArgs! e) -> void +override System.Windows.Forms.PropertyGrid.OnHandleCreated(System.EventArgs! e) -> void +override System.Windows.Forms.PropertyGrid.OnHandleDestroyed(System.EventArgs! e) -> void +override System.Windows.Forms.PropertyGrid.OnMouseDown(System.Windows.Forms.MouseEventArgs! me) -> void +override System.Windows.Forms.PropertyGrid.OnMouseMove(System.Windows.Forms.MouseEventArgs! me) -> void +override System.Windows.Forms.PropertyGrid.OnMouseUp(System.Windows.Forms.MouseEventArgs! me) -> void +override System.Windows.Forms.PropertyGrid.OnPaint(System.Windows.Forms.PaintEventArgs! pevent) -> void +override System.Windows.Forms.PropertyGrid.OnResize(System.EventArgs! e) -> void +override System.Windows.Forms.PropertyGrid.OnSystemColorsChanged(System.EventArgs! e) -> void +override System.Windows.Forms.PropertyGrid.OnVisibleChanged(System.EventArgs! e) -> void override System.Windows.Forms.PropertyGrid.ProcessDialogKey(System.Windows.Forms.Keys keyData) -> bool override System.Windows.Forms.PropertyGrid.Refresh() -> void override System.Windows.Forms.PropertyGrid.ScaleCore(float dx, float dy) -> void @@ -8751,6 +8740,8 @@ System.Windows.Forms.PropertyGrid.MouseEnter -> System.EventHandler? System.Windows.Forms.PropertyGrid.MouseLeave -> System.EventHandler? System.Windows.Forms.PropertyGrid.MouseMove -> System.Windows.Forms.MouseEventHandler? System.Windows.Forms.PropertyGrid.MouseUp -> System.Windows.Forms.MouseEventHandler? +System.Windows.Forms.PropertyGrid.OnComComponentNameChanged(System.ComponentModel.Design.ComponentRenameEventArgs! e) -> void +System.Windows.Forms.PropertyGrid.OnNotifyPropertyValueUIItemsChanged(object? sender, System.EventArgs! e) -> void System.Windows.Forms.PropertyGrid.Padding.get -> System.Windows.Forms.Padding System.Windows.Forms.PropertyGrid.Padding.set -> void System.Windows.Forms.PropertyGrid.PaddingChanged -> System.EventHandler? @@ -13186,9 +13177,18 @@ virtual System.Windows.Forms.PropertyGrid.CanShowCommands.get -> bool virtual System.Windows.Forms.PropertyGrid.CommandsVisible.get -> bool virtual System.Windows.Forms.PropertyGrid.CommandsVisibleIfAvailable.get -> bool virtual System.Windows.Forms.PropertyGrid.CommandsVisibleIfAvailable.set -> void +virtual System.Windows.Forms.PropertyGrid.CreatePropertyTab(System.Type! tabType) -> System.Windows.Forms.Design.PropertyTab? virtual System.Windows.Forms.PropertyGrid.DefaultTabType.get -> System.Type! virtual System.Windows.Forms.PropertyGrid.HelpVisible.get -> bool virtual System.Windows.Forms.PropertyGrid.HelpVisible.set -> void +virtual System.Windows.Forms.PropertyGrid.OnPropertySortChanged(System.EventArgs! e) -> void +virtual System.Windows.Forms.PropertyGrid.OnPropertyTabChanged(System.Windows.Forms.PropertyTabChangedEventArgs! e) -> void +virtual System.Windows.Forms.PropertyGrid.OnPropertyValueChanged(System.Windows.Forms.PropertyValueChangedEventArgs! e) -> void +virtual System.Windows.Forms.PropertyGrid.OnSelectedGridItemChanged(System.Windows.Forms.SelectedGridItemChangedEventArgs! e) -> void +virtual System.Windows.Forms.PropertyGrid.OnSelectedObjectsChanged(System.EventArgs! e) -> void +virtual System.Windows.Forms.PropertyGrid.ShowPropertyPageImage.get -> System.Drawing.Bitmap! +virtual System.Windows.Forms.PropertyGrid.SortByCategoryImage.get -> System.Drawing.Bitmap! +virtual System.Windows.Forms.PropertyGrid.SortByPropertyImage.get -> System.Drawing.Bitmap! virtual System.Windows.Forms.PropertyGrid.ToolbarVisible.get -> bool virtual System.Windows.Forms.PropertyGrid.ToolbarVisible.set -> void virtual System.Windows.Forms.RadioButton.OnCheckedChanged(System.EventArgs! e) -> void From dd5ae276be5f5e8c2203fd5f07bdc725a9891945 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Fri, 23 Feb 2024 11:35:55 -0800 Subject: [PATCH 28/30] Update Pre-Release Iteration and Resource Management Milestone (#10942) Update pre-release iteration and resource management --- .github/policies/resourceManagement.yml | 2 +- eng/Versions.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml index 4723b0d28e9..4f48c6ed37f 100644 --- a/.github/policies/resourceManagement.yml +++ b/.github/policies/resourceManagement.yml @@ -194,7 +194,7 @@ configuration: isRegex: False then: - addMilestone: - milestone: 9.0 Preview2 + milestone: 9.0 Preview3 description: Apply milestone to PRs on the main branch triggerOnOwnActions: true - if: diff --git a/eng/Versions.props b/eng/Versions.props index 3753a3c6ba3..e1ce780c460 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -6,7 +6,7 @@ 0 preview - 2 + 3 $(MajorVersion).$(MinorVersion).$(PatchVersion) false From 1f24b7ccf3b21afc676f4cc344f54a2d6d9473de Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 09:17:30 -0800 Subject: [PATCH 29/30] [main] Update dependencies from dotnet/runtime (#10948) * Update dependencies from https://github.com/dotnet/runtime build 20240224.1 Microsoft.Internal.Runtime.WindowsDesktop.Transport , Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.ILAsm , Microsoft.NETCore.ILDAsm , Microsoft.NETCore.Platforms , Microsoft.Win32.Registry.AccessControl , Microsoft.Win32.SystemEvents , runtime.win-x64.Microsoft.NETCore.ILAsm , runtime.win-x86.Microsoft.NETCore.ILAsm , System.CodeDom , System.ComponentModel.Composition , System.ComponentModel.Composition.Registration , System.Configuration.ConfigurationManager , System.Data.Odbc , System.Data.OleDb , System.Diagnostics.EventLog , System.Diagnostics.PerformanceCounter , System.DirectoryServices , System.DirectoryServices.AccountManagement , System.DirectoryServices.Protocols , System.IO.Hashing , System.IO.Packaging , System.IO.Ports , System.Management , System.Reflection.Context , System.Reflection.MetadataLoadContext , System.Resources.Extensions , System.Runtime.Caching , System.Security.Cryptography.Pkcs , System.Security.Cryptography.ProtectedData , System.Security.Cryptography.Xml , System.Security.Permissions , System.ServiceModel.Syndication , System.ServiceProcess.ServiceController , System.Speech , System.Text.Encoding.CodePages , System.Text.Encodings.Web , System.Text.Json , System.Threading.AccessControl , System.Windows.Extensions , VS.Redist.Common.NetCore.SharedFramework.x64.9.0 From Version 9.0.0-preview.2.24122.9 -> To Version 9.0.0-preview.2.24124.1 * Update dependencies from https://github.com/dotnet/runtime build 20240224.2 Microsoft.Internal.Runtime.WindowsDesktop.Transport , Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.ILAsm , Microsoft.NETCore.ILDAsm , Microsoft.NETCore.Platforms , Microsoft.Win32.Registry.AccessControl , Microsoft.Win32.SystemEvents , runtime.win-x64.Microsoft.NETCore.ILAsm , runtime.win-x86.Microsoft.NETCore.ILAsm , System.CodeDom , System.ComponentModel.Composition , System.ComponentModel.Composition.Registration , System.Configuration.ConfigurationManager , System.Data.Odbc , System.Data.OleDb , System.Diagnostics.EventLog , System.Diagnostics.PerformanceCounter , System.DirectoryServices , System.DirectoryServices.AccountManagement , System.DirectoryServices.Protocols , System.IO.Hashing , System.IO.Packaging , System.IO.Ports , System.Management , System.Reflection.Context , System.Reflection.MetadataLoadContext , System.Resources.Extensions , System.Runtime.Caching , System.Security.Cryptography.Pkcs , System.Security.Cryptography.ProtectedData , System.Security.Cryptography.Xml , System.Security.Permissions , System.ServiceModel.Syndication , System.ServiceProcess.ServiceController , System.Speech , System.Text.Encoding.CodePages , System.Text.Encodings.Web , System.Text.Json , System.Threading.AccessControl , System.Windows.Extensions , VS.Redist.Common.NetCore.SharedFramework.x64.9.0 From Version 9.0.0-preview.2.24122.9 -> To Version 9.0.0-preview.2.24124.2 * Update dependencies from https://github.com/dotnet/runtime build 20240226.1 Microsoft.Internal.Runtime.WindowsDesktop.Transport , Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.ILAsm , Microsoft.NETCore.ILDAsm , Microsoft.NETCore.Platforms , Microsoft.Win32.Registry.AccessControl , Microsoft.Win32.SystemEvents , runtime.win-x64.Microsoft.NETCore.ILAsm , runtime.win-x86.Microsoft.NETCore.ILAsm , System.CodeDom , System.ComponentModel.Composition , System.ComponentModel.Composition.Registration , System.Configuration.ConfigurationManager , System.Data.Odbc , System.Data.OleDb , System.Diagnostics.EventLog , System.Diagnostics.PerformanceCounter , System.DirectoryServices , System.DirectoryServices.AccountManagement , System.DirectoryServices.Protocols , System.IO.Hashing , System.IO.Packaging , System.IO.Ports , System.Management , System.Reflection.Context , System.Reflection.MetadataLoadContext , System.Resources.Extensions , System.Runtime.Caching , System.Security.Cryptography.Pkcs , System.Security.Cryptography.ProtectedData , System.Security.Cryptography.Xml , System.Security.Permissions , System.ServiceModel.Syndication , System.ServiceProcess.ServiceController , System.Speech , System.Text.Encoding.CodePages , System.Text.Encodings.Web , System.Text.Json , System.Threading.AccessControl , System.Windows.Extensions , VS.Redist.Common.NetCore.SharedFramework.x64.9.0 From Version 9.0.0-preview.2.24122.9 -> To Version 9.0.0-preview.3.24126.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 172 ++++++++++++++++++++-------------------- eng/Versions.props | 54 ++++++------- global.json | 2 +- 3 files changed, 114 insertions(+), 114 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ca1252f2ce7..1d261204504 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,178 +7,178 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 52c14fb8d01ddd293a0710642aa1e7ef3a438687 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 diff --git a/eng/Versions.props b/eng/Versions.props index e1ce780c460..433c557dcfa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,35 +15,35 @@ - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 5.0.0-preview.7.20320.5 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 6.0.0 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 - 9.0.0-preview.2.24122.9 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.1 diff --git a/global.json b/global.json index 30cfd572afe..6656f05d51e 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "Microsoft.DotNet.CMake.Sdk": "9.0.0-beta.24114.1", "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24114.1", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24122.9" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.3.24126.1" }, "native-tools": { "cmake": "latest" From bddaf6672d6db7a79bf3d827a36c251f099a3258 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 26 Feb 2024 14:22:22 -0800 Subject: [PATCH 30/30] Fix some trim warnings in DesignerHost (#10943) Annotations on these methods should match those on `IReflect`, otherwise this produces warnings in a blank trimmed winforms app. The `DesignerHost` code is unused, but this still produces warnings due to https://github.com/dotnet/runtime/issues/98870. In any case, annotating these methods seems like the right way to annotate this code in `DesignerHost`. --- .../ComponentModel/Design/DesignerHost.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerHost.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerHost.cs index 8036a4f2803..5061281428a 100644 --- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerHost.cs +++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignerHost.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; @@ -1267,6 +1267,7 @@ bool IDesignerLoaderHost2.IgnoreErrorsDuringReload /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] MethodInfo? IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder? binder, Type[] types, ParameterModifier[]? modifiers) { return typeof(IDesignerHost).GetMethod(name, bindingAttr, binder, types, modifiers); @@ -1275,6 +1276,7 @@ bool IDesignerLoaderHost2.IgnoreErrorsDuringReload /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] MethodInfo? IReflect.GetMethod(string name, BindingFlags bindingAttr) { return typeof(IDesignerHost).GetMethod(name, bindingAttr); @@ -1283,6 +1285,7 @@ bool IDesignerLoaderHost2.IgnoreErrorsDuringReload /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { return typeof(IDesignerHost).GetMethods(bindingAttr); @@ -1291,6 +1294,7 @@ MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] FieldInfo? IReflect.GetField(string name, BindingFlags bindingAttr) { return typeof(IDesignerHost).GetField(name, bindingAttr); @@ -1299,6 +1303,7 @@ MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { return typeof(IDesignerHost).GetFields(bindingAttr); @@ -1307,6 +1312,7 @@ FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] PropertyInfo? IReflect.GetProperty(string name, BindingFlags bindingAttr) { return typeof(IDesignerHost).GetProperty(name, bindingAttr); @@ -1315,6 +1321,7 @@ FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] PropertyInfo? IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder? binder, Type? returnType, Type[] types, ParameterModifier[]? modifiers) { return typeof(IDesignerHost).GetProperty(name, bindingAttr, binder, returnType, types, modifiers); @@ -1323,14 +1330,23 @@ FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { return typeof(IDesignerHost).GetProperties(bindingAttr); } + internal const DynamicallyAccessedMemberTypes GetAllMembers = DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields | + DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | + DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents | + DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties | + DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | + DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; + /// /// IReflect implementation to map DesignerHost to IDesignerHost. This helps keep us private. /// + [DynamicallyAccessedMembers(GetAllMembers)] MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { return typeof(IDesignerHost).GetMember(name, bindingAttr);