1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/ole/safearray.h
3 // Purpose: Helpers for working with OLE SAFEARRAYs.
6 // Copyright: (c) 2012 wxWidgets development team
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 #ifndef _MSW_OLE_SAFEARRAY_H_
11 #define _MSW_OLE_SAFEARRAY_H_
13 #include "wx/msw/ole/oleutils.h"
15 #if wxUSE_OLE && wxUSE_VARIANT
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.
23 // The base class with type-independent methods. It exists solely in order to
24 // reduce the template bloat.
25 class WXDLLIMPEXP_CORE wxSafeArrayBase
28 // If owns a SAFEARRAY, it's unlocked and destroyed.
29 virtual ~wxSafeArrayBase() { Destroy(); }
31 // Unlocks and destroys the owned SAFEARRAY.
34 // Unlocks the owned SAFEARRAY, returns it and gives up its ownership.
37 // Returns true if has a valid SAFEARRAY.
38 bool HasArray() const { return m_array
!= NULL
; }
40 // Returns the number of dimensions.
41 size_t GetDim() const;
43 // Returns lower bound for dimension dim in bound. Dimensions start at 1.
44 bool GetLBound(size_t dim
, long& bound
) const;
46 // Returns upper bound for dimension dim in bound. Dimensions start at 1.
47 bool GetUBound(size_t dim
, long& bound
) const;
49 // Returns element count for dimension dim. Dimensions start at 1.
50 size_t GetCount(size_t dim
) const;
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<>.
66 // wxSafeArrayConvertor<> must be specialized for the type in order to allow
67 // using it with wxSafeArray<>.
69 // We specialize it below for the standard types.
70 template <VARTYPE varType
>
71 struct wxSafeArrayConvertor
{};
74 Macro for specializing wxSafeArrayConvertor for simple types.
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.
80 #define wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(externType, varType) \
82 struct wxSafeArrayConvertor<varType> \
84 typedef externType externT; \
85 typedef externT internT; \
86 static bool ToArray(const externT& from, internT& to) \
91 static bool FromArray(const internT& from, externT& to) \
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
);
103 // Specialization for VT_BSTR using wxString.
105 struct wxSafeArrayConvertor
<VT_BSTR
>
107 typedef wxString externT
;
108 typedef BSTR internT
;
110 static bool ToArray(const wxString
& from
, BSTR
& to
)
112 BSTR bstr
= wxConvertStringToOle(from
);
114 if ( !bstr
&& !from
.empty() )
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.
124 static bool FromArray(const BSTR from
, wxString
& to
)
126 to
= wxConvertStringFromOle(from
);
131 // Specialization for VT_VARIANT using wxVariant.
133 struct wxSafeArrayConvertor
<VT_VARIANT
>
135 typedef wxVariant externT
;
136 typedef VARIANT internT
;
138 static bool ToArray(const wxVariant
& from
, VARIANT
& to
)
140 return wxConvertVariantToOle(from
, to
);
143 static bool FromArray(const VARIANT
& from
, wxVariant
& to
)
145 return wxConvertOleToVariant(from
, to
);
150 template <VARTYPE varType
>
151 class wxSafeArray
: public wxSafeArrayBase
154 typedef wxSafeArrayConvertor
<varType
> Convertor
;
155 typedef typename
Convertor::internT internT
;
156 typedef typename
Convertor::externT externT
;
158 // Default constructor.
164 // Creates and locks a zero-based one-dimensional SAFEARRAY with the given
165 // number of elements.
166 bool Create(size_t count
)
168 SAFEARRAYBOUND bound
;
171 bound
.cElements
= count
;
172 return Create(&bound
, 1);
175 // Creates and locks a SAFEARRAY. See SafeArrayCreate() in MSDN
176 // documentation for more information.
177 bool Create(SAFEARRAYBOUND
* bound
, size_t dimensions
)
179 wxCHECK_MSG( !m_array
, false, wxS("Can't be created twice") );
181 m_array
= SafeArrayCreate(varType
, dimensions
, bound
);
189 Creates a 0-based one-dimensional SAFEARRAY from wxVariant with the
192 Can be called only for wxSafeArray<VT_VARIANT>.
194 bool CreateFromListVariant(const wxVariant
& variant
)
196 wxCHECK(varType
== VT_VARIANT
, false);
197 wxCHECK(variant
.GetType() == wxS("list"), false);
199 if ( !Create(variant
.GetCount()) )
202 VARIANT
* data
= static_cast<VARIANT
*>(m_array
->pvData
);
204 for ( size_t i
= 0; i
< variant
.GetCount(); i
++)
206 if ( !Convertor::ToArray(variant
[i
], data
[i
]) )
213 Creates a 0-based one-dimensional SAFEARRAY from wxArrayString.
215 Can be called only for wxSafeArray<VT_BSTR>.
217 bool CreateFromArrayString(const wxArrayString
& strings
)
219 wxCHECK(varType
== VT_BSTR
, false);
221 if ( !Create(strings
.size()) )
224 BSTR
* data
= static_cast<BSTR
*>(m_array
->pvData
);
226 for ( size_t i
= 0; i
< strings
.size(); i
++ )
228 if ( !Convertor::ToArray(strings
[i
], data
[i
]) )
235 Attaches and locks an existing SAFEARRAY.
236 The array must have the same VARTYPE as this wxSafeArray was
239 bool Attach(SAFEARRAY
* array
)
241 wxCHECK_MSG(!m_array
&& array
, false,
242 wxS("Can only attach a valid array to an uninitialized one") );
245 HRESULT hr
= SafeArrayGetVartype(array
, &vt
);
248 wxLogApiError(wxS("SafeArrayGetVarType()"), hr
);
252 wxCHECK_MSG(vt
== varType
, false,
253 wxS("Attaching array of invalid type"));
260 Indices have the same row-column order as rgIndices in
261 SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
263 bool SetElement(long* indices
, const externT
& element
)
265 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
266 wxCHECK_MSG( indices
, false, wxS("Invalid index") );
270 if ( FAILED( SafeArrayPtrOfIndex(m_array
, indices
, (void**)&data
) ) )
273 return Convertor::ToArray(element
, *data
);
277 Indices have the same row-column order as rgIndices in
278 SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
280 bool GetElement(long* indices
, externT
& element
) const
282 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
283 wxCHECK_MSG( indices
, false, wxS("Invalid index") );
287 if ( FAILED( SafeArrayPtrOfIndex(m_array
, indices
, (void**)&data
) ) )
290 return Convertor::FromArray(*data
, element
);
294 Converts the array to a wxVariant with the list type, regardless of the
295 underlying SAFEARRAY type.
297 If the array is multidimensional, it is flattened using the alghoritm
298 originally employed in wxConvertOleToVariant().
300 bool ConvertToVariant(wxVariant
& variant
) const
302 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
304 size_t dims
= m_array
->cDims
;
307 for ( size_t i
= 0; i
< dims
; i
++ )
308 count
*= m_array
->rgsabound
[i
].cElements
;
310 const internT
* data
= static_cast<const internT
*>(m_array
->pvData
);
314 for ( size_t i1
= 0; i1
< count
; i1
++ )
316 if ( !Convertor::FromArray(data
[i1
], element
) )
321 variant
.Append(element
);
327 Converts an array to an ArrayString.
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().
333 bool ConvertToArrayString(wxArrayString
& strings
) const
335 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
336 wxCHECK(varType
== VT_BSTR
, false);
338 size_t dims
= m_array
->cDims
;
341 for ( size_t i
= 0; i
< dims
; i
++ )
342 count
*= m_array
->rgsabound
[i
].cElements
;
344 const BSTR
* data
= static_cast<const BSTR
*>(m_array
->pvData
);
348 strings
.reserve(count
);
349 for ( size_t i1
= 0; i1
< count
; i1
++ )
351 if ( !Convertor::FromArray(data
[i1
], element
) )
356 strings
.push_back(element
);
361 static bool ConvertToVariant(SAFEARRAY
* psa
, wxVariant
& variant
)
363 wxSafeArray
<varType
> sa
;
366 if ( sa
.Attach(psa
) )
367 result
= sa
.ConvertToVariant(variant
);
375 static bool ConvertToArrayString(SAFEARRAY
* psa
, wxArrayString
& strings
)
377 wxSafeArray
<varType
> sa
;
380 if ( sa
.Attach(psa
) )
381 result
= sa
.ConvertToArrayString(strings
);
389 wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxSafeArray
, varType
);
392 #endif // wxUSE_OLE && wxUSE_VARIANT
394 #endif // _MSW_OLE_SAFEARRAY_H_