From 9e26996463b70f00bcdfa7e8439a8012c237683c Mon Sep 17 00:00:00 2001 From: Reece Date: Mon, 21 Feb 2022 12:27:34 +0000 Subject: [PATCH] [*] Recrinkle win32 process send term and stdin CONIN/OUT win32 logic --- Source/Console/ConsoleStd/ConsoleStd.cpp | 107 +++++++++++++---------- Source/IO/FS/FS.cpp | 2 +- Source/Processes/Process.NT.cpp | 11 ++- Source/Processes/Process.Win32.cpp | 45 ++++++++-- 4 files changed, 106 insertions(+), 59 deletions(-) diff --git a/Source/Console/ConsoleStd/ConsoleStd.cpp b/Source/Console/ConsoleStd/ConsoleStd.cpp index a1ed5f62..4e2b43d7 100644 --- a/Source/Console/ConsoleStd/ConsoleStd.cpp +++ b/Source/Console/ConsoleStd/ConsoleStd.cpp @@ -108,61 +108,76 @@ namespace Aurora::Console::ConsoleStd DWORD dwMode; bool ok; // Obtain a win32 file HANDLE of STDIN - auto fileHandle = CreateFileA("CONIN$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); + auto fileHandle = + #if defined(AURORA_PLATFORM_WIN32) + GetStdHandle(STD_INPUT_HANDLE); + #else + CreateFileW(L"CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + #endif SysAssert(fileHandle != INVALID_HANDLE_VALUE, "Couldn't open CONIN"); gInputStream = fileHandle; // Obtain a win32 file HANDLE of STDOUT - fileHandle = CreateFileA("CONOUT$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); + fileHandle = + #if defined(AURORA_PLATFORM_WIN32) + GetStdHandle(STD_OUTPUT_HANDLE); + #else + CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + #endif SysAssert(fileHandle != INVALID_HANDLE_VALUE, "Couldn't open CONOUT"); gOutputStream = fileHandle; - // Get current console flags - if (GetConsoleMode(gOutputStream, &dwMode)) - { - if (gRuntimeConfig.console.enableStdPassthrough ^ gRuntimeConfig.console.enableStdOut) - { - // Enable escape processing; enable colored output - dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; - ok = SetConsoleMode(gOutputStream, dwMode); - SysAssert(ok, "Couldn't set console mode"); + bool isNotPipe = GetFileType(fileHandle) != FILE_TYPE_PIPE; + + if (isNotPipe) + { + // Get current console flags + if (GetConsoleMode(gOutputStream, &dwMode)) + { + if (gRuntimeConfig.console.enableStdPassthrough ^ gRuntimeConfig.console.enableStdOut) + { + // Enable escape processing; enable colored output + dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; + ok = SetConsoleMode(gOutputStream, dwMode); + SysAssert(ok, "Couldn't set console mode"); + + // Set the output stream to use UTF-8 + ok = SetConsoleOutputCP(CP_UTF8); + SysAssert(ok, "Couldn't maintain UTF-8 stdout stream"); + } + } + + // Set binary mode if redirecting stdin to user + if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdOut) + { + SetConsoleMode(gOutputStream, 0); + } + + if (gRuntimeConfig.console.enableStdPassthrough ^ gRuntimeConfig.console.enableStdIn) + { + ok = SetConsoleCP(CP_UTF8); + #if 0 + SysAssert(ok, "Couldn't maintain UTF-8 stdin stream"); + #endif - // Set the output stream to use UTF-8 - ok = SetConsoleOutputCP(CP_UTF8); - SysAssert(ok, "Couldn't maintain UTF-8 stdout stream"); } } - // Set binary mode if redirecting stdin to user - if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdOut) - { - SetConsoleMode(gOutputStream, 0); - } - - if (gRuntimeConfig.console.enableStdPassthrough ^ gRuntimeConfig.console.enableStdIn) - { - ok = SetConsoleCP(CP_UTF8); - #if 0 - SysAssert(ok, "Couldn't maintain UTF-8 stdin stream"); - #endif - - } - - if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdIn) + if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdIn && isNotPipe) { if (!GetConsoleMode(gInputStream, &dwMode)) { @@ -201,13 +216,11 @@ namespace Aurora::Console::ConsoleStd return; } - if (!gRuntimeConfig.console.forceConsoleWindow) + if (gRuntimeConfig.console.forceConsoleWindow) { - return; + auto ok = AllocConsole(); + SysAssert(ok, "Request of a Win32 console yielded nada, forceConsole wasn't respected"); } - - auto ok = AllocConsole(); - SysAssert(ok, "Request of a Win32 console yielded nada, forceConsole wasn't respected"); } else { diff --git a/Source/IO/FS/FS.cpp b/Source/IO/FS/FS.cpp index 70305472..6b905e3e 100644 --- a/Source/IO/FS/FS.cpp +++ b/Source/IO/FS/FS.cpp @@ -194,7 +194,7 @@ namespace Aurora::IO::FS if (str[1] == kPathSplitter) { auto c = str[0]; - if ((c == '.') || (c == '~') || (c == '!') || (c == '?')) + if ((c == '.') || (c == '~') || (c == '!') || (c == '?' || (c == '^'))) { requiresMountUpdate = true; } diff --git a/Source/Processes/Process.NT.cpp b/Source/Processes/Process.NT.cpp index 6fcd61ea..9eb1d54a 100644 --- a/Source/Processes/Process.NT.cpp +++ b/Source/Processes/Process.NT.cpp @@ -16,6 +16,8 @@ #include "ArgvQuote.hpp" +#include + namespace Aurora::Processes { ProcessImpl::ProcessImpl(const StartupParmaters ¶ms) : startup_(params) @@ -293,7 +295,7 @@ namespace Aurora::Processes startupInfo.hStdOutput = pipeStdOutWrite_; startupInfo.dwFlags |= (inheritHandles ? STARTF_USESTDHANDLES : 0); - auto result = CreateProcessW(Locale::ConvertFromUTF8(this->startup_.process).c_str(), + auto result = CreateProcessW(Locale::ConvertFromUTF8(AuIOFS::NormalizePathRet(this->startup_.process)).c_str(), Locale::ConvertFromUTF8(this->windowsCli_).data(), NULL, NULL, inheritHandles, this->startup_.noShowConsole ? CREATE_NO_WINDOW : NULL, // yea we can keep CREATE_NO_WINDOW on for non-console apps. its legal -> https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags @@ -301,6 +303,7 @@ namespace Aurora::Processes if (!result) { + DWORD wr = GetLastError(); SysPushErrorGen("CreateProcess failed"); return false; } @@ -308,9 +311,9 @@ namespace Aurora::Processes this->process_ = processInfo.hProcess; this->hthread_ = processInfo.hThread; - AuWin32CloseHandle(this->pipeStdOutRead_); - AuWin32CloseHandle(this->pipeStdErrRead_); - AuWin32CloseHandle(this->pipeStdInWrite_); + AuWin32CloseHandle(this->pipeStdOutWrite_); + AuWin32CloseHandle(this->pipeStdErrWrite_); + AuWin32CloseHandle(this->pipeStdInRead_); if (this->type_ == ESpawnType::eSpawnChildProcessWorker) { diff --git a/Source/Processes/Process.Win32.cpp b/Source/Processes/Process.Win32.cpp index 64964d64..b91ae47d 100644 --- a/Source/Processes/Process.Win32.cpp +++ b/Source/Processes/Process.Win32.cpp @@ -60,11 +60,24 @@ namespace Aurora::Processes return exitCode != STILL_ACTIVE; } + + struct Hack + { + HANDLE base; + AuUInt32 count; + }; static BOOL TermWinHandleWin32Thread(HWND handle, LPARAM a) { - SendMessageA(handle, WM_CLOSE, 0, 0); - (*reinterpret_cast(a))++; + DWORD windowpid; + auto context = reinterpret_cast(a); + auto pid = GetProcessId(context->base); + GetWindowThreadProcessId(handle, &windowpid); + if (pid && pid == windowpid) + { + SendMessageA(handle, WM_CLOSE, 0, 0); + context->count++; + } return true; } @@ -72,15 +85,25 @@ namespace Aurora::Processes { THREADENTRY32 te{}; HANDLE h{}; + Hack hello; + + hello.count = 0; + hello.base = handle; + + te.dwSize = sizeof(te); + te.th32OwnerProcessID = GetProcessId(handle); + + if (!te.th32OwnerProcessID) + { + return false; + } h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetProcessId(handle)); if (h == INVALID_HANDLE_VALUE) { return false; } - - te.dwSize = sizeof(te); - AuUInt32 count{}; + if (Thread32First(h, &te)) { do @@ -88,7 +111,7 @@ namespace Aurora::Processes if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) { - EnumThreadWindows(te.th32ThreadID, TermWinHandleWin32Thread, reinterpret_cast(&count)); + EnumThreadWindows(te.th32ThreadID, TermWinHandleWin32Thread, reinterpret_cast(&hello)); } te.dwSize = sizeof(te); } while (Thread32Next(h, &te)); @@ -96,7 +119,7 @@ namespace Aurora::Processes CloseHandle(h); - if (!count) + if (!hello.count) { return false; } @@ -106,11 +129,19 @@ namespace Aurora::Processes static bool SendControlCEquiv(HANDLE handle) { + auto cwnd = GetConsoleWindow(); + if (!(AttachConsole(GetProcessId(handle)))) { return false; } + if (cwnd == GetConsoleWindow()) + { + FreeConsole(); + return false; + } + if (SetConsoleCtrlHandler({}, true)) { GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);