1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/ole/safearray.h
3 // Purpose: Helpers for working with OLE SAFEARRAYs.
7 // Copyright: (c) 2012 wxWidgets development team
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 #ifndef _MSW_OLE_SAFEARRAY_H_
12 #define _MSW_OLE_SAFEARRAY_H_
14 #include "wx/msw/ole/oleutils.h"
16 #if wxUSE_OLE && wxUSE_VARIANT
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.
24 // The base class with type-independent methods. It exists solely in order to
25 // reduce the template bloat.
26 class WXDLLIMPEXP_CORE wxSafeArrayBase
29 // If owns a SAFEARRAY, it's unlocked and destroyed.
30 virtual ~wxSafeArrayBase() { Destroy(); }
32 // Unlocks and destroys the owned SAFEARRAY.
35 // Unlocks the owned SAFEARRAY, returns it and gives up its ownership.
38 // Returns true if has a valid SAFEARRAY.
39 bool HasArray() const { return m_array
!= NULL
; }
41 // Returns the number of dimensions.
42 size_t GetDim() const;
44 // Returns lower bound for dimension dim in bound. Dimensions start at 1.
45 bool GetLBound(size_t dim
, long& bound
) const;
47 // Returns upper bound for dimension dim in bound. Dimensions start at 1.
48 bool GetUBound(size_t dim
, long& bound
) const;
50 // Returns element count for dimension dim. Dimensions start at 1.
51 size_t GetCount(size_t dim
) const;
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<>.
67 // wxSafeArrayConvertor<> must be specialized for the type in order to allow
68 // using it with wxSafeArray<>.
70 // We specialize it below for the standard types.
71 template <VARTYPE varType
>
72 struct wxSafeArrayConvertor
{};
75 Macro for specializing wxSafeArrayConvertor for simple types.
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.
81 #define wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(externType, varType) \
83 struct wxSafeArrayConvertor<varType> \
85 typedef externType externT; \
86 typedef externT internT; \
87 static bool ToArray(const externT& from, internT& to) \
92 static bool FromArray(const internT& from, externT& to) \
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
);
104 // Specialization for VT_BSTR using wxString.
106 struct wxSafeArrayConvertor
<VT_BSTR
>
108 typedef wxString externT
;
109 typedef BSTR internT
;
111 static bool ToArray(const wxString
& from
, BSTR
& to
)
113 BSTR bstr
= wxConvertStringToOle(from
);
115 if ( !bstr
&& !from
.empty() )
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.
125 static bool FromArray(const BSTR from
, wxString
& to
)
127 to
= wxConvertStringFromOle(from
);
132 // Specialization for VT_VARIANT using wxVariant.
134 struct wxSafeArrayConvertor
<VT_VARIANT
>
136 typedef wxVariant externT
;
137 typedef VARIANT internT
;
139 static bool ToArray(const wxVariant
& from
, VARIANT
& to
)
141 return wxConvertVariantToOle(from
, to
);
144 static bool FromArray(const VARIANT
& from
, wxVariant
& to
)
146 return wxConvertOleToVariant(from
, to
);
151 template <VARTYPE varType
>
152 class wxSafeArray
: public wxSafeArrayBase
155 typedef wxSafeArrayConvertor
<varType
> Convertor
;
156 typedef typename
Convertor::internT internT
;
157 typedef typename
Convertor::externT externT
;
159 // Default constructor.
165 // Creates and locks a zero-based one-dimensional SAFEARRAY with the given
166 // number of elements.
167 bool Create(size_t count
)
169 SAFEARRAYBOUND bound
;
172 bound
.cElements
= count
;
173 return Create(&bound
, 1);
176 // Creates and locks a SAFEARRAY. See SafeArrayCreate() in MSDN
177 // documentation for more information.
178 bool Create(SAFEARRAYBOUND
* bound
, size_t dimensions
)
180 wxCHECK_MSG( !m_array
, false, wxS("Can't be created twice") );
182 m_array
= SafeArrayCreate(varType
, dimensions
, bound
);
190 Creates a 0-based one-dimensional SAFEARRAY from wxVariant with the
193 Can be called only for wxSafeArray<VT_VARIANT>.
195 bool CreateFromListVariant(const wxVariant
& variant
)
197 wxCHECK(varType
== VT_VARIANT
, false);
198 wxCHECK(variant
.GetType() == wxS("list"), false);
200 if ( !Create(variant
.GetCount()) )
203 VARIANT
* data
= static_cast<VARIANT
*>(m_array
->pvData
);
205 for ( size_t i
= 0; i
< variant
.GetCount(); i
++)
207 if ( !Convertor::ToArray(variant
[i
], data
[i
]) )
214 Creates a 0-based one-dimensional SAFEARRAY from wxArrayString.
216 Can be called only for wxSafeArray<VT_BSTR>.
218 bool CreateFromArrayString(const wxArrayString
& strings
)
220 wxCHECK(varType
== VT_BSTR
, false);
222 if ( !Create(strings
.size()) )
225 BSTR
* data
= static_cast<BSTR
*>(m_array
->pvData
);
227 for ( size_t i
= 0; i
< strings
.size(); i
++ )
229 if ( !Convertor::ToArray(strings
[i
], data
[i
]) )
236 Attaches and locks an existing SAFEARRAY.
237 The array must have the same VARTYPE as this wxSafeArray was
240 bool Attach(SAFEARRAY
* array
)
242 wxCHECK_MSG(!m_array
&& array
, false,
243 wxS("Can only attach a valid array to an uninitialized one") );
246 HRESULT hr
= SafeArrayGetVartype(array
, &vt
);
249 wxLogApiError(wxS("SafeArrayGetVarType()"), hr
);
253 wxCHECK_MSG(vt
== varType
, false,
254 wxS("Attaching array of invalid type"));
261 Indices have the same row-column order as rgIndices in
262 SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
264 bool SetElement(long* indices
, const externT
& element
)
266 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
267 wxCHECK_MSG( indices
, false, wxS("Invalid index") );
271 if ( FAILED( SafeArrayPtrOfIndex(m_array
, indices
, (void**)&data
) ) )
274 return Convertor::ToArray(element
, *data
);
278 Indices have the same row-column order as rgIndices in
279 SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
281 bool GetElement(long* indices
, externT
& element
) const
283 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
284 wxCHECK_MSG( indices
, false, wxS("Invalid index") );
288 if ( FAILED( SafeArrayPtrOfIndex(m_array
, indices
, (void**)&data
) ) )
291 return Convertor::FromArray(*data
, element
);
295 Converts the array to a wxVariant with the list type, regardless of the
296 underlying SAFEARRAY type.
298 If the array is multidimensional, it is flattened using the alghoritm
299 originally employed in wxConvertOleToVariant().
301 bool ConvertToVariant(wxVariant
& variant
) const
303 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
305 size_t dims
= m_array
->cDims
;
308 for ( size_t i
= 0; i
< dims
; i
++ )
309 count
*= m_array
->rgsabound
[i
].cElements
;
311 const internT
* data
= static_cast<const internT
*>(m_array
->pvData
);
315 for ( size_t i1
= 0; i1
< count
; i1
++ )
317 if ( !Convertor::FromArray(data
[i1
], element
) )
322 variant
.Append(element
);
328 Converts an array to an ArrayString.
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().
334 bool ConvertToArrayString(wxArrayString
& strings
) const
336 wxCHECK_MSG( m_array
, false, wxS("Uninitialized array") );
337 wxCHECK(varType
== VT_BSTR
, false);
339 size_t dims
= m_array
->cDims
;
342 for ( size_t i
= 0; i
< dims
; i
++ )
343 count
*= m_array
->rgsabound
[i
].cElements
;
345 const BSTR
* data
= static_cast<const BSTR
*>(m_array
->pvData
);
349 strings
.reserve(count
);
350 for ( size_t i1
= 0; i1
< count
; i1
++ )
352 if ( !Convertor::FromArray(data
[i1
], element
) )
357 strings
.push_back(element
);
362 static bool ConvertToVariant(SAFEARRAY
* psa
, wxVariant
& variant
)
364 wxSafeArray
<varType
> sa
;
367 if ( sa
.Attach(psa
) )
368 result
= sa
.ConvertToVariant(variant
);
376 static bool ConvertToArrayString(SAFEARRAY
* psa
, wxArrayString
& strings
)
378 wxSafeArray
<varType
> sa
;
381 if ( sa
.Attach(psa
) )
382 result
= sa
.ConvertToArrayString(strings
);
390 wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxSafeArray
, varType
);
393 #endif // wxUSE_OLE && wxUSE_VARIANT
395 #endif // _MSW_OLE_SAFEARRAY_H_