mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-28 08:16:09 +03:00
209 lines
7.2 KiB
C++
209 lines
7.2 KiB
C++
// 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_
|