#include "SubProcessIO.h" #include 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(dwDoneghChildStdInWrite,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(dwDoneghChildStdOutRead,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; }