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