From 5f170b68ebd9ff8345d54ab1c65545ed5a8487fc Mon Sep 17 00:00:00 2001 From: Merith Date: Wed, 4 Mar 2026 04:22:14 -0800 Subject: [PATCH] fix #397 server console --- CMakeLists.txt | 4 +++ .../Windows64/Windows64_Minecraft.cpp | 25 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d83c5c8e..feaf1d5c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,11 @@ target_compile_definitions(MinecraftClient PRIVATE ) if(MSVC) configure_msvc_target(MinecraftClient) + # Use CONSOLE subsystem so the shell waits for the process (important for + # Docker and piped output in server mode). WinMainCRTStartup keeps the + # WinMain entry point. Client mode calls FreeConsole() to detach. target_link_options(MinecraftClient PRIVATE + /SUBSYSTEM:CONSOLE /ENTRY:WinMainCRTStartup $<$:/LTCG /INCREMENTAL:NO> ) endif() diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp index ec89feb18..91a1366ca 100644 --- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp @@ -228,14 +228,14 @@ static BOOL WINAPI HeadlessServerCtrlHandler(DWORD ctrlType) static void SetupHeadlessServerConsole() { - if (AllocConsole()) - { - FILE* stream = NULL; - freopen_s(&stream, "CONIN$", "r", stdin); - freopen_s(&stream, "CONOUT$", "w", stdout); - freopen_s(&stream, "CONOUT$", "w", stderr); - SetConsoleTitleA("Minecraft Server"); - } + // The exe is now linked as /SUBSYSTEM:CONSOLE, so it inherits the parent's + // console automatically. We just need to re-open the CRT streams so that + // printf/scanf go through the console and set up our Ctrl handler. + FILE* stream = NULL; + freopen_s(&stream, "CONIN$", "r", stdin); + freopen_s(&stream, "CONOUT$", "w", stdout); + freopen_s(&stream, "CONOUT$", "w", stderr); + SetConsoleTitleA("Minecraft Server"); SetConsoleCtrlHandler(HeadlessServerCtrlHandler, TRUE); } @@ -1141,6 +1141,15 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, // Load stuff from launch options, including username Win64LaunchOptions launchOptions = ParseLaunchOptions(); + + // The exe is linked as /SUBSYSTEM:CONSOLE so that the shell waits for it + // (required for Docker / piped output in server mode). In client mode we + // don't need the console, so detach from it immediately. + if (!launchOptions.serverMode) + { + FreeConsole(); + } + ApplyScreenMode(launchOptions.screenMode); // If no username, let's fall back