--- /dev/null
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#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<char *>(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