X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Fcore%2Fwindows%2Fprocess.cpp;fp=source%2Fcore%2Fwindows%2Fprocess.cpp;h=7b1efd693aff45fce41594914b4d16dc2264de70;hp=0000000000000000000000000000000000000000;hb=ea60f3548d4769c356b796cb27cd690cdfe4b6d9;hpb=8091a3071918d4cd30f2b9ab903e1d73d12dcb36 diff --git a/source/core/windows/process.cpp b/source/core/windows/process.cpp new file mode 100644 index 0000000..7b1efd6 --- /dev/null +++ b/source/core/windows/process.cpp @@ -0,0 +1,137 @@ +#include +#include +#include +#include "process.h" +#include "process_private.h" + +using namespace std; + +namespace { + +string quote_argument(const string &arg) +{ + string result; + bool need_quotes = false; + bool backslash = false; + for(string::const_iterator i=arg.begin(); i!=arg.end(); ++i) + { + if(*i=='\\') + backslash = true; + else if(*i=='"') + { + if(backslash) + result += '\\'; + result += '\\'; + } + else if(*i==' ') + need_quotes = true; + result += *i; + } + + if(need_quotes) + return "\""+result+"\""; + else + return result; +} + +} + +namespace Msp { + +Process::~Process() +{ + CloseHandle(priv->info.hProcess); + CloseHandle(priv->info.hThread); +} + +void Process::platform_get_self_info(Private &priv) +{ + priv.info.hProcess = GetCurrentProcess(); + priv.info.hThread = 0; + priv.info.dwProcessId = GetCurrentProcessId(); + priv.info.dwThreadId = 0; +} + +void Process::execute(const string &command, bool path_search, const Arguments &args) +{ + string cmdline = quote_argument(command); + for(Arguments::const_iterator i=args.begin(); i!=args.end(); ++i) + { + cmdline += ' '; + cmdline += quote_argument(*i); + } + + STARTUPINFO startup; + startup.cb = sizeof(STARTUPINFO); + startup.lpReserved = 0; + startup.lpDesktop = 0; + startup.lpTitle = 0; + startup.dwFlags = 0; + startup.cbReserved2 = 0; + startup.lpReserved2 = 0; + if(redirect) + { + startup.dwFlags |= STARTF_USESTDHANDLES; + HANDLE self_handle = self().priv->info.hProcess; + HANDLE cin_handle = (cin ? *cin->get_handle(IO::M_READ) : GetStdHandle(STD_INPUT_HANDLE)); + DuplicateHandle(self_handle, cin_handle, self_handle, &startup.hStdInput, 0, true, DUPLICATE_SAME_ACCESS); + HANDLE cout_handle = (cout ? *cout->get_handle(IO::M_WRITE) : GetStdHandle(STD_OUTPUT_HANDLE)); + DuplicateHandle(self_handle, cout_handle, self_handle, &startup.hStdOutput, 0, true, DUPLICATE_SAME_ACCESS); + HANDLE cerr_handle = (cerr ? *cerr->get_handle(IO::M_WRITE) : GetStdHandle(STD_ERROR_HANDLE)); + DuplicateHandle(self_handle, cerr_handle, self_handle, &startup.hStdError, 0, true, DUPLICATE_SAME_ACCESS); + } + const char *cmdptr = (path_search ? 0 : command.c_str()); + const char *wd = (work_dir.empty() ? 0 : work_dir.c_str()); + if(!CreateProcess(cmdptr, const_cast(cmdline.c_str()), 0, 0, false, 0, 0, wd, &startup, &priv->info)) + throw system_error("CreateProcess"); + // XXX Should we close the duplicated handles? What if CreateProcess fails? + + running = true; + + if(this==_self) + TerminateProcess(priv->info.hProcess, 0); +} + +bool Process::wait(bool block) +{ + if(!running) + throw logic_error("not running"); + + DWORD ret = WaitForSingleObject(priv->info.hProcess, (block ? INFINITE : 0)); + if(ret==WAIT_FAILED) + throw system_error("WaitForSingleObject"); + + if(ret==WAIT_OBJECT_0) + { + running = false; + finished = true; + } + + return finished; +} + +void Process::terminate() +{ + TerminateProcess(priv->info.hProcess, 1); +} + +void Process::kill() +{ + TerminateProcess(priv->info.hProcess, 1); +} + +void Process::interrupt() +{ + TerminateProcess(priv->info.hProcess, 1); +} + + +Process::Private::Private() +{ + info.hProcess = 0; + info.hThread = 0; + info.dwProcessId = 0; + info.dwThreadId = 0; +} + +} // namespace Msp