// Copyright (c) 2011 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/process/process.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/win/windows_version.h" namespace base { Process::Process(ProcessHandle handle) : is_current_process_(false), process_(handle) { CHECK_NE(handle, ::GetCurrentProcess()); } Process::Process(RValue other) : is_current_process_(other.object->is_current_process_), process_(other.object->process_.Take()) { other.object->Close(); } Process& Process::operator=(RValue other) { if (this != other.object) { process_.Set(other.object->process_.Take()); is_current_process_ = other.object->is_current_process_; other.object->Close(); } return *this; } // static Process Process::Current() { Process process; process.is_current_process_ = true; return process.Pass(); } // static bool Process::CanBackgroundProcesses() { return true; } bool Process::IsValid() const { return process_.IsValid() || is_current(); } ProcessHandle Process::Handle() const { return is_current_process_ ? GetCurrentProcess() : process_.Get(); } Process Process::Duplicate() const { if (is_current()) return Current(); ProcessHandle out_handle; if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(), Handle(), GetCurrentProcess(), &out_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { return Process(); } return Process(out_handle); } ProcessId Process::pid() const { DCHECK(IsValid()); return GetProcId(Handle()); } bool Process::is_current() const { return is_current_process_; } void Process::Close() { is_current_process_ = false; if (!process_.IsValid()) return; process_.Close(); } void Process::Terminate(int result_code) { DCHECK(IsValid()); // Call NtTerminateProcess directly, without going through the import table, // which might have been hooked with a buggy replacement by third party // software. http://crbug.com/81449. HMODULE module = GetModuleHandle(L"ntdll.dll"); typedef UINT (WINAPI *TerminateProcessPtr)(HANDLE handle, UINT code); TerminateProcessPtr terminate_process = reinterpret_cast( GetProcAddress(module, "NtTerminateProcess")); terminate_process(Handle(), result_code); } bool Process::IsProcessBackgrounded() const { DCHECK(IsValid()); DWORD priority = GetPriority(); if (priority == 0) return false; // Failure case. return ((priority == BELOW_NORMAL_PRIORITY_CLASS) || (priority == IDLE_PRIORITY_CLASS)); } bool Process::SetProcessBackgrounded(bool value) { DCHECK(IsValid()); // Vista and above introduce a real background mode, which not only // sets the priority class on the threads but also on the IO generated // by it. Unfortunately it can only be set for the calling process. DWORD priority; if ((base::win::GetVersion() >= base::win::VERSION_VISTA) && (is_current())) { priority = value ? PROCESS_MODE_BACKGROUND_BEGIN : PROCESS_MODE_BACKGROUND_END; } else { priority = value ? BELOW_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; } return (::SetPriorityClass(Handle(), priority) != 0); } int Process::GetPriority() const { DCHECK(IsValid()); return ::GetPriorityClass(Handle()); } } // namespace base