Improve SAFEARRAY support in wxMSW OLE Automation code.
Add a new wxSafeArray<> class wrapping SAFEARRAY. Also add support for converting VARIANTs containing other, previously unsupported, standard types. Closes #14637. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72543 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -48,6 +48,7 @@
|
||||
#endif
|
||||
|
||||
#include "wx/msw/ole/oleutils.h"
|
||||
#include "wx/msw/ole/safearray.h"
|
||||
|
||||
#if defined(__VISUALC__) && (__VISUALC__ > 1000)
|
||||
#include <docobj.h>
|
||||
@@ -131,96 +132,6 @@ wxBasicString::~wxBasicString()
|
||||
|
||||
#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
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -323,6 +234,52 @@ bool wxVariantDataErrorCode::Write(wxString& str) const
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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)
|
||||
{
|
||||
@@ -351,6 +308,25 @@ WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& ole
|
||||
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;
|
||||
@@ -409,36 +385,22 @@ WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& ole
|
||||
}
|
||||
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
|
||||
{
|
||||
@@ -458,63 +420,53 @@ wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
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:
|
||||
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 )
|
||||
{
|
||||
|
Reference in New Issue
Block a user