diff --git a/docs/changes.txt b/docs/changes.txt index e348292862..d73c20e3a5 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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) ------------------------------ diff --git a/include/wx/msw/ole/automtn.h b/include/wx/msw/ole/automtn.h index a7c5f62a6b..8f85141f1e 100644 --- a/include/wx/msw/ole/automtn.h +++ b/include/wx/msw/ole/automtn.h @@ -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); }; diff --git a/include/wx/msw/ole/oleutils.h b/include/wx/msw/ole/oleutils.h index 1c25d36926..c9f7eb88c8 100644 --- a/include/wx/msw/ole/oleutils.h +++ b/include/wx/msw/ole/oleutils.h @@ -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 diff --git a/interface/wx/msw/ole/automtn.h b/interface/wx/msw/ole/automtn.h index ec0ec35efc..5f2dd6775d 100644 --- a/interface/wx/msw/ole/automtn.h +++ b/interface/wx/msw/ole/automtn.h @@ -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); }; diff --git a/src/msw/ole/automtn.cpp b/src/msw/ole/automtn.cpp index b3f5f72e4a..1c3bd0a2b9 100644 --- a/src/msw/ole/automtn.cpp +++ b/src/msw/ole/automtn.cpp @@ -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, diff --git a/src/msw/ole/oleutils.cpp b/src/msw/ole/oleutils.cpp index 57a7a6c2d7..ab4122e0aa 100644 --- a/src/msw/ole/oleutils.cpp +++ b/src/msw/ole/oleutils.cpp @@ -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::ConvertToVariant(oleVariant.parray, variant); - break; - case VT_I4: - ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); - break; - case VT_R4: - ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); - break; - case VT_R8: - ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); - break; - case VT_VARIANT: - ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); - break; - case VT_BSTR: - { - wxArrayString strings; - if ( wxSafeArray::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::ConvertToVariant(oleVariant.parray, variant); + break; + case VT_I4: + ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); + break; + case VT_R4: + ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); + break; + case VT_R8: + ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); + break; + case VT_VARIANT: + ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); + break; + case VT_BSTR: + { + wxArrayString strings; + if ( wxSafeArray::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 ) diff --git a/tests/Makefile.in b/tests/Makefile.in index 92e23c55bd..26dcca7203 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -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 diff --git a/tests/makefile.bcc b/tests/makefile.bcc index 604a0f377f..4a38261e7b 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -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 diff --git a/tests/makefile.gcc b/tests/makefile.gcc index e583b236c5..3333273806 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -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) $< diff --git a/tests/makefile.vc b/tests/makefile.vc index e923fbed47..06465ab3fe 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -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 diff --git a/tests/makefile.wat b/tests/makefile.wat index ff8e120442..e8d4972c44 100644 --- a/tests/makefile.wat +++ b/tests/makefile.wat @@ -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) $< diff --git a/tests/misc/safearrayconverttest.cpp b/tests/misc/safearrayconverttest.cpp new file mode 100644 index 0000000000..20ad9a75c4 --- /dev/null +++ b/tests/misc/safearrayconverttest.cpp @@ -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 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 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 diff --git a/tests/test.bkl b/tests/test.bkl index fafb129fd4..4830927954 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -210,6 +210,7 @@ misc/guifuncs.cpp misc/selstoretest.cpp misc/garbage.cpp + misc/safearrayconverttest.cpp misc/settings.cpp