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