mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-27 23:37:05 -05:00
fix: Properly forward stdin to main process from forwarder
(cherry picked from commit 1fc857cf7d2a9a525dec5fcda0727a39046b6c86)
This commit is contained in:
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: a2b683e798...25876b73ca
@@ -35,7 +35,7 @@ namespace hex::mcp {
|
|||||||
client.writeString(request);
|
client.writeString(request);
|
||||||
auto response = client.readBytesUntil(0x00);
|
auto response = client.readBytesUntil(0x00);
|
||||||
if (!response.empty() && response.front() != 0x00)
|
if (!response.empty() && response.front() != 0x00)
|
||||||
output << std::string(response.begin(), response.end()) << '\n';
|
output << std::string(response.begin(), response.end()) << std::endl;
|
||||||
|
|
||||||
if (!client.isConnected())
|
if (!client.isConnected())
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
void setupConsoleWindow() {
|
void setupConsoleWindow() {
|
||||||
// Get the handle of the console window
|
// Get the handle of the console window
|
||||||
@@ -66,7 +67,10 @@ int launchExecutable() {
|
|||||||
auto executableFullPath = executablePath->parent_path() / "imhex-gui.exe";
|
auto executableFullPath = executablePath->parent_path() / "imhex-gui.exe";
|
||||||
|
|
||||||
// Handles for the pipes
|
// Handles for the pipes
|
||||||
HANDLE hChildStdoutRead, hChildStdoutWrite;
|
HANDLE hChildStdinRead = nullptr;
|
||||||
|
HANDLE hChildStdinWrite = nullptr;
|
||||||
|
HANDLE hChildStdoutRead = nullptr;
|
||||||
|
HANDLE hChildStdoutWrite = nullptr;
|
||||||
|
|
||||||
// Security attributes to allow the pipes to be inherited
|
// Security attributes to allow the pipes to be inherited
|
||||||
SECURITY_ATTRIBUTES saAttr;
|
SECURITY_ATTRIBUTES saAttr;
|
||||||
@@ -74,17 +78,30 @@ int launchExecutable() {
|
|||||||
saAttr.lpSecurityDescriptor = nullptr;
|
saAttr.lpSecurityDescriptor = nullptr;
|
||||||
saAttr.bInheritHandle = TRUE;
|
saAttr.bInheritHandle = TRUE;
|
||||||
|
|
||||||
// Create pipes for stdout redirection
|
// Create pipes for stdin redirection
|
||||||
if (!::CreatePipe(&hChildStdoutRead, &hChildStdoutWrite, &saAttr, 0)) {
|
if (!::CreatePipe(&hChildStdinRead, &hChildStdinWrite, &saAttr, 0)) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
// Ensure the write handle to stdin is not inherited
|
||||||
|
::SetHandleInformation(hChildStdinWrite, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
|
||||||
|
// Create pipes for stdout redirection
|
||||||
|
if (!::CreatePipe(&hChildStdoutRead, &hChildStdoutWrite, &saAttr, 0)) {
|
||||||
|
::CloseHandle(hChildStdinRead);
|
||||||
|
::CloseHandle(hChildStdinWrite);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
// Ensure the read handle to stdout is not inherited
|
||||||
|
::SetHandleInformation(hChildStdoutRead, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
|
||||||
// Set up the STARTUPINFO structure for the child process
|
// Set up the STARTUPINFO structure for the child process
|
||||||
STARTUPINFO si;
|
STARTUPINFOW si;
|
||||||
::ZeroMemory(&si, sizeof(STARTUPINFO));
|
::ZeroMemory(&si, sizeof(STARTUPINFOW));
|
||||||
si.cb = sizeof(STARTUPINFO);
|
si.cb = sizeof(STARTUPINFOW);
|
||||||
si.hStdOutput = hChildStdoutWrite; // Redirect stdout to the parent process
|
si.hStdInput = hChildStdinRead;
|
||||||
si.dwFlags |= STARTF_USESTDHANDLES; // Enable redirection of stdin, stdout, stderr
|
si.hStdOutput = hChildStdoutWrite;
|
||||||
|
si.hStdError = hChildStdoutWrite; // Also redirect stderr to stdout
|
||||||
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
||||||
@@ -102,29 +119,45 @@ int launchExecutable() {
|
|||||||
&si, // STARTUPINFO
|
&si, // STARTUPINFO
|
||||||
&pi // PROCESS_INFORMATION
|
&pi // PROCESS_INFORMATION
|
||||||
)) {
|
)) {
|
||||||
|
::CloseHandle(hChildStdinRead);
|
||||||
|
::CloseHandle(hChildStdinWrite);
|
||||||
|
::CloseHandle(hChildStdoutRead);
|
||||||
|
::CloseHandle(hChildStdoutWrite);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close unnecessary pipe handles in the parent process
|
// Close handles that the child inherited
|
||||||
|
::CloseHandle(hChildStdinRead);
|
||||||
::CloseHandle(hChildStdoutWrite);
|
::CloseHandle(hChildStdoutWrite);
|
||||||
|
|
||||||
// Read the child process's stdout and stderr and redirect them to the parent's stdout
|
// Get parent's stdin and stdout handles
|
||||||
DWORD bytesRead;
|
HANDLE hParentStdin = ::GetStdHandle(STD_INPUT_HANDLE);
|
||||||
std::array<char, 4096> buffer;
|
HANDLE hParentStdout = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
while (true) {
|
// Thread to forward parent stdin -> child stdin
|
||||||
// Read from stdout
|
auto stdinThread = std::thread([hParentStdin, hChildStdinWrite]() {
|
||||||
if (::ReadFile(hChildStdoutRead, buffer.data(), buffer.size(), &bytesRead, nullptr)) {
|
DWORD bytesRead, bytesWritten;
|
||||||
// Write to the parent's stdout
|
std::array<char, 4096> buffer;
|
||||||
if (bytesRead > 0)
|
|
||||||
::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer.data(), bytesRead, &bytesRead, nullptr);
|
while (::ReadFile(hParentStdin, buffer.data(), buffer.size(), &bytesRead, nullptr) && bytesRead > 0) {
|
||||||
} else {
|
::WriteFile(hChildStdinWrite, buffer.data(), bytesRead, &bytesWritten, nullptr);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
::CloseHandle(hChildStdinWrite);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Thread to forward child stdout -> parent stdout
|
||||||
|
auto stdoutThread = std::thread([hChildStdoutRead, hParentStdout]() {
|
||||||
|
DWORD bytesRead, bytesWritten;
|
||||||
|
std::array<char, 4096> buffer;
|
||||||
|
|
||||||
|
while (::ReadFile(hChildStdoutRead, buffer.data(), buffer.size(), &bytesRead, nullptr) && bytesRead > 0) {
|
||||||
|
::WriteFile(hParentStdout, buffer.data(), bytesRead, &bytesWritten, nullptr);
|
||||||
|
}
|
||||||
|
::CloseHandle(hChildStdoutRead);
|
||||||
|
});
|
||||||
|
|
||||||
// Wait for the child process to exit
|
// Wait for the child process to exit
|
||||||
::WaitForSingleObject(pi.hProcess, INFINITE);
|
::WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
|
|
||||||
// Get the exit code of the child process
|
// Get the exit code of the child process
|
||||||
DWORD exitCode = 0;
|
DWORD exitCode = 0;
|
||||||
@@ -132,10 +165,13 @@ int launchExecutable() {
|
|||||||
exitCode = EXIT_FAILURE;
|
exitCode = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
// Clean up process handles
|
||||||
::CloseHandle(pi.hProcess);
|
::CloseHandle(pi.hProcess);
|
||||||
::CloseHandle(pi.hThread);
|
::CloseHandle(pi.hThread);
|
||||||
::CloseHandle(hChildStdoutRead);
|
|
||||||
|
// Wait for I/O threads to finish
|
||||||
|
if (stdinThread.joinable()) stdinThread.join();
|
||||||
|
if (stdoutThread.joinable()) stdoutThread.join();
|
||||||
|
|
||||||
return static_cast<int>(exitCode);
|
return static_cast<int>(exitCode);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user