| 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));
|
| +}
|
|
|