I needed to run some commands from juce, and getting their stdout or redirecting their output to a file (neither works with the generic juce File call) so i wrote something myself, it’s taken out of context but you get an idea. There is a static call to just call a process and enable output redirection.
ProcessPipe.cpp
#include "ProcessPipe.h"
ProcessPipe::ProcessPipe(const String &_processCommand, const uint32 _executionTimeout, const bool _showOutput)
: executionTimeout(_executionTimeout),
processCommand(_processCommand),
showOutput(_showOutput)
{
}
ProcessPipe::~ProcessPipe()
{
}
const bool ProcessPipe::createProcess()
{
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&pipeStdoutRead, &pipeStdoutWrite, &saAttr, 0))
{
return (false);
}
if (!SetHandleInformation(pipeStdoutRead, HANDLE_FLAG_INHERIT, 0))
{
return (false);
}
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = pipeStdoutWrite;
siStartInfo.hStdOutput = pipeStdoutWrite;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
if (!showOutput)
{
siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
siStartInfo.wShowWindow = SW_HIDE;
}
bSuccess = CreateProcess(NULL, (LPSTR)processCommand.toUTF8(), NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);
if (!bSuccess)
{
startTimer (executionTimeout);
return (false);
}
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return (true);
}
}
const bool ProcessPipe::readOutput(MemoryBlock &output)
{
DWORD dwRead;
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
uint32 dataRead = 0;
if (!CloseHandle(pipeStdoutWrite))
{
return (false);
}
MemoryBlock data(BUFSIZE*8, true);
for (;;)
{
bSuccess = ReadFile (pipeStdoutRead, data, BUFSIZE, &dwRead, NULL);
dataRead = dataRead + dwRead;
if(!bSuccess || dwRead == 0)
{
output.setSize (dataRead);
output.copyFrom (data.getData(), 0, dataRead);
break;
}
}
return (true);
}
void ProcessPipe::timerCallback()
{
Logger::writeToLog (T("timerCallback()"));
DWORD exitStatus;
if (GetExitCodeProcess (piProcInfo.hProcess, &exitStatus))
{
if (exitStatus == STILL_ACTIVE)
{
if (!TerminateProcess (piProcInfo.hProcess, 13))
{
AlertWindow::showMessageBox (AlertWindow::WarningIcon, T("Blad podczas proby zakonczenia procesu"), T("Proces ktory osiagnal timeout nie moze zostac zakonczony: ") + processCommand);
}
}
}
else
{
AlertWindow::showMessageBox (AlertWindow::WarningIcon, T("Blad podczas proby zakonczenia procesu"), T("Nie mozna odczytac statusu procesu: ") + processCommand);
}
}
const bool ProcessPipe::startConsoleApp (const String commandLine, const String arguments)
{
STARTUPINFO siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
const String args = T(" /C \"") + commandLine + T("\" ") + arguments;
Logger::writeToLog (T("ProcessPipe: ") + args);
char wpath[256];
GetWindowsDirectory (wpath, 256);
String cmd(String(wpath) + T("\\system32\\cmd.exe"));
if(CreateProcess(cmd.toUTF8(), // Application name
(LPSTR)args.toUTF8(), // Application arguments
0,
0,
FALSE,
CREATE_DEFAULT_ERROR_MODE,
0,
0, // Working directory
&siStartupInfo,
&piProcessInfo) == FALSE)
{
return (false);
}
else
{
return (true);
}
}
ProcessPipe.h
#include "Includes.h"
#define BUFSIZE 8192
class ProcessPipe : public Timer
{
public:
ProcessPipe(const String &_processCommand, const uint32 _executionTimeout=1000, const bool _showOutput=false);
~ProcessPipe();
const bool createProcess ();
const bool readOutput (MemoryBlock &output);
void timerCallback();
static const bool startConsoleApp (const String commandLine, const String arguments);
private:
String processCommand;
uint32 executionTimeout;
HANDLE pipeStdoutRead;
HANDLE pipeStdoutWrite;
PROCESS_INFORMATION piProcInfo;
bool showOutput;
};