From 84aa07c052940297de351b0e66f746eff53df363 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 22 Sep 2026 04:03:22 -0500 Subject: [PATCH] fix dfhack-run on windows fixes #3827 --- docs/changelog.txt | 1 + library/Console-windows.cpp | 49 +++++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8b4ab870bb..45ebdb2f59 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -89,6 +89,7 @@ Template for new versions: - `buildingplan`: fix roller material estimate asking for one chain per tile instead of one chain total - `buildingplan`: fix "Unlink all" only unlinking some mechanisms (or crashing) when freeing mechanisms from the building - `burrow`: fix ``tiles clear`` and other tile operations silently failing because burrow block z-coordinates were stored incorrectly in the ``Burrows`` module +- `dfhack-run`: on Windows, no longer mutates, hides, and closes the console it inherits when run from an existing terminal (issue #3827) - `export-world-map`: fix crash exporting site data for a site whose owner has an undefined race - `gui/quickfort`: show smoothing designations immediately after applying a blueprint - `overlay`: overlay hotkeys no longer steal typed characters while the game is capturing text input, e.g. when renaming a building diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index 29d8f93c83..7dce13d56d 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -78,6 +78,9 @@ namespace DFHack state = con_unclaimed; in_batch = false; raw_cursor = 0; + console_owned = false; + saved_cp = 0; + saved_output_cp = 0; }; virtual ~Private() { @@ -396,6 +399,9 @@ namespace DFHack HWND ConsoleWindow; HWND MainWindow; WORD default_attributes; + bool console_owned; // false if the console was inherited from a parent process + UINT saved_cp; // code pages to restore on shutdown if the console is borrowed + UINT saved_output_cp; // current state enum console_state { @@ -467,22 +473,32 @@ bool Console::init(bool) } d->MainWindow = h; - // Allocate a console! - AllocConsole(); + // Allocate a console! If the process already has one (e.g. dfhack-run + // launched from an existing terminal), the console is borrowed and must + // not be mutated or freed. + d->console_owned = AllocConsole() != FALSE; d->ConsoleWindow = GetConsoleWindow(); wlock = new std::recursive_mutex(); - HMENU hm = GetSystemMenu(d->ConsoleWindow,false); - DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND); + if (d->console_owned) + { + HMENU hm = GetSystemMenu(d->ConsoleWindow,false); + DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND); + } // force console code pages to utf-8 + d->saved_cp = GetConsoleCP(); + d->saved_output_cp = GetConsoleOutputCP(); SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); // set the screen buffer to be big enough to let us scroll text GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); d->default_attributes = coninfo.wAttributes; - coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer - SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); + if (d->console_owned) + { + coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); + } // redirect unbuffered STDOUT to the console d->console_out = GetStdHandle(STD_OUTPUT_HANDLE); @@ -506,7 +522,10 @@ bool Console::init(bool) // make our own weird streams so our IO isn't redirected std::cin.tie(this); - clear(); + if (d->console_owned) + { + clear(); + } inited = true; // DOESN'T WORK - locks up DF! // ForceForegroundWindow(d->MainWindow); @@ -518,7 +537,17 @@ bool Console::shutdown(void) { assert(inited); std::lock_guard lock{*wlock}; - FreeConsole(); + if (d->console_owned) + { + FreeConsole(); + } + else + { + // the console is borrowed from a parent process; restore the state + // we changed and leave it attached + SetConsoleCP(d->saved_cp); + SetConsoleOutputCP(d->saved_output_cp); + } inited = false; return true; } @@ -611,12 +640,16 @@ void Console::msleep (unsigned int msec) bool Console::hide() { + if (!inited || !d->console_owned) + return false; ShowWindow( GetConsoleWindow(), SW_HIDE ); return true; } bool Console::show() { + if (!inited || !d->console_owned) + return false; ShowWindow( GetConsoleWindow(), SW_RESTORE ); return true; }