1 // Copyright 2020 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_VARIANT_CONVERSIONS_H_ 6 #define BASE_WIN_VARIANT_CONVERSIONS_H_ 7 8 #include <oaidl.h> 9 #include <stdint.h> 10 #include <wtypes.h> 11 12 #include "base/check.h" 13 14 namespace base { 15 namespace win { 16 namespace internal { 17 18 // Returns true if a VARIANT of type |self| can be assigned to a 19 // variant of type |other|. 20 // Does not allow converting unsigned <-> signed or converting between 21 // different sized types, but does allow converting IDispatch* -> IUnknown*. VarTypeIsConvertibleTo(VARTYPE self,VARTYPE other)22constexpr bool VarTypeIsConvertibleTo(VARTYPE self, VARTYPE other) { 23 // IDispatch inherits from IUnknown, so it's safe to 24 // upcast a VT_DISPATCH into an IUnknown*. 25 return (self == other) || (self == VT_DISPATCH && other == VT_UNKNOWN); 26 } 27 28 // VartypeToNativeType contains the underlying |Type| and offset to the 29 // VARIANT union member related to the |ElementVartype| for simple types. 30 template <VARTYPE ElementVartype> 31 struct VartypeToNativeType final {}; 32 33 template <> 34 struct VartypeToNativeType<VT_BOOL> final { 35 using Type = VARIANT_BOOL; 36 static constexpr VARIANT_BOOL VARIANT::*kMemberOffset = &VARIANT::boolVal; 37 }; 38 39 template <> 40 struct VartypeToNativeType<VT_I1> final { 41 using Type = int8_t; 42 static constexpr CHAR VARIANT::*kMemberOffset = &VARIANT::cVal; 43 }; 44 45 template <> 46 struct VartypeToNativeType<VT_UI1> final { 47 using Type = uint8_t; 48 static constexpr BYTE VARIANT::*kMemberOffset = &VARIANT::bVal; 49 }; 50 51 template <> 52 struct VartypeToNativeType<VT_I2> final { 53 using Type = int16_t; 54 static constexpr SHORT VARIANT::*kMemberOffset = &VARIANT::iVal; 55 }; 56 57 template <> 58 struct VartypeToNativeType<VT_UI2> final { 59 using Type = uint16_t; 60 static constexpr USHORT VARIANT::*kMemberOffset = &VARIANT::uiVal; 61 }; 62 63 template <> 64 struct VartypeToNativeType<VT_I4> final { 65 using Type = int32_t; 66 static constexpr LONG VARIANT::*kMemberOffset = &VARIANT::lVal; 67 }; 68 69 template <> 70 struct VartypeToNativeType<VT_UI4> final { 71 using Type = uint32_t; 72 static constexpr ULONG VARIANT::*kMemberOffset = &VARIANT::ulVal; 73 }; 74 75 template <> 76 struct VartypeToNativeType<VT_I8> final { 77 using Type = int64_t; 78 static constexpr LONGLONG VARIANT::*kMemberOffset = &VARIANT::llVal; 79 }; 80 81 template <> 82 struct VartypeToNativeType<VT_UI8> final { 83 using Type = uint64_t; 84 static constexpr ULONGLONG VARIANT::*kMemberOffset = &VARIANT::ullVal; 85 }; 86 87 template <> 88 struct VartypeToNativeType<VT_R4> final { 89 using Type = float; 90 static constexpr FLOAT VARIANT::*kMemberOffset = &VARIANT::fltVal; 91 }; 92 93 template <> 94 struct VartypeToNativeType<VT_R8> final { 95 using Type = double; 96 static constexpr DOUBLE VARIANT::*kMemberOffset = &VARIANT::dblVal; 97 }; 98 99 template <> 100 struct VartypeToNativeType<VT_DATE> final { 101 using Type = DATE; 102 static constexpr DATE VARIANT::*kMemberOffset = &VARIANT::date; 103 }; 104 105 template <> 106 struct VartypeToNativeType<VT_BSTR> final { 107 using Type = BSTR; 108 static constexpr BSTR VARIANT::*kMemberOffset = &VARIANT::bstrVal; 109 }; 110 111 template <> 112 struct VartypeToNativeType<VT_UNKNOWN> final { 113 using Type = IUnknown*; 114 static constexpr IUnknown* VARIANT::*kMemberOffset = &VARIANT::punkVal; 115 }; 116 117 template <> 118 struct VartypeToNativeType<VT_DISPATCH> final { 119 using Type = IDispatch*; 120 static constexpr IDispatch* VARIANT::*kMemberOffset = &VARIANT::pdispVal; 121 }; 122 123 // VariantConverter contains the underlying |Type| and helper methods 124 // related to the |ElementVartype| for simple types. 125 template <VARTYPE ElementVartype> 126 struct VariantConverter final { 127 using Type = typename VartypeToNativeType<ElementVartype>::Type; 128 static constexpr bool IsConvertibleTo(VARTYPE vartype) { 129 return VarTypeIsConvertibleTo(ElementVartype, vartype); 130 } 131 static constexpr bool IsConvertibleFrom(VARTYPE vartype) { 132 return VarTypeIsConvertibleTo(vartype, ElementVartype); 133 } 134 // Get the associated VARIANT union member value. 135 // Returns the value owned by the VARIANT without affecting the lifetime 136 // of managed contents. 137 // e.g. Does not affect IUnknown* reference counts or allocate a BSTR. 138 static Type RawGet(const VARIANT& var) { 139 DCHECK(IsConvertibleFrom(V_VT(&var))); 140 return var.*VartypeToNativeType<ElementVartype>::kMemberOffset; 141 } 142 // Set the associated VARIANT union member value. 143 // The caller is responsible for handling the lifetime of managed contents. 144 // e.g. Incrementing IUnknown* reference counts or allocating a BSTR. 145 static void RawSet(VARIANT* var, Type value) { 146 DCHECK(IsConvertibleTo(V_VT(var))); 147 var->*VartypeToNativeType<ElementVartype>::kMemberOffset = value; 148 } 149 }; 150 151 } // namespace internal 152 } // namespace win 153 } // namespace base 154 155 #endif // BASE_WIN_VARIANT_CONVERSIONS_H_ 156