1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_WIN_WINRT_FOUNDATION_HELPERS_H_
6 #define BASE_WIN_WINRT_FOUNDATION_HELPERS_H_
7
8 #include <windows.foundation.h>
9 #include <wrl/client.h>
10
11 #include <algorithm>
12 #include <vector>
13
14 #include "base/check.h"
15 #include "third_party/abseil-cpp/absl/types/optional.h"
16
17 // This file provides helpers for WinRT types.
18
19 namespace base::win::internal {
20
21 // Template tricks needed to dispatch to the correct implementation.
22 //
23 // For all types which are neither InterfaceGroups nor RuntimeClasses, the
24 // following three typedefs are synonyms for a single C++ type. But for
25 // InterfaceGroups and RuntimeClasses, they are different types:
26 // LogicalT: The C++ Type for the InterfaceGroup or RuntimeClass, when
27 // used as a template parameter. Eg "RCFoo*"
28 // AbiT: The C++ type for the default interface used to represent the
29 // InterfaceGroup or RuntimeClass when passed as a method parameter.
30 // Eg "IFoo*"
31 // ComplexT: An instantiation of the Internal "AggregateType" template that
32 // combines LogicalT with AbiT. Eg "AggregateType<RCFoo*,IFoo*>".
33 // ComplexT is tightly coupled to the interface being implemented,
34 // hence defined in headers which include this file.
35 // For instance base/win/async_operation.h or
36 // base/win/collection_helpers.h
37 //
38 // windows.foundation.collections.h defines the following template and
39 // semantics in Windows::Foundation::Internal:
40 //
41 // template <class LogicalType, class AbiType>
42 // struct AggregateType;
43 //
44 // LogicalType - the Windows Runtime type (eg, runtime class, interface group,
45 // etc) being provided as an argument to an _impl template, when
46 // that type cannot be represented at the ABI.
47 // AbiType - the type used for marshalling, ie "at the ABI", for the
48 // logical type.
49 template <typename TComplex>
50 using AbiType =
51 typename ABI::Windows::Foundation::Internal::GetAbiType<TComplex>::type;
52
53 template <typename TComplex>
54 using LogicalType =
55 typename ABI::Windows::Foundation::Internal::GetLogicalType<TComplex>::type;
56
57 // Compile time switch to decide what container to use for |TComplex|.
58 // Depends on whether the underlying Abi type is a pointer to IUnknown or not.
59 // It queries the internals of Windows::Foundation to obtain this information.
60 template <typename TComplex>
61 using StorageType = std::conditional_t<
62 std::is_convertible<AbiType<TComplex>, IUnknown*>::value,
63 Microsoft::WRL::ComPtr<std::remove_pointer_t<AbiType<TComplex>>>,
64 AbiType<TComplex>>;
65
66 // Similar to StorageType, but returns a absl::optional in case underlying Abi
67 // type is not a pointer to IUnknown.
68 template <typename TComplex>
69 using OptionalStorageType = std::conditional_t<
70 std::is_convertible<AbiType<TComplex>, IUnknown*>::value,
71 Microsoft::WRL::ComPtr<std::remove_pointer_t<AbiType<TComplex>>>,
72 absl::optional<AbiType<TComplex>>>;
73
74 template <typename T>
CopyTo(const T & value,T * ptr)75 HRESULT CopyTo(const T& value, T* ptr) {
76 *ptr = value;
77 return S_OK;
78 }
79
80 template <typename T>
CopyTo(const Microsoft::WRL::ComPtr<T> & value,T ** ptr)81 HRESULT CopyTo(const Microsoft::WRL::ComPtr<T>& value, T** ptr) {
82 return value.CopyTo(ptr);
83 }
84
85 template <typename T>
CopyTo(const absl::optional<T> & value,T * ptr)86 HRESULT CopyTo(const absl::optional<T>& value, T* ptr) {
87 *ptr = *value;
88 return S_OK;
89 }
90
91 template <typename T>
CopyN(typename std::vector<T>::const_iterator first,unsigned count,T * result)92 HRESULT CopyN(typename std::vector<T>::const_iterator first,
93 unsigned count,
94 T* result) {
95 std::copy_n(first, count, result);
96 return S_OK;
97 }
98
99 template <typename T>
CopyN(typename std::vector<Microsoft::WRL::ComPtr<T>>::const_iterator first,unsigned count,T ** result)100 HRESULT CopyN(
101 typename std::vector<Microsoft::WRL::ComPtr<T>>::const_iterator first,
102 unsigned count,
103 T** result) {
104 for (unsigned i = 0; i < count; ++i) {
105 CopyTo(*first++, result++);
106 }
107 return S_OK;
108 }
109
IsEqual(const HSTRING & lhs,const HSTRING & rhs)110 inline bool IsEqual(const HSTRING& lhs, const HSTRING& rhs) {
111 INT32 result;
112 HRESULT hr = ::WindowsCompareStringOrdinal(lhs, rhs, &result);
113 DCHECK(SUCCEEDED(hr));
114 return result == 0;
115 }
116
117 template <typename T>
IsEqual(const T & lhs,const T & rhs)118 bool IsEqual(const T& lhs, const T& rhs) {
119 return lhs == rhs;
120 }
121
122 template <typename T>
IsEqual(const Microsoft::WRL::ComPtr<T> & com_ptr,const T * ptr)123 bool IsEqual(const Microsoft::WRL::ComPtr<T>& com_ptr, const T* ptr) {
124 return com_ptr.Get() == ptr;
125 }
126
127 struct Less {
operatorLess128 bool operator()(const HSTRING& lhs, const HSTRING& rhs) const {
129 INT32 result;
130 HRESULT hr = ::WindowsCompareStringOrdinal(lhs, rhs, &result);
131 DCHECK(SUCCEEDED(hr));
132 return result < 0;
133 }
134
135 template <typename T>
operatorLess136 bool operator()(const Microsoft::WRL::ComPtr<T>& com_ptr,
137 const T* ptr) const {
138 return com_ptr.Get() < ptr;
139 }
140
141 template <typename T>
operatorLess142 constexpr bool operator()(const T& lhs, const T& rhs) const {
143 return lhs < rhs;
144 }
145 };
146
147 } // namespace base::win::internal
148
149 #endif // BASE_WIN_WINRT_FOUNDATION_HELPERS_H_
150