| // 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 |