1 // Copyright 2018 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_ASYNC_OPERATION_H_ 6 #define BASE_WIN_ASYNC_OPERATION_H_ 7 8 #include <unknwn.h> 9 #include <windows.foundation.h> 10 #include <wrl/async.h> 11 #include <wrl/client.h> 12 13 #include <type_traits> 14 #include <utility> 15 16 #include "base/functional/bind.h" 17 #include "base/functional/callback.h" 18 #include "base/memory/weak_ptr.h" 19 #include "base/threading/thread_checker.h" 20 #include "base/win/winrt_foundation_helpers.h" 21 22 namespace base { 23 namespace win { 24 25 // This file provides an implementation of Windows::Foundation::IAsyncOperation. 26 // Specializations exist for "regular" types and interface types that inherit 27 // from IUnknown. Both specializations expose a callback() method, which can be 28 // used to provide the result that will be forwarded to the registered 29 // completion handler. For regular types it expects an instance of that type, 30 // and for interface types it expects a corresponding ComPtr. This class is 31 // thread-affine and all member methods should be called on the same thread that 32 // constructed the object. In order to offload heavy result computation, 33 // base's PostTaskAndReplyWithResult() should be used with the ResultCallback 34 // passed as a reply. 35 // 36 // Example usages: 37 // 38 // // Regular types 39 // auto regular_op = WRL::Make<base::win::AsyncOperation<int>>(); 40 // auto cb = regular_op->callback(); 41 // regular_op->put_Completed(...event handler...); 42 // ... 43 // // This will invoke the event handler. 44 // std::move(cb).Run(123); 45 // ... 46 // // Results can be queried: 47 // int results = 0; 48 // regular_op->GetResults(&results); 49 // EXPECT_EQ(123, results); 50 // 51 // // Interface types 52 // auto interface_op = WRL::Make<base::win::AsyncOperation<FooBar*>>(); 53 // auto cb = interface_op->callback(); 54 // interface_op->put_Completed(...event handler...); 55 // ... 56 // // This will invoke the event handler. 57 // std::move(cb).Run(WRL::Make<IFooBarImpl>()); 58 // ... 59 // // Results can be queried: 60 // WRL::ComPtr<IFooBar> results; 61 // interface_op->GetResults(&results); 62 // // |results| points to the provided IFooBarImpl instance. 63 // 64 // // Offloading a heavy computation: 65 // auto my_op = WRL::Make<base::win::AsyncOperation<FooBar*>>(); 66 // base::ThreadPool::PostTaskAndReplyWithResult( 67 // base::BindOnce(MakeFooBar), my_op->callback()); 68 69 namespace internal { 70 71 // Template tricks needed to dispatch to the correct implementation below. 72 // See base/win/winrt_foundation_helpers.h for explanation. 73 74 template <typename T> 75 using AsyncOperationComplex = 76 typename ABI::Windows::Foundation::IAsyncOperation<T>::TResult_complex; 77 78 template <typename T> 79 using AsyncOperationAbi = AbiType<AsyncOperationComplex<T>>; 80 81 template <typename T> 82 using AsyncOperationOptionalStorage = 83 OptionalStorageType<AsyncOperationComplex<T>>; 84 85 template <typename T> 86 using AsyncOperationStorage = StorageType<AsyncOperationComplex<T>>; 87 88 } // namespace internal 89 90 template <class T> 91 class AsyncOperation 92 : public Microsoft::WRL::RuntimeClass< 93 Microsoft::WRL::RuntimeClassFlags< 94 Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, 95 ABI::Windows::Foundation::IAsyncOperation<T>> { 96 public: 97 using AbiT = internal::AsyncOperationAbi<T>; 98 using OptionalStorageT = internal::AsyncOperationOptionalStorage<T>; 99 using StorageT = internal::AsyncOperationStorage<T>; 100 using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>; 101 using ResultCallback = base::OnceCallback<void(StorageT)>; 102 AsyncOperation()103 AsyncOperation() { 104 // Note: This can't be done in the constructor initializer list. This is 105 // because it relies on weak_factory_ to be initialized, which needs to be 106 // the last class member. Also applies below. 107 callback_ = 108 base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr()); 109 } 110 111 AsyncOperation(const AsyncOperation&) = delete; 112 AsyncOperation& operator=(const AsyncOperation&) = delete; 113 ~AsyncOperation()114 ~AsyncOperation() override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); } 115 116 // ABI::Windows::Foundation::IAsyncOperation: put_Completed(Handler * handler)117 IFACEMETHODIMP put_Completed(Handler* handler) override { 118 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 119 handler_ = handler; 120 return S_OK; 121 } get_Completed(Handler ** handler)122 IFACEMETHODIMP get_Completed(Handler** handler) override { 123 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 124 return handler_.CopyTo(handler); 125 } GetResults(AbiT * results)126 IFACEMETHODIMP GetResults(AbiT* results) override { 127 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 128 return results_ ? internal::CopyTo(results_, results) : E_PENDING; 129 } 130 callback()131 ResultCallback callback() { 132 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 133 DCHECK(!callback_.is_null()); 134 return std::move(callback_); 135 } 136 137 private: InvokeCompletedHandler()138 void InvokeCompletedHandler() { 139 handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); 140 } 141 OnResult(StorageT result)142 void OnResult(StorageT result) { 143 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 144 DCHECK(!results_); 145 results_ = std::move(result); 146 InvokeCompletedHandler(); 147 } 148 149 ResultCallback callback_; 150 Microsoft::WRL::ComPtr<Handler> handler_; 151 OptionalStorageT results_; 152 153 THREAD_CHECKER(thread_checker_); 154 base::WeakPtrFactory<AsyncOperation> weak_factory_{this}; 155 }; 156 157 } // namespace win 158 } // namespace base 159 160 #endif // BASE_WIN_ASYNC_OPERATION_H_ 161