|  | // 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" | 
|  |  | 
|  | 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. | 
|  | // | 
|  | // For all types which are neither InterfaceGroups nor RuntimeClasses, the | 
|  | // following three typedefs are synonyms for a single C++ type.  But for | 
|  | // InterfaceGroups and RuntimeClasses, they are different types: | 
|  | //   LogicalT: The C++ Type for the InterfaceGroup or RuntimeClass, when | 
|  | //             used as a template parameter.  Eg "RCFoo*" | 
|  | //   AbiT:     The C++ type for the default interface used to represent the | 
|  | //             InterfaceGroup or RuntimeClass when passed as a method parameter. | 
|  | //             Eg "IFoo*" | 
|  | //   ComplexT: An instantiation of the Internal "AggregateType" template that | 
|  | //             combines LogicalT with AbiT. Eg "AggregateType<RCFoo*,IFoo*>" | 
|  | // | 
|  | // windows.foundation.collections.h defines the following template and | 
|  | // semantics in Windows::Foundation::Internal: | 
|  | // | 
|  | // template <class LogicalType, class AbiType> | 
|  | // struct AggregateType; | 
|  | // | 
|  | //   LogicalType - the Windows Runtime type (eg, runtime class, inteface group, | 
|  | //                 etc) being provided as an argument to an _impl template, when | 
|  | //                 that type cannot be represented at the ABI. | 
|  | //   AbiType     - the type used for marshalling, ie "at the ABI", for the | 
|  | //                 logical type. | 
|  | template <typename T> | 
|  | using ComplexT = | 
|  | typename ABI::Windows::Foundation::IAsyncOperation<T>::TResult_complex; | 
|  |  | 
|  | template <typename T> | 
|  | using AbiT = | 
|  | typename ABI::Windows::Foundation::Internal::GetAbiType<ComplexT<T>>::type; | 
|  |  | 
|  | template <typename T> | 
|  | using LogicalT = typename ABI::Windows::Foundation::Internal::GetLogicalType< | 
|  | ComplexT<T>>::type; | 
|  |  | 
|  | template <typename T> | 
|  | using InterfaceT = std::remove_pointer_t<AbiT<T>>; | 
|  |  | 
|  | // Implementation of shared functionality. | 
|  | template <class T> | 
|  | class AsyncOperationBase | 
|  | : public Microsoft::WRL::RuntimeClass< | 
|  | Microsoft::WRL::RuntimeClassFlags< | 
|  | Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, | 
|  | ABI::Windows::Foundation::IAsyncOperation<T>> { | 
|  | public: | 
|  | using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>; | 
|  |  | 
|  | AsyncOperationBase() = default; | 
|  | ~AsyncOperationBase() { 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); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | void InvokeCompletedHandler() { | 
|  | handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); | 
|  | } | 
|  |  | 
|  | THREAD_CHECKER(thread_checker_); | 
|  |  | 
|  | private: | 
|  | Microsoft::WRL::ComPtr<Handler> handler_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(AsyncOperationBase); | 
|  | }; | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | template <typename T, typename Enable = void> | 
|  | class AsyncOperation; | 
|  |  | 
|  | template <typename T> | 
|  | class AsyncOperation< | 
|  | T, | 
|  | std::enable_if_t<std::is_base_of<IUnknown, internal::InterfaceT<T>>::value>> | 
|  | : public internal::AsyncOperationBase<T> { | 
|  | public: | 
|  | using InterfacePointer = Microsoft::WRL::ComPtr<internal::InterfaceT<T>>; | 
|  | using ResultCallback = base::OnceCallback<void(InterfacePointer)>; | 
|  |  | 
|  | AsyncOperation() : weak_factory_(this) { | 
|  | // 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()); | 
|  | } | 
|  |  | 
|  | ResultCallback callback() { | 
|  | // Note: `this->` here and below is necessary due to the | 
|  | // -Wmicrosoft-template compiler warning. | 
|  | DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | 
|  | DCHECK(!callback_.is_null()); | 
|  | return std::move(callback_); | 
|  | } | 
|  |  | 
|  | // ABI::Windows::Foundation::IAsyncOperation: | 
|  | IFACEMETHODIMP GetResults(internal::AbiT<T>* results) override { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | 
|  | return ptr_ ? ptr_.CopyTo(results) : E_PENDING; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void OnResult(InterfacePointer ptr) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | 
|  | DCHECK(!ptr_); | 
|  | ptr_ = std::move(ptr); | 
|  | this->InvokeCompletedHandler(); | 
|  | } | 
|  |  | 
|  | ResultCallback callback_; | 
|  | InterfacePointer ptr_; | 
|  | base::WeakPtrFactory<AsyncOperation> weak_factory_; | 
|  | }; | 
|  |  | 
|  | template <typename T> | 
|  | class AsyncOperation< | 
|  | T, | 
|  | std::enable_if_t< | 
|  | !std::is_base_of<IUnknown, internal::InterfaceT<T>>::value>> | 
|  | : public internal::AsyncOperationBase<T> { | 
|  | public: | 
|  | using ResultCallback = base::OnceCallback<void(T)>; | 
|  |  | 
|  | AsyncOperation() : weak_factory_(this) { | 
|  | callback_ = | 
|  | base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr()); | 
|  | } | 
|  |  | 
|  | ResultCallback callback() { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | 
|  | DCHECK(!callback_.is_null()); | 
|  | return std::move(callback_); | 
|  | } | 
|  |  | 
|  | // ABI::Windows::Foundation::IAsyncOperation: | 
|  | IFACEMETHODIMP GetResults(internal::AbiT<T>* results) override { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | 
|  | if (!value_) | 
|  | return E_PENDING; | 
|  |  | 
|  | *results = *value_; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void OnResult(T result) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); | 
|  | DCHECK(!value_); | 
|  | value_.emplace(std::move(result)); | 
|  | this->InvokeCompletedHandler(); | 
|  | } | 
|  |  | 
|  | ResultCallback callback_; | 
|  | base::Optional<T> value_; | 
|  | base::WeakPtrFactory<AsyncOperation> weak_factory_; | 
|  | }; | 
|  |  | 
|  | }  // namespace win | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_WIN_ASYNC_OPERATION_H_ |