OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/process/launch.h" | 5 #include "base/process/launch.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <io.h> | 8 #include <io.h> |
9 #include <windows.h> | 9 #include <windows.h> |
10 #include <userenv.h> | 10 #include <userenv.h> |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize); | 96 setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize); |
97 _dup2(_fileno(stderr), 2); | 97 _dup2(_fileno(stderr), 2); |
98 } | 98 } |
99 | 99 |
100 // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. | 100 // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. |
101 std::ios::sync_with_stdio(); | 101 std::ios::sync_with_stdio(); |
102 } | 102 } |
103 | 103 |
104 bool LaunchProcess(const string16& cmdline, | 104 bool LaunchProcess(const string16& cmdline, |
105 const LaunchOptions& options, | 105 const LaunchOptions& options, |
106 win::ScopedHandle* process_handle) { | 106 ProcessHandle* process_handle) { |
107 STARTUPINFO startup_info = {}; | 107 STARTUPINFO startup_info = {}; |
108 startup_info.cb = sizeof(startup_info); | 108 startup_info.cb = sizeof(startup_info); |
109 if (options.empty_desktop_name) | 109 if (options.empty_desktop_name) |
110 startup_info.lpDesktop = L""; | 110 startup_info.lpDesktop = L""; |
111 startup_info.dwFlags = STARTF_USESHOWWINDOW; | 111 startup_info.dwFlags = STARTF_USESHOWWINDOW; |
112 startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW; | 112 startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW; |
113 | 113 |
114 if (options.stdin_handle || options.stdout_handle || options.stderr_handle) { | 114 if (options.stdin_handle || options.stdout_handle || options.stderr_handle) { |
115 DCHECK(options.inherit_handles); | 115 DCHECK(options.inherit_handles); |
116 DCHECK(options.stdin_handle); | 116 DCHECK(options.stdin_handle); |
(...skipping 12 matching lines...) Expand all Loading... |
129 | 129 |
130 // If this code is run under a debugger, the launched process is | 130 // If this code is run under a debugger, the launched process is |
131 // automatically associated with a job object created by the debugger. | 131 // automatically associated with a job object created by the debugger. |
132 // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. | 132 // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. |
133 flags |= CREATE_BREAKAWAY_FROM_JOB; | 133 flags |= CREATE_BREAKAWAY_FROM_JOB; |
134 } | 134 } |
135 | 135 |
136 if (options.force_breakaway_from_job_) | 136 if (options.force_breakaway_from_job_) |
137 flags |= CREATE_BREAKAWAY_FROM_JOB; | 137 flags |= CREATE_BREAKAWAY_FROM_JOB; |
138 | 138 |
139 PROCESS_INFORMATION temp_process_info = {}; | 139 base::win::ScopedProcessInformation process_info; |
140 | 140 |
141 if (options.as_user) { | 141 if (options.as_user) { |
142 flags |= CREATE_UNICODE_ENVIRONMENT; | 142 flags |= CREATE_UNICODE_ENVIRONMENT; |
143 void* enviroment_block = NULL; | 143 void* enviroment_block = NULL; |
144 | 144 |
145 if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { | 145 if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { |
146 DPLOG(ERROR); | 146 DPLOG(ERROR); |
147 return false; | 147 return false; |
148 } | 148 } |
149 | 149 |
150 BOOL launched = | 150 BOOL launched = |
151 CreateProcessAsUser(options.as_user, NULL, | 151 CreateProcessAsUser(options.as_user, NULL, |
152 const_cast<wchar_t*>(cmdline.c_str()), | 152 const_cast<wchar_t*>(cmdline.c_str()), |
153 NULL, NULL, options.inherit_handles, flags, | 153 NULL, NULL, options.inherit_handles, flags, |
154 enviroment_block, NULL, &startup_info, | 154 enviroment_block, NULL, &startup_info, |
155 &temp_process_info); | 155 process_info.Receive()); |
156 DestroyEnvironmentBlock(enviroment_block); | 156 DestroyEnvironmentBlock(enviroment_block); |
157 if (!launched) { | 157 if (!launched) { |
158 DPLOG(ERROR); | 158 DPLOG(ERROR); |
159 return false; | 159 return false; |
160 } | 160 } |
161 } else { | 161 } else { |
162 if (!CreateProcess(NULL, | 162 if (!CreateProcess(NULL, |
163 const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, | 163 const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, |
164 options.inherit_handles, flags, NULL, NULL, | 164 options.inherit_handles, flags, NULL, NULL, |
165 &startup_info, &temp_process_info)) { | 165 &startup_info, process_info.Receive())) { |
166 DPLOG(ERROR); | 166 DPLOG(ERROR); |
167 return false; | 167 return false; |
168 } | 168 } |
169 } | 169 } |
170 base::win::ScopedProcessInformation process_info(temp_process_info); | |
171 | 170 |
172 if (options.job_handle) { | 171 if (options.job_handle) { |
173 if (0 == AssignProcessToJobObject(options.job_handle, | 172 if (0 == AssignProcessToJobObject(options.job_handle, |
174 process_info.process_handle())) { | 173 process_info.process_handle())) { |
175 DLOG(ERROR) << "Could not AssignProcessToObject."; | 174 DLOG(ERROR) << "Could not AssignProcessToObject."; |
176 KillProcess(process_info.process_handle(), kProcessKilledExitCode, true); | 175 KillProcess(process_info.process_handle(), kProcessKilledExitCode, true); |
177 return false; | 176 return false; |
178 } | 177 } |
179 | 178 |
180 ResumeThread(process_info.thread_handle()); | 179 ResumeThread(process_info.thread_handle()); |
181 } | 180 } |
182 | 181 |
183 if (options.wait) | 182 if (options.wait) |
184 WaitForSingleObject(process_info.process_handle(), INFINITE); | 183 WaitForSingleObject(process_info.process_handle(), INFINITE); |
185 | 184 |
186 // If the caller wants the process handle, we won't close it. | 185 // If the caller wants the process handle, we won't close it. |
187 if (process_handle) | 186 if (process_handle) |
188 process_handle->Set(process_info.TakeProcessHandle()); | 187 *process_handle = process_info.TakeProcessHandle(); |
189 | 188 |
190 return true; | 189 return true; |
191 } | 190 } |
192 | 191 |
193 bool LaunchProcess(const CommandLine& cmdline, | 192 bool LaunchProcess(const CommandLine& cmdline, |
194 const LaunchOptions& options, | 193 const LaunchOptions& options, |
195 ProcessHandle* process_handle) { | 194 ProcessHandle* process_handle) { |
196 if (!process_handle) | 195 return LaunchProcess(cmdline.GetCommandLineString(), options, process_handle); |
197 return LaunchProcess(cmdline.GetCommandLineString(), options, NULL); | |
198 | |
199 win::ScopedHandle process; | |
200 bool rv = LaunchProcess(cmdline.GetCommandLineString(), options, &process); | |
201 *process_handle = process.Take(); | |
202 return rv; | |
203 } | 196 } |
204 | 197 |
205 bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) { | 198 bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) { |
206 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; | 199 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; |
207 limit_info.BasicLimitInformation.LimitFlags = limit_flags; | 200 limit_info.BasicLimitInformation.LimitFlags = limit_flags; |
208 return 0 != SetInformationJobObject( | 201 return 0 != SetInformationJobObject( |
209 job_object, | 202 job_object, |
210 JobObjectExtendedLimitInformation, | 203 JobObjectExtendedLimitInformation, |
211 &limit_info, | 204 &limit_info, |
212 sizeof(limit_info)); | 205 sizeof(limit_info)); |
(...skipping 20 matching lines...) Expand all Loading... |
233 win::ScopedHandle scoped_out_write(out_write); | 226 win::ScopedHandle scoped_out_write(out_write); |
234 | 227 |
235 // Ensure the read handle to the pipe for STDOUT is not inherited. | 228 // Ensure the read handle to the pipe for STDOUT is not inherited. |
236 if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { | 229 if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { |
237 NOTREACHED() << "Failed to disabled pipe inheritance"; | 230 NOTREACHED() << "Failed to disabled pipe inheritance"; |
238 return false; | 231 return false; |
239 } | 232 } |
240 | 233 |
241 FilePath::StringType writable_command_line_string(cl.GetCommandLineString()); | 234 FilePath::StringType writable_command_line_string(cl.GetCommandLineString()); |
242 | 235 |
243 STARTUPINFO start_info = {}; | 236 base::win::ScopedProcessInformation proc_info; |
| 237 STARTUPINFO start_info = { 0 }; |
244 | 238 |
245 start_info.cb = sizeof(STARTUPINFO); | 239 start_info.cb = sizeof(STARTUPINFO); |
246 start_info.hStdOutput = out_write; | 240 start_info.hStdOutput = out_write; |
247 // Keep the normal stdin and stderr. | 241 // Keep the normal stdin and stderr. |
248 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | 242 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
249 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); | 243 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
250 start_info.dwFlags |= STARTF_USESTDHANDLES; | 244 start_info.dwFlags |= STARTF_USESTDHANDLES; |
251 | 245 |
252 // Create the child process. | 246 // Create the child process. |
253 PROCESS_INFORMATION temp_process_info = {}; | |
254 if (!CreateProcess(NULL, | 247 if (!CreateProcess(NULL, |
255 &writable_command_line_string[0], | 248 &writable_command_line_string[0], |
256 NULL, NULL, | 249 NULL, NULL, |
257 TRUE, // Handles are inherited. | 250 TRUE, // Handles are inherited. |
258 0, NULL, NULL, &start_info, &temp_process_info)) { | 251 0, NULL, NULL, &start_info, proc_info.Receive())) { |
259 NOTREACHED() << "Failed to start process"; | 252 NOTREACHED() << "Failed to start process"; |
260 return false; | 253 return false; |
261 } | 254 } |
262 base::win::ScopedProcessInformation proc_info(temp_process_info); | |
263 | 255 |
264 // Close our writing end of pipe now. Otherwise later read would not be able | 256 // Close our writing end of pipe now. Otherwise later read would not be able |
265 // to detect end of child's output. | 257 // to detect end of child's output. |
266 scoped_out_write.Close(); | 258 scoped_out_write.Close(); |
267 | 259 |
268 // Read output from the child process's pipe for STDOUT | 260 // Read output from the child process's pipe for STDOUT |
269 const int kBufferSize = 1024; | 261 const int kBufferSize = 1024; |
270 char buffer[kBufferSize]; | 262 char buffer[kBufferSize]; |
271 | 263 |
272 for (;;) { | 264 for (;;) { |
273 DWORD bytes_read = 0; | 265 DWORD bytes_read = 0; |
274 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); | 266 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); |
275 if (!success || bytes_read == 0) | 267 if (!success || bytes_read == 0) |
276 break; | 268 break; |
277 output->append(buffer, bytes_read); | 269 output->append(buffer, bytes_read); |
278 } | 270 } |
279 | 271 |
280 // Let's wait for the process to finish. | 272 // Let's wait for the process to finish. |
281 WaitForSingleObject(proc_info.process_handle(), INFINITE); | 273 WaitForSingleObject(proc_info.process_handle(), INFINITE); |
282 | 274 |
283 return true; | 275 return true; |
284 } | 276 } |
285 | 277 |
286 void RaiseProcessToHighPriority() { | 278 void RaiseProcessToHighPriority() { |
287 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); | 279 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); |
288 } | 280 } |
289 | 281 |
290 } // namespace base | 282 } // namespace base |
OLD | NEW |