1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/win/scoped_variant.h"
6 #include "base/logging.h"
7
8 namespace base {
9 namespace win {
10
11 // Global, const instance of an empty variant.
12 const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
13
~ScopedVariant()14 ScopedVariant::~ScopedVariant() {
15 COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
16 ::VariantClear(&var_);
17 }
18
ScopedVariant(const wchar_t * str)19 ScopedVariant::ScopedVariant(const wchar_t* str) {
20 var_.vt = VT_EMPTY;
21 Set(str);
22 }
23
ScopedVariant(const wchar_t * str,UINT length)24 ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) {
25 var_.vt = VT_BSTR;
26 var_.bstrVal = ::SysAllocStringLen(str, length);
27 }
28
ScopedVariant(int value,VARTYPE vt)29 ScopedVariant::ScopedVariant(int value, VARTYPE vt) {
30 var_.vt = vt;
31 var_.lVal = value;
32 }
33
ScopedVariant(double value,VARTYPE vt)34 ScopedVariant::ScopedVariant(double value, VARTYPE vt) {
35 DCHECK(vt == VT_R8 || vt == VT_DATE);
36 var_.vt = vt;
37 var_.dblVal = value;
38 }
39
ScopedVariant(IDispatch * dispatch)40 ScopedVariant::ScopedVariant(IDispatch* dispatch) {
41 var_.vt = VT_EMPTY;
42 Set(dispatch);
43 }
44
ScopedVariant(IUnknown * unknown)45 ScopedVariant::ScopedVariant(IUnknown* unknown) {
46 var_.vt = VT_EMPTY;
47 Set(unknown);
48 }
49
ScopedVariant(SAFEARRAY * safearray)50 ScopedVariant::ScopedVariant(SAFEARRAY* safearray) {
51 var_.vt = VT_EMPTY;
52 Set(safearray);
53 }
54
ScopedVariant(const VARIANT & var)55 ScopedVariant::ScopedVariant(const VARIANT& var) {
56 var_.vt = VT_EMPTY;
57 Set(var);
58 }
59
Reset(const VARIANT & var)60 void ScopedVariant::Reset(const VARIANT& var) {
61 if (&var != &var_) {
62 ::VariantClear(&var_);
63 var_ = var;
64 }
65 }
66
Release()67 VARIANT ScopedVariant::Release() {
68 VARIANT var = var_;
69 var_.vt = VT_EMPTY;
70 return var;
71 }
72
Swap(ScopedVariant & var)73 void ScopedVariant::Swap(ScopedVariant& var) {
74 VARIANT tmp = var_;
75 var_ = var.var_;
76 var.var_ = tmp;
77 }
78
Receive()79 VARIANT* ScopedVariant::Receive() {
80 DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
81 return &var_;
82 }
83
Copy() const84 VARIANT ScopedVariant::Copy() const {
85 VARIANT ret = { VT_EMPTY };
86 ::VariantCopy(&ret, &var_);
87 return ret;
88 }
89
Compare(const VARIANT & var,bool ignore_case) const90 int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const {
91 ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
92 HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var),
93 LOCALE_USER_DEFAULT, flags);
94 int ret = 0;
95
96 switch (hr) {
97 case VARCMP_LT:
98 ret = -1;
99 break;
100
101 case VARCMP_GT:
102 case VARCMP_NULL:
103 ret = 1;
104 break;
105
106 default:
107 // Equal.
108 break;
109 }
110
111 return ret;
112 }
113
Set(const wchar_t * str)114 void ScopedVariant::Set(const wchar_t* str) {
115 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
116 var_.vt = VT_BSTR;
117 var_.bstrVal = ::SysAllocString(str);
118 }
119
Set(int8 i8)120 void ScopedVariant::Set(int8 i8) {
121 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
122 var_.vt = VT_I1;
123 var_.cVal = i8;
124 }
125
Set(uint8 ui8)126 void ScopedVariant::Set(uint8 ui8) {
127 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
128 var_.vt = VT_UI1;
129 var_.bVal = ui8;
130 }
131
Set(int16 i16)132 void ScopedVariant::Set(int16 i16) {
133 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
134 var_.vt = VT_I2;
135 var_.iVal = i16;
136 }
137
Set(uint16 ui16)138 void ScopedVariant::Set(uint16 ui16) {
139 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
140 var_.vt = VT_UI2;
141 var_.uiVal = ui16;
142 }
143
Set(int32 i32)144 void ScopedVariant::Set(int32 i32) {
145 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
146 var_.vt = VT_I4;
147 var_.lVal = i32;
148 }
149
Set(uint32 ui32)150 void ScopedVariant::Set(uint32 ui32) {
151 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
152 var_.vt = VT_UI4;
153 var_.ulVal = ui32;
154 }
155
Set(int64 i64)156 void ScopedVariant::Set(int64 i64) {
157 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
158 var_.vt = VT_I8;
159 var_.llVal = i64;
160 }
161
Set(uint64 ui64)162 void ScopedVariant::Set(uint64 ui64) {
163 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
164 var_.vt = VT_UI8;
165 var_.ullVal = ui64;
166 }
167
Set(float r32)168 void ScopedVariant::Set(float r32) {
169 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
170 var_.vt = VT_R4;
171 var_.fltVal = r32;
172 }
173
Set(double r64)174 void ScopedVariant::Set(double r64) {
175 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
176 var_.vt = VT_R8;
177 var_.dblVal = r64;
178 }
179
SetDate(DATE date)180 void ScopedVariant::SetDate(DATE date) {
181 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
182 var_.vt = VT_DATE;
183 var_.date = date;
184 }
185
Set(IDispatch * disp)186 void ScopedVariant::Set(IDispatch* disp) {
187 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
188 var_.vt = VT_DISPATCH;
189 var_.pdispVal = disp;
190 if (disp)
191 disp->AddRef();
192 }
193
Set(bool b)194 void ScopedVariant::Set(bool b) {
195 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
196 var_.vt = VT_BOOL;
197 var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
198 }
199
Set(IUnknown * unk)200 void ScopedVariant::Set(IUnknown* unk) {
201 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
202 var_.vt = VT_UNKNOWN;
203 var_.punkVal = unk;
204 if (unk)
205 unk->AddRef();
206 }
207
Set(SAFEARRAY * array)208 void ScopedVariant::Set(SAFEARRAY* array) {
209 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
210 if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
211 var_.vt |= VT_ARRAY;
212 var_.parray = array;
213 } else {
214 DCHECK(!array) << "Unable to determine safearray vartype";
215 var_.vt = VT_EMPTY;
216 }
217 }
218
Set(const VARIANT & var)219 void ScopedVariant::Set(const VARIANT& var) {
220 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
221 if (FAILED(::VariantCopy(&var_, &var))) {
222 DLOG(ERROR) << "VariantCopy failed";
223 var_.vt = VT_EMPTY;
224 }
225 }
226
operator =(const VARIANT & var)227 ScopedVariant& ScopedVariant::operator=(const VARIANT& var) {
228 if (&var != &var_) {
229 VariantClear(&var_);
230 Set(var);
231 }
232 return *this;
233 }
234
IsLeakableVarType(VARTYPE vt)235 bool ScopedVariant::IsLeakableVarType(VARTYPE vt) {
236 bool leakable = false;
237 switch (vt & VT_TYPEMASK) {
238 case VT_BSTR:
239 case VT_DISPATCH:
240 // we treat VT_VARIANT as leakable to err on the safe side.
241 case VT_VARIANT:
242 case VT_UNKNOWN:
243 case VT_SAFEARRAY:
244
245 // very rarely used stuff (if ever):
246 case VT_VOID:
247 case VT_PTR:
248 case VT_CARRAY:
249 case VT_USERDEFINED:
250 case VT_LPSTR:
251 case VT_LPWSTR:
252 case VT_RECORD:
253 case VT_INT_PTR:
254 case VT_UINT_PTR:
255 case VT_FILETIME:
256 case VT_BLOB:
257 case VT_STREAM:
258 case VT_STORAGE:
259 case VT_STREAMED_OBJECT:
260 case VT_STORED_OBJECT:
261 case VT_BLOB_OBJECT:
262 case VT_VERSIONED_STREAM:
263 case VT_BSTR_BLOB:
264 leakable = true;
265 break;
266 }
267
268 if (!leakable && (vt & VT_ARRAY) != 0) {
269 leakable = true;
270 }
271
272 return leakable;
273 }
274
275 } // namespace win
276 } // namespace base
277