project64/Source/Project64/UserInterface/Debugger/ScriptAPI/ScriptAPI_exec.cpp

150 lines
4.1 KiB
C++

#include <stdafx.h>
#include <windows.h>
#include "ScriptAPI.h"
void ScriptAPI::Define_exec(duk_context* ctx)
{
DefineGlobalFunction(ctx, "exec", js_exec);
}
duk_ret_t ScriptAPI::js_exec(duk_context* ctx)
{
CheckArgs(ctx, { Arg_String, Arg_OptObject });
CScriptInstance* inst = GetInstance(ctx);
CScriptSystem* sys = inst->System();
const char* command = duk_get_string(ctx, 0);
struct
{
bool bShowWindow = false;
bool bVerbose = false;
stdstr cwd;
} options;
options.cwd = sys->InstallDirPath();
if (duk_is_object(ctx, 1))
{
duk_get_prop_string(ctx, 1, "hidden");
options.bShowWindow = duk_get_boolean_default(ctx, -1, false) != 0;
duk_pop(ctx);
duk_get_prop_string(ctx, 1, "verbose");
options.bVerbose = duk_get_boolean_default(ctx, -1, false) != 0;
duk_pop(ctx);
if (duk_has_prop_string(ctx, 1, "cwd"))
{
duk_get_prop_string(ctx, 1, "cwd");
options.cwd = duk_get_string(ctx, -1);
duk_pop(ctx);
}
}
stdstr resultStdOut;
stdstr resultStdErr;
DWORD resultExitCode = EXIT_FAILURE;
SECURITY_ATTRIBUTES secAttr;
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.bInheritHandle = TRUE;
secAttr.lpSecurityDescriptor = nullptr;
HANDLE hStdIn_r, hStdIn_w;
HANDLE hStdOut_r, hStdOut_w;
HANDLE hStdErr_r, hStdErr_w;
CreatePipe(&hStdIn_r, &hStdIn_w, &secAttr, 0);
CreatePipe(&hStdOut_r, &hStdOut_w, &secAttr, 0);
CreatePipe(&hStdErr_r, &hStdErr_w, &secAttr, 0);
STARTUPINFOA startupInfo;
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdInput = hStdIn_r;
startupInfo.hStdOutput = hStdOut_w;
startupInfo.hStdError = hStdErr_w;
if (!options.bShowWindow)
{
startupInfo.dwFlags |= STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;
}
PROCESS_INFORMATION processInfo;
BOOL bSuccess = CreateProcessA(nullptr, (LPSTR)stdstr_f("cmd /c %s", command).c_str(), nullptr, nullptr, TRUE,
0, nullptr, options.cwd.c_str(), &startupInfo, &processInfo);
if (bSuccess)
{
CloseHandle(hStdIn_r);
CloseHandle(hStdIn_w);
CloseHandle(hStdOut_w);
CloseHandle(hStdErr_w);
char buffer[1024];
DWORD nBytesRead;
while (ReadFile(hStdOut_r, buffer, sizeof(buffer), &nBytesRead, nullptr) && nBytesRead != 0)
{
for (size_t i = 0; i < nBytesRead; i++)
{
resultStdOut += buffer[i];
}
if (options.bVerbose)
{
sys->ConsolePrint("%.*s", nBytesRead, buffer);
}
}
while (ReadFile(hStdErr_r, buffer, sizeof(buffer), &nBytesRead, nullptr) && nBytesRead != 0)
{
for (size_t i = 0; i < nBytesRead; i++)
{
resultStdErr += buffer[i];
}
}
CloseHandle(hStdErr_r);
CloseHandle(hStdOut_r);
CloseHandle(processInfo.hThread);
WaitForSingleObject(processInfo.hProcess, INFINITE);
GetExitCodeProcess(processInfo.hProcess, &resultExitCode);
CloseHandle(processInfo.hProcess);
}
else
{
CloseHandle(hStdIn_r);
CloseHandle(hStdIn_w);
CloseHandle(hStdOut_r);
CloseHandle(hStdOut_w);
CloseHandle(hStdErr_r);
CloseHandle(hStdErr_w);
}
if (!bSuccess || resultExitCode != 0)
{
const DukPropListEntry props[] = {
{ "status", DukInt(resultExitCode) },
{ "stdout", DukString(resultStdOut.c_str()) },
{ "stderr", DukString(resultStdErr.c_str()) },
{ "pid", DukUInt(processInfo.dwProcessId) },
{ nullptr }
};
duk_push_error_object(ctx, resultExitCode, "exec(): process returned %d", resultExitCode);
DukPutPropList(ctx, -1, props);
return duk_throw(ctx);
}
else
{
duk_push_string(ctx, resultStdOut.c_str());
}
return 1;
}