mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-31 02:26:29 +03:00
Fix create pseudo-console spawn issues in Windows (SpartanJ/ecode#856).
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
#ifndef EE_CONTAINERS_HPP
|
||||
#define EE_CONTAINERS_HPP
|
||||
|
||||
#ifdef EEPP_NO_THIRDPARTY_CONTAINERS
|
||||
#include <eepp/config.hpp>
|
||||
|
||||
#if defined( EEPP_NO_THIRDPARTY_CONTAINERS ) || ( defined( EE_DEBUG ) && defined( EE_COMPILER_MSVC ) )
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#else
|
||||
@@ -11,7 +13,7 @@
|
||||
|
||||
namespace EE {
|
||||
|
||||
#ifdef EEPP_NO_THIRDPARTY_CONTAINERS
|
||||
#if defined( EEPP_NO_THIRDPARTY_CONTAINERS ) || ( defined( EE_DEBUG ) && defined( EE_COMPILER_MSVC ) )
|
||||
|
||||
template <typename Key, typename Value> using UnorderedMap = std::unordered_map<Key, Value>;
|
||||
|
||||
|
||||
@@ -248,42 +248,6 @@ static std::wstring stringToWideString( const std::string& str ) {
|
||||
|
||||
#define HANDLE_WIN_ERR( err ) HRESULT_FROM_WIN32( err ), PrintWinApiError( err )
|
||||
|
||||
static HRESULT InitializeStartupInfoAttachedToPseudoConsole( STARTUPINFOEXW* pStartupInfo,
|
||||
HPCON hpc ) {
|
||||
// Prepare Startup Information structure
|
||||
STARTUPINFOEXW si;
|
||||
ZeroMemory( &si, sizeof( si ) );
|
||||
si.StartupInfo.cb = sizeof( STARTUPINFOEXW );
|
||||
|
||||
// Discover the size required for the list
|
||||
SIZE_T bytesRequired;
|
||||
InitializeProcThreadAttributeList( NULL, 1, 0, &bytesRequired );
|
||||
|
||||
// Allocate memory to represent the list
|
||||
si.lpAttributeList =
|
||||
(PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc( GetProcessHeap(), 0, bytesRequired );
|
||||
if ( !si.lpAttributeList ) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
// Initialize the list memory location
|
||||
if ( !InitializeProcThreadAttributeList( si.lpAttributeList, 1, 0, &bytesRequired ) ) {
|
||||
HeapFree( GetProcessHeap(), 0, si.lpAttributeList );
|
||||
return HRESULT_FROM_WIN32( GetLastError() );
|
||||
}
|
||||
|
||||
// Set the pseudoconsole information into the list
|
||||
if ( !UpdateProcThreadAttribute( si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
hpc, sizeof( hpc ), NULL, NULL ) ) {
|
||||
HeapFree( GetProcessHeap(), 0, si.lpAttributeList );
|
||||
return HRESULT_FROM_WIN32( GetLastError() );
|
||||
}
|
||||
|
||||
*pStartupInfo = si;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Process::Process( AutoHandle&& hProcess, void* lpAttributeList, int pid ) :
|
||||
mStatus( ProcessStatus::RUNNING ),
|
||||
mExitCode( 1 ),
|
||||
@@ -393,11 +357,13 @@ std::unique_ptr<Process> Process::createWithPipe( const std::string& program,
|
||||
oss << ' ' << arg;
|
||||
}
|
||||
std::wstring commandLine = stringToWideString( oss.str() );
|
||||
// TODO: If workingDirectory is relative, make it absolute (relative to the
|
||||
// current process working directory)
|
||||
|
||||
std::vector<wchar_t> cmdLineMutable(commandLine.begin(), commandLine.end());
|
||||
cmdLineMutable.push_back(0);
|
||||
|
||||
std::wstring workingDir = stringToWideString( workingDirectory );
|
||||
|
||||
if ( CreateProcessW( NULL, (LPWSTR)commandLine.c_str(), NULL, NULL, TRUE, 0, NULL,
|
||||
if ( CreateProcessW( NULL, (LPWSTR)cmdLineMutable.data(), NULL, NULL, TRUE, 0, NULL,
|
||||
workingDir.empty() ? NULL : workingDir.c_str(), &siStartInfo,
|
||||
&piProcInfo ) ) {
|
||||
std::unique_ptr<Pipe> pipe = std::unique_ptr<Pipe>(
|
||||
@@ -434,6 +400,12 @@ Process::createWithPseudoTerminal( const std::string& program, const std::vector
|
||||
AutoHandle hThread{};
|
||||
|
||||
STARTUPINFOEXW startupInfo{};
|
||||
startupInfo.StartupInfo.cb = sizeof( STARTUPINFOEXW );
|
||||
startupInfo.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
startupInfo.StartupInfo.hStdInput = INVALID_HANDLE_VALUE;
|
||||
startupInfo.StartupInfo.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
startupInfo.StartupInfo.hStdError = INVALID_HANDLE_VALUE;
|
||||
|
||||
PROCESS_INFORMATION piClient{};
|
||||
|
||||
std::ostringstream oss;
|
||||
@@ -442,19 +414,32 @@ Process::createWithPseudoTerminal( const std::string& program, const std::vector
|
||||
oss << ' ' << arg;
|
||||
}
|
||||
std::wstring commandLine = stringToWideString( oss.str() );
|
||||
// TODO: If workingDirectory is relative, make it absolute (relative to the
|
||||
// current process working directory)
|
||||
std::wstring workingDir = stringToWideString( workingDirectory );
|
||||
|
||||
if ( ( hr = InitializeStartupInfoAttachedToPseudoConsole( &startupInfo,
|
||||
pseudoTerminal.mPHPC ) ) != S_OK ) {
|
||||
Log::error( "InitializeStartupInfoAttachedToPseudoConsole failed." );
|
||||
PrintErrorResult( hr );
|
||||
SIZE_T bytesRequired = 0;
|
||||
InitializeProcThreadAttributeList( NULL, 1, 0, &bytesRequired );
|
||||
|
||||
startupInfo.lpAttributeList =
|
||||
(PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc( GetProcessHeap(), 0, bytesRequired );
|
||||
|
||||
if ( !startupInfo.lpAttributeList ) {
|
||||
Log::error( "HeapAlloc failed for attribute list." );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( !InitializeProcThreadAttributeList( startupInfo.lpAttributeList, 1, 0, &bytesRequired ) ) {
|
||||
Log::error( "InitializeProcThreadAttributeList failed." );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( !UpdateProcThreadAttribute( startupInfo.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
pseudoTerminal.mPHPC, sizeof( HPCON ), NULL, NULL ) ) {
|
||||
Log::error( "UpdateProcThreadAttribute failed." );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = CreateProcessW( NULL, // No module name - use Command Line
|
||||
(wchar_t*)commandLine.c_str(), // Command Line
|
||||
commandLine.data(), // Must be a mutable buffer to prevent ERROR_INSUFFICIENT_BUFFER
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
FALSE, // Inherit handles
|
||||
@@ -480,6 +465,10 @@ Process::createWithPseudoTerminal( const std::string& program, const std::vector
|
||||
return std::unique_ptr<Process>(
|
||||
new Process( std::move( hProcess ), startupInfo.lpAttributeList, piClient.dwProcessId ) );
|
||||
fail:
|
||||
if ( startupInfo.lpAttributeList ) {
|
||||
DeleteProcThreadAttributeList( startupInfo.lpAttributeList );
|
||||
HeapFree( GetProcessHeap(), 0, startupInfo.lpAttributeList );
|
||||
}
|
||||
return std::unique_ptr<Process>();
|
||||
}
|
||||
|
||||
@@ -489,4 +478,4 @@ int Process::pid() {
|
||||
|
||||
}} // namespace eterm::System
|
||||
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user