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.
5 #include "base/win/scoped_process_information.h"
7 #include "base/logging.h"
8 #include "base/win/scoped_handle.h"
9 #include "base/win/windows_version.h"
16 // Duplicates source into target, returning true upon success. |target| is
17 // guaranteed to be untouched in case of failure. Succeeds with no side-effects
19 bool CheckAndDuplicateHandle(HANDLE source
, ScopedHandle
* target
) {
25 // TODO(shrikant): Remove following code as soon as we gather some
26 // information regarding AppContainer related DuplicateHandle failures that
27 // only seem to happen on certain machine and only random launches (normally
28 // renderer launches seem to succeed even on those machines.)
29 if (base::win::GetVersion() == base::win::VERSION_WIN8
||
30 base::win::GetVersion() == base::win::VERSION_WIN8_1
) {
31 typedef LONG (WINAPI
*NtDuplicateObject
)(
32 IN HANDLE SourceProcess
,
33 IN HANDLE SourceHandle
,
34 IN HANDLE TargetProcess
,
35 OUT PHANDLE TargetHandle
,
36 IN ACCESS_MASK DesiredAccess
,
40 typedef ULONG (WINAPI
*RtlNtStatusToDosError
)(IN LONG Status
);
42 NtDuplicateObject nt_duplicate_object
=
43 reinterpret_cast<NtDuplicateObject
>(::GetProcAddress(
44 GetModuleHandle(L
"ntdll.dll"), "NtDuplicateObject"));
45 if (nt_duplicate_object
!= NULL
) {
46 LONG status
= nt_duplicate_object(::GetCurrentProcess(), source
,
47 ::GetCurrentProcess(), &temp
,
48 0, FALSE
, DUPLICATE_SAME_ACCESS
);
50 DPLOG(ERROR
) << "Failed to duplicate a handle.";
51 RtlNtStatusToDosError ntstatus_to_doserror
=
52 reinterpret_cast<RtlNtStatusToDosError
>(::GetProcAddress(
53 GetModuleHandle(L
"ntdll.dll"), "RtlNtStatusToDosError"));
54 if (ntstatus_to_doserror
!= NULL
) {
55 ::SetLastError(ntstatus_to_doserror(status
));
61 if (!::DuplicateHandle(::GetCurrentProcess(), source
,
62 ::GetCurrentProcess(), &temp
, 0, FALSE
,
63 DUPLICATE_SAME_ACCESS
)) {
64 DPLOG(ERROR
) << "Failed to duplicate a handle.";
74 ScopedProcessInformation::ScopedProcessInformation()
75 : process_id_(0), thread_id_(0) {
78 ScopedProcessInformation::ScopedProcessInformation(
79 const PROCESS_INFORMATION
& process_info
) : process_id_(0), thread_id_(0) {
83 ScopedProcessInformation::~ScopedProcessInformation() {
87 bool ScopedProcessInformation::IsValid() const {
88 return process_id_
|| process_handle_
.Get() ||
89 thread_id_
|| thread_handle_
.Get();
92 void ScopedProcessInformation::Close() {
93 process_handle_
.Close();
94 thread_handle_
.Close();
99 void ScopedProcessInformation::Set(const PROCESS_INFORMATION
& process_info
) {
103 process_handle_
.Set(process_info
.hProcess
);
104 thread_handle_
.Set(process_info
.hThread
);
105 process_id_
= process_info
.dwProcessId
;
106 thread_id_
= process_info
.dwThreadId
;
109 bool ScopedProcessInformation::DuplicateFrom(
110 const ScopedProcessInformation
& other
) {
111 DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL";
112 DCHECK(other
.IsValid()) << "source ScopedProcessInformation must be valid";
114 if (CheckAndDuplicateHandle(other
.process_handle(), &process_handle_
) &&
115 CheckAndDuplicateHandle(other
.thread_handle(), &thread_handle_
)) {
116 process_id_
= other
.process_id();
117 thread_id_
= other
.thread_id();
124 PROCESS_INFORMATION
ScopedProcessInformation::Take() {
125 PROCESS_INFORMATION process_information
= {};
126 process_information
.hProcess
= process_handle_
.Take();
127 process_information
.hThread
= thread_handle_
.Take();
128 process_information
.dwProcessId
= process_id();
129 process_information
.dwThreadId
= thread_id();
133 return process_information
;
136 HANDLE
ScopedProcessInformation::TakeProcessHandle() {
138 return process_handle_
.Take();
141 HANDLE
ScopedProcessInformation::TakeThreadHandle() {
143 return thread_handle_
.Take();