mirror of
https://bitbucket.org/theswgsource/src-1.2.git
synced 2026-07-30 00:15:47 -04:00
Initial commit of the sharedFoundation library
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
//
|
||||
// ProcessSpawner.cpp
|
||||
//
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#include "sharedFoundation/FirstSharedFoundation.h"
|
||||
#include "sharedFoundation/ProcessSpawner.h"
|
||||
|
||||
#include "sharedFoundation/Os.h"
|
||||
|
||||
#include <minmax.h>
|
||||
|
||||
ProcessSpawner::ProcessSpawner()
|
||||
{
|
||||
m_asConsole=false;
|
||||
hProcess=0;
|
||||
hOutputRead=0;
|
||||
hInputWrite=0;
|
||||
currentLine=currentRead=readBuffer;
|
||||
}
|
||||
|
||||
|
||||
ProcessSpawner::~ProcessSpawner()
|
||||
{
|
||||
if (hProcess)
|
||||
{
|
||||
CloseHandle(hProcess);
|
||||
hProcess=0;
|
||||
}
|
||||
if (hOutputRead)
|
||||
{
|
||||
CloseHandle(hOutputRead);
|
||||
hOutputRead=0;
|
||||
}
|
||||
if (hInputWrite)
|
||||
{
|
||||
CloseHandle(hInputWrite);
|
||||
hInputWrite=0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessSpawner::terminate(unsigned exitCode)
|
||||
{
|
||||
if (!hProcess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return TerminateProcess(hProcess, exitCode)!=0;
|
||||
}
|
||||
|
||||
bool ProcessSpawner::create(const char *commandLine, const char *startupFolder, bool asConsole)
|
||||
{
|
||||
if (hProcess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!commandLine)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!startupFolder)
|
||||
{
|
||||
startupFolder=Os::getProgramStartupDirectory();
|
||||
}
|
||||
|
||||
m_asConsole=asConsole;
|
||||
|
||||
STARTUPINFO sinfo;
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
sinfo.cb=sizeof(sinfo);
|
||||
|
||||
HANDLE hOutputWrite=0;
|
||||
HANDLE hErrorWrite=0;
|
||||
HANDLE hInputRead=0;
|
||||
|
||||
if (asConsole)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength=sizeof(sa);
|
||||
sa.lpSecurityDescriptor=0;
|
||||
sa.bInheritHandle=true;
|
||||
|
||||
// -----------------------------------------------------
|
||||
|
||||
// Create the child output pipe.
|
||||
HANDLE hOutputReadTmp;
|
||||
CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0);
|
||||
|
||||
// Create a duplicate of the output write handle for the std error
|
||||
// write handle. This is necessary in case the child application
|
||||
// closes one of its std output handles.
|
||||
DuplicateHandle(
|
||||
GetCurrentProcess(), hOutputWrite,
|
||||
GetCurrentProcess(),&hErrorWrite,
|
||||
0,
|
||||
TRUE,DUPLICATE_SAME_ACCESS
|
||||
);
|
||||
|
||||
|
||||
// Create the child input pipe.
|
||||
HANDLE hInputWriteTmp;
|
||||
CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0);
|
||||
|
||||
// Create new output read handle and the input write handles. Set
|
||||
// the Properties to FALSE. Otherwise, the child inherits the
|
||||
// properties and, as a result, non-closeable handles to the pipes
|
||||
// are created.
|
||||
DuplicateHandle(
|
||||
GetCurrentProcess(), hOutputReadTmp,
|
||||
GetCurrentProcess(), &hOutputRead, // Address of new handle.
|
||||
0, FALSE, // Make it uninheritable.
|
||||
DUPLICATE_SAME_ACCESS
|
||||
);
|
||||
|
||||
DuplicateHandle(
|
||||
GetCurrentProcess(), hInputWriteTmp,
|
||||
GetCurrentProcess(), &hInputWrite, // Address of new handle.
|
||||
0,FALSE, // Make it uninheritable.
|
||||
DUPLICATE_SAME_ACCESS
|
||||
);
|
||||
|
||||
|
||||
// Close inheritable copies of the handles you do not want to be
|
||||
// inherited.
|
||||
CloseHandle(hOutputReadTmp); hOutputReadTmp=0;
|
||||
CloseHandle(hInputWriteTmp); hInputWriteTmp=0;
|
||||
|
||||
sinfo.dwFlags|=(STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
|
||||
sinfo.hStdError=hErrorWrite;
|
||||
sinfo.hStdInput=hInputRead;
|
||||
sinfo.hStdOutput=hOutputWrite;
|
||||
sinfo.wShowWindow = SW_HIDE;
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION pinfo;
|
||||
BOOL result = CreateProcess(
|
||||
0,
|
||||
(char *)commandLine,
|
||||
0,
|
||||
0,
|
||||
TRUE,
|
||||
CREATE_NEW_CONSOLE,
|
||||
0,
|
||||
startupFolder,
|
||||
&sinfo,
|
||||
&pinfo
|
||||
);
|
||||
|
||||
if (asConsole)
|
||||
{
|
||||
// Close pipe handles (do not continue to modify the parent).
|
||||
// You need to make sure that no handles to the write end of the
|
||||
// output pipe are maintained in this process or else the pipe will
|
||||
// not close when the child process exits and the ReadFile will hang.
|
||||
CloseHandle(hOutputWrite); hOutputWrite=0;
|
||||
CloseHandle(hErrorWrite); hErrorWrite=0;
|
||||
CloseHandle(hInputRead); hInputRead=0;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
CloseHandle(pinfo.hThread);
|
||||
hProcess=pinfo.hProcess;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to launch turf
|
||||
hProcess=0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessSpawner::isFinished(unsigned waitTime)
|
||||
{
|
||||
if (!hProcess)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD waitResult = WaitForSingleObject(hProcess, waitTime);
|
||||
|
||||
return waitResult==WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool ProcessSpawner::getExitCode(unsigned &o_code)
|
||||
{
|
||||
if (!hProcess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD exitCode;
|
||||
BOOL result = GetExitCodeProcess(hProcess, &exitCode);
|
||||
if (result)
|
||||
{
|
||||
o_code=exitCode;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessSpawner::_returnExistingLine(char *buffer, const int bufferSize)
|
||||
{
|
||||
const char *const bufferStop = buffer + bufferSize;
|
||||
char *iter = currentLine;
|
||||
while (iter!=currentRead)
|
||||
{
|
||||
if (buffer==bufferStop)
|
||||
{
|
||||
currentLine=iter;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*iter=='\n')
|
||||
{
|
||||
*buffer++=0;
|
||||
_stepIter(iter);
|
||||
currentLine=iter;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buffer++=*iter;
|
||||
_stepIter(iter);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessSpawner::getOutputString(char *buffer, int bufferSize)
|
||||
{
|
||||
if (_returnExistingLine(buffer, bufferSize))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
if (!hOutputRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwAvail = 0;
|
||||
if (!::PeekNamedPipe(hOutputRead, NULL, 0, NULL, &dwAvail, NULL))
|
||||
{
|
||||
// ERROR
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dwAvail)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwRead;
|
||||
|
||||
if (currentRead >= currentLine)
|
||||
{
|
||||
const unsigned bufferAvailable = sizeof(readBuffer) - (currentRead - readBuffer);
|
||||
unsigned toRead = dwAvail;
|
||||
if (toRead > bufferAvailable)
|
||||
{
|
||||
toRead=bufferAvailable;
|
||||
}
|
||||
|
||||
dwRead=0;
|
||||
if (!::ReadFile(hOutputRead, currentRead, min(bufferAvailable, dwAvail), &dwRead, NULL) || !dwRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
dwAvail-=dwRead;
|
||||
currentRead+=dwRead;
|
||||
if (currentRead==readBuffer+sizeof(readBuffer))
|
||||
{
|
||||
currentRead=readBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (dwAvail>0)
|
||||
{
|
||||
const unsigned bufferAvailable = currentLine - currentRead - 1;
|
||||
if (bufferAvailable)
|
||||
{
|
||||
unsigned toRead = dwAvail;
|
||||
if (toRead > bufferAvailable)
|
||||
{
|
||||
toRead=bufferAvailable;
|
||||
}
|
||||
|
||||
dwRead=0;
|
||||
if (!::ReadFile(hOutputRead, currentRead, min(bufferAvailable, dwAvail), &dwRead, NULL) || !dwRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
currentRead+=dwRead;
|
||||
|
||||
DEBUG_FATAL(currentRead>=currentLine, (""));
|
||||
}
|
||||
}
|
||||
|
||||
return _returnExistingLine(buffer, bufferSize);
|
||||
}
|
||||
Reference in New Issue
Block a user