#include "ProcessUtilities.h" #include #include class MutexGrabber { public: MutexGrabber(HANDLE ahMutex) : hMutex(ahMutex) { WaitForSingleObject(hMutex,INFINITE); } ~MutexGrabber() { ReleaseMutex(hMutex); } private: HANDLE hMutex; }; class ProcessInfo { public: ProcessInfo() : AccessMutex(NULL), SignalEvent(NULL), StdOutputFileHandle(NULL), StdErrorFileHandle(NULL), Process(NULL), ProcessFinished(false) { } ~ProcessInfo() { CloseHandle(AccessMutex); CloseHandle(SignalEvent); CloseHandle(StdOutputFileHandle); CloseHandle(StdErrorFileHandle); CloseHandle(Process); } HANDLE AccessMutex; HANDLE SignalEvent; HANDLE StdOutputFileHandle; HANDLE StdErrorFileHandle; HANDLE Process; bool ProcessFinished; ProcessController* Master; std::string OutputBuffer; std::string ErrorBuffer; void monitorStdOutput(); void monitorStdError(); }; void ProcessInfo::monitorStdOutput() { while (true) { char Buffer[1025]; DWORD ActuallyRead; if (!ReadFile(StdOutputFileHandle,Buffer,1024,&ActuallyRead,NULL)) break; MutexGrabber Lock(AccessMutex); OutputBuffer += std::string(Buffer,ActuallyRead); if (OutputBuffer.length()) SetEvent(SignalEvent); } MutexGrabber Lock(AccessMutex); CloseHandle(StdOutputFileHandle); StdOutputFileHandle = NULL; SetEvent(SignalEvent); } void ProcessInfo::monitorStdError() { while (true) { char Buffer[1025]; DWORD ActuallyRead; if (!ReadFile(StdErrorFileHandle,Buffer,1024,&ActuallyRead,NULL)) break; MutexGrabber Lock(AccessMutex); ErrorBuffer += std::string(Buffer,ActuallyRead); if (ErrorBuffer.length()) SetEvent(SignalEvent); } MutexGrabber Lock(AccessMutex); CloseHandle(StdErrorFileHandle); StdErrorFileHandle = NULL; SetEvent(SignalEvent); } DWORD WINAPI MonitorStdOutput(LPVOID lpvThreadParam) { ProcessInfo* PI = static_cast(lpvThreadParam); PI->monitorStdOutput(); return 0; } DWORD WINAPI MonitorStdError(LPVOID lpvThreadParam) { ProcessInfo* PI = static_cast(lpvThreadParam); PI->monitorStdError(); return 0; } std::vector Processes; bool launchProcess(ProcessController* theController, const std::string& Executable, const std::vector& Args) { /* std::cout << Executable; for (unsigned int i=0; iProcess = piProcInfo.hProcess; PI->StdOutputFileHandle = StdOutRd; PI->StdErrorFileHandle = StdErrRd; PI->Master = theController; PI->AccessMutex = CreateMutex(NULL,false,NULL); if (!PI->AccessMutex) { std::cerr << "Can't mutex" << std::endl; return false; } PI->SignalEvent = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PI->SignalEvent) { std::cerr << "Can't organize event" << std::endl; return false; } HANDLE StdOutputThread = CreateThread(NULL,0,MonitorStdOutput,PI,0,NULL); if (!StdOutputThread) { std::cerr << "Can't thread a needle" << std::endl; return false; } CloseHandle(StdOutputThread); HANDLE StdErrorThread = CreateThread(NULL,0,MonitorStdError,PI,0,NULL); if (!StdOutputThread) { std::cerr << "Can't thread a needle" << std::endl; return false; } CloseHandle(StdErrorThread); Processes.push_back(PI); // return true; } unsigned int waitForProcessEvent() { if (!Processes.size()) return 0; // TODO wait for some process shit to happen std::vector ReadSignals; for (unsigned int i=0; iSignalEvent); for (unsigned int i=0; iProcessFinished) ReadSignals.push_back(Processes[i]->Process); DWORD Res = WaitForMultipleObjects( ReadSignals.size(), &ReadSignals[0], false, 3000); if (Res == WAIT_TIMEOUT) { std::cout << "Waiting..." << std::endl; return Processes.size(); } else if (Res == WAIT_FAILED) { std::cout << "WaitForMultipleObjects failed" << std::endl; return Processes.size(); } Res -= WAIT_OBJECT_0; bool ProcessFinished = false; if (Res >= Processes.size()) { Res -= Processes.size(); for (unsigned int i=0; iProcessFinished) { if (Res == 0) { ProcessFinished = true; Res = i; break; } else --Res; } } } ProcessInfo* PI = Processes[Res]; std::string Output,Error; bool BrokenPipe = false; { MutexGrabber Lock(PI->AccessMutex); if (ProcessFinished) PI->ProcessFinished = true; Output = PI->OutputBuffer; PI->OutputBuffer.clear(); Error = PI->ErrorBuffer; PI->ErrorBuffer.clear(); BrokenPipe = (PI->StdOutputFileHandle == NULL) && (PI->StdErrorFileHandle == NULL) && PI->ProcessFinished; } if (Output.length()) PI->Master->standardOutput(Output); if (Error.length()) PI->Master->standardError(Error); if (BrokenPipe) { DWORD ExitCode = 10; GetExitCodeProcess(PI->Process,&ExitCode); PI->Master->finished(ExitCode); PI->Master->signalFinish(ExitCode); if (ExitCode) PI->Master->failed(); // std::cout << "exit code=" << ExitCode << std::endl; delete PI; Processes.erase(Processes.begin()+Res); } return Processes.size(); } bool isShellRedirective(const std::string& S) { return (S=="|") || (S=="<") || (S==">"); } bool shellLaunchProcess(ProcessController* theController, const std::string& Executable, const std::vector& Args) { unsigned int i=0; for (i=0; i NewArgs; NewArgs.push_back("/c"); NewArgs.push_back(ShellCommand); return launchProcess(theController, "cmd.exe", NewArgs); }