SubProcessIO/SubProcessIO.cpp

277 lines
6.3 KiB
C++

#include "SubProcessIO.h"
#include <windows.h>
struct SubProcessIO::_impl
{
HANDLE ghChildStdInRead;
HANDLE ghChildStdInWrite;
HANDLE ghChildStdOutRead;
HANDLE ghChildStdOutWrite;
HANDLE hChildProcess;
bool flagDetach;
bool flagStopped;
bool flagTerminateOnDestruct;
};
SubProcessIO::SubProcessIO(const std::string& Command,bool TerminateOnDestruct) throw(std::runtime_error)
{
_pimpl=new _impl;
_pimpl->ghChildStdInRead=NULL;
_pimpl->ghChildStdInWrite=NULL;
_pimpl->ghChildStdOutRead=NULL;
_pimpl->ghChildStdOutWrite=NULL;
_pimpl->flagDetach=false;
_pimpl->flagStopped=true;
_pimpl->flagTerminateOnDestruct=TerminateOnDestruct;
int ret;
if((ret=createSubProcessWith(Command))<0)
{
char buff[128];
memset(buff,0,128);
snprintf(buff,0,"Error on createSubProcessWith(...), ReturnVal: %d",ret);
throw std::runtime_error(buff);
}
else
{
_pimpl->flagStopped=false;
}
}
SubProcessIO::~SubProcessIO()
{
if(!_pimpl->flagStopped)
{
/// Process is running
if(!_pimpl->flagDetach)
{
/// Process not detached...
if(_pimpl->flagTerminateOnDestruct)
{
/// Terminate Flag is set. Then call terminate!
terminate();
}
else
{
/// Terminate Flag is not set. Then wait the child process to exit.
wait();
}
}
else
{
/// Process is detached. Do nothing.
}
}
/// Close I/O Handle.
CloseHandle(_pimpl->ghChildStdInWrite);
CloseHandle(_pimpl->ghChildStdOutRead);
/// Close Child Process Handle.
CloseHandle(_pimpl->hChildProcess);
delete _pimpl;
}
// protected
int SubProcessIO::createSubProcessWith(const std::string& Command)
{
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength=sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle=TRUE;
saAttr.lpSecurityDescriptor=NULL;
if( ! CreatePipe(&(_pimpl->ghChildStdOutRead),&(_pimpl->ghChildStdOutWrite),&saAttr,0))
{
printf("Error on Create Pipe.\n");
return -1;
}
if( ! SetHandleInformation(_pimpl->ghChildStdOutRead,HANDLE_FLAG_INHERIT,0) )
{
printf("Error on SetHandleInformation.\n");
return -2;
}
if( ! CreatePipe(&(_pimpl->ghChildStdInRead),&(_pimpl->ghChildStdInWrite),&saAttr,0))
{
printf("Error on Create Another Pipe.\n");
return -3;
}
if( ! SetHandleInformation(_pimpl->ghChildStdInWrite,HANDLE_FLAG_INHERIT,0))
{
printf("Error on another SetHandleInformation.\n");
return -4;
}
/// Create SubProcess.
PROCESS_INFORMATION procInfo;
STARTUPINFO startInfo;
BOOL bSuccess=FALSE;
ZeroMemory(&procInfo,sizeof(PROCESS_INFORMATION));
ZeroMemory(&startInfo,sizeof(STARTUPINFO));
startInfo.cb=sizeof(STARTUPINFO);
startInfo.hStdError=_pimpl->ghChildStdOutWrite;
startInfo.hStdOutput=_pimpl->ghChildStdOutWrite;
startInfo.hStdInput=_pimpl->ghChildStdInRead;
startInfo.dwFlags|=STARTF_USESTDHANDLES;
/// Create Child Process (Real Call)
bSuccess=CreateProcess(NULL,(char*)Command.c_str(),
NULL, /// security attribute
NULL, /// primary thread attribute
TRUE, /// inherit handles
0, /// creation flag
NULL, /// use parent's environment
NULL, /// use parent's current directory
&startInfo, /// Use this start info
&procInfo /// Use this process info
);
if(!bSuccess)
{
printf("Failed on CreateProcess.\n");
return -5;
}
else
{
/// Close Thread Handle.
CloseHandle(procInfo.hThread);
//CloseHandle(procInfo.hProcess);
_pimpl->hChildProcess=procInfo.hProcess;
/// Close Not Used Handle in father process.
CloseHandle(_pimpl->ghChildStdOutWrite);
CloseHandle(_pimpl->ghChildStdInRead);
}
return 0;
}
int SubProcessIO::writeToSubProcess(const char* buffer,int szToWrite)
{
if(szToWrite<=0) return -1;
DWORD dwWritten,dwDone,dwAll;
dwDone=0;
dwAll=szToWrite;
while(dwDone<dwAll)
{
dwWritten=0;
BOOL bSuccess=WriteFile(_pimpl->ghChildStdInWrite,buffer+dwDone,dwAll-dwDone,&dwWritten,NULL);
if(!bSuccess)
{
/// Error on WriteFile
return -2;
}
dwDone+=dwWritten;
}
return 0;
}
int SubProcessIO::peekSubProcess()
{
DWORD available;
if(!PeekNamedPipe(_pimpl->ghChildStdOutRead,NULL,0,NULL,&available,NULL))
{
printf("Failed to peek named pipe.\n");
return -1;
}
else
{
return available;
}
}
int SubProcessIO::readFromSubProcess(char* buffer,int szToRead)
{
if(szToRead<=0) return -1;
DWORD dwRead,dwDone,dwAll;
dwDone=0;
dwAll=szToRead;
while(dwDone<dwAll)
{
BOOL bSuccess=ReadFile(_pimpl->ghChildStdOutRead,buffer+dwDone,dwAll-dwDone,&dwRead,NULL);
if(!bSuccess)
{
/// Read Error.
return -2;
}
dwDone+=dwRead;
}
return 0;
}
int SubProcessIO::wait()
{
DWORD ret=WaitForSingleObject(_pimpl->hChildProcess,INFINITE);
switch(ret)
{
case WAIT_ABANDONED:
return -1;
case WAIT_OBJECT_0:
return 0;
case WAIT_TIMEOUT:
return -2;
case WAIT_FAILED:
return -3;
}
return -4;
}
int SubProcessIO::wait(int ms)
{
DWORD ret=WaitForSingleObject(_pimpl->hChildProcess,ms);
switch(ret)
{
case WAIT_ABANDONED:
return -1;
case WAIT_OBJECT_0:
return 0;
case WAIT_TIMEOUT:
return -2;
case WAIT_FAILED:
return -3;
}
return -4;
}
int SubProcessIO::getExitCode()
{
DWORD code;
GetExitCodeProcess(_pimpl->hChildProcess,&code);
return code;
}
int SubProcessIO::terminate()
{
BOOL ret=TerminateProcess(_pimpl->hChildProcess,0);
if(ret!=FALSE)
{
/// Terminate Successfully.
_pimpl->flagStopped=true;
return 0;
}
else
{
/// Terminate Error.
return -1;
}
}
void SubProcessIO::detach()
{
_pimpl->flagDetach=true;
}