Fill Process on Windows
This commit is contained in:
@ -3,16 +3,63 @@
|
||||
#include "TessesFramework/Platform/Environment.hpp"
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
extern "C" {
|
||||
#include <windows.h>
|
||||
}
|
||||
#include "TessesFramework/Filesystem/VFSFix.hpp"
|
||||
#include 'TessesFramework/Text/StringConverter.hpp'
|
||||
using namespace Tesses::Framework::Text::StringConverter;
|
||||
static void escape_windows_args(std::string& str, std::vector<std::string> args)
|
||||
{
|
||||
bool first = true;
|
||||
for (auto item : args)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
str.push_back('\"');
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
str.append(" \"");
|
||||
}
|
||||
|
||||
for (auto c : item)
|
||||
{
|
||||
if (c == '"') str.append("\\\"");
|
||||
else str.push_back(c);
|
||||
}
|
||||
|
||||
str.push_back('\"');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Tesses::Framework::Platform {
|
||||
|
||||
class ProcessData {
|
||||
public:
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
HANDLE stdin_strm;
|
||||
HANDLE stdout_strm;
|
||||
HANDLE stderr_strm;
|
||||
|
||||
|
||||
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||
#else
|
||||
int stdin_strm;
|
||||
@ -23,7 +70,12 @@ namespace Tesses::Framework::Platform {
|
||||
ProcessData() {
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
|
||||
stdin_strm = NULL;
|
||||
stdout_strm = NULL;
|
||||
stderr_strm = NULL;
|
||||
|
||||
|
||||
|
||||
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||
|
||||
#else
|
||||
@ -35,23 +87,30 @@ namespace Tesses::Framework::Platform {
|
||||
};
|
||||
class ProcessStream : public Tesses::Framework::Streams::Stream {
|
||||
#if defined(_WIN32)
|
||||
HANDLE strm;
|
||||
bool writing;
|
||||
bool eos;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
#else
|
||||
int strm;
|
||||
|
||||
bool writing;
|
||||
bool shouldClose;
|
||||
bool eos;
|
||||
#endif
|
||||
public:
|
||||
#if defined(_WIN32)
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
#else
|
||||
ProcessStream(int strm, bool writing, bool shouldClose)
|
||||
ProcessStream(HANDLE strm, bool writing)
|
||||
{
|
||||
this->strm = strm;
|
||||
this->writing = writing;
|
||||
this->eos = false;
|
||||
}
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
#else
|
||||
ProcessStream(int strm, bool writing)
|
||||
{
|
||||
this->strm = strm;
|
||||
this->writing = writing;
|
||||
this->shouldClose=shouldClose;
|
||||
this->eos=false;
|
||||
}
|
||||
#endif
|
||||
@ -59,7 +118,7 @@ namespace Tesses::Framework::Platform {
|
||||
{
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
return true;
|
||||
return this->strm == NULL || eos;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return true;
|
||||
#else
|
||||
@ -70,7 +129,7 @@ namespace Tesses::Framework::Platform {
|
||||
{
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
return false;
|
||||
return !writing && this->strm != NULL;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return false;
|
||||
#else
|
||||
@ -81,7 +140,8 @@ namespace Tesses::Framework::Platform {
|
||||
{
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
return false;
|
||||
|
||||
return writing && this->strm != NULL;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return false;
|
||||
#else
|
||||
@ -93,7 +153,15 @@ namespace Tesses::Framework::Platform {
|
||||
{
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
return 0;
|
||||
if (this->strm == NULL || this->eos && writing) return 0;
|
||||
|
||||
DWORD dataR = (DWORD)sz;
|
||||
if (!ReadFile(this->strm, buff, dataR, &dataR, NULL))
|
||||
return 0;
|
||||
if (dataR == 0) {
|
||||
this->eos = true;
|
||||
}
|
||||
return (size_t)dataW;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return 0;
|
||||
#else
|
||||
@ -110,30 +178,22 @@ namespace Tesses::Framework::Platform {
|
||||
{
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
return 0;
|
||||
if (this->strm == NULL || !writing) return 0;
|
||||
DWORD dataW=(DWORD)sz;
|
||||
if (!WriteFile(this->strm, buff, dataW, &dataW, NULL))
|
||||
return 0;
|
||||
|
||||
return (size_t)dataW;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return 0;
|
||||
#else
|
||||
if(this->strm < 0 && !writing) return 0;
|
||||
if(this->strm < 0 || !writing) return 0;
|
||||
auto r = write(this->strm,buff,sz);
|
||||
if(r == -1) return 0;
|
||||
return (size_t)r;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
~ProcessStream()
|
||||
{
|
||||
//TODO: Implement for WIN32
|
||||
#if defined(_WIN32)
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
//do nothing
|
||||
#else
|
||||
if(this->strm > -1 && this->shouldClose)
|
||||
close(this->strm);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -174,14 +234,28 @@ namespace Tesses::Framework::Platform {
|
||||
}
|
||||
Process::~Process()
|
||||
{
|
||||
ProcessData* p = this->hidden.GetField<ProcessData*>();
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (p->stdin_strm != NULL)
|
||||
CloseHandle(p->stdin_strm);
|
||||
|
||||
if (p->stdout_strm != NULL)
|
||||
CloseHandle(p->stdout_strm);
|
||||
|
||||
if (p->stderr_strm != NULL)
|
||||
CloseHandle(p->stderr_strm);
|
||||
|
||||
CloseHandle(p->pi.hProcess);
|
||||
CloseHandle(p->pi.hThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Process::Start()
|
||||
{
|
||||
auto p =
|
||||
ProcessData* p =
|
||||
this->hidden.GetField<ProcessData*>();
|
||||
std::vector<std::pair<std::string,std::string>> envs;
|
||||
|
||||
@ -204,6 +278,114 @@ namespace Tesses::Framework::Platform {
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
std::u16string u16_name;
|
||||
std::u16string u16_args;
|
||||
std::string args;
|
||||
escape_windows_args(args,this->args);
|
||||
UTF16::FromUTF8(u16_name,this->name);
|
||||
UTF16::FromUTF8(u16_args, args);
|
||||
std::u16string env = {};
|
||||
|
||||
for (auto envItem : this->env)
|
||||
{
|
||||
auto partOld = envItem.first + "=" + envItem.second;
|
||||
std::u16string part = {};
|
||||
|
||||
UTF16::FromUTF8(part,partOld);
|
||||
env.append(part);
|
||||
env.push_back(0);
|
||||
}
|
||||
env.push_back(0);
|
||||
|
||||
std::u16string workDir = {};
|
||||
|
||||
if (!this->workingDirectory.empty())
|
||||
UTF16::FromUTF8(workDir, this->workingDirectory);
|
||||
|
||||
SECURITY_ATTRIBUTES attr;
|
||||
attr.nLength = sizeof(attr);
|
||||
attr.lpSecurityDescriptor = NULL;
|
||||
attr.bInheritHandle = true;
|
||||
p->si->hStdInput = NULL;
|
||||
p->si->hStdOutput = NULL;
|
||||
|
||||
p->si->hStdError = NULL;
|
||||
|
||||
p->stdin_strm = NULL;
|
||||
p->stdout_strm = NULL;
|
||||
p->stderr_strm = NULL;
|
||||
|
||||
if (this->redirectStdIn)
|
||||
{
|
||||
if (!CreatePipe(&p->si->hStdInput, &p->stdin_strm, &attr,0)) return false;
|
||||
}
|
||||
|
||||
if (this->redirectStdOut)
|
||||
{
|
||||
if (!CreatePipe(&p->stdout_strm, &p->si->hStdOutput, &attr, 0))
|
||||
{
|
||||
if (this->redirectStdIn)
|
||||
{
|
||||
CloseHandle(p->stdin_strm);
|
||||
CloseHandle(p->si->hStdInput);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this->redirectStdErr)
|
||||
{
|
||||
if (!CreatePipe(&p->stderr_strm, &p->si->hStdError, &attr, 0))
|
||||
{
|
||||
if (this->redirectStdIn)
|
||||
{
|
||||
CloseHandle(p->stdin_strm);
|
||||
CloseHandle(p->si->hStdInput);
|
||||
}
|
||||
if (this->redirectStdOut)
|
||||
{
|
||||
CloseHandle(p->stdout_strm);
|
||||
CloseHandle(p->si->hStdOutput);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreateProcessW(u16_name.c_str(), u16_args.data(), NULL, NULL, (this->redirectStdIn || this->redirectStdOut || this->redirectStdErr), CREATE_UNICODE_ENVIRONMENT, (LPCWSTR)env.c_str(), workDir.empty() ? (LPCWSTR)NULL : (LPCWSTR)workDir.c_str(), &(p->si), &(p->pi)))
|
||||
{
|
||||
if (this->redirectStdIn)
|
||||
{
|
||||
CloseHandle(p->stdin_strm);
|
||||
CloseHandle(p->si->hStdInput);
|
||||
}
|
||||
if (this->redirectStdOut)
|
||||
{
|
||||
CloseHandle(p->stdout_strm);
|
||||
CloseHandle(p->si->hStdOutput);
|
||||
}
|
||||
if (this->redirectStdErr)
|
||||
{
|
||||
CloseHandle(p->stderr_strm);
|
||||
CloseHandle(p->si->hStdError);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
BOOL
|
||||
WINAPI
|
||||
CreateProcessW(
|
||||
_In_opt_ LPCWSTR lpApplicationName,
|
||||
_Inout_opt_ LPWSTR lpCommandLine,
|
||||
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
_In_ BOOL bInheritHandles,
|
||||
_In_ DWORD dwCreationFlags,
|
||||
_In_opt_ LPVOID lpEnvironment,
|
||||
_In_opt_ LPCWSTR lpCurrentDirectory,
|
||||
_In_ LPSTARTUPINFOW lpStartupInfo,
|
||||
_Out_ LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
*/
|
||||
return false;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return false;
|
||||
@ -352,34 +534,34 @@ namespace Tesses::Framework::Platform {
|
||||
#endif
|
||||
}
|
||||
|
||||
Tesses::Framework::Streams::Stream* Process::GetStdinStream(bool closeUnderlying)
|
||||
Tesses::Framework::Streams::Stream* Process::GetStdinStream()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return nullptr;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return nullptr;
|
||||
#else
|
||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdin_strm,true,closeUnderlying);
|
||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdin_strm,true);
|
||||
#endif
|
||||
}
|
||||
Tesses::Framework::Streams::Stream* Process::GetStdoutStream(bool closeUnderlying)
|
||||
Tesses::Framework::Streams::Stream* Process::GetStdoutStream()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return nullptr;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return nullptr;
|
||||
#else
|
||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdout_strm,false,closeUnderlying);
|
||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdout_strm,false);
|
||||
#endif
|
||||
}
|
||||
Tesses::Framework::Streams::Stream* Process::GetStderrStream(bool closeUnderlying)
|
||||
Tesses::Framework::Streams::Stream* Process::GetStderrStream()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return nullptr;
|
||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
||||
return nullptr;
|
||||
#else
|
||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stderr_strm,false,closeUnderlying);
|
||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stderr_strm,false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user