1*6777b538SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_com_initializer.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <wrl/implements.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <ostream>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/win/resource_exhaustion.h"
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker namespace base {
15*6777b538SAndroid Build Coastguard Worker namespace win {
16*6777b538SAndroid Build Coastguard Worker
ScopedCOMInitializer(Uninitialization uninitialization)17*6777b538SAndroid Build Coastguard Worker ScopedCOMInitializer::ScopedCOMInitializer(Uninitialization uninitialization) {
18*6777b538SAndroid Build Coastguard Worker Initialize(COINIT_APARTMENTTHREADED, uninitialization);
19*6777b538SAndroid Build Coastguard Worker }
20*6777b538SAndroid Build Coastguard Worker
ScopedCOMInitializer(SelectMTA mta,Uninitialization uninitialization)21*6777b538SAndroid Build Coastguard Worker ScopedCOMInitializer::ScopedCOMInitializer(SelectMTA mta,
22*6777b538SAndroid Build Coastguard Worker Uninitialization uninitialization) {
23*6777b538SAndroid Build Coastguard Worker Initialize(COINIT_MULTITHREADED, uninitialization);
24*6777b538SAndroid Build Coastguard Worker }
25*6777b538SAndroid Build Coastguard Worker
~ScopedCOMInitializer()26*6777b538SAndroid Build Coastguard Worker ScopedCOMInitializer::~ScopedCOMInitializer() {
27*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
28*6777b538SAndroid Build Coastguard Worker if (Succeeded()) {
29*6777b538SAndroid Build Coastguard Worker if (com_balancer_) {
30*6777b538SAndroid Build Coastguard Worker com_balancer_->Disable();
31*6777b538SAndroid Build Coastguard Worker com_balancer_.Reset();
32*6777b538SAndroid Build Coastguard Worker }
33*6777b538SAndroid Build Coastguard Worker CoUninitialize();
34*6777b538SAndroid Build Coastguard Worker }
35*6777b538SAndroid Build Coastguard Worker }
36*6777b538SAndroid Build Coastguard Worker
Succeeded() const37*6777b538SAndroid Build Coastguard Worker bool ScopedCOMInitializer::Succeeded() const {
38*6777b538SAndroid Build Coastguard Worker return SUCCEEDED(hr_);
39*6777b538SAndroid Build Coastguard Worker }
40*6777b538SAndroid Build Coastguard Worker
GetCOMBalancerReferenceCountForTesting() const41*6777b538SAndroid Build Coastguard Worker DWORD ScopedCOMInitializer::GetCOMBalancerReferenceCountForTesting() const {
42*6777b538SAndroid Build Coastguard Worker if (com_balancer_)
43*6777b538SAndroid Build Coastguard Worker return com_balancer_->GetReferenceCountForTesting();
44*6777b538SAndroid Build Coastguard Worker return 0;
45*6777b538SAndroid Build Coastguard Worker }
46*6777b538SAndroid Build Coastguard Worker
Initialize(COINIT init,Uninitialization uninitialization)47*6777b538SAndroid Build Coastguard Worker void ScopedCOMInitializer::Initialize(COINIT init,
48*6777b538SAndroid Build Coastguard Worker Uninitialization uninitialization) {
49*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
50*6777b538SAndroid Build Coastguard Worker // COINIT_DISABLE_OLE1DDE is always added based on:
51*6777b538SAndroid Build Coastguard Worker // https://docs.microsoft.com/en-us/windows/desktop/learnwin32/initializing-the-com-library
52*6777b538SAndroid Build Coastguard Worker if (uninitialization == Uninitialization::kBlockPremature) {
53*6777b538SAndroid Build Coastguard Worker com_balancer_ = Microsoft::WRL::Details::Make<internal::ComInitBalancer>(
54*6777b538SAndroid Build Coastguard Worker init | COINIT_DISABLE_OLE1DDE);
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker hr_ = ::CoInitializeEx(nullptr, init | COINIT_DISABLE_OLE1DDE);
58*6777b538SAndroid Build Coastguard Worker DCHECK_NE(RPC_E_CHANGED_MODE, hr_) << "Invalid COM thread model change";
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker // CoInitializeEx may call RegisterClassEx to get an ATOM. On failure, the
61*6777b538SAndroid Build Coastguard Worker // call to RegisterClassEx sets the last error code to
62*6777b538SAndroid Build Coastguard Worker // ERROR_NOT_ENOUGH_MEMORY. CoInitializeEx is retuning the converted error
63*6777b538SAndroid Build Coastguard Worker // code (a.k.a HRESULT_FROM_WIN32(...)). The following code handles the case
64*6777b538SAndroid Build Coastguard Worker // where HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY) is being returned by
65*6777b538SAndroid Build Coastguard Worker // CoInitializeEx. We assume they are due to ATOM exhaustion. This appears to
66*6777b538SAndroid Build Coastguard Worker // happen most often when the browser is being driven by automation tools,
67*6777b538SAndroid Build Coastguard Worker // though the underlying reason for this remains a mystery
68*6777b538SAndroid Build Coastguard Worker // (https://crbug.com/1470483). There is nothing that Chrome can do to
69*6777b538SAndroid Build Coastguard Worker // meaningfully run until the user restarts their session by signing out of
70*6777b538SAndroid Build Coastguard Worker // Windows or restarting their computer.
71*6777b538SAndroid Build Coastguard Worker if (init == COINIT_APARTMENTTHREADED &&
72*6777b538SAndroid Build Coastguard Worker hr_ == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY)) {
73*6777b538SAndroid Build Coastguard Worker base::win::OnResourceExhausted();
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker }
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker } // namespace win
78*6777b538SAndroid Build Coastguard Worker } // namespace base
79