@@ -12,6 +12,7 @@ Date: August 2012
12
12
13
13
#ifdef _WIN32
14
14
#include < process.h>
15
+ #include < windows.h>
15
16
#else
16
17
17
18
#include < cstring>
@@ -37,14 +38,85 @@ int run(const std::string &what, const std::vector<std::string> &argv)
37
38
return run (what, argv, " " , " " , " " );
38
39
}
39
40
40
- #ifndef _WIN32
41
+ #ifdef _WIN32
42
+ #define STDIN_FILENO 0
43
+ #define STDOUT_FILENO 1
44
+ #define STDERR_FILENO 2
45
+ using fdt = HANDLE;
46
+ #else
47
+ using fdt = int ;
48
+ #endif
49
+
41
50
// / open given file to replace either stdin, stderr, stdout
42
- static int stdio_redirection (int fd, const std::string &file)
51
+ static fdt stdio_redirection (int fd, const std::string &file)
43
52
{
44
- int result_fd = fd;
53
+ fdt result_fd;
54
+
55
+ #ifdef _WIN32
56
+ std::string name;
57
+
58
+ SECURITY_ATTRIBUTES SecurityAttributes;
59
+ ZeroMemory (&SecurityAttributes, sizeof SecurityAttributes);
60
+ SecurityAttributes.bInheritHandle = true ;
61
+
62
+ switch (fd)
63
+ {
64
+ case STDIN_FILENO:
65
+ name = " stdin" ;
66
+ if (file.empty ())
67
+ result_fd = GetStdHandle (STD_INPUT_HANDLE);
68
+ else
69
+ result_fd = CreateFileW (
70
+ widen (file).c_str (),
71
+ GENERIC_READ,
72
+ 0 ,
73
+ &SecurityAttributes,
74
+ OPEN_EXISTING,
75
+ FILE_ATTRIBUTE_READONLY,
76
+ NULL );
77
+ break ;
78
+
79
+ case STDOUT_FILENO:
80
+ name = " stdout" ;
81
+ if (file.empty ())
82
+ result_fd = GetStdHandle (STD_OUTPUT_HANDLE);
83
+ else
84
+ result_fd = CreateFileW (
85
+ widen (file).c_str (),
86
+ GENERIC_WRITE,
87
+ 0 ,
88
+ &SecurityAttributes,
89
+ CREATE_ALWAYS,
90
+ FILE_ATTRIBUTE_NORMAL,
91
+ NULL );
92
+ break ;
93
+
94
+ case STDERR_FILENO:
95
+ name = " stderr" ;
96
+ if (file.empty ())
97
+ result_fd = GetStdHandle (STD_ERROR_HANDLE);
98
+ else
99
+ result_fd = CreateFileW (
100
+ widen (file).c_str (),
101
+ GENERIC_WRITE,
102
+ 0 ,
103
+ &SecurityAttributes,
104
+ CREATE_ALWAYS,
105
+ FILE_ATTRIBUTE_NORMAL,
106
+ NULL );
107
+ break ;
108
+
109
+ default :
110
+ UNREACHABLE;
111
+ }
112
+
113
+ if (result_fd == INVALID_HANDLE_VALUE)
114
+ perror ((" Failed to open " + name + " file " + file).c_str ());
115
+
116
+ #else
45
117
46
118
if (file.empty ())
47
- return result_fd ;
119
+ return fd ;
48
120
49
121
int flags = 0 , mode = 0 ;
50
122
std::string name;
@@ -68,12 +140,13 @@ static int stdio_redirection(int fd, const std::string &file)
68
140
}
69
141
70
142
result_fd = open (file.c_str (), flags, mode);
143
+
71
144
if (result_fd == -1 )
72
145
perror ((" Failed to open " + name + " file " + file).c_str ());
146
+ #endif
73
147
74
148
return result_fd;
75
149
}
76
- #endif
77
150
78
151
#ifdef _WIN32
79
152
// Read
@@ -140,56 +213,87 @@ int run(
140
213
const std::string &std_output,
141
214
const std::string &std_error)
142
215
{
143
- #ifdef _WIN32
144
- // we use the cmd.exe shell to do stdin/stdout/stderr redirection on Windows
145
- if (!std_input.empty () || !std_output.empty () || !std_error.empty ())
216
+ #ifdef _WIN32
217
+ // unicode commandline, quoted
218
+ std::wstring cmdline;
219
+
220
+ // we replace argv[0] by what
221
+ cmdline = quote_windows_arg (widen (what));
222
+
223
+ for (std::size_t i = 1 ; i < argv.size (); i++)
146
224
{
147
- std::vector<std::string> new_argv = argv ;
148
- new_argv. insert (new_argv. begin (), " cmd.exe " );
149
- new_argv. insert (new_argv. begin () + 1 , " /c " );
225
+ cmdline += L" " ;
226
+ cmdline += quote_windows_arg ( widen (argv[i]) );
227
+ }
150
228
151
- if (!std_input.empty ())
152
- {
153
- new_argv.push_back (" <" );
154
- new_argv.push_back (std_input);
155
- }
229
+ PROCESS_INFORMATION piProcInfo;
230
+ STARTUPINFOW siStartInfo;
156
231
157
- if (!std_output.empty ())
158
- {
159
- new_argv.push_back (" >" );
160
- new_argv.push_back (std_output);
161
- }
232
+ ZeroMemory (&piProcInfo, sizeof piProcInfo);
233
+ ZeroMemory (&siStartInfo, sizeof siStartInfo);
162
234
163
- if (!std_error.empty ())
164
- {
165
- new_argv.push_back (" 2>" );
166
- new_argv.push_back (std_error);
167
- }
235
+ siStartInfo.cb = sizeof siStartInfo;
168
236
169
- // this is recursive
170
- return run (new_argv[ 0 ], new_argv, " " , " " , " " );
171
- }
237
+ siStartInfo. hStdInput = stdio_redirection (STDIN_FILENO, std_input);
238
+ siStartInfo. hStdOutput = stdio_redirection (STDOUT_FILENO, std_output );
239
+ siStartInfo. hStdError = stdio_redirection (STDERR_FILENO, std_error);
172
240
173
- // unicode and whitespace-quoted version of the arguments
174
- std::vector<std::wstring> wargv;
241
+ siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
175
242
176
- wargv.resize (argv.size ());
243
+ // CreateProcessW wants to modify the command line
244
+ std::vector<wchar_t > mutable_cmdline (cmdline.begin (), cmdline.end ());
245
+ mutable_cmdline.push_back (0 ); // zero termination
246
+ wchar_t *cmdline_ptr = mutable_cmdline.data ();
177
247
178
- for (std::size_t i=0 ; i<argv.size (); i++)
179
- wargv[i]=quote_windows_arg (widen (argv[i]));
248
+ BOOL bSuccess = CreateProcessW (
249
+ NULL , // application name
250
+ cmdline_ptr, // command line
251
+ NULL , // process security attributes
252
+ NULL , // primary thread security attributes
253
+ true , // handles are inherited
254
+ 0 , // creation flags
255
+ NULL , // use parent's environment
256
+ NULL , // use parent's current directory
257
+ &siStartInfo, // STARTUPINFO
258
+ &piProcInfo); // PROCESS_INFORMATION
180
259
181
- std::vector<const wchar_t *> _argv (argv.size ()+1 );
260
+ if (!bSuccess)
261
+ {
262
+ if (!std_input.empty ())
263
+ CloseHandle (siStartInfo.hStdInput );
264
+ if (!std_output.empty ())
265
+ CloseHandle (siStartInfo.hStdOutput );
266
+ if (!std_error.empty ())
267
+ CloseHandle (siStartInfo.hStdError );
268
+ return -1 ;
269
+ }
182
270
183
- for (std:: size_t i= 0 ; i<wargv. size (); i++)
184
- _argv[i]=wargv[i]. c_str ( );
271
+ // wait for child to finish
272
+ WaitForSingleObject (piProcInfo. hProcess , INFINITE );
185
273
186
- _argv[argv.size ()]=NULL ;
274
+ if (!std_input.empty ())
275
+ CloseHandle (siStartInfo.hStdInput );
276
+ if (!std_output.empty ())
277
+ CloseHandle (siStartInfo.hStdOutput );
278
+ if (!std_error.empty ())
279
+ CloseHandle (siStartInfo.hStdError );
187
280
188
- std::wstring wide_what=widen (what);
189
- int status=_wspawnvp (_P_WAIT, wide_what.c_str (), _argv.data ());
190
- return status;
281
+ DWORD exit_code;
191
282
192
- #else
283
+ // get exit code
284
+ if (!GetExitCodeProcess (piProcInfo.hProcess , &exit_code))
285
+ {
286
+ CloseHandle (piProcInfo.hProcess );
287
+ CloseHandle (piProcInfo.hThread );
288
+ return -1 ;
289
+ }
290
+
291
+ CloseHandle (piProcInfo.hProcess );
292
+ CloseHandle (piProcInfo.hThread );
293
+
294
+ return exit_code;
295
+
296
+ #else
193
297
int stdin_fd = stdio_redirection (STDIN_FILENO, std_input);
194
298
int stdout_fd = stdio_redirection (STDOUT_FILENO, std_output);
195
299
int stderr_fd = stdio_redirection (STDERR_FILENO, std_error);
@@ -280,5 +384,5 @@ int run(
280
384
281
385
return 1 ;
282
386
}
283
- #endif
387
+ #endif
284
388
}
0 commit comments