[PATCH v3 1/4] Cygwin: pty: Use OpenConsole.exe if available
Takashi Yano
takashi.yano@nifty.ne.jp
Mon Feb 23 08:01:27 GMT 2026
This patch replaces legacy conhost.exe with OpenConsole.exe if
it is available. This enables various new features such as mouse
support in pseudo console and bug fixes. The legacy conhost has
problems, e.g. character attributes are mangled or ignored, and
terminal reports are not passed through. This patch resolve the
issue by loading /usr/bin/OpenColnsole.exe instead of conhost.exe
if it is available.
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Suggested-by: Thomas Wolff <towo@towo.net>
Reviewed-by:
---
winsup/cygwin/fhandler/pty.cc | 171 +++++++++++++++++++++++++++++++++-
1 file changed, 168 insertions(+), 3 deletions(-)
diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index c1e03db41..576f11dea 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -34,6 +34,166 @@ details. */
#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
#endif /* PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE */
+/* The source code of following two functions, i.e. create_conhost_handle()
+ and CreatePseudoConsole_new(), are borrowed from
+ Microsoft WindowsTerminal project: https://github.com/microsoft/terminal/
+ that is licensed under MIT license. */
+
+/* ----------------------------------------------------------------------------
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+---------------------------------------------------------------------------- */
+
+static NTSTATUS
+create_conhost_handle (PHANDLE handle, PCWSTR device_name,
+ ACCESS_MASK desired_access, HANDLE parent,
+ BOOLEAN inheritable, ULONG open_options)
+{
+ ULONG flags = OBJ_CASE_INSENSITIVE;
+ if (inheritable)
+ flags |= OBJ_INHERIT;
+
+ UNICODE_STRING name;
+ RtlInitUnicodeString (&name, device_name);
+
+ OBJECT_ATTRIBUTES object_attributes;
+ InitializeObjectAttributes (&object_attributes, &name, flags, parent, NULL);
+
+ IO_STATUS_BLOCK io;
+ return NtOpenFile (handle, desired_access, &object_attributes, &io,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ open_options);
+}
+
+extern "C" WINBASEAPI HRESULT WINAPI
+CreatePseudoConsole_new (COORD size, HANDLE h_input, HANDLE h_output,
+ DWORD flags, HPCON *hpcon)
+{
+
+ HANDLE h_con_server, h_con_reference;
+ NTSTATUS status;
+ BOOL res;
+ HANDLE h_read_pipe, h_write_pipe;
+ BOOL inherit_cursor;
+ path_conv conhost ("/usr/bin/OpenConsole.exe");
+ size_t len;
+ HANDLE inherited_handles[4];
+ STARTUPINFOEXW si = {0, };
+ PROCESS_INFORMATION pi;
+ SIZE_T list_size = 0;
+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list;
+ HPCON_INTERNAL *hpcon_internal;
+
+ status = create_conhost_handle (&h_con_server, L"\\Device\\ConDrv\\Server",
+ GENERIC_ALL, NULL, TRUE, 0);
+ if (!NT_SUCCESS (status))
+ goto cleanup;
+ status = create_conhost_handle (&h_con_reference, L"\\Reference",
+ GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
+ h_con_server, FALSE,
+ FILE_SYNCHRONOUS_IO_NONALERT);
+ if (!NT_SUCCESS (status))
+ goto cleanup_h_con_server;
+
+ res = CreatePipe (&h_read_pipe, &h_write_pipe, &sec_none, 0);
+ if (!res)
+ goto cleanup_h_con_reference;
+ res = SetHandleInformation (h_read_pipe,
+ HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+ if (!res)
+ goto cleanup_pipe;
+
+ inherit_cursor = (flags & PSEUDOCONSOLE_INHERIT_CURSOR) ? TRUE : FALSE;
+
+ WCHAR cmd[MAX_PATH];
+ len = conhost.get_wide_win32_path_len ();
+ conhost.get_wide_win32_path (cmd);
+ __small_swprintf (cmd + len,
+ L" --headless %W"
+ "--width %d --height %d --signal 0x%x --server 0x%x",
+ inherit_cursor ? L"--inheritcursor " : L"",
+ size.X, size.Y, h_read_pipe, h_con_server);
+
+ si.StartupInfo.cb = sizeof (STARTUPINFOEXW);
+ si.StartupInfo.hStdInput = h_input;
+ si.StartupInfo.hStdOutput = h_output;
+ si.StartupInfo.hStdError = h_output;
+ si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ inherited_handles[0] = h_con_server;
+ inherited_handles[1] = h_input;
+ inherited_handles[2] = h_output;
+ inherited_handles[3] = h_read_pipe;
+
+ InitializeProcThreadAttributeList (NULL, 1, 0, &list_size);
+ attr_list =
+ (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc (GetProcessHeap (), 0, list_size);
+ if (!attr_list)
+ goto cleanup_pipe;
+
+ si.lpAttributeList = attr_list;
+ InitializeProcThreadAttributeList (si.lpAttributeList, 1, 0, &list_size);
+ UpdateProcThreadAttribute (si.lpAttributeList, 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ inherited_handles, sizeof (inherited_handles),
+ NULL, NULL);
+
+
+ res = CreateProcessW (NULL, cmd, NULL, NULL,
+ TRUE, EXTENDED_STARTUPINFO_PRESENT,
+ NULL, NULL, &si.StartupInfo, &pi);
+ if (!res)
+ goto cleanup_heap;
+
+ hpcon_internal = (HPCON_INTERNAL *)
+ HeapAlloc (GetProcessHeap (), 0, sizeof (HPCON_INTERNAL));
+ if (!hpcon_internal)
+ goto cleanup_heap;
+ hpcon_internal->hWritePipe = h_write_pipe;
+ hpcon_internal->hConDrvReference = h_con_reference;
+ hpcon_internal->hConHostProcess = pi.hProcess;
+ *hpcon = (HPCON) hpcon_internal;
+
+ HeapFree (GetProcessHeap(), 0, attr_list);
+ CloseHandle (h_con_server);
+ CloseHandle (pi.hThread);
+ CloseHandle (pi.hProcess);
+
+ return S_OK;
+
+cleanup_heap:
+ HeapFree (GetProcessHeap(), 0, attr_list);
+cleanup_pipe:
+ CloseHandle (h_read_pipe);
+ CloseHandle (h_write_pipe);
+cleanup_h_con_reference:
+ CloseHandle (h_con_reference);
+cleanup_h_con_server:
+ CloseHandle (h_con_server);
+cleanup:
+ return E_FAIL;
+}
+
+
extern "C" int sscanf (const char *, const char *, ...);
#define close_maybe(h) \
@@ -3329,9 +3489,14 @@ fhandler_pty_slave::setup_pseudoconsole ()
const DWORD inherit_cursor = 1;
hpcon = NULL;
SetLastError (ERROR_SUCCESS);
- HRESULT res = CreatePseudoConsole (size, get_handle_nat (),
- get_output_handle_nat (),
- inherit_cursor, &hpcon);
+ /* Try OpenConsole.exe before conhost.exe */
+ HRESULT res = CreatePseudoConsole_new (size, get_handle_nat (),
+ get_output_handle_nat (),
+ inherit_cursor, &hpcon);
+ if (res != S_OK) /* Fallback to legacy conhost.exe */
+ res = CreatePseudoConsole (size, get_handle_nat (),
+ get_output_handle_nat (),
+ inherit_cursor, &hpcon);
if (res != S_OK || GetLastError () == ERROR_PROC_NOT_FOUND)
{
if (res != S_OK)
--
2.51.0
More information about the Cygwin-patches
mailing list