1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/win/scoped_process_information.h"
6
7#include "base/logging.h"
8#include "base/win/scoped_handle.h"
9
10namespace base {
11namespace win {
12
13namespace {
14
15// Duplicates source into target, returning true upon success. |target| is
16// guaranteed to be untouched in case of failure. Succeeds with no side-effects
17// if source is NULL.
18bool CheckAndDuplicateHandle(HANDLE source, HANDLE* target) {
19  if (!source)
20    return true;
21
22  HANDLE temp = NULL;
23  if (!::DuplicateHandle(::GetCurrentProcess(), source,
24                         ::GetCurrentProcess(), &temp, 0, FALSE,
25                         DUPLICATE_SAME_ACCESS)) {
26    DPLOG(ERROR) << "Failed to duplicate a handle.";
27    return false;
28  }
29  *target = temp;
30  return true;
31}
32
33}  // namespace
34
35ScopedProcessInformation::ScopedProcessInformation()
36    : process_id_(0), thread_id_(0) {
37}
38
39ScopedProcessInformation::~ScopedProcessInformation() {
40  Close();
41}
42
43ScopedProcessInformation::Receiver ScopedProcessInformation::Receive() {
44  DCHECK(!IsValid()) << "process_information_ must be NULL";
45  return Receiver(this);
46}
47
48bool ScopedProcessInformation::IsValid() const {
49  return process_id_ || process_handle_.Get() ||
50         thread_id_ || thread_handle_.Get();
51}
52
53void ScopedProcessInformation::Close() {
54  process_handle_.Close();
55  thread_handle_.Close();
56  process_id_ = 0;
57  thread_id_ = 0;
58}
59
60void ScopedProcessInformation::Set(const PROCESS_INFORMATION& process_info) {
61  if (IsValid())
62    Close();
63
64  process_handle_.Set(process_info.hProcess);
65  thread_handle_.Set(process_info.hThread);
66  process_id_ = process_info.dwProcessId;
67  thread_id_ = process_info.dwThreadId;
68}
69
70bool ScopedProcessInformation::DuplicateFrom(
71    const ScopedProcessInformation& other) {
72  DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL";
73  DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid";
74
75  if (CheckAndDuplicateHandle(other.process_handle(),
76                              process_handle_.Receive()) &&
77      CheckAndDuplicateHandle(other.thread_handle(),
78                              thread_handle_.Receive())) {
79    process_id_ = other.process_id();
80    thread_id_ = other.thread_id();
81    return true;
82  }
83
84  return false;
85}
86
87PROCESS_INFORMATION ScopedProcessInformation::Take() {
88  PROCESS_INFORMATION process_information = {};
89  process_information.hProcess = process_handle_.Take();
90  process_information.hThread = thread_handle_.Take();
91  process_information.dwProcessId = process_id();
92  process_information.dwThreadId = thread_id();
93  process_id_ = 0;
94  thread_id_ = 0;
95
96  return process_information;
97}
98
99HANDLE ScopedProcessInformation::TakeProcessHandle() {
100  process_id_ = 0;
101  return process_handle_.Take();
102}
103
104HANDLE ScopedProcessInformation::TakeThreadHandle() {
105  thread_id_ = 0;
106  return thread_handle_.Take();
107}
108
109}  // namespace win
110}  // namespace base
111