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