• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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