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