]> git.saurik.com Git - wxWidgets.git/blob - include/wx/msw/ole/safearray.h
Fix wxPropertyGrid::GetPropertyRect when the last item is collapsed.
[wxWidgets.git] / include / wx / msw / ole / safearray.h
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/ole/safearray.h
3 // Purpose: Helpers for working with OLE SAFEARRAYs.
4 // Author: PB
5 // Created: 2012-09-23
6 // Copyright: (c) 2012 wxWidgets development team
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifndef _MSW_OLE_SAFEARRAY_H_
11 #define _MSW_OLE_SAFEARRAY_H_
12
13 #include "wx/msw/ole/oleutils.h"
14
15 #if wxUSE_OLE && wxUSE_VARIANT
16
17 /*
18 wxSafeArray is wxWidgets wrapper for working with MS Windows SAFEARRAYs.
19 It also has convenience functions for converting between SAFEARRAY
20 and wxVariant with list type or wxArrayString.
21 */
22
23 // The base class with type-independent methods. It exists solely in order to
24 // reduce the template bloat.
25 class WXDLLIMPEXP_CORE wxSafeArrayBase
26 {
27 public:
28 // If owns a SAFEARRAY, it's unlocked and destroyed.
29 virtual ~wxSafeArrayBase() { Destroy(); }
30
31 // Unlocks and destroys the owned SAFEARRAY.
32 void Destroy();
33
34 // Unlocks the owned SAFEARRAY, returns it and gives up its ownership.
35 SAFEARRAY* Detach();
36
37 // Returns true if has a valid SAFEARRAY.
38 bool HasArray() const { return m_array != NULL; }
39
40 // Returns the number of dimensions.
41 size_t GetDim() const;
42
43 // Returns lower bound for dimension dim in bound. Dimensions start at 1.
44 bool GetLBound(size_t dim, long& bound) const;
45
46 // Returns upper bound for dimension dim in bound. Dimensions start at 1.
47 bool GetUBound(size_t dim, long& bound) const;
48
49 // Returns element count for dimension dim. Dimensions start at 1.
50 size_t GetCount(size_t dim) const;
51
52 protected:
53 // Default constructor, protected so the class can't be used on its own,
54 // it's only used as a base class of wxSafeArray<>.
55 wxSafeArrayBase()
56 {
57 m_array = NULL;
58 }
59
60 bool Lock();
61 bool Unlock();
62
63 SAFEARRAY* m_array;
64 };
65
66 // wxSafeArrayConvertor<> must be specialized for the type in order to allow
67 // using it with wxSafeArray<>.
68 //
69 // We specialize it below for the standard types.
70 template <VARTYPE varType>
71 struct wxSafeArrayConvertor {};
72
73 /**
74 Macro for specializing wxSafeArrayConvertor for simple types.
75
76 The template parameters are:
77 - externType: basic C data type, e.g. wxFloat64 or wxInt32
78 - varType: corresponding VARIANT type constant, e.g. VT_R8 or VT_I4.
79 */
80 #define wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(externType, varType) \
81 template <> \
82 struct wxSafeArrayConvertor<varType> \
83 { \
84 typedef externType externT; \
85 typedef externT internT; \
86 static bool ToArray(const externT& from, internT& to) \
87 { \
88 to = from; \
89 return true; \
90 } \
91 static bool FromArray(const internT& from, externT& to) \
92 { \
93 to = from; \
94 return true; \
95 } \
96 }
97
98 wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxInt16, VT_I2);
99 wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxInt32, VT_I4);
100 wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxFloat32, VT_R4);
101 wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxFloat64, VT_R8);
102
103 // Specialization for VT_BSTR using wxString.
104 template <>
105 struct wxSafeArrayConvertor<VT_BSTR>
106 {
107 typedef wxString externT;
108 typedef BSTR internT;
109
110 static bool ToArray(const wxString& from, BSTR& to)
111 {
112 BSTR bstr = wxConvertStringToOle(from);
113
114 if ( !bstr && !from.empty() )
115 {
116 // BSTR can be NULL for empty strings but if the string was
117 // not empty, it means we failed to allocate memory for it.
118 return false;
119 }
120 to = bstr;
121 return true;
122 }
123
124 static bool FromArray(const BSTR from, wxString& to)
125 {
126 to = wxConvertStringFromOle(from);
127 return true;
128 }
129 };
130
131 // Specialization for VT_VARIANT using wxVariant.
132 template <>
133 struct wxSafeArrayConvertor<VT_VARIANT>
134 {
135 typedef wxVariant externT;
136 typedef VARIANT internT;
137
138 static bool ToArray(const wxVariant& from, VARIANT& to)
139 {
140 return wxConvertVariantToOle(from, to);
141 }
142
143 static bool FromArray(const VARIANT& from, wxVariant& to)
144 {
145 return wxConvertOleToVariant(from, to);
146 }
147 };
148
149
150 template <VARTYPE varType>
151 class wxSafeArray : public wxSafeArrayBase
152 {
153 public:
154 typedef wxSafeArrayConvertor<varType> Convertor;
155 typedef typename Convertor::internT internT;
156 typedef typename Convertor::externT externT;
157
158 // Default constructor.
159 wxSafeArray()
160 {
161 m_array = NULL;
162 }
163
164 // Creates and locks a zero-based one-dimensional SAFEARRAY with the given
165 // number of elements.
166 bool Create(size_t count)
167 {
168 SAFEARRAYBOUND bound;
169
170 bound.lLbound = 0;
171 bound.cElements = count;
172 return Create(&bound, 1);
173 }
174
175 // Creates and locks a SAFEARRAY. See SafeArrayCreate() in MSDN
176 // documentation for more information.
177 bool Create(SAFEARRAYBOUND* bound, size_t dimensions)
178 {
179 wxCHECK_MSG( !m_array, false, wxS("Can't be created twice") );
180
181 m_array = SafeArrayCreate(varType, dimensions, bound);
182 if ( !m_array )
183 return false;
184
185 return Lock();
186 }
187
188 /**
189 Creates a 0-based one-dimensional SAFEARRAY from wxVariant with the
190 list type.
191
192 Can be called only for wxSafeArray<VT_VARIANT>.
193 */
194 bool CreateFromListVariant(const wxVariant& variant)
195 {
196 wxCHECK(varType == VT_VARIANT, false);
197 wxCHECK(variant.GetType() == wxS("list"), false);
198
199 if ( !Create(variant.GetCount()) )
200 return false;
201
202 VARIANT* data = static_cast<VARIANT*>(m_array->pvData);
203
204 for ( size_t i = 0; i < variant.GetCount(); i++)
205 {
206 if ( !Convertor::ToArray(variant[i], data[i]) )
207 return false;
208 }
209 return true;
210 }
211
212 /**
213 Creates a 0-based one-dimensional SAFEARRAY from wxArrayString.
214
215 Can be called only for wxSafeArray<VT_BSTR>.
216 */
217 bool CreateFromArrayString(const wxArrayString& strings)
218 {
219 wxCHECK(varType == VT_BSTR, false);
220
221 if ( !Create(strings.size()) )
222 return false;
223
224 BSTR* data = static_cast<BSTR*>(m_array->pvData);
225
226 for ( size_t i = 0; i < strings.size(); i++ )
227 {
228 if ( !Convertor::ToArray(strings[i], data[i]) )
229 return false;
230 }
231 return true;
232 }
233
234 /**
235 Attaches and locks an existing SAFEARRAY.
236 The array must have the same VARTYPE as this wxSafeArray was
237 instantiated with.
238 */
239 bool Attach(SAFEARRAY* array)
240 {
241 wxCHECK_MSG(!m_array && array, false,
242 wxS("Can only attach a valid array to an uninitialized one") );
243
244 VARTYPE vt;
245 HRESULT hr = SafeArrayGetVartype(array, &vt);
246 if ( FAILED(hr) )
247 {
248 wxLogApiError(wxS("SafeArrayGetVarType()"), hr);
249 return false;
250 }
251
252 wxCHECK_MSG(vt == varType, false,
253 wxS("Attaching array of invalid type"));
254
255 m_array = array;
256 return Lock();
257 }
258
259 /**
260 Indices have the same row-column order as rgIndices in
261 SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
262 */
263 bool SetElement(long* indices, const externT& element)
264 {
265 wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
266 wxCHECK_MSG( indices, false, wxS("Invalid index") );
267
268 internT* data;
269
270 if ( FAILED( SafeArrayPtrOfIndex(m_array, indices, (void**)&data) ) )
271 return false;
272
273 return Convertor::ToArray(element, *data);
274 }
275
276 /**
277 Indices have the same row-column order as rgIndices in
278 SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
279 */
280 bool GetElement(long* indices, externT& element) const
281 {
282 wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
283 wxCHECK_MSG( indices, false, wxS("Invalid index") );
284
285 internT* data;
286
287 if ( FAILED( SafeArrayPtrOfIndex(m_array, indices, (void**)&data) ) )
288 return false;
289
290 return Convertor::FromArray(*data, element);
291 }
292
293 /**
294 Converts the array to a wxVariant with the list type, regardless of the
295 underlying SAFEARRAY type.
296
297 If the array is multidimensional, it is flattened using the alghoritm
298 originally employed in wxConvertOleToVariant().
299 */
300 bool ConvertToVariant(wxVariant& variant) const
301 {
302 wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
303
304 size_t dims = m_array->cDims;
305 size_t count = 1;
306
307 for ( size_t i = 0; i < dims; i++ )
308 count *= m_array->rgsabound[i].cElements;
309
310 const internT* data = static_cast<const internT*>(m_array->pvData);
311 externT element;
312
313 variant.ClearList();
314 for ( size_t i1 = 0; i1 < count; i1++ )
315 {
316 if ( !Convertor::FromArray(data[i1], element) )
317 {
318 variant.ClearList();
319 return false;
320 }
321 variant.Append(element);
322 }
323 return true;
324 }
325
326 /**
327 Converts an array to an ArrayString.
328
329 Can be called only for wxSafeArray<VT_BSTR>. If the array is
330 multidimensional, it is flattened using the alghoritm originally
331 employed in wxConvertOleToVariant().
332 */
333 bool ConvertToArrayString(wxArrayString& strings) const
334 {
335 wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
336 wxCHECK(varType == VT_BSTR, false);
337
338 size_t dims = m_array->cDims;
339 size_t count = 1;
340
341 for ( size_t i = 0; i < dims; i++ )
342 count *= m_array->rgsabound[i].cElements;
343
344 const BSTR* data = static_cast<const BSTR*>(m_array->pvData);
345 wxString element;
346
347 strings.clear();
348 strings.reserve(count);
349 for ( size_t i1 = 0; i1 < count; i1++ )
350 {
351 if ( !Convertor::FromArray(data[i1], element) )
352 {
353 strings.clear();
354 return false;
355 }
356 strings.push_back(element);
357 }
358 return true;
359 }
360
361 static bool ConvertToVariant(SAFEARRAY* psa, wxVariant& variant)
362 {
363 wxSafeArray<varType> sa;
364 bool result = false;
365
366 if ( sa.Attach(psa) )
367 result = sa.ConvertToVariant(variant);
368
369 if ( sa.HasArray() )
370 sa.Detach();
371
372 return result;
373 }
374
375 static bool ConvertToArrayString(SAFEARRAY* psa, wxArrayString& strings)
376 {
377 wxSafeArray<varType> sa;
378 bool result = false;
379
380 if ( sa.Attach(psa) )
381 result = sa.ConvertToArrayString(strings);
382
383 if ( sa.HasArray() )
384 sa.Detach();
385
386 return result;
387 }
388
389 wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxSafeArray, varType);
390 };
391
392 #endif // wxUSE_OLE && wxUSE_VARIANT
393
394 #endif // _MSW_OLE_SAFEARRAY_H_