Index: base/test/test_process_util_win.cc |
diff --git a/base/test/test_process_util_win.cc b/base/test/test_process_util_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1e6fde0d29fc45a07f81e3bcc92fd0990b9b2827 |
--- /dev/null |
+++ b/base/test/test_process_util_win.cc |
@@ -0,0 +1,161 @@ |
+// Copyright (c) 2013 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. |
+ |
+#include "base/test/test_process_util_win.h" |
+ |
+#include <windows.h> |
+#include <winternl.h> |
+ |
+#include <algorithm> |
+ |
+#include "base/logging.h" |
+#include "base/process_util.h" |
+#include "base/string_util.h" |
+#include "base/win/scoped_handle.h" |
+ |
+namespace { |
+ |
+typedef LONG WINAPI |
+NtQueryInformationProcess( |
+ IN HANDLE ProcessHandle, |
+ IN PROCESSINFOCLASS ProcessInformationClass, |
+ OUT PVOID ProcessInformation, |
+ IN ULONG ProcessInformationLength, |
+ OUT PULONG ReturnLength OPTIONAL |
+); |
+ |
+// Get the function pointer to NtQueryInformationProcess in NTDLL.DLL |
+static bool GetQIP(NtQueryInformationProcess** qip_func_ptr) { |
+ static NtQueryInformationProcess* qip_func = |
+ reinterpret_cast<NtQueryInformationProcess*>( |
+ GetProcAddress(GetModuleHandle(L"ntdll.dll"), |
+ "NtQueryInformationProcess")); |
+ DCHECK(qip_func) << "Could not get pointer to NtQueryInformationProcess."; |
+ *qip_func_ptr = qip_func; |
+ return qip_func != NULL; |
+} |
+ |
+// Get the command line of a process |
+bool GetCommandLineForProcess(uint32 process_id, string16* cmd_line) { |
+ DCHECK(process_id != 0); |
+ DCHECK(cmd_line); |
+ |
+ // Open the process |
+ base::win::ScopedHandle process_handle(::OpenProcess( |
+ PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, |
+ false, |
+ process_id)); |
+ if (!process_handle) { |
+ DLOG(ERROR) << "Failed to open process " << process_id << ", last error = " |
+ << GetLastError(); |
+ } |
+ |
+ // Obtain Process Environment Block |
+ NtQueryInformationProcess* qip_func = NULL; |
+ if (process_handle) { |
+ GetQIP(&qip_func); |
+ } |
+ |
+ // Read the address of the process params from the peb. |
+ DWORD process_params_address = 0; |
+ if (qip_func) { |
+ PROCESS_BASIC_INFORMATION info = { 0 }; |
+ // NtQueryInformationProcess returns an NTSTATUS for whom negative values |
+ // are negative. Just check for that instead of pulling in DDK macros. |
+ if ((qip_func(process_handle.Get(), |
+ ProcessBasicInformation, |
+ &info, |
+ sizeof(info), |
+ NULL)) < 0) { |
+ DLOG(ERROR) << "Failed to invoke NtQueryProcessInformation, last error = " |
+ << GetLastError(); |
+ } else { |
+ BYTE* peb = reinterpret_cast<BYTE*>(info.PebBaseAddress); |
+ |
+ // The process command line parameters are (or were once) located at |
+ // the base address of the PEB + 0x10 for 32 bit processes. 64 bit |
+ // processes have a different PEB struct as per |
+ // http://msdn.microsoft.com/en-us/library/aa813706(VS.85).aspx. |
+ // TODO(robertshield): See about doing something about this. |
+ SIZE_T bytes_read = 0; |
+ if (!::ReadProcessMemory(process_handle.Get(), |
+ peb + 0x10, |
+ &process_params_address, |
+ sizeof(process_params_address), |
+ &bytes_read)) { |
+ DLOG(ERROR) << "Failed to read process params address, last error = " |
+ << GetLastError(); |
+ } |
+ } |
+ } |
+ |
+ // Copy all the process parameters into a buffer. |
+ bool success = false; |
+ string16 buffer; |
+ if (process_params_address) { |
+ SIZE_T bytes_read; |
+ RTL_USER_PROCESS_PARAMETERS params = { 0 }; |
+ if (!::ReadProcessMemory(process_handle.Get(), |
+ reinterpret_cast<void*>(process_params_address), |
+ ¶ms, |
+ sizeof(params), |
+ &bytes_read)) { |
+ DLOG(ERROR) << "Failed to read RTL_USER_PROCESS_PARAMETERS, " |
+ << "last error = " << GetLastError(); |
+ } else { |
+ // Read the command line parameter |
+ const int max_cmd_line_len = std::min( |
+ static_cast<int>(params.CommandLine.MaximumLength), |
+ 4096); |
+ buffer.resize(max_cmd_line_len + 1); |
+ if (!::ReadProcessMemory(process_handle.Get(), |
+ params.CommandLine.Buffer, |
+ &buffer[0], |
+ max_cmd_line_len, |
+ &bytes_read)) { |
+ DLOG(ERROR) << "Failed to copy process command line, " |
+ << "last error = " << GetLastError(); |
+ } else { |
+ *cmd_line = buffer; |
+ success = true; |
+ } |
+ } |
+ } |
+ |
+ return success; |
+} |
+ |
+// Used to filter processes by process ID. |
+class ArgumentFilter : public base::ProcessFilter { |
+ public: |
+ explicit ArgumentFilter(const string16& argument) |
+ : argument_to_find_(argument) {} |
+ |
+ // Returns true to indicate set-inclusion and false otherwise. This method |
+ // should not have side-effects and should be idempotent. |
+ virtual bool Includes(const base::ProcessEntry& entry) const { |
+ bool found = false; |
+ string16 command_line; |
+ if (GetCommandLineForProcess(entry.pid(), &command_line)) { |
+ string16::const_iterator it = |
+ std::search(command_line.begin(), |
+ command_line.end(), |
+ argument_to_find_.begin(), |
+ argument_to_find_.end(), |
+ base::CaseInsensitiveCompareASCII<wchar_t>()); |
+ found = (it != command_line.end()); |
+ } |
+ return found; |
+ } |
+ |
+ protected: |
+ string16 argument_to_find_; |
+}; |
+ |
+} // namespace |
+ |
+bool KillAllNamedProcessesWithArgument(const string16& process_name, |
+ const string16& argument) { |
+ return base::KillProcesses(process_name, 0, &ArgumentFilter(argument)); |
+} |