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