|  | // 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>>; | 
|  |  | 
|  | // Compile time switch to decide what container to use for the async results for | 
|  | // |T|. Depends on whether the underlying Abi type is a pointer to IUnknown or | 
|  | // not. It queries the internals of Windows::Foundation to obtain this | 
|  | // information. | 
|  | template <typename T> | 
|  | using ResultT = | 
|  | std::conditional_t<std::is_convertible<AbiT<T>, IUnknown*>::value, | 
|  | Microsoft::WRL::ComPtr<std::remove_pointer_t<AbiT<T>>>, | 
|  | AbiT<T>>; | 
|  |  | 
|  | template <typename T> | 
|  | using StorageT = | 
|  | std::conditional_t<std::is_convertible<AbiT<T>, IUnknown*>::value, | 
|  | Microsoft::WRL::ComPtr<std::remove_pointer_t<AbiT<T>>>, | 
|  | base::Optional<AbiT<T>>>; | 
|  |  | 
|  | template <typename T> | 
|  | HRESULT CopyStorage(const Microsoft::WRL::ComPtr<T>& storage, T** results) { | 
|  | return storage.CopyTo(results); | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | HRESULT CopyStorage(const base::Optional<T>& storage, T* results) { | 
|  | *results = *storage; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | }  // 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 StorageT = internal::StorageT<T>; | 
|  | using ResultT = internal::ResultT<T>; | 
|  | using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>; | 
|  | using ResultCallback = base::OnceCallback<void(ResultT)>; | 
|  |  | 
|  | 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()); | 
|  | } | 
|  |  | 
|  | ~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(internal::AbiT<T>* results) override { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | 
|  | return storage_ ? internal::CopyStorage(storage_, 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(ResultT result) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); | 
|  | DCHECK(!storage_); | 
|  | storage_ = std::move(result); | 
|  | InvokeCompletedHandler(); | 
|  | } | 
|  |  | 
|  | ResultCallback callback_; | 
|  | Microsoft::WRL::ComPtr<Handler> handler_; | 
|  | StorageT storage_; | 
|  |  | 
|  | THREAD_CHECKER(thread_checker_); | 
|  | base::WeakPtrFactory<AsyncOperation> weak_factory_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(AsyncOperation); | 
|  | }; | 
|  |  | 
|  | }  // namespace win | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_WIN_ASYNC_OPERATION_H_ |