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