• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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