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