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