]> git.tdb.fi Git - libs/core.git/blob - source/core/windows/process.cpp
829365088115289bcdedc0ebc315911f3bf3175c
[libs/core.git] / source / core / windows / process.cpp
1 #include <windows.h>
2 #include <msp/core/systemerror.h>
3 #include <msp/io/handle_private.h>
4 #include <msp/strings/utils.h>
5 #include "process.h"
6 #include "process_private.h"
7
8 using namespace std;
9
10 namespace {
11
12 string quote_argument(const string &arg)
13 {
14         string result;
15         bool need_quotes = false;
16         bool backslash = false;
17         for(char c: arg)
18         {
19                 if(c=='\\')
20                         backslash = true;
21                 else if(c=='"')
22                 {
23                         if(backslash)
24                                 result += '\\';
25                         result += '\\';
26                 }
27                 else if(c==' ')
28                         need_quotes = true;
29                 result += c;
30         }
31
32         if(need_quotes)
33                 return "\""+result+"\"";
34         else
35                 return result;
36 }
37
38 }
39
40 namespace Msp {
41
42 Process::~Process()
43 {
44         CloseHandle(priv->info.hProcess);
45         CloseHandle(priv->info.hThread);
46 }
47
48 void Process::platform_get_self_info(Private &priv)
49 {
50         priv.info.hProcess = GetCurrentProcess();
51         priv.info.hThread = 0;
52         priv.info.dwProcessId = GetCurrentProcessId();
53         priv.info.dwThreadId = 0;
54 }
55
56 void Process::execute(const string &command, bool path_search, const Arguments &args)
57 {
58         string cmdline = quote_argument(command);
59         for(const string &a: args)
60                 append(cmdline, " ", quote_argument(a));
61
62         STARTUPINFO startup;
63         startup.cb = sizeof(STARTUPINFO);
64         startup.lpReserved = 0;
65         startup.lpDesktop = 0;
66         startup.lpTitle = 0;
67         startup.dwFlags = 0;
68         startup.cbReserved2 = 0;
69         startup.lpReserved2 = 0;
70         if(redirect)
71         {
72                 startup.dwFlags |= STARTF_USESTDHANDLES;
73                 HANDLE self_handle = self().priv->info.hProcess;
74                 HANDLE cin_handle = (cin ? *cin->get_handle(IO::M_READ) : GetStdHandle(STD_INPUT_HANDLE));
75                 DuplicateHandle(self_handle, cin_handle, self_handle, &startup.hStdInput, 0, true, DUPLICATE_SAME_ACCESS);
76                 HANDLE cout_handle = (cout ? *cout->get_handle(IO::M_WRITE) : GetStdHandle(STD_OUTPUT_HANDLE));
77                 DuplicateHandle(self_handle, cout_handle, self_handle, &startup.hStdOutput, 0, true, DUPLICATE_SAME_ACCESS);
78                 HANDLE cerr_handle = (cerr ? *cerr->get_handle(IO::M_WRITE) : GetStdHandle(STD_ERROR_HANDLE));
79                 DuplicateHandle(self_handle, cerr_handle, self_handle, &startup.hStdError, 0, true, DUPLICATE_SAME_ACCESS);
80         }
81         const char *cmdptr = (path_search ? 0 : command.c_str());
82         const char *wd = (work_dir.empty() ? 0 : work_dir.c_str());
83         if(!CreateProcess(cmdptr, const_cast<char *>(cmdline.c_str()), 0, 0, true, 0, 0, wd, &startup, &priv->info))
84                 throw system_error("CreateProcess");
85
86         if(redirect)
87         {
88                 CloseHandle(startup.hStdInput);
89                 CloseHandle(startup.hStdOutput);
90                 CloseHandle(startup.hStdError);
91         }
92
93         running = true;
94
95         if(this==_self)
96                 TerminateProcess(priv->info.hProcess, 0);
97 }
98
99 bool Process::wait(bool block)
100 {
101         if(!running)
102                 throw logic_error("not running");
103
104         DWORD ret = WaitForSingleObject(priv->info.hProcess, (block ? INFINITE : 0));
105         if(ret==WAIT_FAILED)
106                 throw system_error("WaitForSingleObject");
107
108         if(ret==WAIT_OBJECT_0)
109         {
110                 running = false;
111                 finished = true;
112                 DWORD ec;
113                 if(GetExitCodeProcess(priv->info.hProcess, &ec))
114                         exit_code = ec;
115         }
116
117         return finished;
118 }
119
120 void Process::terminate()
121 {
122         TerminateProcess(priv->info.hProcess, 1);
123 }
124
125 void Process::kill()
126 {
127         TerminateProcess(priv->info.hProcess, 1);
128 }
129
130 void Process::interrupt()
131 {
132         TerminateProcess(priv->info.hProcess, 1);
133 }
134
135
136 Process::Private::Private()
137 {
138         info.hProcess = 0;
139         info.hThread = 0;
140         info.dwProcessId = 0;
141         info.dwThreadId = 0;
142 }
143
144 } // namespace Msp