[*] Recrinkle win32 process send term and stdin CONIN/OUT win32 logic

This commit is contained in:
Reece Wilson 2022-02-21 12:27:34 +00:00
parent c6d649e3de
commit 9e26996463
4 changed files with 106 additions and 59 deletions

View File

@ -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
{

View File

@ -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;
}

View File

@ -16,6 +16,8 @@
#include "ArgvQuote.hpp"
#include <Source/IO/FS/FS.hpp>
namespace Aurora::Processes
{
ProcessImpl::ProcessImpl(const StartupParmaters &params) : 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)
{

View File

@ -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<AuUInt32 *>(a))++;
DWORD windowpid;
auto context = reinterpret_cast<Hack *>(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<LPARAM>(&count));
EnumThreadWindows(te.th32ThreadID, TermWinHandleWin32Thread, reinterpret_cast<LPARAM>(&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);