In 64 bits, LONG is actually defined as int in Cygwin gcc headers, so is different from long -- even if both types use identical representation. Just add the casts to fix this for now, as this is the smallest ABI-preserving change. Ideally, something better and less ugly would need to be done in the future. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76502 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			395 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			395 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////
 | |
| // Name:        msw/ole/safearray.h
 | |
| // Purpose:     Helpers for working with OLE SAFEARRAYs.
 | |
| // Author:      PB
 | |
| // Created:     2012-09-23
 | |
| // Copyright:   (c) 2012 wxWidgets development team
 | |
| // Licence:     wxWindows licence
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #ifndef _MSW_OLE_SAFEARRAY_H_
 | |
| #define _MSW_OLE_SAFEARRAY_H_
 | |
| 
 | |
| #include "wx/msw/ole/oleutils.h"
 | |
| 
 | |
| #if wxUSE_OLE && wxUSE_VARIANT
 | |
| 
 | |
| /*
 | |
|     wxSafeArray is wxWidgets wrapper for working with MS Windows SAFEARRAYs.
 | |
|     It also has convenience functions for converting between SAFEARRAY
 | |
|     and wxVariant with list type or wxArrayString.
 | |
| */
 | |
| 
 | |
| // The base class with type-independent methods. It exists solely in order to
 | |
| // reduce the template bloat.
 | |
| class WXDLLIMPEXP_CORE wxSafeArrayBase
 | |
| {
 | |
| public:
 | |
|     // If owns a SAFEARRAY, it's unlocked and destroyed.
 | |
|     virtual ~wxSafeArrayBase() { Destroy(); }
 | |
| 
 | |
|     // Unlocks and destroys the owned SAFEARRAY.
 | |
|     void Destroy();
 | |
| 
 | |
|     // Unlocks the owned SAFEARRAY, returns it and gives up its ownership.
 | |
|     SAFEARRAY* Detach();
 | |
| 
 | |
|     // Returns true if has a valid SAFEARRAY.
 | |
|     bool HasArray() const { return m_array != NULL; }
 | |
| 
 | |
|     // Returns the number of dimensions.
 | |
|     size_t GetDim() const;
 | |
| 
 | |
|     // Returns lower bound for dimension dim in bound. Dimensions start at 1.
 | |
|     bool GetLBound(size_t dim, long& bound) const;
 | |
| 
 | |
|     // Returns upper bound for dimension dim in bound. Dimensions start at 1.
 | |
|     bool GetUBound(size_t dim, long& bound) const;
 | |
| 
 | |
|     // Returns element count for dimension dim. Dimensions start at 1.
 | |
|     size_t GetCount(size_t dim) const;
 | |
| 
 | |
| protected:
 | |
|     // Default constructor, protected so the class can't be used on its own,
 | |
|     // it's only used as a base class of wxSafeArray<>.
 | |
|     wxSafeArrayBase()
 | |
|     {
 | |
|         m_array = NULL;
 | |
|     }
 | |
| 
 | |
|     bool Lock();
 | |
|     bool Unlock();
 | |
| 
 | |
|     SAFEARRAY* m_array;
 | |
| };
 | |
| 
 | |
| // wxSafeArrayConvertor<> must be specialized for the type in order to allow
 | |
| // using it with wxSafeArray<>.
 | |
| //
 | |
| // We specialize it below for the standard types.
 | |
| template <VARTYPE varType>
 | |
| struct wxSafeArrayConvertor {};
 | |
| 
 | |
| /**
 | |
|     Macro for specializing wxSafeArrayConvertor for simple types.
 | |
| 
 | |
|     The template parameters are:
 | |
|         - externType: basic C data type, e.g. wxFloat64 or wxInt32
 | |
|         - varType: corresponding VARIANT type constant, e.g. VT_R8 or VT_I4.
 | |
| */
 | |
| #define wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(externType, varType) \
 | |
| template <>                                                 \
 | |
| struct wxSafeArrayConvertor<varType>                        \
 | |
| {                                                           \
 | |
|     typedef externType externT;                             \
 | |
|     typedef externT    internT;                             \
 | |
|     static bool ToArray(const externT& from, internT& to)   \
 | |
|     {                                                       \
 | |
|         to = from;                                          \
 | |
|         return true;                                        \
 | |
|     }                                                       \
 | |
|     static bool FromArray(const internT& from, externT& to) \
 | |
|     {                                                       \
 | |
|         to = from;                                          \
 | |
|         return true;                                        \
 | |
|     }                                                       \
 | |
| }
 | |
| 
 | |
| wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxInt16, VT_I2);
 | |
| wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxInt32, VT_I4);
 | |
| wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxFloat32, VT_R4);
 | |
| wxSPECIALIZE_WXSAFEARRAY_CONVERTOR_SIMPLE(wxFloat64, VT_R8);
 | |
| 
 | |
| // Specialization for VT_BSTR using wxString.
 | |
| template <>
 | |
| struct wxSafeArrayConvertor<VT_BSTR>
 | |
| {
 | |
|     typedef wxString externT;
 | |
|     typedef BSTR internT;
 | |
| 
 | |
|     static bool ToArray(const wxString& from, BSTR& to)
 | |
|     {
 | |
|         BSTR bstr = wxConvertStringToOle(from);
 | |
| 
 | |
|         if ( !bstr && !from.empty() )
 | |
|         {
 | |
|             // BSTR can be NULL for empty strings but if the string was
 | |
|             // not empty, it means we failed to allocate memory for it.
 | |
|             return false;
 | |
|         }
 | |
|         to = bstr;
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     static bool FromArray(const BSTR from, wxString& to)
 | |
|     {
 | |
|         to = wxConvertStringFromOle(from);
 | |
|         return true;
 | |
|     }
 | |
| };
 | |
| 
 | |
| // Specialization for VT_VARIANT using wxVariant.
 | |
| template <>
 | |
| struct wxSafeArrayConvertor<VT_VARIANT>
 | |
| {
 | |
|     typedef wxVariant externT;
 | |
|     typedef VARIANT internT;
 | |
| 
 | |
|     static bool ToArray(const wxVariant& from, VARIANT& to)
 | |
|     {
 | |
|         return wxConvertVariantToOle(from, to);
 | |
|     }
 | |
| 
 | |
|     static bool FromArray(const VARIANT& from, wxVariant& to)
 | |
|     {
 | |
|         return wxConvertOleToVariant(from, to);
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <VARTYPE varType>
 | |
| class wxSafeArray : public wxSafeArrayBase
 | |
| {
 | |
| public:
 | |
|     typedef wxSafeArrayConvertor<varType> Convertor;
 | |
|     typedef typename Convertor::internT internT;
 | |
|     typedef typename Convertor::externT externT;
 | |
| 
 | |
|     // Default constructor.
 | |
|     wxSafeArray()
 | |
|     {
 | |
|         m_array = NULL;
 | |
|     }
 | |
| 
 | |
|     // Creates and locks a zero-based one-dimensional SAFEARRAY with the given
 | |
|     // number of elements.
 | |
|     bool Create(size_t count)
 | |
|     {
 | |
|         SAFEARRAYBOUND bound;
 | |
| 
 | |
|         bound.lLbound = 0;
 | |
|         bound.cElements = count;
 | |
|         return Create(&bound, 1);
 | |
|     }
 | |
| 
 | |
|     // Creates and locks a SAFEARRAY. See SafeArrayCreate() in MSDN
 | |
|     // documentation for more information.
 | |
|     bool Create(SAFEARRAYBOUND* bound, size_t dimensions)
 | |
|     {
 | |
|         wxCHECK_MSG( !m_array, false, wxS("Can't be created twice") );
 | |
| 
 | |
|         m_array = SafeArrayCreate(varType, dimensions, bound);
 | |
|         if ( !m_array )
 | |
|             return false;
 | |
| 
 | |
|         return Lock();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|         Creates a 0-based one-dimensional SAFEARRAY from wxVariant with the
 | |
|         list type.
 | |
| 
 | |
|         Can be called only for wxSafeArray<VT_VARIANT>.
 | |
|     */
 | |
|     bool CreateFromListVariant(const wxVariant& variant)
 | |
|     {
 | |
|         wxCHECK(varType == VT_VARIANT, false);
 | |
|         wxCHECK(variant.GetType() == wxS("list"), false);
 | |
| 
 | |
|         if ( !Create(variant.GetCount()) )
 | |
|             return false;
 | |
| 
 | |
|         VARIANT* data = static_cast<VARIANT*>(m_array->pvData);
 | |
| 
 | |
|         for ( size_t i = 0; i < variant.GetCount(); i++)
 | |
|         {
 | |
|             if ( !Convertor::ToArray(variant[i], data[i]) )
 | |
|                 return false;
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|         Creates a 0-based one-dimensional SAFEARRAY from wxArrayString.
 | |
| 
 | |
|         Can be called only for wxSafeArray<VT_BSTR>.
 | |
|     */
 | |
|     bool CreateFromArrayString(const wxArrayString& strings)
 | |
|     {
 | |
|         wxCHECK(varType == VT_BSTR, false);
 | |
| 
 | |
|         if ( !Create(strings.size()) )
 | |
|             return false;
 | |
| 
 | |
|         BSTR* data = static_cast<BSTR*>(m_array->pvData);
 | |
| 
 | |
|         for ( size_t i = 0; i < strings.size(); i++ )
 | |
|         {
 | |
|             if ( !Convertor::ToArray(strings[i], data[i]) )
 | |
|                 return false;
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|         Attaches and locks an existing SAFEARRAY.
 | |
|         The array must have the same VARTYPE as this wxSafeArray was
 | |
|         instantiated with.
 | |
|     */
 | |
|     bool Attach(SAFEARRAY* array)
 | |
|     {
 | |
|         wxCHECK_MSG(!m_array && array, false,
 | |
|                     wxS("Can only attach a valid array to an uninitialized one") );
 | |
| 
 | |
|         VARTYPE vt;
 | |
|         HRESULT hr = SafeArrayGetVartype(array, &vt);
 | |
|         if ( FAILED(hr) )
 | |
|         {
 | |
|             wxLogApiError(wxS("SafeArrayGetVarType()"), hr);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         wxCHECK_MSG(vt == varType, false,
 | |
|                     wxS("Attaching array of invalid type"));
 | |
| 
 | |
|         m_array = array;
 | |
|         return Lock();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|         Indices have the same row-column order as rgIndices in
 | |
|         SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
 | |
|     */
 | |
|     bool SetElement(long* indices, const externT& element)
 | |
|     {
 | |
|         wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
 | |
|         wxCHECK_MSG( indices, false, wxS("Invalid index") );
 | |
| 
 | |
|         internT* data;
 | |
| 
 | |
|         if ( FAILED( SafeArrayPtrOfIndex(m_array, (LONG *)indices, (void**)&data) ) )
 | |
|             return false;
 | |
| 
 | |
|         return Convertor::ToArray(element, *data);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|         Indices have the same row-column order as rgIndices in
 | |
|         SafeArrayPutElement(), i.e. they follow BASIC rules, NOT C ones.
 | |
|     */
 | |
|     bool GetElement(long* indices, externT& element) const
 | |
|     {
 | |
|         wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
 | |
|         wxCHECK_MSG( indices, false, wxS("Invalid index") );
 | |
| 
 | |
|         internT* data;
 | |
| 
 | |
|         if ( FAILED( SafeArrayPtrOfIndex(m_array, (LONG *)indices, (void**)&data) ) )
 | |
|             return false;
 | |
| 
 | |
|         return Convertor::FromArray(*data, element);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|         Converts the array to a wxVariant with the list type, regardless of the
 | |
|         underlying SAFEARRAY type.
 | |
| 
 | |
|         If the array is multidimensional, it is flattened using the alghoritm
 | |
|         originally employed in wxConvertOleToVariant().
 | |
|     */
 | |
|     bool ConvertToVariant(wxVariant& variant) const
 | |
|     {
 | |
|         wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
 | |
| 
 | |
|         size_t dims = m_array->cDims;
 | |
|         size_t count = 1;
 | |
| 
 | |
|         for ( size_t i = 0; i < dims; i++ )
 | |
|             count *= m_array->rgsabound[i].cElements;
 | |
| 
 | |
|         const internT* data = static_cast<const internT*>(m_array->pvData);
 | |
|         externT element;
 | |
| 
 | |
|         variant.ClearList();
 | |
|         for ( size_t i1 = 0; i1 < count; i1++ )
 | |
|         {
 | |
|             if ( !Convertor::FromArray(data[i1], element) )
 | |
|             {
 | |
|                 variant.ClearList();
 | |
|                 return false;
 | |
|             }
 | |
|             variant.Append(element);
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|         Converts an array to an ArrayString.
 | |
| 
 | |
|         Can be called only for wxSafeArray<VT_BSTR>. If the array is
 | |
|         multidimensional, it is flattened using the alghoritm originally
 | |
|         employed in wxConvertOleToVariant().
 | |
|     */
 | |
|     bool ConvertToArrayString(wxArrayString& strings) const
 | |
|     {
 | |
|         wxCHECK_MSG( m_array, false, wxS("Uninitialized array") );
 | |
|         wxCHECK(varType == VT_BSTR, false);
 | |
| 
 | |
|         size_t dims = m_array->cDims;
 | |
|         size_t count = 1;
 | |
| 
 | |
|         for ( size_t i = 0; i < dims; i++ )
 | |
|             count *= m_array->rgsabound[i].cElements;
 | |
| 
 | |
|         const BSTR* data = static_cast<const BSTR*>(m_array->pvData);
 | |
|         wxString element;
 | |
| 
 | |
|         strings.clear();
 | |
|         strings.reserve(count);
 | |
|         for ( size_t i1 = 0; i1 < count; i1++ )
 | |
|         {
 | |
|             if ( !Convertor::FromArray(data[i1], element) )
 | |
|             {
 | |
|                 strings.clear();
 | |
|                 return false;
 | |
|             }
 | |
|             strings.push_back(element);
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     static bool ConvertToVariant(SAFEARRAY* psa, wxVariant& variant)
 | |
|     {
 | |
|         wxSafeArray<varType> sa;
 | |
|         bool result = false;
 | |
| 
 | |
|         if ( sa.Attach(psa) )
 | |
|             result = sa.ConvertToVariant(variant);
 | |
| 
 | |
|         if ( sa.HasArray() )
 | |
|             sa.Detach();
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     static bool ConvertToArrayString(SAFEARRAY* psa, wxArrayString& strings)
 | |
|     {
 | |
|         wxSafeArray<varType> sa;
 | |
|         bool result = false;
 | |
| 
 | |
|         if ( sa.Attach(psa) )
 | |
|             result = sa.ConvertToArrayString(strings);
 | |
| 
 | |
|         if ( sa.HasArray() )
 | |
|             sa.Detach();
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxSafeArray, varType);
 | |
| };
 | |
| 
 | |
| #endif // wxUSE_OLE && wxUSE_VARIANT
 | |
| 
 | |
| #endif // _MSW_OLE_SAFEARRAY_H_
 |