|  | // 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 { | 
|  |  | 
|  | // Closes the provided handle if it is not NULL. | 
|  | void CheckAndCloseHandle(HANDLE handle) { | 
|  | if (!handle) | 
|  | return; | 
|  | if (::CloseHandle(handle)) | 
|  | return; | 
|  | CHECK(false); | 
|  | } | 
|  |  | 
|  | // 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, HANDLE* target) { | 
|  | if (!source) | 
|  | return true; | 
|  |  | 
|  | HANDLE temp = NULL; | 
|  | if (!::DuplicateHandle(::GetCurrentProcess(), source, | 
|  | ::GetCurrentProcess(), &temp, 0, FALSE, | 
|  | DUPLICATE_SAME_ACCESS)) { | 
|  | DPLOG(ERROR) << "Failed to duplicate a handle."; | 
|  | return false; | 
|  | } | 
|  | *target = temp; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | ScopedProcessInformation::ScopedProcessInformation() | 
|  | : process_information_() { | 
|  | } | 
|  |  | 
|  | ScopedProcessInformation::~ScopedProcessInformation() { | 
|  | Close(); | 
|  | } | 
|  |  | 
|  | PROCESS_INFORMATION* ScopedProcessInformation::Receive() { | 
|  | DCHECK(!IsValid()) << "process_information_ must be NULL"; | 
|  | return &process_information_; | 
|  | } | 
|  |  | 
|  | bool ScopedProcessInformation::IsValid() const { | 
|  | return process_information_.hThread || process_information_.hProcess || | 
|  | process_information_.dwProcessId || process_information_.dwThreadId; | 
|  | } | 
|  |  | 
|  |  | 
|  | void ScopedProcessInformation::Close() { | 
|  | CheckAndCloseHandle(process_information_.hThread); | 
|  | CheckAndCloseHandle(process_information_.hProcess); | 
|  | Reset(); | 
|  | } | 
|  |  | 
|  | void ScopedProcessInformation::Swap(ScopedProcessInformation* other) { | 
|  | DCHECK(other); | 
|  | PROCESS_INFORMATION temp = other->process_information_; | 
|  | other->process_information_ = process_information_; | 
|  | process_information_ = temp; | 
|  | } | 
|  |  | 
|  | bool ScopedProcessInformation::DuplicateFrom( | 
|  | const ScopedProcessInformation& other) { | 
|  | DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL"; | 
|  | DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid"; | 
|  |  | 
|  | ScopedHandle duplicate_process; | 
|  | ScopedHandle duplicate_thread; | 
|  |  | 
|  | if (CheckAndDuplicateHandle(other.process_handle(), | 
|  | duplicate_process.Receive()) && | 
|  | CheckAndDuplicateHandle(other.thread_handle(), | 
|  | duplicate_thread.Receive())) { | 
|  | process_information_.dwProcessId = other.process_id(); | 
|  | process_information_.dwThreadId = other.thread_id(); | 
|  | process_information_.hProcess = duplicate_process.Take(); | 
|  | process_information_.hThread = duplicate_thread.Take(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | PROCESS_INFORMATION ScopedProcessInformation::Take() { | 
|  | PROCESS_INFORMATION process_information = process_information_; | 
|  | Reset(); | 
|  | return process_information; | 
|  | } | 
|  |  | 
|  | HANDLE ScopedProcessInformation::TakeProcessHandle() { | 
|  | HANDLE process = process_information_.hProcess; | 
|  | process_information_.hProcess = NULL; | 
|  | process_information_.dwProcessId = 0; | 
|  | return process; | 
|  | } | 
|  |  | 
|  | HANDLE ScopedProcessInformation::TakeThreadHandle() { | 
|  | HANDLE thread = process_information_.hThread; | 
|  | process_information_.hThread = NULL; | 
|  | process_information_.dwThreadId = 0; | 
|  | return thread; | 
|  | } | 
|  |  | 
|  | void ScopedProcessInformation::Reset() { | 
|  | process_information_.hThread = NULL; | 
|  | process_information_.hProcess = NULL; | 
|  | process_information_.dwProcessId = 0; | 
|  | process_information_.dwThreadId = 0; | 
|  | } | 
|  |  | 
|  | }  // namespace win | 
|  | }  // namespace base |