#endif
#include "wx/msw/ole/oleutils.h"
+#include "wx/msw/ole/safearray.h"
#if defined(__VISUALC__) && (__VISUALC__ > 1000)
#include <docobj.h>
#if wxUSE_VARIANT
-namespace
-{
-
-// Helper class for creating and filling SAFEARRAY. To use it, call Create()
-// first, then SetElement() for each element and finally Detach() the SAFEARRAY
-// from it if you don't want it to be deleted when this class is.
-class wxSafeArrayHelper
-{
-public:
- wxSafeArrayHelper();
- ~wxSafeArrayHelper();
-
- bool Create(VARTYPE vt, long count); // creates and locks the array
-
- bool SetElement(size_t index, const wxVariant& variant);
- bool SetElement(size_t index, const wxString& str);
-
- SAFEARRAY* Detach(); // unlocks the array and gives up its ownership
-
-private:
- void Unlock();
-
- SAFEARRAY* m_array;
-};
-
-wxSafeArrayHelper::wxSafeArrayHelper()
-{
- m_array = NULL;
-}
-
-wxSafeArrayHelper::~wxSafeArrayHelper()
-{
- if ( m_array )
- {
- Unlock();
- SafeArrayDestroy(m_array);
- }
-}
-
-bool wxSafeArrayHelper::Create(VARTYPE vt, long count)
-{
- SAFEARRAYBOUND saBound;
-
- saBound.lLbound = 0;
- saBound.cElements = count;
- m_array = SafeArrayCreate(vt, 1, &saBound);
- if ( !m_array )
- return false;
- return SUCCEEDED( SafeArrayLock(m_array) );
-}
-
-bool wxSafeArrayHelper::SetElement(size_t index, const wxVariant& variant)
-{
- VARIANT* data = (VARIANT*)m_array->pvData;
- return wxConvertVariantToOle(variant, data[index]);
-}
-
-bool wxSafeArrayHelper::SetElement(size_t index, const wxString& str)
-{
- BSTR bstr = wxConvertStringToOle(str);
-
- if ( !bstr && !str.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;
- }
-
- BSTR* data = (BSTR*)m_array->pvData;
- data[index] = bstr;
- return true;
-}
-
-SAFEARRAY* wxSafeArrayHelper::Detach()
-{
- Unlock();
- SAFEARRAY* result = m_array;
- m_array = NULL;
- return result;
-}
-
-void wxSafeArrayHelper::Unlock()
-{
- if ( m_array )
- SafeArrayUnlock(m_array);
-}
-
-} // unnamed namespace
-
-
// ----------------------------------------------------------------------------
// wxVariantDataCurrency
// ----------------------------------------------------------------------------
}
+// ----------------------------------------------------------------------------
+// wxVariantDataSafeArray
+// ----------------------------------------------------------------------------
+
+#if wxUSE_ANY
+
+bool wxVariantDataSafeArray::GetAsAny(wxAny* any) const
+{
+ *any = m_value;
+ return true;
+}
+
+wxVariantData* wxVariantDataSafeArray::VariantDataFactory(const wxAny& any)
+{
+ return new wxVariantDataSafeArray(wxANY_AS(any, SAFEARRAY*));
+}
+
+REGISTER_WXANY_CONVERSION(SAFEARRAY*, wxVariantDataSafeArray)
+
+#endif // wxUSE_ANY
+
+bool wxVariantDataSafeArray::Eq(wxVariantData& data) const
+{
+ wxASSERT_MSG( (data.GetType() == wxS("safearray")),
+ "wxVariantDataSafeArray::Eq: argument mismatch" );
+
+ wxVariantDataSafeArray& otherData = (wxVariantDataSafeArray&) data;
+
+ return otherData.m_value == m_value;
+}
+
+#if wxUSE_STD_IOSTREAM
+bool wxVariantDataSafeArray::Write(wxSTD ostream& str) const
+{
+ wxString s;
+ Write(s);
+ str << s;
+ return true;
+}
+#endif
+
+bool wxVariantDataSafeArray::Write(wxString& str) const
+{
+ str.Printf(wxS("SAFEARRAY: %p"), (void*)m_value);
+ return true;
+}
WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant)
{
if (type == wxT("errorcode"))
{
wxVariantDataErrorCode* const
- ec = wxDynamicCastVariantData(variant.GetData(),
- wxVariantDataErrorCode);
+ ec = wxStaticCastVariantData(variant.GetData(),
+ wxVariantDataErrorCode);
oleVariant.vt = VT_ERROR;
oleVariant.scode = ec->GetValue();
}
else if (type == wxT("currency"))
{
wxVariantDataCurrency* const
- c = wxDynamicCastVariantData(variant.GetData(),
- wxVariantDataCurrency);
+ c = wxStaticCastVariantData(variant.GetData(),
+ wxVariantDataCurrency);
oleVariant.vt = VT_CY;
oleVariant.cyVal = c->GetValue();
}
+ else if (type == wxT("safearray"))
+ {
+ wxVariantDataSafeArray* const
+ vsa = wxStaticCastVariantData(variant.GetData(),
+ wxVariantDataSafeArray);
+ SAFEARRAY* psa = vsa->GetValue();
+ VARTYPE vt;
+
+ wxCHECK(psa, false);
+ HRESULT hr = SafeArrayGetVartype(psa, &vt);
+ if ( FAILED(hr) )
+ {
+ wxLogApiError(wxS("SafeArrayGetVartype()"), hr);
+ SafeArrayDestroy(psa);
+ return false;
+ }
+ oleVariant.vt = vt | VT_ARRAY;
+ oleVariant.parray = psa;
+ }
else if (type == wxT("long"))
{
oleVariant.vt = VT_I4;
}
else if (type == wxT("list"))
{
- wxSafeArrayHelper sah;
-
- if (!sah.Create(VT_VARIANT, variant.GetCount()))
+ wxSafeArray<VT_VARIANT> safeArray;
+ if (!safeArray.CreateFromListVariant(variant))
return false;
- for (size_t i = 0; i < variant.GetCount(); i++)
- {
- if (!sah.SetElement(i, variant[i]))
- return false;
- }
-
oleVariant.vt = VT_VARIANT | VT_ARRAY;
- oleVariant.parray = sah.Detach();
+ oleVariant.parray = safeArray.Detach();
}
else if (type == wxT("arrstring"))
{
- wxArrayString strings(variant.GetArrayString());
- wxSafeArrayHelper sah;
+ wxSafeArray<VT_BSTR> safeArray;
- if (!sah.Create(VT_BSTR, strings.GetCount()))
+ if (!safeArray.CreateFromArrayString(variant.GetArrayString()))
return false;
- for (size_t i = 0; i < strings.GetCount(); i++)
- {
- if (!sah.SetElement(i, strings[i]))
- return false;
- }
-
oleVariant.vt = VT_BSTR | VT_ARRAY;
- oleVariant.parray = sah.Detach();
+ oleVariant.parray = safeArray.Detach();
}
else
{
bool ok = true;
if ( oleVariant.vt & VT_ARRAY )
{
-
- // Compute the total number of elements in all array dimensions
- int cElements = 1;
- for ( int cDims = 0; cDims < oleVariant.parray->cDims; cDims++ )
- cElements *= oleVariant.parray->rgsabound[cDims].cElements;
-
- // Get a pointer to the data
- void* pvdata;
- HRESULT hr = SafeArrayAccessData(oleVariant.parray, &pvdata);
- if ( FAILED(hr) )
- return false;
-
+ // TODO: We currently return arrays as wxVariant of the list type
+ // containing the flattened form of array but we should allow
+ // getting it as wxVariantDataSafeArray instead. Doing this is
+ // simple, we'd just need to do something like this:
+ //
+ // if ( oleVariant.parray && SafeArrayGetDim(oleVariant.parray) > 1 )
+ // {
+ // variant.SetData(new wxVariantDataSafeArray(oleVariant.parray));
+ // }
+ //
+ // but currently we don't do it for compatibility reasons.
switch (oleVariant.vt & VT_TYPEMASK)
{
+ case VT_I2:
+ ok = wxSafeArray<VT_I2>::ConvertToVariant(oleVariant.parray, variant);
+ break;
+ case VT_I4:
+ ok = wxSafeArray<VT_I4>::ConvertToVariant(oleVariant.parray, variant);
+ break;
+ case VT_R4:
+ ok = wxSafeArray<VT_R4>::ConvertToVariant(oleVariant.parray, variant);
+ break;
+ case VT_R8:
+ ok = wxSafeArray<VT_R8>::ConvertToVariant(oleVariant.parray, variant);
+ break;
case VT_VARIANT:
- {
- variant.ClearList();
- VARIANTARG *variant_data=(VARIANTARG*)pvdata;
- for ( int i = 0; i < cElements; i++ )
- {
- VARIANTARG& oleElement = variant_data[i];
- wxVariant vElement;
- if ( !wxConvertOleToVariant(oleElement, vElement) )
- {
- ok = false;
- variant.ClearList();
- break;
- }
-
- variant.Append(vElement);
- }
- }
+ ok = wxSafeArray<VT_VARIANT>::ConvertToVariant(oleVariant.parray, variant);
break;
-
case VT_BSTR:
{
wxArrayString strings;
- BSTR *string_val=(BSTR*)pvdata;
- for ( int i = 0; i < cElements; ++i )
- {
- wxString str=wxConvertStringFromOle(*string_val);
- strings.Add(str);
- ++string_val;
- }
- variant=strings;
+ if ( wxSafeArray<VT_BSTR>::ConvertToArrayString(oleVariant.parray, strings) )
+ variant = strings;
+ else
+ ok = false;
}
break;
-
default:
- wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
- oleVariant.vt & VT_TYPEMASK);
- variant = wxVariant();
ok = false;
break;
}
-
- SafeArrayUnaccessData(oleVariant.parray);
+ if ( !ok )
+ {
+ wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
+ oleVariant.vt & VT_TYPEMASK);
+ variant = wxVariant();
+ }
}
else if ( oleVariant.vt & VT_BYREF )
{