From bb2a72f67f4b90e1b31ccbc0f3c3ea9b280d2ffd Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Fri, 26 Jan 2024 15:04:53 +0100 Subject: [PATCH] issue a warning in legacy W10 terminals (PS/cmd) Those terminal emulators block stdout/stderr output when scrolled, which effectively stops UltraGrid. The behavior doesn't occur in MS Terminal app, which is encouraged instead. Note that Windows Terminal still runs cmd.exe or powershell.exe as a shell while the cmd/PS process can acts like both terminal emulator and shell. We also do not trigger the warning if UG is run from within MSYS2 terminal. --- src/host.cpp | 12 ++++++++++ src/utils/windows.c | 56 ++++++++++++++++++++++++++++++++++++++------- src/utils/windows.h | 1 + 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/host.cpp b/src/host.cpp index 106296917..a5ab09755 100644 --- a/src/host.cpp +++ b/src/host.cpp @@ -116,6 +116,8 @@ extern "C" { #include #endif +#define MOD_NAME "[host] " + using std::array; using std::cout; using std::endl; @@ -458,6 +460,16 @@ struct init_data *common_preinit(int argc, char *argv[]) if (init_com) { com_initialize(&init.com_initialized, nullptr); } + + // warn in W10 "legacy" terminal emulators + if ((win_has_ancestor_process("powershell.exe") || + win_has_ancestor_process("cmd.exe")) && + !win_has_ancestor_process("WindowsTerminal.exe")) { + MSG(WARNING, "Running inside PS/cmd terminal is not recommended " + "because scrolling the output freezes the process, " + "consider using Windows Terminal instead!\n"); + Sleep(1000); + } #endif if (strstr(argv[0], "run_tests") == nullptr) { diff --git a/src/utils/windows.c b/src/utils/windows.c index a3f0ea296..ce099b8d5 100644 --- a/src/utils/windows.c +++ b/src/utils/windows.c @@ -35,21 +35,18 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#include "config_unix.h" -#include "config_win32.h" -#endif - -#include "utils/windows.h" - #ifdef _WIN32 #include #include +#include #include #include "debug.h" #endif // defined _WIN32 +#include "utils/windows.h" + +#define MOD_NAME "[utils/win] " + bool com_initialize(bool *com_initialized, const char *err_prefix) { #ifdef _WIN32 @@ -183,6 +180,49 @@ const char *win_wstr_to_str(const wchar_t *wstr) { } return res; } + +static bool +GetProcessInfo(HANDLE hSnapshot, DWORD processId, PROCESSENTRY32 *pe32) +{ + if (!Process32First(hSnapshot, pe32)) { + return false; + } + + do { + if (pe32->th32ProcessID == processId) { + return true; + } + } while (Process32Next(hSnapshot, pe32)); + + return false; +} + +/** + * @returns true if there is a process "name" among current process ancestors + * @param name the searched process name (case insensitive) + */ +bool +win_has_ancestor_process(const char *name) +{ + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + return false; + } + DWORD pid = GetCurrentProcessId(); + PROCESSENTRY32 pe32 = { .dwSize = sizeof(PROCESSENTRY32) }; + while (GetProcessInfo(hSnapshot, pid, &pe32)) { + MSG(DEBUG, "%s: %s PID: %ld, PPID: %ld\n", __func__ + pe32.szExeFile, pid, pe32.th32ParentProcessID); + if (_stricmp(pe32.szExeFile, name) == 0) { + CloseHandle(hSnapshot); + return true; + } + pid = pe32.th32ParentProcessID; + } + CloseHandle(hSnapshot); + return false; +} + #endif // defined _WIN32 /* vim: set expandtab sw=8 tw=120: */ diff --git a/src/utils/windows.h b/src/utils/windows.h index 1e5fd01d3..41c3859c3 100644 --- a/src/utils/windows.h +++ b/src/utils/windows.h @@ -85,6 +85,7 @@ void com_uninitialize(bool *com_initialized); const char *hresult_to_str(HRESULT res); const char *get_win32_error(DWORD error); const char *win_wstr_to_str(const wchar_t *wstr); +bool win_has_ancestor_process(const char *name); #endif // defined _WIN32 #ifdef __cplusplus