@@ -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,82 @@ 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 ;
45
78
46
- if (file.empty ())
47
- return result_fd;
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
48
117
49
118
int flags = 0 , mode = 0 ;
50
119
std::string name;
@@ -68,12 +137,13 @@ static int stdio_redirection(int fd, const std::string &file)
68
137
}
69
138
70
139
result_fd = open (file.c_str (), flags, mode);
140
+
71
141
if (result_fd == -1 )
72
142
perror ((" Failed to open " + name + " file " + file).c_str ());
143
+ #endif
73
144
74
145
return result_fd;
75
146
}
76
- #endif
77
147
78
148
#ifdef _WIN32
79
149
// Read
@@ -140,56 +210,87 @@ int run(
140
210
const std::string &std_output,
141
211
const std::string &std_error)
142
212
{
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 ())
213
+ #ifdef _WIN32
214
+ // unicode commandline, quoted
215
+ std::wstring cmdline;
216
+
217
+ // we replace argv[0] by what
218
+ cmdline = quote_windows_arg (widen (what));
219
+
220
+ for (std::size_t i = 1 ; i < argv.size (); i++)
146
221
{
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 " );
222
+ cmdline += L" " ;
223
+ cmdline += quote_windows_arg ( widen (argv[i]) );
224
+ }
150
225
151
- if (!std_input.empty ())
152
- {
153
- new_argv.push_back (" <" );
154
- new_argv.push_back (std_input);
155
- }
226
+ PROCESS_INFORMATION piProcInfo;
227
+ STARTUPINFOW siStartInfo;
156
228
157
- if (!std_output.empty ())
158
- {
159
- new_argv.push_back (" >" );
160
- new_argv.push_back (std_output);
161
- }
229
+ ZeroMemory (&piProcInfo, sizeof piProcInfo);
230
+ ZeroMemory (&siStartInfo, sizeof siStartInfo);
162
231
163
- if (!std_error.empty ())
164
- {
165
- new_argv.push_back (" 2>" );
166
- new_argv.push_back (std_error);
167
- }
232
+ siStartInfo.cb = sizeof siStartInfo;
168
233
169
- // this is recursive
170
- return run (new_argv[0 ], new_argv, " " , " " , " " );
171
- }
234
+ siStartInfo.hStdInput = stdio_redirection (STDIN_FILENO, std_input);
235
+ siStartInfo.hStdOutput = stdio_redirection (STDOUT_FILENO, std_output);
236
+ siStartInfo.hStdError = stdio_redirection (STDERR_FILENO, std_error);
237
+
238
+ siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
239
+
240
+ // CreateProcessW wants to modify the command line
241
+ std::vector<wchar_t > mutable_cmdline (cmdline.begin (), cmdline.end ());
242
+ mutable_cmdline.push_back (0 ); // zero termination
243
+ wchar_t *cmdline_ptr = mutable_cmdline.data ();
172
244
173
- // unicode and whitespace-quoted version of the arguments
174
- std::vector<std::wstring> wargv;
245
+ BOOL bSuccess = CreateProcessW (
246
+ NULL , // application name
247
+ cmdline_ptr, // command line
248
+ NULL , // process security attributes
249
+ NULL , // primary thread security attributes
250
+ true , // handles are inherited
251
+ 0 , // creation flags
252
+ NULL , // use parent's environment
253
+ NULL , // use parent's current directory
254
+ &siStartInfo, // STARTUPINFO
255
+ &piProcInfo); // PROCESS_INFORMATION
256
+
257
+ if (!bSuccess)
258
+ {
259
+ if (!std_input.empty ())
260
+ CloseHandle (siStartInfo.hStdInput );
261
+ if (!std_output.empty ())
262
+ CloseHandle (siStartInfo.hStdOutput );
263
+ if (!std_error.empty ())
264
+ CloseHandle (siStartInfo.hStdError );
265
+ return -1 ;
266
+ }
175
267
176
- wargv.resize (argv.size ());
268
+ // wait for child to finish
269
+ WaitForSingleObject (piProcInfo.hProcess , INFINITE);
177
270
178
- for (std::size_t i=0 ; i<argv.size (); i++)
179
- wargv[i]=quote_windows_arg (widen (argv[i]));
271
+ if (!std_input.empty ())
272
+ CloseHandle (siStartInfo.hStdInput );
273
+ if (!std_output.empty ())
274
+ CloseHandle (siStartInfo.hStdOutput );
275
+ if (!std_error.empty ())
276
+ CloseHandle (siStartInfo.hStdError );
180
277
181
- std::vector< const wchar_t *> _argv (argv. size ()+ 1 ) ;
278
+ DWORD exit_code ;
182
279
183
- for (std::size_t i=0 ; i<wargv.size (); i++)
184
- _argv[i]=wargv[i].c_str ();
280
+ // get exit code
281
+ if (!GetExitCodeProcess (piProcInfo.hProcess , &exit_code))
282
+ {
283
+ CloseHandle (piProcInfo.hProcess );
284
+ CloseHandle (piProcInfo.hThread );
285
+ return -1 ;
286
+ }
185
287
186
- _argv[argv.size ()]=NULL ;
288
+ CloseHandle (piProcInfo.hProcess );
289
+ CloseHandle (piProcInfo.hThread );
187
290
188
- std::wstring wide_what=widen (what);
189
- int status=_wspawnvp (_P_WAIT, wide_what.c_str (), _argv.data ());
190
- return status;
291
+ return exit_code;
191
292
192
- #else
293
+ #else
193
294
int stdin_fd = stdio_redirection (STDIN_FILENO, std_input);
194
295
int stdout_fd = stdio_redirection (STDOUT_FILENO, std_output);
195
296
int stderr_fd = stdio_redirection (STDERR_FILENO, std_error);
@@ -280,5 +381,5 @@ int run(
280
381
281
382
return 1 ;
282
383
}
283
- #endif
384
+ #endif
284
385
}
0 commit comments