|  | // Copyright (c) 2012 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/win/scoped_process_information.h" | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "base/win/scoped_handle.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace win { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Duplicates source into target, returning true upon success. |target| is | 
|  | // guaranteed to be untouched in case of failure. Succeeds with no side-effects | 
|  | // if source is NULL. | 
|  | bool CheckAndDuplicateHandle(HANDLE source, ScopedHandle* target) { | 
|  | if (!source) | 
|  | return true; | 
|  |  | 
|  | HANDLE temp = NULL; | 
|  | if (!::DuplicateHandle(::GetCurrentProcess(), source, ::GetCurrentProcess(), | 
|  | &temp, 0, FALSE, DUPLICATE_SAME_ACCESS)) { | 
|  | DWORD last_error = ::GetLastError(); | 
|  | DPLOG(ERROR) << "Failed to duplicate a handle " << last_error; | 
|  | ::SetLastError(last_error); | 
|  | return false; | 
|  | } | 
|  | target->Set(temp); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | ScopedProcessInformation::ScopedProcessInformation() | 
|  | : process_id_(0), thread_id_(0) {} | 
|  |  | 
|  | ScopedProcessInformation::ScopedProcessInformation( | 
|  | const PROCESS_INFORMATION& process_info) | 
|  | : process_id_(0), thread_id_(0) { | 
|  | Set(process_info); | 
|  | } | 
|  |  | 
|  | ScopedProcessInformation::~ScopedProcessInformation() { | 
|  | Close(); | 
|  | } | 
|  |  | 
|  | bool ScopedProcessInformation::IsValid() const { | 
|  | return process_id_ || process_handle_.Get() || thread_id_ || | 
|  | thread_handle_.Get(); | 
|  | } | 
|  |  | 
|  | void ScopedProcessInformation::Close() { | 
|  | process_handle_.Close(); | 
|  | thread_handle_.Close(); | 
|  | process_id_ = 0; | 
|  | thread_id_ = 0; | 
|  | } | 
|  |  | 
|  | void ScopedProcessInformation::Set(const PROCESS_INFORMATION& process_info) { | 
|  | if (IsValid()) | 
|  | Close(); | 
|  |  | 
|  | process_handle_.Set(process_info.hProcess); | 
|  | thread_handle_.Set(process_info.hThread); | 
|  | process_id_ = process_info.dwProcessId; | 
|  | thread_id_ = process_info.dwThreadId; | 
|  | } | 
|  |  | 
|  | bool ScopedProcessInformation::DuplicateFrom( | 
|  | const ScopedProcessInformation& other) { | 
|  | DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL"; | 
|  | DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid"; | 
|  |  | 
|  | if (CheckAndDuplicateHandle(other.process_handle(), &process_handle_) && | 
|  | CheckAndDuplicateHandle(other.thread_handle(), &thread_handle_)) { | 
|  | process_id_ = other.process_id(); | 
|  | thread_id_ = other.thread_id(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | PROCESS_INFORMATION ScopedProcessInformation::Take() { | 
|  | PROCESS_INFORMATION process_information = {}; | 
|  | process_information.hProcess = process_handle_.Take(); | 
|  | process_information.hThread = thread_handle_.Take(); | 
|  | process_information.dwProcessId = process_id(); | 
|  | process_information.dwThreadId = thread_id(); | 
|  | process_id_ = 0; | 
|  | thread_id_ = 0; | 
|  |  | 
|  | return process_information; | 
|  | } | 
|  |  | 
|  | HANDLE ScopedProcessInformation::TakeProcessHandle() { | 
|  | process_id_ = 0; | 
|  | return process_handle_.Take(); | 
|  | } | 
|  |  | 
|  | HANDLE ScopedProcessInformation::TakeThreadHandle() { | 
|  | thread_id_ = 0; | 
|  | return thread_handle_.Take(); | 
|  | } | 
|  |  | 
|  | }  // namespace win | 
|  | }  // namespace base |