123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // 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/bind.h"
- #include "base/callback.h"
- #include "base/macros.h"
- #include "base/memory/weak_ptr.h"
- #include "base/optional.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::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() { 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};
- DISALLOW_COPY_AND_ASSIGN(AsyncOperation);
- };
- } // namespace win
- } // namespace base
- #endif // BASE_WIN_ASYNC_OPERATION_H_
|