// 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 #include #include #include #include #include #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>(); // 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>(); // auto cb = interface_op->callback(); // interface_op->put_Completed(...event handler...); // ... // // This will invoke the event handler. // std::move(cb).Run(WRL::Make()); // ... // // Results can be queried: // WRL::ComPtr results; // interface_op->GetResults(&results); // // |results| points to the provided IFooBarImpl instance. // // // Offloading a heavy computation: // auto my_op = WRL::Make>(); // 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 using AsyncOperationComplex = typename ABI::Windows::Foundation::IAsyncOperation::TResult_complex; template using AsyncOperationAbi = AbiType>; template using AsyncOperationOptionalStorage = OptionalStorageType>; template using AsyncOperationStorage = StorageType>; } // namespace internal template class AsyncOperation : public Microsoft::WRL::RuntimeClass< Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, ABI::Windows::Foundation::IAsyncOperation> { public: using AbiT = internal::AsyncOperationAbi; using OptionalStorageT = internal::AsyncOperationOptionalStorage; using StorageT = internal::AsyncOperationStorage; using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler; using ResultCallback = base::OnceCallback; 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() 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_; OptionalStorageT results_; THREAD_CHECKER(thread_checker_); base::WeakPtrFactory weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(AsyncOperation); }; } // namespace win } // namespace base #endif // BASE_WIN_ASYNC_OPERATION_H_