From 3f6220e6eb60f87620ae140137bc846f42c392ce Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL)" Date: Tue, 11 May 2021 12:15:20 -0700 Subject: [PATCH 1/4] Handle exception if ConsoleHost tries to set cursor out of bounds because screen buffer changed --- .../host/msh/ConsoleControl.cs | 38 ------------------- .../host/msh/ConsoleHostRawUserInterface.cs | 17 +++++---- .../utils/PInvokeDllNames.cs | 1 - 3 files changed, 9 insertions(+), 47 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs index 7670731fc16..3b78674d89b 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleControl.cs @@ -2818,40 +2818,6 @@ internal static bool IsCJKOutputCodePage(out uint codePage) #region Cursor - /// - /// Wraps Win32 SetConsoleCursorPosition. - /// - /// - /// handle for the console where cursor position is set - /// - /// - /// location to which the cursor will be set - /// - /// - /// If Win32's SetConsoleCursorPosition fails - /// - internal static void SetConsoleCursorPosition(ConsoleHandle consoleHandle, Coordinates cursorPosition) - { - Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); - Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); - - ConsoleControl.COORD c; - - c.X = (short)cursorPosition.X; - c.Y = (short)cursorPosition.Y; - - bool result = NativeMethods.SetConsoleCursorPosition(consoleHandle.DangerousGetHandle(), c); - - if (!result) - { - int err = Marshal.GetLastWin32Error(); - - HostException e = CreateHostException(err, "SetConsoleCursorPosition", - ErrorCategory.ResourceUnavailable, ConsoleControlStrings.SetConsoleCursorPositionExceptionTemplate); - throw e; - } - } - /// /// Wraps Win32 GetConsoleCursorInfo. /// @@ -3159,10 +3125,6 @@ out DWORD numberOfEventsRead [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleCtrlHandler(BreakHandler handlerRoutine, bool add); - [DllImport(PinvokeDllNames.SetConsoleCursorPositionDllName, SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetConsoleCursorPosition(NakedWin32Handle consoleOutput, COORD cursorPosition); - [DllImport(PinvokeDllNames.SetConsoleModeDllName, SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetConsoleMode(NakedWin32Handle consoleHandle, DWORD mode); diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs index 2a6ea89176d..95f4d054053 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs @@ -190,14 +190,15 @@ public override set { - // cursor position can't be outside the buffer area - - ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO bufferInfo; - - ConsoleHandle handle = GetBufferInfo(out bufferInfo); - - CheckCoordinateWithinBuffer(ref value, ref bufferInfo, "value"); - ConsoleControl.SetConsoleCursorPosition(handle, value); + try + { + Console.SetCursorPosition(value.X, value.Y); + } + catch (ArgumentOutOfRangeException) + { + // if screen buffer has changed, we can set it anywhere reasonable as the screen buffer + // might change again, so we ignore this + } } } diff --git a/src/System.Management.Automation/utils/PInvokeDllNames.cs b/src/System.Management.Automation/utils/PInvokeDllNames.cs index 7dd28be8cdd..b562d6ad637 100644 --- a/src/System.Management.Automation/utils/PInvokeDllNames.cs +++ b/src/System.Management.Automation/utils/PInvokeDllNames.cs @@ -116,7 +116,6 @@ internal static class PinvokeDllNames internal const string PeekConsoleInputDllName = "api-ms-win-core-console-l2-1-0.dll"; /*103*/ internal const string GetNumberOfConsoleInputEventsDllName = "api-ms-win-core-console-l1-1-0.dll"; /*104*/ internal const string SetConsoleCtrlHandlerDllName = "api-ms-win-core-console-l1-1-0.dll"; /*105*/ - internal const string SetConsoleCursorPositionDllName = "api-ms-win-core-console-l2-1-0.dll"; /*106*/ internal const string SetConsoleModeDllName = "api-ms-win-core-console-l1-1-0.dll"; /*107*/ internal const string SetConsoleScreenBufferSizeDllName = "api-ms-win-core-console-l2-1-0.dll"; /*108*/ internal const string SetConsoleTextAttributeDllName = "api-ms-win-core-console-l2-1-0.dll"; /*109*/ From af29b17324ba282689b96e2b56600af350e663e6 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 11 May 2021 12:53:29 -0700 Subject: [PATCH 2/4] fix typo in comment so that it makes sense now --- .../host/msh/ConsoleHostRawUserInterface.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs index 95f4d054053..bca63be834b 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs @@ -196,7 +196,7 @@ public override } catch (ArgumentOutOfRangeException) { - // if screen buffer has changed, we can set it anywhere reasonable as the screen buffer + // if screen buffer has changed, we cannot set it anywhere reasonable as the screen buffer // might change again, so we ignore this } } From be29403822248bbe0b88470c9d0e5a925b4e1198 Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL)" Date: Wed, 12 May 2021 12:14:21 -0700 Subject: [PATCH 3/4] address Ilya's feedback to update Get to use Console API and renumber pinvokes --- .../host/msh/ConsoleHostRawUserInterface.cs | 7 +--- .../utils/PInvokeDllNames.cs | 42 +++++++++---------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs index bca63be834b..0cd3d7651cc 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs @@ -181,11 +181,8 @@ public override { get { - ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO bufferInfo; - GetBufferInfo(out bufferInfo); - - Coordinates c = new Coordinates(bufferInfo.CursorPosition.X, bufferInfo.CursorPosition.Y); - return c; + var pos = Console.GetCursorPosition(); + return new Coordinates(pos.Item1, pos.Item2); } set diff --git a/src/System.Management.Automation/utils/PInvokeDllNames.cs b/src/System.Management.Automation/utils/PInvokeDllNames.cs index b562d6ad637..bff2ca2656e 100644 --- a/src/System.Management.Automation/utils/PInvokeDllNames.cs +++ b/src/System.Management.Automation/utils/PInvokeDllNames.cs @@ -116,26 +116,26 @@ internal static class PinvokeDllNames internal const string PeekConsoleInputDllName = "api-ms-win-core-console-l2-1-0.dll"; /*103*/ internal const string GetNumberOfConsoleInputEventsDllName = "api-ms-win-core-console-l1-1-0.dll"; /*104*/ internal const string SetConsoleCtrlHandlerDllName = "api-ms-win-core-console-l1-1-0.dll"; /*105*/ - internal const string SetConsoleModeDllName = "api-ms-win-core-console-l1-1-0.dll"; /*107*/ - internal const string SetConsoleScreenBufferSizeDllName = "api-ms-win-core-console-l2-1-0.dll"; /*108*/ - internal const string SetConsoleTextAttributeDllName = "api-ms-win-core-console-l2-1-0.dll"; /*109*/ - internal const string SetConsoleWindowInfoDllName = "api-ms-win-core-console-l2-1-0.dll"; /*110*/ - internal const string WriteConsoleOutputDllName = "api-ms-win-core-console-l2-1-0.dll"; /*111*/ - internal const string ReadConsoleOutputDllName = "api-ms-win-core-console-l2-1-0.dll"; /*112*/ - internal const string ScrollConsoleScreenBufferDllName = "api-ms-win-core-console-l2-1-0.dll"; /*113*/ - internal const string SendInputDllName = "ext-ms-win-ntuser-keyboard-l1-2-1.dll"; /*114*/ - internal const string GetConsoleCursorInfoDllName = "api-ms-win-core-console-l2-1-0.dll"; /*115*/ - internal const string SetConsoleCursorInfoDllName = "api-ms-win-core-console-l2-1-0.dll"; /*116*/ - internal const string ReadConsoleInputDllName = "api-ms-win-core-console-l1-1-0.dll"; /*117*/ - internal const string GetVersionExDllName = "api-ms-win-core-sysinfo-l1-1-0.dll"; /*118*/ - internal const string FormatMessageDllName = "api-ms-win-core-localization-l1-2-0.dll"; /*119*/ - internal const string CreateToolhelp32SnapshotDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*120*/ - internal const string Process32FirstDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*121*/ - internal const string Process32NextDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*122*/ - internal const string GetACPDllName = "api-ms-win-core-localization-l1-2-0.dll"; /*123*/ - internal const string DeleteServiceDllName = "api-ms-win-service-management-l1-1-0.dll"; /*124*/ - internal const string QueryServiceConfigDllName = "api-ms-win-service-management-l2-1-0.dll"; /*125*/ - internal const string QueryServiceConfig2DllName = "api-ms-win-service-management-l2-1-0.dll"; /*126*/ - internal const string SetServiceObjectSecurityDllName = "api-ms-win-service-management-l2-1-0.dll"; /*127*/ + internal const string SetConsoleModeDllName = "api-ms-win-core-console-l1-1-0.dll"; /*106*/ + internal const string SetConsoleScreenBufferSizeDllName = "api-ms-win-core-console-l2-1-0.dll"; /*107*/ + internal const string SetConsoleTextAttributeDllName = "api-ms-win-core-console-l2-1-0.dll"; /*108*/ + internal const string SetConsoleWindowInfoDllName = "api-ms-win-core-console-l2-1-0.dll"; /*109*/ + internal const string WriteConsoleOutputDllName = "api-ms-win-core-console-l2-1-0.dll"; /*110*/ + internal const string ReadConsoleOutputDllName = "api-ms-win-core-console-l2-1-0.dll"; /*111*/ + internal const string ScrollConsoleScreenBufferDllName = "api-ms-win-core-console-l2-1-0.dll"; /*112*/ + internal const string SendInputDllName = "ext-ms-win-ntuser-keyboard-l1-2-1.dll"; /*113*/ + internal const string GetConsoleCursorInfoDllName = "api-ms-win-core-console-l2-1-0.dll"; /*114*/ + internal const string SetConsoleCursorInfoDllName = "api-ms-win-core-console-l2-1-0.dll"; /*115*/ + internal const string ReadConsoleInputDllName = "api-ms-win-core-console-l1-1-0.dll"; /*116*/ + internal const string GetVersionExDllName = "api-ms-win-core-sysinfo-l1-1-0.dll"; /*117*/ + internal const string FormatMessageDllName = "api-ms-win-core-localization-l1-2-0.dll"; /*118*/ + internal const string CreateToolhelp32SnapshotDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*119*/ + internal const string Process32FirstDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*120*/ + internal const string Process32NextDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*121*/ + internal const string GetACPDllName = "api-ms-win-core-localization-l1-2-0.dll"; /*122*/ + internal const string DeleteServiceDllName = "api-ms-win-service-management-l1-1-0.dll"; /*123*/ + internal const string QueryServiceConfigDllName = "api-ms-win-service-management-l2-1-0.dll"; /*124*/ + internal const string QueryServiceConfig2DllName = "api-ms-win-service-management-l2-1-0.dll"; /*125*/ + internal const string SetServiceObjectSecurityDllName = "api-ms-win-service-management-l2-1-0.dll"; /*126*/ } } From 8ad85fd642e7fa8f9807d8d32adec60bf2976396 Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL)" Date: Thu, 13 May 2021 15:57:10 -0700 Subject: [PATCH 4/4] revert change to get for CursorPosition --- .../host/msh/ConsoleHostRawUserInterface.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs index 0cd3d7651cc..bca63be834b 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostRawUserInterface.cs @@ -181,8 +181,11 @@ public override { get { - var pos = Console.GetCursorPosition(); - return new Coordinates(pos.Item1, pos.Item2); + ConsoleControl.CONSOLE_SCREEN_BUFFER_INFO bufferInfo; + GetBufferInfo(out bufferInfo); + + Coordinates c = new Coordinates(bufferInfo.CursorPosition.X, bufferInfo.CursorPosition.Y); + return c; } set