• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 #ifndef BASE_WIN_COM_INIT_BALANCER_H_
6 #define BASE_WIN_COM_INIT_BALANCER_H_
7 
8 #include <objidl.h>
9 #include <winnt.h>
10 #include <wrl/implements.h>
11 
12 #include "base/base_export.h"
13 #include "base/threading/thread_checker.h"
14 #include "base/win/windows_types.h"
15 #include "third_party/abseil-cpp/absl/types/optional.h"
16 
17 namespace base {
18 namespace win {
19 namespace internal {
20 
21 // Implementation class of the IInitializeSpy Interface that prevents premature
22 // uninitialization of the COM library, often caused by unbalanced
23 // CoInitialize/CoUninitialize pairs. The use of this class is encouraged in
24 // COM-supporting threads that execute third-party code.
25 //
26 // Disable() must be called before uninitializing the COM library in order to
27 // revoke the registered spy and allow for the successful uninitialization of
28 // the COM library.
29 class BASE_EXPORT ComInitBalancer
30     : public Microsoft::WRL::RuntimeClass<
31           Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
32           IInitializeSpy> {
33  public:
34   // Constructs a COM initialize balancer. |co_init| defines the apartment's
35   // concurrency model used by the balancer.
36   explicit ComInitBalancer(DWORD co_init);
37 
38   ComInitBalancer(const ComInitBalancer&) = delete;
39   ComInitBalancer& operator=(const ComInitBalancer&) = delete;
40 
41   ~ComInitBalancer() override;
42 
43   // Disables balancer by revoking the registered spy and consequently
44   // unblocking attempts to uninitialize the COM library.
45   void Disable();
46 
47   DWORD GetReferenceCountForTesting() const;
48 
49  private:
50   // IInitializeSpy:
51   IFACEMETHODIMP PreInitialize(DWORD apartment_type,
52                                DWORD reference_count) override;
53   IFACEMETHODIMP PostInitialize(HRESULT result,
54                                 DWORD apartment_type,
55                                 DWORD new_reference_count) override;
56   IFACEMETHODIMP PreUninitialize(DWORD reference_count) override;
57   IFACEMETHODIMP PostUninitialize(DWORD new_reference_count) override;
58 
59   const DWORD co_init_;
60 
61   // The current apartment reference count set after the completion of the last
62   // call made to CoInitialize or CoUninitialize.
63   DWORD reference_count_ = 0;
64 
65   absl::optional<ULARGE_INTEGER> spy_cookie_;
66   THREAD_CHECKER(thread_checker_);
67 };
68 
69 }  // namespace internal
70 }  // namespace win
71 }  // namespace base
72 
73 #endif  // BASE_WIN_COM_INIT_BALANCER_H_
74