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/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/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 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index bf529cff234..1d261204504 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,205 +7,205 @@ Note: if the Uri is a new place, you will need to add a subscription from that p --> - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + https://github.com/dotnet/runtime - 963626276e11bf5587aaed69826b62682b05d9c4 + c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4 - + 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..433c557dcfa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -6,7 +6,7 @@ 0 preview - 2 + 3 $(MajorVersion).$(MinorVersion).$(PatchVersion) false @@ -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.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.24115.1 - 9.0.0-preview.2.24115.1 + 9.0.0-preview.3.24126.1 + 9.0.0-preview.3.24126.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.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 @@ -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 @@ -103,6 +103,7 @@ $(MicrosoftCodeAnalysisAnalyzersVersion) 8.0.0-preview.23327.3 1.2.0-beta.507 + 6.3.4 diff --git a/global.json b/global.json index eca3d4a3a5a..6656f05d51e 100644 --- a/global.json +++ b/global.json @@ -14,11 +14,11 @@ "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" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.3.24126.1" }, "native-tools": { "cmake": "latest" 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.Drawing.Common/src/GlobalUsings.cs b/src/System.Drawing.Common/src/GlobalUsings.cs index 9b5ed3dc48b..c7e6245d339 100644 --- a/src/System.Drawing.Common/src/GlobalUsings.cs +++ b/src/System.Drawing.Common/src/GlobalUsings.cs @@ -18,12 +18,15 @@ 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; 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..edb7b1421e7 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,7 @@ LevelsParams PALETTEENTRY PaletteFlags PaletteType -PixelFormat* +PathPointType 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..3e2069f9cc5 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); @@ -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/Drawing2D/GraphicsPath.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.cs index 5165a26ba42..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(); @@ -494,40 +658,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(); } @@ -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/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/Graphics.cs b/src/System.Drawing.Common/src/System/Drawing/Graphics.cs index 8c45cb461db..a90946bac8b 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 @@ -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) { @@ -1114,19 +1220,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 @@ -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); - public void FillClosedCurve(Brush brush, Point[] points, Drawing2D.FillMode fillmode, float tension) +#if NET9_0_OR_GREATER + /// + public void FillClosedCurve(Brush brush, ReadOnlySpan points, FillMode fillmode) => + FillClosedCurve(brush, points, fillmode, 0.5f); + +#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) { @@ -3366,7 +3605,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, srcRect: default, transform: default, GraphicsUnit.Pixel, imageAttr: 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 +3636,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/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/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/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/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.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/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/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.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(); } 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.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/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/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.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.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 @@ + 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.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/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.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); 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.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; +} 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/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.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/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/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/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 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/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) 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/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..13aab3c9f86 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) { - // Valid values are 0x0 to 0x4 - SourceGenerated.EnumValidator.Validate(value); + return; + } - // Check if the value is either center, stretch or zoom; - if (value == ImageLayout.Center || value == ImageLayout.Zoom || value == ImageLayout.Stretch) - { - SetStyle(ControlStyles.ResizeRedraw, true); + // Valid values are 0x0 to 0x4 + SourceGenerated.EnumValidator.Validate(value); - // Only for images that support transparency. - if (ControlPaint.IsImageTransparent(BackgroundImage)) - { - DoubleBuffered = true; - } - } + // Check if the value is either center, stretch or zoom; + if (value is ImageLayout.Center or ImageLayout.Zoom or ImageLayout.Stretch) + { + SetStyle(ControlStyles.ResizeRedraw, true); - Properties.SetObject(s_backgroundImageLayoutProperty, value); - OnBackgroundImageLayoutChanged(EventArgs.Empty); + // Only for images that support transparency. + if (ControlPaint.IsImageTransparent(BackgroundImage)) + { + DoubleBuffered = true; + } } + + 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 { @@ -5205,7 +5177,7 @@ public DragDropEffects DoDragDrop( Point cursorOffset, bool useDefaultDragImage) { - ComTypes.IDataObject dataObject = PrepareIncomingDragData(data); + ComTypes.IDataObject dataObject = CreateRuntimeDataObjectForDrag(data); DROPEFFECT finalEffect; @@ -5231,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) { @@ -5377,18 +5324,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 +5536,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 +5547,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 +5722,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 +5942,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 +6437,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 +6580,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 +6591,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 +6608,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 +6894,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 +8513,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 +8534,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 +8546,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 +8613,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 +9081,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 +9204,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 +9216,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 +9274,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 +9295,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 +9480,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 +9504,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 +9916,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 +9944,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 +9956,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 +10048,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 +10058,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 +10344,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 +10606,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 +10682,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 +11760,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 +13475,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/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/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/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/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/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/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/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) + ]); } } } 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/Controls/TreeView/TreeNode.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeNode.cs index 3a403eac303..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() { @@ -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 @@ -1684,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 7b95d2b739b..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) { @@ -2096,31 +2093,34 @@ 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); } } /// - /// 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) { _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; + } + ToggleState newState = nodeAccessibleObject.ToggleState; ToggleState oldState = newState == ToggleState.ToggleState_On ? ToggleState.ToggleState_Off @@ -2134,24 +2134,22 @@ 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) { _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); @@ -2159,24 +2157,22 @@ 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) { _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); @@ -2184,40 +2180,39 @@ 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) { _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; + } + nodeAccessibleObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); nodeAccessibleObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_SelectionItem_ElementSelectedEventId); @@ -2230,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 @@ -2373,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; } /// @@ -2433,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; @@ -2455,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) @@ -2484,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); @@ -2514,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) @@ -2846,14 +2837,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); } } } @@ -3094,7 +3085,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); } } @@ -3105,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) { @@ -3452,7 +3443,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 => 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/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/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/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); } 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/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/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/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/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); + } +} 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); + } + } +} 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; } 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() { 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/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/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 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 } 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; } 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 }; } 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);