From e6045d5d068318b05ee5ce986fcebacbb182e3f1 Mon Sep 17 00:00:00 2001 From: Kiritow <1362050620@qq.com> Date: Thu, 1 Jun 2017 19:44:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20'SubProcessIO.cpp'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SubProcessIO.cpp | 276 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 SubProcessIO.cpp diff --git a/SubProcessIO.cpp b/SubProcessIO.cpp new file mode 100644 index 0000000..00c27b4 --- /dev/null +++ b/SubProcessIO.cpp @@ -0,0 +1,276 @@ +#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; +}