summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/process_util.h16
-rw-r--r--base/process_util_unittest.cc35
-rw-r--r--base/process_util_win.cc78
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) {