| 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 |