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