diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Kernel32/Interop.FormatMessageW.cs b/src/System.Windows.Forms.Primitives/src/Interop/Kernel32/Interop.FormatMessageW.cs index 3683268d59b..0866f07d07a 100644 --- a/src/System.Windows.Forms.Primitives/src/Interop/Kernel32/Interop.FormatMessageW.cs +++ b/src/System.Windows.Forms.Primitives/src/Interop/Kernel32/Interop.FormatMessageW.cs @@ -3,21 +3,18 @@ // See the LICENSE file in the project root for more information. using System.Runtime.InteropServices; -using System.Text; internal partial class Interop { internal partial class Kernel32 { [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] - public static extern uint FormatMessageW( + public static extern unsafe uint FormatMessageW( FormatMessageOptions dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, -#pragma warning disable CA1838 // Avoid 'StringBuilder' parameters for P/Invokes - StringBuilder lpBuffer, -#pragma warning restore CA1838 // Avoid 'StringBuilder' parameters for P/Invokes + char* lpBuffer, int nSize, IntPtr arguments); } diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.DragQueryFileW.cs b/src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.DragQueryFileW.cs index d9272e898a5..9665786c7e4 100644 --- a/src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.DragQueryFileW.cs +++ b/src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.DragQueryFileW.cs @@ -3,45 +3,39 @@ // See the LICENSE file in the project root for more information. using System.Runtime.InteropServices; -using System.Text; internal static partial class Interop { internal static partial class Shell32 { [DllImport(Libraries.Shell32, ExactSpelling = true, EntryPoint = "DragQueryFileW", CharSet = CharSet.Unicode)] -#pragma warning disable CA1838 // Avoid 'StringBuilder' parameters for P/Invokes - private static extern uint DragQueryFileWInternal(IntPtr hDrop, uint iFile, StringBuilder? lpszFile, uint cch); -#pragma warning restore CA1838 // Avoid 'StringBuilder' parameters for P/Invokes + private static extern unsafe uint DragQueryFileWInternal(IntPtr hDrop, uint iFile, char* lpszFile, uint cch); - public static uint DragQueryFileW(IntPtr hDrop, uint iFile, StringBuilder? lpszFile) + public static unsafe uint DragQueryFileW(IntPtr hDrop, uint iFile, ref string? lpszFile) { - if (lpszFile is null || lpszFile.Capacity == 0 || iFile == 0xFFFFFFFF) + if (lpszFile is null || iFile == 0xFFFFFFFF) { + lpszFile = string.Empty; return DragQueryFileWInternal(hDrop, iFile, null, 0); } uint resultValue = 0; + uint capacity; - // iterating by allocating chunk of memory each time we find the length is not sufficient. - // Performance should not be an issue for current MAX_PATH length due to this - if ((resultValue = DragQueryFileWInternal(hDrop, iFile, lpszFile, (uint)lpszFile.Capacity)) == lpszFile.Capacity) + // passing null for buffer will return actual number of characters in the file name. + // So, one extra call would be suffice to avoid while loop in case of long path. + if ((capacity = DragQueryFileWInternal(hDrop, iFile, null, 0)) < Kernel32.MAX_UNICODESTRING_LEN) { - // passing null for buffer will return actual number of characters in the file name. - // So, one extra call would be suffice to avoid while loop in case of long path. - uint capacity = DragQueryFileWInternal(hDrop, iFile, null, 0); - if (capacity < Kernel32.MAX_UNICODESTRING_LEN) + Span charSpan = new char[(int)capacity]; + fixed (char* pCharSpan = charSpan) { - lpszFile.EnsureCapacity((int)capacity); - resultValue = DragQueryFileWInternal(hDrop, iFile, lpszFile, (uint)capacity); - } - else - { - resultValue = 0; + resultValue = DragQueryFileWInternal(hDrop, iFile, pCharSpan, capacity); } + + // Set lpszFile to the buffer's data. + lpszFile = charSpan.Slice(0, (int)resultValue).SliceAtFirstNull().ToString(); } - lpszFile.Length = (int)resultValue; return resultValue; } } diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Shlwapi/Interop.SHLoadIndirectString.cs b/src/System.Windows.Forms.Primitives/src/Interop/Shlwapi/Interop.SHLoadIndirectString.cs index 43919239511..0b269d02ca4 100644 --- a/src/System.Windows.Forms.Primitives/src/Interop/Shlwapi/Interop.SHLoadIndirectString.cs +++ b/src/System.Windows.Forms.Primitives/src/Interop/Shlwapi/Interop.SHLoadIndirectString.cs @@ -3,15 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Runtime.InteropServices; -using System.Text; internal static partial class Interop { internal static partial class Shlwapi { [DllImport(Libraries.Shlwapi, ExactSpelling = true, CharSet = CharSet.Unicode)] -#pragma warning disable CA1838 // Avoid 'StringBuilder' parameters for P/Invokes - public static extern HRESULT SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved); -#pragma warning restore CA1838 // Avoid 'StringBuilder' parameters for P/Invokes + public static extern unsafe HRESULT SHLoadIndirectString(string pszSource, char* psZOutBuf, uint cchOutBuf, IntPtr ppvReserved); } } diff --git a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs b/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs index 58fa2388d64..4810bd13286 100644 --- a/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs +++ b/src/System.Windows.Forms.Primitives/src/System/Windows/Forms/Internals/UnsafeNativeMethods.cs @@ -2,18 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.ComponentModel; using System.Runtime.InteropServices; -using System.Text; using static Interop; namespace System.Windows.Forms { internal static class UnsafeNativeMethods { - [DllImport(Libraries.User32)] -#pragma warning disable CA1838 // Avoid 'StringBuilder' parameters for P/Invokes - public static extern int GetClassName(HandleRef hwnd, StringBuilder lpClassName, int nMaxCount); -#pragma warning restore CA1838 // Avoid 'StringBuilder' parameters for P/Invokes + [DllImport(Libraries.User32, CharSet = CharSet.Unicode)] + public static extern unsafe int GetClassName(HandleRef hwnd, char* lpClassName, int nMaxCount); [DllImport(Libraries.Comdlg32, SetLastError = true, CharSet = CharSet.Auto)] public static extern HRESULT PrintDlgEx([In, Out] NativeMethods.PRINTDLGEX lppdex); @@ -22,39 +20,47 @@ internal static class UnsafeNativeMethods public static extern bool GetOpenFileName([In, Out] NativeMethods.OPENFILENAME_I ofn); [DllImport(Libraries.Kernel32, CharSet = CharSet.Auto, SetLastError = true)] -#pragma warning disable CA1838 // Avoid 'StringBuilder' parameters for P/Invokes - public static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length); -#pragma warning restore CA1838 // Avoid 'StringBuilder' parameters for P/Invokes + public static extern unsafe int GetModuleFileName(HandleRef hModule, char* buffer, int length); - public static StringBuilder GetModuleFileNameLongPath(HandleRef hModule) + public static unsafe string GetModuleFileNameLongPath(HandleRef hModule) { - StringBuilder buffer = new StringBuilder(Kernel32.MAX_PATH); + Span buffer = new char[Kernel32.MAX_PATH]; int noOfTimes = 1; - int length = 0; + int length; + int error = 0; + // Iterating by allocating chunk of memory each time we find the length is not sufficient. // Performance should not be an issue for current MAX_PATH length due to this change. - while (((length = GetModuleFileName(hModule, buffer, buffer.Capacity)) == buffer.Capacity) - && Marshal.GetLastWin32Error() == ERROR.INSUFFICIENT_BUFFER - && buffer.Capacity < Kernel32.MAX_UNICODESTRING_LEN) + while (((length = GetModuleFileName(hModule, buffer)) == buffer.Length) + && (error = Marshal.GetLastWin32Error()) == ERROR.INSUFFICIENT_BUFFER + && buffer.Length < Kernel32.MAX_UNICODESTRING_LEN) { noOfTimes += 2; // Increasing buffer size by 520 in each iteration. int capacity = noOfTimes * Kernel32.MAX_PATH < Kernel32.MAX_UNICODESTRING_LEN ? noOfTimes * Kernel32.MAX_PATH : Kernel32.MAX_UNICODESTRING_LEN; - buffer.EnsureCapacity(capacity); + buffer = new char[capacity]; } - buffer.Length = length; - return buffer; + if (error == ERROR.INSUFFICIENT_BUFFER) + { + // probably should localize this. + throw new Win32Exception("Error getting the module file names."); + } + + return buffer.Slice(0, length).SliceAtFirstNull().ToString(); } [DllImport(Libraries.Comdlg32, SetLastError = true, CharSet = CharSet.Auto)] public static extern bool GetSaveFileName([In, Out] NativeMethods.OPENFILENAME_I ofn); - [DllImport(Libraries.Kernel32, CharSet = CharSet.Auto)] -#pragma warning disable CA1838 // Avoid 'StringBuilder' parameters for P/Invokes - public static extern void GetTempFileName(string tempDirName, string prefixName, int unique, StringBuilder sb); -#pragma warning restore CA1838 // Avoid 'StringBuilder' parameters for P/Invokes - [DllImport(Libraries.Oleacc, ExactSpelling = true, CharSet = CharSet.Auto)] public static extern int CreateStdAccessibleObject(HandleRef hWnd, int objID, ref Guid refiid, [In, Out, MarshalAs(UnmanagedType.Interface)] ref object? pAcc); + + private static unsafe int GetModuleFileName(HandleRef hModule, Span buffer) + { + fixed (char* pBuffer = buffer) + { + return GetModuleFileName(hModule, pBuffer, buffer.Length); + } + } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs index af304baf2a7..1377bf9a92e 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs @@ -289,8 +289,8 @@ public static string ExecutablePath { if (s_executablePath is null) { - StringBuilder sb = UnsafeNativeMethods.GetModuleFileNameLongPath(NativeMethods.NullHandleRef); - s_executablePath = Path.GetFullPath(sb.ToString()); + string path = UnsafeNativeMethods.GetModuleFileNameLongPath(NativeMethods.NullHandleRef); + s_executablePath = Path.GetFullPath(path); } return s_executablePath; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.AutoCompleteDropDownFinder.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.AutoCompleteDropDownFinder.cs index 9f4f016b5e1..8a5dd53b8d6 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.AutoCompleteDropDownFinder.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.AutoCompleteDropDownFinder.cs @@ -2,8 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.ComponentModel; using System.Runtime.InteropServices; -using System.Text; using static Interop; using static Interop.User32; @@ -16,7 +16,6 @@ public partial class ComboBox /// private class AutoCompleteDropDownFinder { - private const int MaxClassName = 256; private const string AutoCompleteClassName = "Auto-Suggest Dropdown"; private bool _shouldSubClass; @@ -53,11 +52,20 @@ private BOOL Callback(IntPtr hWnd) return BOOL.TRUE; } - static string GetClassName(HandleRef hRef) + private static unsafe string GetClassName(HandleRef hRef) { - StringBuilder sb = new StringBuilder(MaxClassName); - UnsafeNativeMethods.GetClassName(hRef, sb, MaxClassName); - return sb.ToString(); + Span buffer = stackalloc char[256]; + fixed (char* valueChars = buffer) + { + int result = UnsafeNativeMethods.GetClassName(hRef, valueChars, buffer.Length); + if (result == 0) + { + // probably should localize this. + throw new Win32Exception("Failed to get window class name."); + } + } + + return buffer.SliceAtFirstNull().ToString(); } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ComponentModel/COM2Interop/COM2PropertyDescriptor.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ComponentModel/COM2Interop/COM2PropertyDescriptor.cs index 74fa055349d..acaa13f476c 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ComponentModel/COM2Interop/COM2PropertyDescriptor.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ComponentModel/COM2Interop/COM2PropertyDescriptor.cs @@ -11,7 +11,6 @@ using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; -using System.Text; using static Interop; using static Interop.Ole32; @@ -1323,24 +1322,27 @@ public unsafe override void SetValue(object component, object value) } else if (errorInfo is null) { - StringBuilder strMessage = new StringBuilder(256); - - uint result = Kernel32.FormatMessageW( - Kernel32.FormatMessageOptions.FROM_SYSTEM | Kernel32.FormatMessageOptions.IGNORE_INSERTS, - IntPtr.Zero, - (uint)hr, - Kernel32.GetThreadLocale().RawValue, - strMessage, - 255, - IntPtr.Zero); - - if (result == 0) + Span buffer = stackalloc char[256]; + fixed (char* valueChars = buffer) { - errorInfo = string.Format(CultureInfo.CurrentCulture, string.Format(SR.DispInvokeFailed, "SetValue", hr)); - } - else - { - errorInfo = TrimNewline(strMessage); + uint length = Kernel32.FormatMessageW( + Kernel32.FormatMessageOptions.FROM_SYSTEM | + Kernel32.FormatMessageOptions.IGNORE_INSERTS, + IntPtr.Zero, + (uint)hr, + Kernel32.GetThreadLocale().RawValue, + valueChars, + buffer.Length, + IntPtr.Zero); + if (length == 0) + { + errorInfo = string.Format(CultureInfo.CurrentCulture, + string.Format(SR.DispInvokeFailed, "SetValue", hr)); + } + else + { + errorInfo = TrimNewline(buffer.Slice(0, (int)length).SliceAtFirstNull().ToString()); + } } } @@ -1348,7 +1350,7 @@ public unsafe override void SetValue(object component, object value) } } - private static string TrimNewline(StringBuilder errorInfo) + private static string TrimNewline(string errorInfo) { int index = errorInfo.Length - 1; while (index >= 0 && (errorInfo[index] == '\n' || errorInfo[index] == '\r')) @@ -1356,7 +1358,7 @@ private static string TrimNewline(StringBuilder errorInfo) index--; } - return errorInfo.ToString(0, index + 1); + return errorInfo.Substring(0, index + 1); } /// 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 3b944ed1ed3..6936b280ea8 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -14,7 +14,6 @@ using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; -using System.Text; using System.Windows.Forms.Automation; using System.Windows.Forms.Layout; using Microsoft.Win32; @@ -2502,7 +2501,7 @@ public int Height set => SetBounds(_x, _y, _width, value, BoundsSpecified.Height); } - internal bool HostedInWin32DialogManager + internal unsafe bool HostedInWin32DialogManager { get { @@ -2517,22 +2516,20 @@ internal bool HostedInWin32DialogManager { IntPtr parentHandle = User32.GetParent(this); IntPtr lastParentHandle = parentHandle; - - StringBuilder sb = new StringBuilder(32); - SetState(States.HostedInDialog, false); - + Span buffer = stackalloc char[256]; while (parentHandle != IntPtr.Zero) { - int len = UnsafeNativeMethods.GetClassName(new HandleRef(null, lastParentHandle), null, 0); - if (len > sb.Capacity) + int length = 0; + fixed (char* valueChars = buffer) { - sb.Capacity = len + 5; + length = UnsafeNativeMethods.GetClassName(new HandleRef(null, lastParentHandle), valueChars, buffer.Length); } - UnsafeNativeMethods.GetClassName(new HandleRef(null, lastParentHandle), sb, sb.Capacity); + string result = buffer.Slice(0, length).SliceAtFirstNull().ToString(); - if (sb.ToString() == "#32770") + // class name #32770 + if (result == "#32770") { SetState(States.HostedInDialog, true); break; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataObject.OleConverter.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataObject.OleConverter.cs index f3155cdfcb1..68ecc4e6e41 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataObject.OleConverter.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataObject.OleConverter.cs @@ -391,24 +391,24 @@ private static object ReadObjectFromHandleDeserializer(Stream stream, bool restr /// private static string[]? ReadFileListFromHandle(IntPtr hdrop) { - uint count = Shell32.DragQueryFileW(hdrop, 0xFFFFFFFF, null); + string? fileName = null; + uint count = Shell32.DragQueryFileW(hdrop, 0xFFFFFFFF, ref fileName); if (count == 0) { return null; } - var sb = new StringBuilder(Kernel32.MAX_PATH); var files = new string[count]; for (uint i = 0; i < count; i++) { - uint charlen = Shell32.DragQueryFileW(hdrop, i, sb); - if (charlen == 0) + uint length = Shell32.DragQueryFileW(hdrop, i, ref fileName); + if (length == 0 || string.IsNullOrEmpty(fileName)) { continue; } - string s = sb.ToString(0, (int)charlen); - files[i] = s; + string fullPath = Path.GetFullPath(fileName); + files[i] = fileName; } return files; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/InputLanguage.cs b/src/System.Windows.Forms/src/System/Windows/Forms/InputLanguage.cs index f3d111166e7..cb4a12dce0b 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/InputLanguage.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/InputLanguage.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Text; using Microsoft.Win32; using static Interop; @@ -281,15 +280,18 @@ Look in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\000 /// Returning null from this method will force us to use the legacy codepath (pulling the text /// directly from the registry). /// - private static string? GetLocalizedKeyboardLayoutName(string? layoutDisplayName) + private static unsafe string? GetLocalizedKeyboardLayoutName(string? layoutDisplayName) { if (layoutDisplayName is not null) { - var sb = new StringBuilder(512); - HRESULT res = Shlwapi.SHLoadIndirectString(layoutDisplayName, sb, (uint)sb.Capacity, IntPtr.Zero); - if (res == HRESULT.S_OK) + Span buf = stackalloc char[512]; + fixed (char* valueChars = buf) { - return sb.ToString(); + if (Shlwapi.SHLoadIndirectString(layoutDisplayName, valueChars, (uint)buf.Length, IntPtr.Zero).Succeeded()) + { + string? result = buf.SliceAtFirstNull().ToString(); + return result; + } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs index 19d80d11f42..541816da491 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs @@ -5162,9 +5162,7 @@ private unsafe void SetBackgroundImage() { // save the image to a temporary file name _backgroundImageFileName = Path.GetTempFileName(); - BackgroundImage.Save(_backgroundImageFileName, System.Drawing.Imaging.ImageFormat.Bmp); - lvbkImage.cchImageMax = (uint)(_backgroundImageFileName.Length + 1); lvbkImage.ulFlags = LVBKIF.SOURCE_URL; if (BackgroundImageTiled) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs b/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs index e013755a6be..6a2b178d373 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/RichTextBox.cs @@ -300,8 +300,7 @@ protected override CreateParams CreateParams throw new Win32Exception(lastWin32Error, string.Format(SR.LoadDLLError, richEditControlDllVersion)); } - StringBuilder pathBuilder = UnsafeNativeMethods.GetModuleFileNameLongPath(new HandleRef(null, moduleHandle)); - string path = pathBuilder.ToString(); + string path = UnsafeNativeMethods.GetModuleFileNameLongPath(new HandleRef(null, moduleHandle)); FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(path); Debug.Assert(versionInfo is not null && !string.IsNullOrEmpty(versionInfo.ProductVersion), "Couldn't get the version info for the richedit dll"); @@ -3395,22 +3394,22 @@ internal unsafe void WmReflectNotify(ref Message m) break; case EN.DROPFILES: ENDROPFILES* endropfiles = (ENDROPFILES*)m.LParamInternal; + string path = string.Empty; // Only look at the first file. - var path = new StringBuilder(Kernel32.MAX_PATH); - if (Shell32.DragQueryFileW(endropfiles->hDrop, 0, path) != 0) + if (Shell32.DragQueryFileW(endropfiles->hDrop, 0, ref path) != 0) { // Try to load the file as an RTF try { - LoadFile(path.ToString(), RichTextBoxStreamType.RichText); + LoadFile(path, RichTextBoxStreamType.RichText); } catch { // we failed to load as rich text so try it as plain text try { - LoadFile(path.ToString(), RichTextBoxStreamType.PlainText); + LoadFile(path, RichTextBoxStreamType.PlainText); } catch { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/TaskDialog.cs b/src/System.Windows.Forms/src/System/Windows/Forms/TaskDialog.cs index b2d0f83edcd..a3c27f55432 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/TaskDialog.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/TaskDialog.cs @@ -794,8 +794,7 @@ internal void UpdateCaption(string? caption) if (TaskDialogPage.IsNativeStringNullOrEmpty(caption)) { caption = Path.GetFileName( - UnsafeNativeMethods.GetModuleFileNameLongPath(NativeMethods.NullHandleRef) - .ToString()); + UnsafeNativeMethods.GetModuleFileNameLongPath(NativeMethods.NullHandleRef)); } User32.SetWindowTextW(_handle, caption); diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComponentModel/Com2Interop/Com2PropertyDescriptorTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComponentModel/Com2Interop/Com2PropertyDescriptorTests.cs index 1c3d3b38816..8d2b9bd7419 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComponentModel/Com2Interop/Com2PropertyDescriptorTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComponentModel/Com2Interop/Com2PropertyDescriptorTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Reflection; -using System.Text; using Xunit; namespace System.Windows.Forms.ComponentModel.Com2Interop.Tests @@ -33,7 +32,7 @@ static Com2PropertyDescriptorTests() [InlineData("bla bla bla\r\n\nr\n\r\n\r\n", "bla bla bla\r\n\nr")] public void TrimNewline_should_remove_all_trailing_CR_LF(string message, string expected) { - string result = (string)s_miVersionInfo.Invoke(null, new[] { new StringBuilder(message) }); + string result = (string)s_miVersionInfo.Invoke(null, new[] { message }); Assert.Equal(expected, result); } 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 b730d3b14d8..d6d6a9a52d7 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 @@ -10732,12 +10732,15 @@ private class SubRichTextBox : RichTextBox public new void WndProc(ref Message m) => base.WndProc(ref m); } - private static string GetClassName(IntPtr hWnd) + private static unsafe string GetClassName(IntPtr hWnd) { - const int MaxClassName = 256; - StringBuilder sb = new StringBuilder(MaxClassName); - UnsafeNativeMethods.GetClassName(new HandleRef(null, hWnd), sb, MaxClassName); - return sb.ToString(); + Span buf = stackalloc char[256]; + fixed (char* valueChars = buf) + { + _ = UnsafeNativeMethods.GetClassName(new HandleRef(null, hWnd), valueChars, buf.Length); + } + + return buf.SliceAtFirstNull().ToString(); } ///