diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs
index 8ddeca197af..0a0775a18a5 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs
@@ -716,35 +716,48 @@ internal static void SetMode(ConsoleHandle consoleHandle, ConsoleModes mode)
///
///
/// Handle to the console device returned by GetInputHandle
- ///
- /// Initial contents of the edit buffer, if any. charactersToRead should be at least as large as the length of this string.
+ ///
+ /// Length of initial content of the edit buffer. Zero if no initial content exists.
+ /// Must be less than editBuffer length.
+ ///
+ ///
+ /// Edit buffer with optional initial content.
+ /// Caution! Last position in the edit buffer is for a null in native code.
///
///
/// Number of characters to read from the device.
+ /// Must be less than editBuffer length.
///
///
- /// true to allow the user to terminate input by hitting the tab or shift-tab key, in addition to the enter key
+ /// True to allow the user to terminate input by hitting the tab or shift-tab key, in addition to the enter key
///
///
- /// bit mask indicating the state of the control/shift keys at the point input was terminated.
+ /// Bit mask indicating the state of the control/shift keys at the point input was terminated.
+ ///
///
///
///
/// If Win32's ReadConsole fails
///
- internal static string ReadConsole(ConsoleHandle consoleHandle, string initialContent,
- int charactersToRead, bool endOnTab, out uint keyState)
+ internal static string ReadConsole(
+ ConsoleHandle consoleHandle,
+ int initialContentLength,
+ Span editBuffer,
+ int charactersToRead,
+ bool endOnTab,
+ out uint keyState)
{
Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
- Dbg.Assert(initialContent != null, "if no initial content is desired, pass string.Empty");
+ Dbg.Assert(initialContentLength < editBuffer.Length, "initialContentLength must be less than editBuffer.Length");
+ Dbg.Assert(charactersToRead < editBuffer.Length, "charactersToRead must be less than editBuffer.Length");
keyState = 0;
CONSOLE_READCONSOLE_CONTROL control = new CONSOLE_READCONSOLE_CONTROL();
control.nLength = (ULONG)Marshal.SizeOf(control);
- control.nInitialChars = (ULONG)initialContent.Length;
+ control.nInitialChars = (ULONG)initialContentLength;
control.dwControlKeyState = 0;
if (endOnTab)
{
@@ -753,28 +766,34 @@ internal static string ReadConsole(ConsoleHandle consoleHandle, string initialCo
control.dwCtrlWakeupMask = (1 << TAB);
}
- DWORD charsReadUnused = 0;
- StringBuilder buffer = new StringBuilder(initialContent, charactersToRead);
+ DWORD charsReaded = 0;
+
bool result =
NativeMethods.ReadConsole(
consoleHandle.DangerousGetHandle(),
- buffer,
+ editBuffer,
(DWORD)charactersToRead,
- out charsReadUnused,
+ out charsReaded,
ref control);
keyState = control.dwControlKeyState;
if (result == false)
{
int err = Marshal.GetLastWin32Error();
- HostException e = CreateHostException(err, "ReadConsole",
- ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleExceptionTemplate);
+ HostException e = CreateHostException(
+ err,
+ "ReadConsole",
+ ErrorCategory.ReadError,
+ ConsoleControlStrings.ReadConsoleExceptionTemplate);
throw e;
}
- if (charsReadUnused > (uint)buffer.Length)
- charsReadUnused = (uint)buffer.Length;
- return buffer.ToString(0, (int)charsReadUnused);
+ if (charsReaded > (uint)charactersToRead)
+ {
+ charsReaded = (uint)charactersToRead;
+ }
+
+ return editBuffer.Slice(0, (int)charsReaded).ToString();
}
///
@@ -3019,15 +3038,30 @@ IntPtr reserved
[DllImport(PinvokeDllNames.ReadConsoleDllName, SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool ReadConsole
+ private static extern unsafe bool ReadConsole
(
NakedWin32Handle consoleInput,
- StringBuilder buffer,
+ char* lpBuffer,
DWORD numberOfCharsToRead,
out DWORD numberOfCharsRead,
ref CONSOLE_READCONSOLE_CONTROL controlData
);
+ internal static unsafe bool ReadConsole
+ (
+ NakedWin32Handle consoleInput,
+ Span buffer,
+ DWORD numberOfCharsToRead,
+ out DWORD numberOfCharsRead,
+ ref CONSOLE_READCONSOLE_CONTROL controlData
+ )
+ {
+ fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer))
+ {
+ return ReadConsole(consoleInput, bufferPtr, numberOfCharsToRead, out numberOfCharsRead, ref controlData);
+ }
+ }
+
[DllImport(PinvokeDllNames.PeekConsoleInputDllName, SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PeekConsoleInput
diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs
index d735428d1eb..bc8fa54f8a3 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs
@@ -307,8 +307,9 @@ private object ReadLineSafe(bool isSecureString, char? printToken)
#if UNIX
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
#else
- uint unused = 0;
- string key = ConsoleControl.ReadConsole(handle, string.Empty, 1, false, out unused);
+ const int CharactersToRead = 1;
+ Span inputBuffer = stackalloc char[CharactersToRead + 1];
+ string key = ConsoleControl.ReadConsole(handle, initialContentLength: 0, inputBuffer, charactersToRead: CharactersToRead, endOnTab: false, out _);
#endif
#if UNIX
@@ -1287,7 +1288,7 @@ internal enum ReadLineResult
endedOnBreak = 3
}
- private const int maxInputLineLength = 8192;
+ private const int MaxInputLineLength = 1024;
///
/// Reads a line of input from the console. Returns when the user hits enter, a break key, a break event occurs. In
@@ -1468,13 +1469,19 @@ private string ReadLineFromConsole(bool endOnTab, string initialContent, bool ca
_rawui.ClearKeyCache();
uint keyState = 0;
string s = string.Empty;
+ Span inputBuffer = stackalloc char[MaxInputLineLength + 1];
+ if (initialContent.Length > 0)
+ {
+ initialContent.AsSpan().CopyTo(inputBuffer);
+ }
+
#endif
do
{
#if UNIX
keyInfo = Console.ReadKey(true);
#else
- s += ConsoleControl.ReadConsole(handle, initialContent, maxInputLineLength, endOnTab, out keyState);
+ s += ConsoleControl.ReadConsole(handle, initialContent.Length, inputBuffer, MaxInputLineLength, endOnTab, out keyState);
Dbg.Assert(s != null, "s should never be null");
#endif
@@ -1861,9 +1868,9 @@ internal string ReadLineWithTabCompletion(Executor exec)
completedInput += restOfLine;
}
- if (completedInput.Length > (maxInputLineLength - 2))
+ if (completedInput.Length > (MaxInputLineLength - 2))
{
- completedInput = completedInput.Substring(0, maxInputLineLength - 2);
+ completedInput = completedInput.Substring(0, MaxInputLineLength - 2);
}
// Remove any nulls from the string...