safearray.h 11 KB

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