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 ProcessHandle* process_handle) { | 106 win::ScopedHandle* 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 base::win::ScopedProcessInformation process_info; | 139 PROCESS_INFORMATION temp_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 process_info.Receive()); | 155 &temp_process_info); |
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, process_info.Receive())) { | 165 &startup_info, &temp_process_info)) { |
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); |
170 | 171 |
171 if (options.job_handle) { | 172 if (options.job_handle) { |
172 if (0 == AssignProcessToJobObject(options.job_handle, | 173 if (0 == AssignProcessToJobObject(options.job_handle, |
173 process_info.process_handle())) { | 174 process_info.process_handle())) { |
174 DLOG(ERROR) << "Could not AssignProcessToObject."; | 175 DLOG(ERROR) << "Could not AssignProcessToObject."; |
175 KillProcess(process_info.process_handle(), kProcessKilledExitCode, true); | 176 KillProcess(process_info.process_handle(), kProcessKilledExitCode, true); |
176 return false; | 177 return false; |
177 } | 178 } |
178 | 179 |
179 ResumeThread(process_info.thread_handle()); | 180 ResumeThread(process_info.thread_handle()); |
180 } | 181 } |
181 | 182 |
182 if (options.wait) | 183 if (options.wait) |
183 WaitForSingleObject(process_info.process_handle(), INFINITE); | 184 WaitForSingleObject(process_info.process_handle(), INFINITE); |
184 | 185 |
185 // If the caller wants the process handle, we won't close it. | 186 // If the caller wants the process handle, we won't close it. |
186 if (process_handle) | 187 if (process_handle) |
187 *process_handle = process_info.TakeProcessHandle(); | 188 process_handle->Set(process_info.TakeProcessHandle()); |
188 | 189 |
189 return true; | 190 return true; |
190 } | 191 } |
191 | 192 |
192 bool LaunchProcess(const CommandLine& cmdline, | 193 bool LaunchProcess(const CommandLine& cmdline, |
193 const LaunchOptions& options, | 194 const LaunchOptions& options, |
194 ProcessHandle* process_handle) { | 195 ProcessHandle* process_handle) { |
195 return LaunchProcess(cmdline.GetCommandLineString(), options, process_handle); | 196 if (!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; |
196 } | 203 } |
197 | 204 |
198 bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) { | 205 bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) { |
199 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; | 206 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; |
200 limit_info.BasicLimitInformation.LimitFlags = limit_flags; | 207 limit_info.BasicLimitInformation.LimitFlags = limit_flags; |
201 return 0 != SetInformationJobObject( | 208 return 0 != SetInformationJobObject( |
202 job_object, | 209 job_object, |
203 JobObjectExtendedLimitInformation, | 210 JobObjectExtendedLimitInformation, |
204 &limit_info, | 211 &limit_info, |
205 sizeof(limit_info)); | 212 sizeof(limit_info)); |
(...skipping 20 matching lines...) Expand all Loading... |
226 win::ScopedHandle scoped_out_write(out_write); | 233 win::ScopedHandle scoped_out_write(out_write); |
227 | 234 |
228 // Ensure the read handle to the pipe for STDOUT is not inherited. | 235 // Ensure the read handle to the pipe for STDOUT is not inherited. |
229 if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { | 236 if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { |
230 NOTREACHED() << "Failed to disabled pipe inheritance"; | 237 NOTREACHED() << "Failed to disabled pipe inheritance"; |
231 return false; | 238 return false; |
232 } | 239 } |
233 | 240 |
234 FilePath::StringType writable_command_line_string(cl.GetCommandLineString()); | 241 FilePath::StringType writable_command_line_string(cl.GetCommandLineString()); |
235 | 242 |
236 base::win::ScopedProcessInformation proc_info; | 243 STARTUPINFO start_info = {}; |
237 STARTUPINFO start_info = { 0 }; | |
238 | 244 |
239 start_info.cb = sizeof(STARTUPINFO); | 245 start_info.cb = sizeof(STARTUPINFO); |
240 start_info.hStdOutput = out_write; | 246 start_info.hStdOutput = out_write; |
241 // Keep the normal stdin and stderr. | 247 // Keep the normal stdin and stderr. |
242 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | 248 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
243 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); | 249 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
244 start_info.dwFlags |= STARTF_USESTDHANDLES; | 250 start_info.dwFlags |= STARTF_USESTDHANDLES; |
245 | 251 |
246 // Create the child process. | 252 // Create the child process. |
| 253 PROCESS_INFORMATION temp_process_info = {}; |
247 if (!CreateProcess(NULL, | 254 if (!CreateProcess(NULL, |
248 &writable_command_line_string[0], | 255 &writable_command_line_string[0], |
249 NULL, NULL, | 256 NULL, NULL, |
250 TRUE, // Handles are inherited. | 257 TRUE, // Handles are inherited. |
251 0, NULL, NULL, &start_info, proc_info.Receive())) { | 258 0, NULL, NULL, &start_info, &temp_process_info)) { |
252 NOTREACHED() << "Failed to start process"; | 259 NOTREACHED() << "Failed to start process"; |
253 return false; | 260 return false; |
254 } | 261 } |
| 262 base::win::ScopedProcessInformation proc_info(temp_process_info); |
255 | 263 |
256 // Close our writing end of pipe now. Otherwise later read would not be able | 264 // Close our writing end of pipe now. Otherwise later read would not be able |
257 // to detect end of child's output. | 265 // to detect end of child's output. |
258 scoped_out_write.Close(); | 266 scoped_out_write.Close(); |
259 | 267 |
260 // Read output from the child process's pipe for STDOUT | 268 // Read output from the child process's pipe for STDOUT |
261 const int kBufferSize = 1024; | 269 const int kBufferSize = 1024; |
262 char buffer[kBufferSize]; | 270 char buffer[kBufferSize]; |
263 | 271 |
264 for (;;) { | 272 for (;;) { |
265 DWORD bytes_read = 0; | 273 DWORD bytes_read = 0; |
266 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); | 274 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); |
267 if (!success || bytes_read == 0) | 275 if (!success || bytes_read == 0) |
268 break; | 276 break; |
269 output->append(buffer, bytes_read); | 277 output->append(buffer, bytes_read); |
270 } | 278 } |
271 | 279 |
272 // Let's wait for the process to finish. | 280 // Let's wait for the process to finish. |
273 WaitForSingleObject(proc_info.process_handle(), INFINITE); | 281 WaitForSingleObject(proc_info.process_handle(), INFINITE); |
274 | 282 |
275 return true; | 283 return true; |
276 } | 284 } |
277 | 285 |
278 void RaiseProcessToHighPriority() { | 286 void RaiseProcessToHighPriority() { |
279 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); | 287 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); |
280 } | 288 } |
281 | 289 |
282 } // namespace base | 290 } // namespace base |
OLD | NEW |