diff options
Diffstat (limited to 'base')
-rw-r--r-- | base/process_util.h | 16 | ||||
-rw-r--r-- | base/process_util_unittest.cc | 35 | ||||
-rw-r--r-- | base/process_util_win.cc | 78 |
3 files changed, 122 insertions, 7 deletions
diff --git a/base/process_util.h b/base/process_util.h index 20cdd5e..9eb8690 100644 --- a/base/process_util.h +++ b/base/process_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -119,19 +119,25 @@ bool LaunchApp(const std::vector<std::string>& argv, bool wait, ProcessHandle* process_handle); #endif -// Execute the application specified by cl. This function delegates to one +// Executes the application specified by cl. This function delegates to one // of the above two platform-specific functions. bool LaunchApp(const CommandLine& cl, bool wait, bool start_hidden, ProcessHandle* process_handle); -#if defined(OS_POSIX) -// Execute the application specified by |cl| and wait for it to exit. Store +#if defined(OS_WIN) +// Executes the application specified by |cmd_line| and copies the contents +// printed to the standard output to |output|, which should be non NULL. +// Blocks until the started process terminates. +// Returns true if the application was run successfully, false otherwise. +bool GetAppOutput(const std::wstring& cmd_line, std::string* output); +#elif defined(OS_POSIX) +// Executes the application specified by |cl| and wait for it to exit. Stores // the output (stdout) in |output|. Redirects stderr to /dev/null. Returns true // on success (application launched and exited cleanly, with exit code // indicating success). |output| is modified only when the function finished // successfully. bool GetAppOutput(const CommandLine& cl, std::string* output); -#endif // defined(OS_POSIX) +#endif // Used to filter processes by process ID. class ProcessFilter { diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc index fba7b2b..76b705d 100644 --- a/base/process_util_unittest.cc +++ b/base/process_util_unittest.cc @@ -1,11 +1,13 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #define _CRT_SECURE_NO_WARNINGS #include "base/command_line.h" +#include "base/file_path.h" #include "base/multiprocess_test.h" +#include "base/path_service.h" #include "base/platform_thread.h" #include "base/process_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -128,6 +130,37 @@ TEST_F(ProcessUtilTest, CalcFreeMemory) { delete[] alloc; delete metrics; } + +TEST_F(ProcessUtilTest, GetAppOutput) { + // Let's create a decently long message. + std::string message; + for (int i = 0; i < 1025; i++) { // 1025 so it does not end on a kilo-byte + // boundary. + message += "Hello!"; + } + + FilePath python_runtime; + ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime)); + python_runtime = python_runtime.Append(FILE_PATH_LITERAL("third_party")) + .Append(FILE_PATH_LITERAL("python_24")) + .Append(FILE_PATH_LITERAL("python.exe")); + + // You have to put every parameter between quotes, otherwise this won't work, + // don't ask me why. + std::wstring cmd_line = L"\"" + python_runtime.value() + L"\" " + + L"\"-c\" \"import sys; sys.stdout.write('" + ASCIIToWide(message) + + L"');\""; + std::string output; + ASSERT_TRUE(base::GetAppOutput(cmd_line, &output)); + EXPECT_EQ(message, output); + + // Let's make sure stderr is ignored. + cmd_line = L"\"" + python_runtime.value() + L"\" " + + L"\"-c\" \"import sys; sys.stderr.write('Hello!');\""; + output.clear(); + ASSERT_TRUE(base::GetAppOutput(cmd_line, &output)); + EXPECT_EQ("", output); +} #endif // defined(OS_WIN) #if defined(OS_POSIX) diff --git a/base/process_util_win.cc b/base/process_util_win.cc index 2fe9a00..3664c5c 100644 --- a/base/process_util_win.cc +++ b/base/process_util_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -182,6 +182,82 @@ bool KillProcessById(ProcessId process_id, int exit_code, bool wait) { return ret; } +bool GetAppOutput(const std::wstring& cmd_line, std::string* output) { + if (!output) { + NOTREACHED(); + return false; + } + + HANDLE out_read = NULL; + HANDLE out_write = NULL; + + SECURITY_ATTRIBUTES sa_attr; + // Set the bInheritHandle flag so pipe handles are inherited. + sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); + sa_attr.bInheritHandle = TRUE; + sa_attr.lpSecurityDescriptor = NULL; + + // Create the pipe for the child process's STDOUT. + if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { + NOTREACHED() << "Failed to create pipe"; + return false; + } + + // Ensure the read handle to the pipe for STDOUT is not inherited. + if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { + NOTREACHED() << "Failed to disabled pipe inheritance"; + return false; + } + + // Now create the child process + PROCESS_INFORMATION proc_info = { 0 }; + STARTUPINFO start_info = { 0 }; + + start_info.cb = sizeof(STARTUPINFO); + start_info.hStdOutput = out_write; + // Keep the normal stdin and stderr. + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + start_info.dwFlags |= STARTF_USESTDHANDLES; + + // Create the child process. + if (!CreateProcess(NULL, const_cast<wchar_t*>(cmd_line.c_str()), NULL, NULL, + TRUE, // Handles are inherited. + 0, NULL, NULL, &start_info, &proc_info)) { + NOTREACHED() << "Failed to start process"; + return false; + } + + // We don't need the thread handle, close it now. + CloseHandle(proc_info.hThread); + + if (!CloseHandle(out_write)) { + NOTREACHED() << "Failed to close std out write pipe."; + return false; + } + + // Read output from the child process's pipe for STDOUT + const int kBufferSize = 1024; + char buffer[kBufferSize]; + + for (;;) { + DWORD bytes_read = 0; + BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); + if (!success || bytes_read == 0) + break; + output->append(buffer, bytes_read); + } + + // Let's wait for the process to finish. + WaitForSingleObject(proc_info.hProcess, INFINITE); + CloseHandle(proc_info.hProcess); + + BOOL r = CloseHandle(out_read); + DCHECK(r) << "Failed to close std out read pipe."; + + return true; +} + bool KillProcess(ProcessHandle process, int exit_code, bool wait) { bool result = (TerminateProcess(process, exit_code) != FALSE); if (result && wait) { |