Add wxOleConvertVariant_ReturnSafeArrays flag for better SAFEARRAY handling.

While we can't change the type of wxVariant to which SAFEARRAYs are converted
by default, it's much more convenient to work with the variant objects of the
correct type, i.e. using wxVariantDataSafeArray, when dealing with SAFEARRAYs,
so add a flag which can be set to tell a wxAutomationObject to behave in this
way.

Closes #14700.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@75004 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2013-10-14 15:08:35 +00:00
parent b881ffc9a9
commit 910f1a96d2
17 changed files with 379 additions and 47 deletions

View File

@ -568,6 +568,10 @@ All:
- Add possibility to validate the input files against a schema to wxrc.
- Fix recently broken compilation with Intel compiler.
wxMSW:
- Optional better handling of SAFEARRAYs in wxAutomationObject (PB).
3.0-RC1: (released 2013-10-07)
------------------------------

View File

@ -115,11 +115,22 @@ public:
// this object. The default is LOCALE_SYSTEM_DEFAULT.
void SetLCID(WXLCID lcid);
// Returns the flags used for conversions between wxVariant and OLE
// VARIANT, see wxConvertVariantToOleFlags. The default value is
// wxOleConvertVariant_Default but all the objects obtained by GetObject()
// inherit the flags from the one that created them.
long GetConvertVariantFlags() const;
// Sets the flags used for conversions between wxVariant and OLE VARIANT,
// see wxConvertVariantToOleFlags (default is wxOleConvertVariant_Default.
void SetConvertVariantFlags(long flags);
public: // public for compatibility only, don't use m_dispatchPtr directly.
WXIDISPATCH* m_dispatchPtr;
private:
WXLCID m_lcid;
long m_convertVariantFlags;
wxDECLARE_NO_COPY_CLASS(wxAutomationObject);
};

View File

@ -316,9 +316,25 @@ private:
SAFEARRAY* m_value;
};
// Used by wxAutomationObject for its wxConvertOleToVariant() calls.
enum wxOleConvertVariantFlags
{
wxOleConvertVariant_Default = 0,
// If wxOleConvertVariant_ReturnSafeArrays flag is set, SAFEARRAYs
// contained in OLE VARIANTs will be returned as wxVariants
// with wxVariantDataSafeArray type instead of wxVariants
// with the list type containing the (flattened) SAFEARRAY's elements.
wxOleConvertVariant_ReturnSafeArrays = 1
};
WXDLLIMPEXP_CORE
bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant);
WXDLLIMPEXP_CORE
bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant,
long flags = wxOleConvertVariant_Default);
WXDLLIMPEXP_CORE bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant);
WXDLLIMPEXP_CORE bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant);
#endif // wxUSE_VARIANT
// Convert string to Unicode

View File

@ -41,6 +41,34 @@ enum wxAutomationInstanceFlags
wxAutomationInstance_SilentIfNone = 2
};
/**
Flags used for conversions between wxVariant and OLE VARIANT.
These flags are used by wxAutomationObject for its wxConvertOleToVariant()
calls. They can be obtained by wxAutomationObject::GetConvertVariantFlags()
and set by wxAutomationObject::SetConvertVariantFlags().
@since 3.0
@header{wx/msw/ole/oleutils.h}
*/
enum wxOleConvertVariantFlags
{
/**
Default value.
*/
wxOleConvertVariant_Default = 0,
/**
If this flag is used, SAFEARRAYs contained in OLE VARIANTs will be
returned as wxVariants with wxVariantDataSafeArray type instead of
wxVariants with the list type containing the (flattened) SAFEARRAY's
elements.
*/
wxOleConvertVariant_ReturnSafeArrays = 1
};
/**
@class wxVariantDataCurrency
@ -580,5 +608,28 @@ public:
*/
void SetLCID(LCID lcid);
/**
Returns the flags used for conversions between wxVariant and OLE
VARIANT, see wxConvertVariantToOleFlags.
The default value is wxOleConvertVariant_Default for compatibility but
it can be changed using SetConvertVariantFlags().
Notice that objects obtained by GetObject() inherit the flags from the
one that created them.
@since 3.0
*/
long GetConvertVariantFlags() const;
/**
Sets the flags used for conversions between wxVariant and OLE VARIANT,
see wxConvertVariantToOleFlags.
The default value is wxOleConvertVariant_Default.
@since 3.0
*/
void SetConvertVariantFlags(long flags);
};

View File

@ -70,6 +70,7 @@ wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr)
{
m_dispatchPtr = dispatchPtr;
m_lcid = LOCALE_SYSTEM_DEFAULT;
m_convertVariantFlags = wxOleConvertVariant_Default;
}
wxAutomationObject::~wxAutomationObject()
@ -214,7 +215,7 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
if (vReturnPtr)
{
// Convert result to wxVariant form
if (!wxConvertOleToVariant(vReturn, retValue))
if (!wxConvertOleToVariant(vReturn, retValue, m_convertVariantFlags))
return false;
// Mustn't release the dispatch pointer
if (vReturn.vt == VT_DISPATCH)
@ -474,6 +475,7 @@ bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& prop
{
obj.SetDispatchPtr(dispatch);
obj.SetLCID(GetLCID());
obj.SetConvertVariantFlags(GetConvertVariantFlags());
return true;
}
else
@ -488,6 +490,7 @@ bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& prop
{
obj.SetDispatchPtr(dispatch);
obj.SetLCID(GetLCID());
obj.SetConvertVariantFlags(GetConvertVariantFlags());
return true;
}
else
@ -607,6 +610,17 @@ void wxAutomationObject::SetLCID(LCID lcid)
m_lcid = lcid;
}
long wxAutomationObject::GetConvertVariantFlags() const
{
return m_convertVariantFlags;
}
void wxAutomationObject::SetConvertVariantFlags(long flags)
{
m_convertVariantFlags = flags;
}
static void
ShowException(const wxString& member,
HRESULT hr,

View File

@ -414,57 +414,53 @@ WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& ole
#endif
WXDLLEXPORT bool
wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant, long flags)
{
bool ok = true;
if ( oleVariant.vt & VT_ARRAY )
{
// 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)
if ( flags & wxOleConvertVariant_ReturnSafeArrays )
{
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;
if ( wxSafeArray<VT_BSTR>::ConvertToArrayString(oleVariant.parray, strings) )
variant = strings;
else
ok = false;
}
break;
default:
ok = false;
break;
variant.SetData(new wxVariantDataSafeArray(oleVariant.parray));
}
if ( !ok )
else
{
wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
oleVariant.vt & VT_TYPEMASK);
variant = wxVariant();
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:
ok = wxSafeArray<VT_VARIANT>::ConvertToVariant(oleVariant.parray, variant);
break;
case VT_BSTR:
{
wxArrayString strings;
if ( wxSafeArray<VT_BSTR>::ConvertToArrayString(oleVariant.parray, strings) )
variant = strings;
else
ok = false;
}
break;
default:
ok = false;
break;
}
if ( !ok )
{
wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
oleVariant.vt & VT_TYPEMASK);
variant = wxVariant();
}
}
}
else if ( oleVariant.vt & VT_BYREF )

View File

@ -223,6 +223,7 @@ TEST_GUI_OBJECTS = \
test_gui_guifuncs.o \
test_gui_selstoretest.o \
test_gui_garbage.o \
test_gui_safearrayconverttest.o \
test_gui_settings.o \
test_gui_socket.o \
test_gui_boxsizer.o \
@ -932,6 +933,9 @@ test_gui_selstoretest.o: $(srcdir)/misc/selstoretest.cpp $(TEST_GUI_ODEP)
test_gui_garbage.o: $(srcdir)/misc/garbage.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/misc/garbage.cpp
test_gui_safearrayconverttest.o: $(srcdir)/misc/safearrayconverttest.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/misc/safearrayconverttest.cpp
test_gui_settings.o: $(srcdir)/misc/settings.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/misc/settings.cpp

View File

@ -209,6 +209,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_guifuncs.obj \
$(OBJS)\test_gui_selstoretest.obj \
$(OBJS)\test_gui_garbage.obj \
$(OBJS)\test_gui_safearrayconverttest.obj \
$(OBJS)\test_gui_settings.obj \
$(OBJS)\test_gui_socket.obj \
$(OBJS)\test_gui_boxsizer.obj \
@ -976,6 +977,9 @@ $(OBJS)\test_gui_selstoretest.obj: .\misc\selstoretest.cpp
$(OBJS)\test_gui_garbage.obj: .\misc\garbage.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\misc\garbage.cpp
$(OBJS)\test_gui_safearrayconverttest.obj: .\misc\safearrayconverttest.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\misc\safearrayconverttest.cpp
$(OBJS)\test_gui_settings.obj: .\misc\settings.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\misc\settings.cpp

View File

@ -202,6 +202,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_guifuncs.o \
$(OBJS)\test_gui_selstoretest.o \
$(OBJS)\test_gui_garbage.o \
$(OBJS)\test_gui_safearrayconverttest.o \
$(OBJS)\test_gui_settings.o \
$(OBJS)\test_gui_socket.o \
$(OBJS)\test_gui_boxsizer.o \
@ -961,6 +962,9 @@ $(OBJS)\test_gui_selstoretest.o: ./misc/selstoretest.cpp
$(OBJS)\test_gui_garbage.o: ./misc/garbage.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
$(OBJS)\test_gui_safearrayconverttest.o: ./misc/safearrayconverttest.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
$(OBJS)\test_gui_settings.o: ./misc/settings.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<

View File

@ -206,6 +206,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_guifuncs.obj \
$(OBJS)\test_gui_selstoretest.obj \
$(OBJS)\test_gui_garbage.obj \
$(OBJS)\test_gui_safearrayconverttest.obj \
$(OBJS)\test_gui_settings.obj \
$(OBJS)\test_gui_socket.obj \
$(OBJS)\test_gui_boxsizer.obj \
@ -1116,6 +1117,9 @@ $(OBJS)\test_gui_selstoretest.obj: .\misc\selstoretest.cpp
$(OBJS)\test_gui_garbage.obj: .\misc\garbage.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\misc\garbage.cpp
$(OBJS)\test_gui_safearrayconverttest.obj: .\misc\safearrayconverttest.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\misc\safearrayconverttest.cpp
$(OBJS)\test_gui_settings.obj: .\misc\settings.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\misc\settings.cpp

View File

@ -465,6 +465,7 @@ TEST_GUI_OBJECTS = &
$(OBJS)\test_gui_guifuncs.obj &
$(OBJS)\test_gui_selstoretest.obj &
$(OBJS)\test_gui_garbage.obj &
$(OBJS)\test_gui_safearrayconverttest.obj &
$(OBJS)\test_gui_settings.obj &
$(OBJS)\test_gui_socket.obj &
$(OBJS)\test_gui_boxsizer.obj &
@ -1023,6 +1024,9 @@ $(OBJS)\test_gui_selstoretest.obj : .AUTODEPEND .\misc\selstoretest.cpp
$(OBJS)\test_gui_garbage.obj : .AUTODEPEND .\misc\garbage.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
$(OBJS)\test_gui_safearrayconverttest.obj : .AUTODEPEND .\misc\safearrayconverttest.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
$(OBJS)\test_gui_settings.obj : .AUTODEPEND .\misc\settings.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<

View File

@ -0,0 +1,204 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/misc/safearrayconverttest.cpp
// Purpose: Test conversions between wxVariant and OLE VARIANT using SAFEARRAYs
// Author: PB
// RCS-ID: $Id: typeinfotest.cpp 67656 2011-04-30 10:57:04Z DS $
// Copyright: (c) the wxWidgets team
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "testprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifdef __WINDOWS__
#if wxUSE_OLE && wxUSE_VARIANT
#include "wx/msw/ole/oleutils.h"
#include "wx/msw/ole/safearray.h"
// need this to be able to use CPPUNIT_ASSERT_EQUAL with wxVariant objects
inline std::ostream& operator<<(std::ostream& ostr, const wxVariant& v)
{
ostr << v.GetString();
return ostr;
}
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class SafeArrayConvertTestCase : public CppUnit::TestCase
{
public:
SafeArrayConvertTestCase () { }
private:
CPPUNIT_TEST_SUITE( SafeArrayConvertTestCase );
CPPUNIT_TEST( VariantListDefault );
CPPUNIT_TEST( VariantStringsDefault );
CPPUNIT_TEST( VariantListReturnSafeArray );
CPPUNIT_TEST( StringsReturnSafeArray );
CPPUNIT_TEST_SUITE_END();
void VariantListDefault();
void VariantStringsDefault();
void VariantListReturnSafeArray();
void StringsReturnSafeArray();
DECLARE_NO_COPY_CLASS(SafeArrayConvertTestCase )
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( SafeArrayConvertTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( SafeArrayConvertTestCase, "SafeArrayConvertTestCase" );
// test converting a wxVariant with the list type to an OLE VARIANT
// and back to wxVariant the list type
void SafeArrayConvertTestCase::VariantListDefault()
{
wxVariant variant;
VARIANT oleVariant;
variant.NullList();
variant.Append(true);
variant.Append(12.34);
variant.Append(42L);
variant.Append("ABC");
CPPUNIT_ASSERT( wxConvertVariantToOle(variant, oleVariant) );
wxVariant variantCopy;
CPPUNIT_ASSERT( wxConvertOleToVariant(oleVariant, variantCopy) );
CPPUNIT_ASSERT( variant == variantCopy );
}
// test converting a wxVariant with the arrstring type to an OLE VARIANT
// and back to a wxVariant with the arrstring type
void SafeArrayConvertTestCase::VariantStringsDefault()
{
wxVariant variant;
wxArrayString as;
VARIANT oleVariant;
as.push_back("abc");
as.push_back("def");
as.push_back("ghi");
variant = as;
CPPUNIT_ASSERT( wxConvertVariantToOle(variant, oleVariant) );
wxVariant variantCopy;
CPPUNIT_ASSERT( wxConvertOleToVariant(oleVariant, variantCopy) );
CPPUNIT_ASSERT( variant == variantCopy );
}
// test converting a wxVariant with the list type to an OLE VARIANT
// and then to a wxVariant with the safearray type
void SafeArrayConvertTestCase::VariantListReturnSafeArray()
{
wxVariant variant;
VARIANT oleVariant;
variant.NullList();
variant.Append(true);
variant.Append(12.34);
variant.Append(42L);
variant.Append("test");
CPPUNIT_ASSERT( wxConvertVariantToOle(variant, oleVariant) );
wxVariant variantCopy;
CPPUNIT_ASSERT(
wxConvertOleToVariant(oleVariant, variantCopy,
wxOleConvertVariant_ReturnSafeArrays)
);
CPPUNIT_ASSERT( variantCopy.GetType() == wxT("safearray") );
wxSafeArray<VT_VARIANT> safeArray;
wxVariantDataSafeArray*
vsa = wxStaticCastVariantData(variantCopy.GetData(),
wxVariantDataSafeArray);
long bound;
CPPUNIT_ASSERT( vsa );
CPPUNIT_ASSERT( safeArray.Attach(vsa->GetValue()) );
CPPUNIT_ASSERT_EQUAL( 1, safeArray.GetDim() );
CPPUNIT_ASSERT( safeArray.GetLBound(1, bound) );
CPPUNIT_ASSERT_EQUAL( 0, bound );
CPPUNIT_ASSERT( safeArray.GetUBound(1, bound) );
const long count = variant.GetCount();
// bound + 1 because safearray elements are accessed by index ranging from
// LBound to UBound inclusive
CPPUNIT_ASSERT_EQUAL( bound + 1, count );
wxVariant variantItem;
for ( long i = 0; i < count; i++ )
{
CPPUNIT_ASSERT( safeArray.GetElement(&i, variantItem) );
CPPUNIT_ASSERT_EQUAL( variantItem, variant[i] );
}
}
// test converting a wxArrayString to an OLE VARIANT
// and then to a wxVariant with the safearray type
void SafeArrayConvertTestCase::StringsReturnSafeArray()
{
wxArrayString as;
wxSafeArray<VT_BSTR> safeArray;
as.push_back("abc");
as.push_back("def");
as.push_back("ghi");
CPPUNIT_ASSERT( safeArray.CreateFromArrayString(as) );
VARIANT oleVariant;
wxVariant variant;
oleVariant.vt = VT_BSTR | VT_ARRAY;
oleVariant.parray = safeArray.Detach();
CPPUNIT_ASSERT( oleVariant.parray );
CPPUNIT_ASSERT(
wxConvertOleToVariant(oleVariant, variant,
wxOleConvertVariant_ReturnSafeArrays)
);
CPPUNIT_ASSERT( variant.GetType() == wxT("safearray") );
wxVariantDataSafeArray*
vsa = wxStaticCastVariantData(variant.GetData(),
wxVariantDataSafeArray);
long bound;
CPPUNIT_ASSERT( vsa );
CPPUNIT_ASSERT( safeArray.Attach(vsa->GetValue()) );
CPPUNIT_ASSERT_EQUAL( 1, safeArray.GetDim() );
CPPUNIT_ASSERT( safeArray.GetLBound(1, bound) );
CPPUNIT_ASSERT_EQUAL( 0, bound );
CPPUNIT_ASSERT( safeArray.GetUBound(1, bound) );
const long count = as.size();
CPPUNIT_ASSERT_EQUAL( bound + 1, count );
wxString str;
for ( long i = 0; i < count; i++ )
{
CPPUNIT_ASSERT( safeArray.GetElement(&i, str) );
CPPUNIT_ASSERT( str == as[i] );
}
}
#endif // __WINDOWS__
#endif // wxUSE_OLE && wxUSE_VARIANT

View File

@ -210,6 +210,7 @@
misc/guifuncs.cpp
misc/selstoretest.cpp
misc/garbage.cpp
misc/safearrayconverttest.cpp
misc/settings.cpp
<!--
This one is intentionally duplicated here (it is also part of

View File

@ -381,6 +381,10 @@ SOURCE=.\controls\richtextctrltest.cpp
# End Source File
# Begin Source File
SOURCE=.\misc\safearrayconverttest.cpp
# End Source File
# Begin Source File
SOURCE=.\..\samples\sample.rc
# End Source File
# Begin Source File

View File

@ -502,6 +502,9 @@
<File
RelativePath=".\controls\richtextctrltest.cpp">
</File>
<File
RelativePath=".\misc\safearrayconverttest.cpp">
</File>
<File
RelativePath=".\controls\searchctrltest.cpp">
</File>

View File

@ -705,6 +705,10 @@
RelativePath=".\controls\richtextctrltest.cpp"
>
</File>
<File
RelativePath=".\misc\safearrayconverttest.cpp"
>
</File>
<File
RelativePath=".\controls\searchctrltest.cpp"
>

View File

@ -691,6 +691,10 @@
RelativePath=".\controls\richtextctrltest.cpp"
>
</File>
<File
RelativePath=".\misc\safearrayconverttest.cpp"
>
</File>
<File
RelativePath=".\controls\searchctrltest.cpp"
>