From 226fa6db3dc88370446602fd7490a8890305ffd3 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 23 Sep 2012 22:49:50 +0000
Subject: [PATCH] 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
---
 Makefile.in                    |  42 ++++
 build/bakefiles/files.bkl      |   2 +
 build/msw/makefile.bcc         |  28 +++
 build/msw/makefile.gcc         |  28 +++
 build/msw/makefile.vc          |  28 +++
 build/msw/makefile.wat         |  28 +++
 build/msw/wx_core.dsp          |   8 +
 build/msw/wx_vc7_core.vcproj   |   6 +
 build/msw/wx_vc8_core.vcproj   |   8 +
 build/msw/wx_vc9_core.vcproj   |   8 +
 docs/changes.txt               |   1 +
 include/wx/msw/ole/oleutils.h  |  29 +++
 include/wx/msw/ole/safearray.h | 395 +++++++++++++++++++++++++++++++++
 interface/wx/msw/ole/automtn.h | 129 ++++++++++-
 interface/wx/variant.h         |   6 +-
 src/msw/ole/automtn.cpp        |   6 +
 src/msw/ole/oleutils.cpp       | 260 +++++++++-------------
 src/msw/ole/safearray.cpp      | 134 +++++++++++
 18 files changed, 988 insertions(+), 158 deletions(-)
 create mode 100644 include/wx/msw/ole/safearray.h
 create mode 100644 src/msw/ole/safearray.cpp

diff --git a/Makefile.in b/Makefile.in
index dd2e500832..073ae2ebef 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -3151,6 +3151,7 @@ COND_TOOLKIT_MSW_GUI_HDR =  \
 	wx/msw/ole/dropsrc.h \
 	wx/msw/ole/droptgt.h \
 	wx/msw/ole/oleutils.h \
+	wx/msw/ole/safearray.h \
 	wx/msw/ownerdrw.h \
 	wx/msw/palette.h \
 	wx/msw/panel.h \
@@ -3668,6 +3669,7 @@ COND_TOOLKIT_WINCE_GUI_HDR =  \
 	wx/msw/ole/dropsrc.h \
 	wx/msw/ole/droptgt.h \
 	wx/msw/ole/oleutils.h \
+	wx/msw/ole/safearray.h \
 	wx/msw/ownerdrw.h \
 	wx/msw/palette.h \
 	wx/msw/panel.h \
@@ -5268,6 +5270,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS =  \
 	monodll_dropsrc.o \
 	monodll_droptgt.o \
 	monodll_oleutils.o \
+	monodll_safearray.o \
 	monodll_msw_palette.o \
 	monodll_msw_pen.o \
 	monodll_msw_popupwin.o \
@@ -5329,6 +5332,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS =  \
 	monodll_dropsrc.o \
 	monodll_droptgt.o \
 	monodll_oleutils.o \
+	monodll_safearray.o \
 	monodll_msw_palette.o \
 	monodll_msw_pen.o \
 	monodll_msw_popupwin.o \
@@ -6204,6 +6208,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS_1 =  \
 	monodll_dropsrc.o \
 	monodll_droptgt.o \
 	monodll_oleutils.o \
+	monodll_safearray.o \
 	monodll_msw_palette.o \
 	monodll_msw_pen.o \
 	monodll_msw_popupwin.o \
@@ -6265,6 +6270,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS_1 =  \
 	monodll_dropsrc.o \
 	monodll_droptgt.o \
 	monodll_oleutils.o \
+	monodll_safearray.o \
 	monodll_msw_palette.o \
 	monodll_msw_pen.o \
 	monodll_msw_popupwin.o \
@@ -7474,6 +7480,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS_2 =  \
 	monolib_dropsrc.o \
 	monolib_droptgt.o \
 	monolib_oleutils.o \
+	monolib_safearray.o \
 	monolib_msw_palette.o \
 	monolib_msw_pen.o \
 	monolib_msw_popupwin.o \
@@ -7535,6 +7542,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS_2 =  \
 	monolib_dropsrc.o \
 	monolib_droptgt.o \
 	monolib_oleutils.o \
+	monolib_safearray.o \
 	monolib_msw_palette.o \
 	monolib_msw_pen.o \
 	monolib_msw_popupwin.o \
@@ -8410,6 +8418,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS_3 =  \
 	monolib_dropsrc.o \
 	monolib_droptgt.o \
 	monolib_oleutils.o \
+	monolib_safearray.o \
 	monolib_msw_palette.o \
 	monolib_msw_pen.o \
 	monolib_msw_popupwin.o \
@@ -8471,6 +8480,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS_3 =  \
 	monolib_dropsrc.o \
 	monolib_droptgt.o \
 	monolib_oleutils.o \
+	monolib_safearray.o \
 	monolib_msw_palette.o \
 	monolib_msw_pen.o \
 	monolib_msw_popupwin.o \
@@ -9855,6 +9865,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS_4 =  \
 	coredll_dropsrc.o \
 	coredll_droptgt.o \
 	coredll_oleutils.o \
+	coredll_safearray.o \
 	coredll_msw_palette.o \
 	coredll_msw_pen.o \
 	coredll_msw_popupwin.o \
@@ -9916,6 +9927,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS_4 =  \
 	coredll_dropsrc.o \
 	coredll_droptgt.o \
 	coredll_oleutils.o \
+	coredll_safearray.o \
 	coredll_msw_palette.o \
 	coredll_msw_pen.o \
 	coredll_msw_popupwin.o \
@@ -10791,6 +10803,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS_5 =  \
 	coredll_dropsrc.o \
 	coredll_droptgt.o \
 	coredll_oleutils.o \
+	coredll_safearray.o \
 	coredll_msw_palette.o \
 	coredll_msw_pen.o \
 	coredll_msw_popupwin.o \
@@ -10852,6 +10865,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS_5 =  \
 	coredll_dropsrc.o \
 	coredll_droptgt.o \
 	coredll_oleutils.o \
+	coredll_safearray.o \
 	coredll_msw_palette.o \
 	coredll_msw_pen.o \
 	coredll_msw_popupwin.o \
@@ -11500,6 +11514,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS_6 =  \
 	corelib_dropsrc.o \
 	corelib_droptgt.o \
 	corelib_oleutils.o \
+	corelib_safearray.o \
 	corelib_msw_palette.o \
 	corelib_msw_pen.o \
 	corelib_msw_popupwin.o \
@@ -11561,6 +11576,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS_6 =  \
 	corelib_dropsrc.o \
 	corelib_droptgt.o \
 	corelib_oleutils.o \
+	corelib_safearray.o \
 	corelib_msw_palette.o \
 	corelib_msw_pen.o \
 	corelib_msw_popupwin.o \
@@ -12436,6 +12452,7 @@ COND_TOOLKIT_MSW___LOWLEVEL_SRC_OBJECTS_7 =  \
 	corelib_dropsrc.o \
 	corelib_droptgt.o \
 	corelib_oleutils.o \
+	corelib_safearray.o \
 	corelib_msw_palette.o \
 	corelib_msw_pen.o \
 	corelib_msw_popupwin.o \
@@ -12497,6 +12514,7 @@ COND_TOOLKIT_WINCE___LOWLEVEL_SRC_OBJECTS_7 =  \
 	corelib_dropsrc.o \
 	corelib_droptgt.o \
 	corelib_oleutils.o \
+	corelib_safearray.o \
 	corelib_msw_palette.o \
 	corelib_msw_pen.o \
 	corelib_msw_popupwin.o \
@@ -19413,6 +19431,12 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@monodll_oleutils.o: $(srcdir)/src/msw/ole/oleutils.cpp $(MONODLL_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/ole/oleutils.cpp
 
+@COND_TOOLKIT_MSW_USE_GUI_1@monodll_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(MONODLL_ODEP)
+@COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
+@COND_TOOLKIT_WINCE_USE_GUI_1@monodll_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(MONODLL_ODEP)
+@COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
 @COND_TOOLKIT_MSW_USE_GUI_1@monodll_msw_palette.o: $(srcdir)/src/msw/palette.cpp $(MONODLL_ODEP)
 @COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/palette.cpp
 
@@ -25110,6 +25134,12 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@monolib_oleutils.o: $(srcdir)/src/msw/ole/oleutils.cpp $(MONOLIB_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/ole/oleutils.cpp
 
+@COND_TOOLKIT_MSW_USE_GUI_1@monolib_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(MONOLIB_ODEP)
+@COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
+@COND_TOOLKIT_WINCE_USE_GUI_1@monolib_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(MONOLIB_ODEP)
+@COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
 @COND_TOOLKIT_MSW_USE_GUI_1@monolib_msw_palette.o: $(srcdir)/src/msw/palette.cpp $(MONOLIB_ODEP)
 @COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/palette.cpp
 
@@ -30972,6 +31002,12 @@ coredll_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(COREDLL_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@coredll_oleutils.o: $(srcdir)/src/msw/ole/oleutils.cpp $(COREDLL_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/msw/ole/oleutils.cpp
 
+@COND_TOOLKIT_MSW_USE_GUI_1@coredll_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(COREDLL_ODEP)
+@COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
+@COND_TOOLKIT_WINCE_USE_GUI_1@coredll_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(COREDLL_ODEP)
+@COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
 @COND_TOOLKIT_MSW_USE_GUI_1@coredll_msw_palette.o: $(srcdir)/src/msw/palette.cpp $(COREDLL_ODEP)
 @COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/msw/palette.cpp
 
@@ -35217,6 +35253,12 @@ corelib_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(CORELIB_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@corelib_oleutils.o: $(srcdir)/src/msw/ole/oleutils.cpp $(CORELIB_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/msw/ole/oleutils.cpp
 
+@COND_TOOLKIT_MSW_USE_GUI_1@corelib_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(CORELIB_ODEP)
+@COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
+@COND_TOOLKIT_WINCE_USE_GUI_1@corelib_safearray.o: $(srcdir)/src/msw/ole/safearray.cpp $(CORELIB_ODEP)
+@COND_TOOLKIT_WINCE_USE_GUI_1@	$(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/msw/ole/safearray.cpp
+
 @COND_TOOLKIT_MSW_USE_GUI_1@corelib_msw_palette.o: $(srcdir)/src/msw/palette.cpp $(CORELIB_ODEP)
 @COND_TOOLKIT_MSW_USE_GUI_1@	$(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/msw/palette.cpp
 
diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl
index f9a867b51c..2084242cf8 100644
--- a/build/bakefiles/files.bkl
+++ b/build/bakefiles/files.bkl
@@ -1683,6 +1683,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     src/msw/ole/dropsrc.cpp
     src/msw/ole/droptgt.cpp
     src/msw/ole/oleutils.cpp
+    src/msw/ole/safearray.cpp
     src/msw/palette.cpp
     src/msw/pen.cpp
     src/msw/popupwin.cpp
@@ -1842,6 +1843,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     wx/msw/ole/dropsrc.h
     wx/msw/ole/droptgt.h
     wx/msw/ole/oleutils.h
+    wx/msw/ole/safearray.h
     wx/msw/ownerdrw.h
     wx/msw/palette.h
     wx/msw/panel.h
diff --git a/build/msw/makefile.bcc b/build/msw/makefile.bcc
index 0a40aceed1..e6fb7888a3 100644
--- a/build/msw/makefile.bcc
+++ b/build/msw/makefile.bcc
@@ -1787,6 +1787,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  \
 	$(OBJS)\monodll_dropsrc.obj \
 	$(OBJS)\monodll_droptgt.obj \
 	$(OBJS)\monodll_oleutils.obj \
+	$(OBJS)\monodll_safearray.obj \
 	$(OBJS)\monodll_palette.obj \
 	$(OBJS)\monodll_pen.obj \
 	$(OBJS)\monodll_popupwin.obj \
@@ -2061,6 +2062,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  \
 	$(OBJS)\monodll_dropsrc.obj \
 	$(OBJS)\monodll_droptgt.obj \
 	$(OBJS)\monodll_oleutils.obj \
+	$(OBJS)\monodll_safearray.obj \
 	$(OBJS)\monodll_palette.obj \
 	$(OBJS)\monodll_pen.obj \
 	$(OBJS)\monodll_popupwin.obj \
@@ -2576,6 +2578,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  \
 	$(OBJS)\monolib_dropsrc.obj \
 	$(OBJS)\monolib_droptgt.obj \
 	$(OBJS)\monolib_oleutils.obj \
+	$(OBJS)\monolib_safearray.obj \
 	$(OBJS)\monolib_palette.obj \
 	$(OBJS)\monolib_pen.obj \
 	$(OBJS)\monolib_popupwin.obj \
@@ -2850,6 +2853,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  \
 	$(OBJS)\monolib_dropsrc.obj \
 	$(OBJS)\monolib_droptgt.obj \
 	$(OBJS)\monolib_oleutils.obj \
+	$(OBJS)\monolib_safearray.obj \
 	$(OBJS)\monolib_palette.obj \
 	$(OBJS)\monolib_pen.obj \
 	$(OBJS)\monolib_popupwin.obj \
@@ -3246,6 +3250,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  \
 	$(OBJS)\coredll_dropsrc.obj \
 	$(OBJS)\coredll_droptgt.obj \
 	$(OBJS)\coredll_oleutils.obj \
+	$(OBJS)\coredll_safearray.obj \
 	$(OBJS)\coredll_palette.obj \
 	$(OBJS)\coredll_pen.obj \
 	$(OBJS)\coredll_popupwin.obj \
@@ -3520,6 +3525,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  \
 	$(OBJS)\coredll_dropsrc.obj \
 	$(OBJS)\coredll_droptgt.obj \
 	$(OBJS)\coredll_oleutils.obj \
+	$(OBJS)\coredll_safearray.obj \
 	$(OBJS)\coredll_palette.obj \
 	$(OBJS)\coredll_pen.obj \
 	$(OBJS)\coredll_popupwin.obj \
@@ -3792,6 +3798,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  \
 	$(OBJS)\corelib_dropsrc.obj \
 	$(OBJS)\corelib_droptgt.obj \
 	$(OBJS)\corelib_oleutils.obj \
+	$(OBJS)\corelib_safearray.obj \
 	$(OBJS)\corelib_palette.obj \
 	$(OBJS)\corelib_pen.obj \
 	$(OBJS)\corelib_popupwin.obj \
@@ -4066,6 +4073,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  \
 	$(OBJS)\corelib_dropsrc.obj \
 	$(OBJS)\corelib_droptgt.obj \
 	$(OBJS)\corelib_oleutils.obj \
+	$(OBJS)\corelib_safearray.obj \
 	$(OBJS)\corelib_palette.obj \
 	$(OBJS)\corelib_pen.obj \
 	$(OBJS)\corelib_popupwin.obj \
@@ -7442,6 +7450,11 @@ $(OBJS)\monodll_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\monodll_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\monodll_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) -q -c -P -o$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\palette.cpp
@@ -9863,6 +9876,11 @@ $(OBJS)\monolib_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\monolib_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\monolib_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) -q -c -P -o$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\palette.cpp
@@ -12248,6 +12266,11 @@ $(OBJS)\coredll_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\coredll_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\coredll_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) -q -c -P -o$@ $(COREDLL_CXXFLAGS) ..\..\src\msw\palette.cpp
@@ -13663,6 +13686,11 @@ $(OBJS)\corelib_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\corelib_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\corelib_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) -q -c -P -o$@ $(CORELIB_CXXFLAGS) ..\..\src\msw\palette.cpp
diff --git a/build/msw/makefile.gcc b/build/msw/makefile.gcc
index ae37b9d80b..7200c59fe4 100644
--- a/build/msw/makefile.gcc
+++ b/build/msw/makefile.gcc
@@ -1800,6 +1800,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  \
 	$(OBJS)\monodll_dropsrc.o \
 	$(OBJS)\monodll_droptgt.o \
 	$(OBJS)\monodll_oleutils.o \
+	$(OBJS)\monodll_safearray.o \
 	$(OBJS)\monodll_palette.o \
 	$(OBJS)\monodll_pen.o \
 	$(OBJS)\monodll_popupwin.o \
@@ -2076,6 +2077,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  \
 	$(OBJS)\monodll_dropsrc.o \
 	$(OBJS)\monodll_droptgt.o \
 	$(OBJS)\monodll_oleutils.o \
+	$(OBJS)\monodll_safearray.o \
 	$(OBJS)\monodll_palette.o \
 	$(OBJS)\monodll_pen.o \
 	$(OBJS)\monodll_popupwin.o \
@@ -2595,6 +2597,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  \
 	$(OBJS)\monolib_dropsrc.o \
 	$(OBJS)\monolib_droptgt.o \
 	$(OBJS)\monolib_oleutils.o \
+	$(OBJS)\monolib_safearray.o \
 	$(OBJS)\monolib_palette.o \
 	$(OBJS)\monolib_pen.o \
 	$(OBJS)\monolib_popupwin.o \
@@ -2871,6 +2874,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  \
 	$(OBJS)\monolib_dropsrc.o \
 	$(OBJS)\monolib_droptgt.o \
 	$(OBJS)\monolib_oleutils.o \
+	$(OBJS)\monolib_safearray.o \
 	$(OBJS)\monolib_palette.o \
 	$(OBJS)\monolib_pen.o \
 	$(OBJS)\monolib_popupwin.o \
@@ -3281,6 +3285,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  \
 	$(OBJS)\coredll_dropsrc.o \
 	$(OBJS)\coredll_droptgt.o \
 	$(OBJS)\coredll_oleutils.o \
+	$(OBJS)\coredll_safearray.o \
 	$(OBJS)\coredll_palette.o \
 	$(OBJS)\coredll_pen.o \
 	$(OBJS)\coredll_popupwin.o \
@@ -3557,6 +3562,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  \
 	$(OBJS)\coredll_dropsrc.o \
 	$(OBJS)\coredll_droptgt.o \
 	$(OBJS)\coredll_oleutils.o \
+	$(OBJS)\coredll_safearray.o \
 	$(OBJS)\coredll_palette.o \
 	$(OBJS)\coredll_pen.o \
 	$(OBJS)\coredll_popupwin.o \
@@ -3835,6 +3841,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  \
 	$(OBJS)\corelib_dropsrc.o \
 	$(OBJS)\corelib_droptgt.o \
 	$(OBJS)\corelib_oleutils.o \
+	$(OBJS)\corelib_safearray.o \
 	$(OBJS)\corelib_palette.o \
 	$(OBJS)\corelib_pen.o \
 	$(OBJS)\corelib_popupwin.o \
@@ -4111,6 +4118,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  \
 	$(OBJS)\corelib_dropsrc.o \
 	$(OBJS)\corelib_droptgt.o \
 	$(OBJS)\corelib_oleutils.o \
+	$(OBJS)\corelib_safearray.o \
 	$(OBJS)\corelib_palette.o \
 	$(OBJS)\corelib_pen.o \
 	$(OBJS)\corelib_popupwin.o \
@@ -7611,6 +7619,11 @@ $(OBJS)\monodll_oleutils.o: ../../src/msw/ole/oleutils.cpp
 	$(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $<
 endif
 
+ifeq ($(USE_GUI),1)
+$(OBJS)\monodll_safearray.o: ../../src/msw/ole/safearray.cpp
+	$(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $<
+endif
+
 ifeq ($(USE_GUI),1)
 $(OBJS)\monodll_palette.o: ../../src/msw/palette.cpp
 	$(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $<
@@ -10032,6 +10045,11 @@ $(OBJS)\monolib_oleutils.o: ../../src/msw/ole/oleutils.cpp
 	$(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $<
 endif
 
+ifeq ($(USE_GUI),1)
+$(OBJS)\monolib_safearray.o: ../../src/msw/ole/safearray.cpp
+	$(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $<
+endif
+
 ifeq ($(USE_GUI),1)
 $(OBJS)\monolib_palette.o: ../../src/msw/palette.cpp
 	$(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $<
@@ -12417,6 +12435,11 @@ $(OBJS)\coredll_oleutils.o: ../../src/msw/ole/oleutils.cpp
 	$(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $<
 endif
 
+ifeq ($(USE_GUI),1)
+$(OBJS)\coredll_safearray.o: ../../src/msw/ole/safearray.cpp
+	$(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $<
+endif
+
 ifeq ($(USE_GUI),1)
 $(OBJS)\coredll_palette.o: ../../src/msw/palette.cpp
 	$(CXX) -c -o $@ $(COREDLL_CXXFLAGS) $(CPPDEPS) $<
@@ -13832,6 +13855,11 @@ $(OBJS)\corelib_oleutils.o: ../../src/msw/ole/oleutils.cpp
 	$(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $<
 endif
 
+ifeq ($(USE_GUI),1)
+$(OBJS)\corelib_safearray.o: ../../src/msw/ole/safearray.cpp
+	$(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $<
+endif
+
 ifeq ($(USE_GUI),1)
 $(OBJS)\corelib_palette.o: ../../src/msw/palette.cpp
 	$(CXX) -c -o $@ $(CORELIB_CXXFLAGS) $(CPPDEPS) $<
diff --git a/build/msw/makefile.vc b/build/msw/makefile.vc
index 40f693e7a1..6a6aafad93 100644
--- a/build/msw/makefile.vc
+++ b/build/msw/makefile.vc
@@ -2079,6 +2079,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  \
 	$(OBJS)\monodll_dropsrc.obj \
 	$(OBJS)\monodll_droptgt.obj \
 	$(OBJS)\monodll_oleutils.obj \
+	$(OBJS)\monodll_safearray.obj \
 	$(OBJS)\monodll_palette.obj \
 	$(OBJS)\monodll_pen.obj \
 	$(OBJS)\monodll_popupwin.obj \
@@ -2353,6 +2354,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  \
 	$(OBJS)\monodll_dropsrc.obj \
 	$(OBJS)\monodll_droptgt.obj \
 	$(OBJS)\monodll_oleutils.obj \
+	$(OBJS)\monodll_safearray.obj \
 	$(OBJS)\monodll_palette.obj \
 	$(OBJS)\monodll_pen.obj \
 	$(OBJS)\monodll_popupwin.obj \
@@ -2874,6 +2876,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  \
 	$(OBJS)\monolib_dropsrc.obj \
 	$(OBJS)\monolib_droptgt.obj \
 	$(OBJS)\monolib_oleutils.obj \
+	$(OBJS)\monolib_safearray.obj \
 	$(OBJS)\monolib_palette.obj \
 	$(OBJS)\monolib_pen.obj \
 	$(OBJS)\monolib_popupwin.obj \
@@ -3148,6 +3151,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  \
 	$(OBJS)\monolib_dropsrc.obj \
 	$(OBJS)\monolib_droptgt.obj \
 	$(OBJS)\monolib_oleutils.obj \
+	$(OBJS)\monolib_safearray.obj \
 	$(OBJS)\monolib_palette.obj \
 	$(OBJS)\monolib_pen.obj \
 	$(OBJS)\monolib_popupwin.obj \
@@ -3610,6 +3614,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  \
 	$(OBJS)\coredll_dropsrc.obj \
 	$(OBJS)\coredll_droptgt.obj \
 	$(OBJS)\coredll_oleutils.obj \
+	$(OBJS)\coredll_safearray.obj \
 	$(OBJS)\coredll_palette.obj \
 	$(OBJS)\coredll_pen.obj \
 	$(OBJS)\coredll_popupwin.obj \
@@ -3884,6 +3889,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  \
 	$(OBJS)\coredll_dropsrc.obj \
 	$(OBJS)\coredll_droptgt.obj \
 	$(OBJS)\coredll_oleutils.obj \
+	$(OBJS)\coredll_safearray.obj \
 	$(OBJS)\coredll_palette.obj \
 	$(OBJS)\coredll_pen.obj \
 	$(OBJS)\coredll_popupwin.obj \
@@ -4162,6 +4168,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  \
 	$(OBJS)\corelib_dropsrc.obj \
 	$(OBJS)\corelib_droptgt.obj \
 	$(OBJS)\corelib_oleutils.obj \
+	$(OBJS)\corelib_safearray.obj \
 	$(OBJS)\corelib_palette.obj \
 	$(OBJS)\corelib_pen.obj \
 	$(OBJS)\corelib_popupwin.obj \
@@ -4436,6 +4443,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  \
 	$(OBJS)\corelib_dropsrc.obj \
 	$(OBJS)\corelib_droptgt.obj \
 	$(OBJS)\corelib_oleutils.obj \
+	$(OBJS)\corelib_safearray.obj \
 	$(OBJS)\corelib_palette.obj \
 	$(OBJS)\corelib_pen.obj \
 	$(OBJS)\corelib_popupwin.obj \
@@ -8126,6 +8134,11 @@ $(OBJS)\monodll_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\monodll_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\monodll_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\palette.cpp
@@ -10547,6 +10560,11 @@ $(OBJS)\monolib_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\monolib_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\monolib_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\palette.cpp
@@ -12932,6 +12950,11 @@ $(OBJS)\coredll_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\coredll_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\coredll_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(COREDLL_CXXFLAGS) ..\..\src\msw\palette.cpp
@@ -14347,6 +14370,11 @@ $(OBJS)\corelib_oleutils.obj: ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\msw\ole\oleutils.cpp
 !endif
 
+!if "$(USE_GUI)" == "1"
+$(OBJS)\corelib_safearray.obj: ..\..\src\msw\ole\safearray.cpp
+	$(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\msw\ole\safearray.cpp
+!endif
+
 !if "$(USE_GUI)" == "1"
 $(OBJS)\corelib_palette.obj: ..\..\src\msw\palette.cpp
 	$(CXX) /c /nologo /TP /Fo$@ $(CORELIB_CXXFLAGS) ..\..\src\msw\palette.cpp
diff --git a/build/msw/makefile.wat b/build/msw/makefile.wat
index 3f98157977..248328c26c 100644
--- a/build/msw/makefile.wat
+++ b/build/msw/makefile.wat
@@ -293,6 +293,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  &
 	$(OBJS)\monodll_dropsrc.obj &
 	$(OBJS)\monodll_droptgt.obj &
 	$(OBJS)\monodll_oleutils.obj &
+	$(OBJS)\monodll_safearray.obj &
 	$(OBJS)\monodll_palette.obj &
 	$(OBJS)\monodll_pen.obj &
 	$(OBJS)\monodll_popupwin.obj &
@@ -569,6 +570,7 @@ ____CORE_SRC_FILENAMES_OBJECTS =  &
 	$(OBJS)\monodll_dropsrc.obj &
 	$(OBJS)\monodll_droptgt.obj &
 	$(OBJS)\monodll_oleutils.obj &
+	$(OBJS)\monodll_safearray.obj &
 	$(OBJS)\monodll_palette.obj &
 	$(OBJS)\monodll_pen.obj &
 	$(OBJS)\monodll_popupwin.obj &
@@ -1093,6 +1095,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  &
 	$(OBJS)\monolib_dropsrc.obj &
 	$(OBJS)\monolib_droptgt.obj &
 	$(OBJS)\monolib_oleutils.obj &
+	$(OBJS)\monolib_safearray.obj &
 	$(OBJS)\monolib_palette.obj &
 	$(OBJS)\monolib_pen.obj &
 	$(OBJS)\monolib_popupwin.obj &
@@ -1369,6 +1372,7 @@ ____CORE_SRC_FILENAMES_1_OBJECTS =  &
 	$(OBJS)\monolib_dropsrc.obj &
 	$(OBJS)\monolib_droptgt.obj &
 	$(OBJS)\monolib_oleutils.obj &
+	$(OBJS)\monolib_safearray.obj &
 	$(OBJS)\monolib_palette.obj &
 	$(OBJS)\monolib_pen.obj &
 	$(OBJS)\monolib_popupwin.obj &
@@ -1790,6 +1794,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  &
 	$(OBJS)\coredll_dropsrc.obj &
 	$(OBJS)\coredll_droptgt.obj &
 	$(OBJS)\coredll_oleutils.obj &
+	$(OBJS)\coredll_safearray.obj &
 	$(OBJS)\coredll_palette.obj &
 	$(OBJS)\coredll_pen.obj &
 	$(OBJS)\coredll_popupwin.obj &
@@ -2066,6 +2071,7 @@ ____CORE_SRC_FILENAMES_2_OBJECTS =  &
 	$(OBJS)\coredll_dropsrc.obj &
 	$(OBJS)\coredll_droptgt.obj &
 	$(OBJS)\coredll_oleutils.obj &
+	$(OBJS)\coredll_safearray.obj &
 	$(OBJS)\coredll_palette.obj &
 	$(OBJS)\coredll_pen.obj &
 	$(OBJS)\coredll_popupwin.obj &
@@ -2346,6 +2352,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  &
 	$(OBJS)\corelib_dropsrc.obj &
 	$(OBJS)\corelib_droptgt.obj &
 	$(OBJS)\corelib_oleutils.obj &
+	$(OBJS)\corelib_safearray.obj &
 	$(OBJS)\corelib_palette.obj &
 	$(OBJS)\corelib_pen.obj &
 	$(OBJS)\corelib_popupwin.obj &
@@ -2622,6 +2629,7 @@ ____CORE_SRC_FILENAMES_3_OBJECTS =  &
 	$(OBJS)\corelib_dropsrc.obj &
 	$(OBJS)\corelib_droptgt.obj &
 	$(OBJS)\corelib_oleutils.obj &
+	$(OBJS)\corelib_safearray.obj &
 	$(OBJS)\corelib_palette.obj &
 	$(OBJS)\corelib_pen.obj &
 	$(OBJS)\corelib_popupwin.obj &
@@ -7884,6 +7892,11 @@ $(OBJS)\monodll_oleutils.obj :  .AUTODEPEND ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(MONODLL_CXXFLAGS) $<
 !endif
 
+!ifeq USE_GUI 1
+$(OBJS)\monodll_safearray.obj :  .AUTODEPEND ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -bt=nt -zq -fo=$^@ $(MONODLL_CXXFLAGS) $<
+!endif
+
 !ifeq USE_GUI 1
 $(OBJS)\monodll_palette.obj :  .AUTODEPEND ..\..\src\msw\palette.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(MONODLL_CXXFLAGS) $<
@@ -10305,6 +10318,11 @@ $(OBJS)\monolib_oleutils.obj :  .AUTODEPEND ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(MONOLIB_CXXFLAGS) $<
 !endif
 
+!ifeq USE_GUI 1
+$(OBJS)\monolib_safearray.obj :  .AUTODEPEND ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -bt=nt -zq -fo=$^@ $(MONOLIB_CXXFLAGS) $<
+!endif
+
 !ifeq USE_GUI 1
 $(OBJS)\monolib_palette.obj :  .AUTODEPEND ..\..\src\msw\palette.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(MONOLIB_CXXFLAGS) $<
@@ -12690,6 +12708,11 @@ $(OBJS)\coredll_oleutils.obj :  .AUTODEPEND ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(COREDLL_CXXFLAGS) $<
 !endif
 
+!ifeq USE_GUI 1
+$(OBJS)\coredll_safearray.obj :  .AUTODEPEND ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -bt=nt -zq -fo=$^@ $(COREDLL_CXXFLAGS) $<
+!endif
+
 !ifeq USE_GUI 1
 $(OBJS)\coredll_palette.obj :  .AUTODEPEND ..\..\src\msw\palette.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(COREDLL_CXXFLAGS) $<
@@ -14105,6 +14128,11 @@ $(OBJS)\corelib_oleutils.obj :  .AUTODEPEND ..\..\src\msw\ole\oleutils.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(CORELIB_CXXFLAGS) $<
 !endif
 
+!ifeq USE_GUI 1
+$(OBJS)\corelib_safearray.obj :  .AUTODEPEND ..\..\src\msw\ole\safearray.cpp
+	$(CXX) -bt=nt -zq -fo=$^@ $(CORELIB_CXXFLAGS) $<
+!endif
+
 !ifeq USE_GUI 1
 $(OBJS)\corelib_palette.obj :  .AUTODEPEND ..\..\src\msw\palette.cpp
 	$(CXX) -bt=nt -zq -fo=$^@ $(CORELIB_CXXFLAGS) $<
diff --git a/build/msw/wx_core.dsp b/build/msw/wx_core.dsp
index 2970995eb5..dab6894f7e 100644
--- a/build/msw/wx_core.dsp
+++ b/build/msw/wx_core.dsp
@@ -2315,6 +2315,10 @@ SOURCE=..\..\src\msw\richmsgdlg.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=..\..\src\msw\ole\safearray.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\src\msw\scrolbar.cpp
 
 !IF  "$(CFG)" == "core - Win32 DLL Universal Release"
@@ -5360,6 +5364,10 @@ SOURCE=..\..\include\wx\msw\richmsgdlg.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\..\include\wx\msw\ole\safearray.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\include\wx\msw\scrolbar.h
 # End Source File
 # Begin Source File
diff --git a/build/msw/wx_vc7_core.vcproj b/build/msw/wx_vc7_core.vcproj
index e4b627a904..6c6888b9c3 100644
--- a/build/msw/wx_vc7_core.vcproj
+++ b/build/msw/wx_vc7_core.vcproj
@@ -2098,6 +2098,9 @@
 					Name="DLL Universal Release|Win32"
 					ExcludedFromBuild="TRUE"/>
 			</File>
+			<File
+				RelativePath="..\..\src\msw\ole\safearray.cpp">
+			</File>
 			<File
 				RelativePath="..\..\src\msw\scrolbar.cpp">
 				<FileConfiguration
@@ -4591,6 +4594,9 @@
 			<File
 				RelativePath="..\..\include\wx\msw\richmsgdlg.h">
 			</File>
+			<File
+				RelativePath="..\..\include\wx\msw\ole\safearray.h">
+			</File>
 			<File
 				RelativePath="..\..\include\wx\msw\scrolbar.h">
 			</File>
diff --git a/build/msw/wx_vc8_core.vcproj b/build/msw/wx_vc8_core.vcproj
index 13d622ea5f..178f1159b4 100644
--- a/build/msw/wx_vc8_core.vcproj
+++ b/build/msw/wx_vc8_core.vcproj
@@ -2831,6 +2831,10 @@
 					ExcludedFromBuild="true"
 				/>
 			</File>
+			<File
+				RelativePath="..\..\src\msw\ole\safearray.cpp"
+				>
+			</File>
 			<File
 				RelativePath="..\..\src\msw\scrolbar.cpp"
 				>
@@ -6143,6 +6147,10 @@
 				RelativePath="..\..\include\wx\msw\richmsgdlg.h"
 				>
 			</File>
+			<File
+				RelativePath="..\..\include\wx\msw\ole\safearray.h"
+				>
+			</File>
 			<File
 				RelativePath="..\..\include\wx\msw\scrolbar.h"
 				>
diff --git a/build/msw/wx_vc9_core.vcproj b/build/msw/wx_vc9_core.vcproj
index 89758906c7..68d8e74f06 100644
--- a/build/msw/wx_vc9_core.vcproj
+++ b/build/msw/wx_vc9_core.vcproj
@@ -2827,6 +2827,10 @@
 					ExcludedFromBuild="true"
 				/>
 			</File>
+			<File
+				RelativePath="..\..\src\msw\ole\safearray.cpp"
+				>
+			</File>
 			<File
 				RelativePath="..\..\src\msw\scrolbar.cpp"
 				>
@@ -6139,6 +6143,10 @@
 				RelativePath="..\..\include\wx\msw\richmsgdlg.h"
 				>
 			</File>
+			<File
+				RelativePath="..\..\include\wx\msw\ole\safearray.h"
+				>
+			</File>
 			<File
 				RelativePath="..\..\include\wx\msw\scrolbar.h"
 				>
diff --git a/docs/changes.txt b/docs/changes.txt
index f18a37c37e..1c45e52d1d 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -570,6 +570,7 @@ wxMSW:
 - Fix setting colours for the text part of wxComboBox (Igor Korot).
 - Add support for CURRENCY and SCODE types to OLE Automation helpers (PB).
 - Allow setting LCID used by wxAutomationObject (PB).
+- Better support for SAFEARRAY in OLE Automation code (PB).
 - Fix calling Iconize(false) on hidden top level windows (Christian Walther).
 - Don't send any events from wxSpinCtrl::SetRange() even if the value changed.
 
diff --git a/include/wx/msw/ole/oleutils.h b/include/wx/msw/ole/oleutils.h
index 257025d7fb..37cbd5fb9e 100644
--- a/include/wx/msw/ole/oleutils.h
+++ b/include/wx/msw/ole/oleutils.h
@@ -289,6 +289,35 @@ private:
     SCODE m_value;
 };
 
+// wrapper for SAFEARRAY, used for passing multidimensional arrays in wxVariant
+class WXDLLIMPEXP_CORE wxVariantDataSafeArray : public wxVariantData
+{
+public:
+    wxEXPLICIT wxVariantDataSafeArray(SAFEARRAY* value = NULL)
+    {
+        m_value = value;
+    }
+
+    SAFEARRAY* GetValue() const { return m_value; }
+    void SetValue(SAFEARRAY* value) { m_value = value; }
+
+    virtual bool Eq(wxVariantData& data) const;
+
+#if wxUSE_STD_IOSTREAM
+    virtual bool Write(wxSTD ostream& str) const;
+#endif
+    virtual bool Write(wxString& str) const;
+
+    wxVariantData* Clone() const { return new wxVariantDataSafeArray(m_value); }
+    virtual wxString GetType() const { return wxS("safearray"); }
+
+    DECLARE_WXANY_CONVERSION()
+
+private:
+    SAFEARRAY* m_value;
+};
+
+
 WXDLLIMPEXP_CORE bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant);
 WXDLLIMPEXP_CORE bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant);
 #endif // wxUSE_VARIANT
diff --git a/include/wx/msw/ole/safearray.h b/include/wx/msw/ole/safearray.h
new file mode 100644
index 0000000000..7ce6f35e84
--- /dev/null
+++ b/include/wx/msw/ole/safearray.h
@@ -0,0 +1,395 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        msw/ole/safearray.h
+// Purpose:     Helpers for working with OLE SAFEARRAYs.
+// Author:      PB
+// Created:     2012-09-23
+// RCS-ID:      $Id$
+// 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, 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, 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_
diff --git a/interface/wx/msw/ole/automtn.h b/interface/wx/msw/ole/automtn.h
index 9e7f3287a8..cfa2cb7144 100644
--- a/interface/wx/msw/ole/automtn.h
+++ b/interface/wx/msw/ole/automtn.h
@@ -215,6 +215,133 @@ public:
     virtual bool GetAsAny(wxAny* any) const;
 };
 
+/**
+    @class wxVariantDataSafeArray
+
+    This class represents a thin wrapper for Microsoft Windows SAFEARRAY type.
+
+    It is used for converting between wxVariant and OLE VARIANT
+    with type set to VT_ARRAY, which has more than one dimension.
+    When wxVariant stores wxVariantDataSafeArray, it returns "safearray" as its type.
+
+    wxVariantDataSafeArray does NOT manage the SAFEARRAY it points to.
+    If you want to pass it to a wxAutomationObject as a parameter:
+        -# Assign a SAFEARRAY pointer to it and store it in a wxVariant.
+        -# Call the wxAutomationObject method (CallMethod(), SetProperty() or Invoke())
+        -# wxAutomationObject will destroy the array after the approapriate automation call.
+
+    An example of creating a 2-dimensional SAFEARRAY containing VARIANTs
+    and storing it in a wxVariant
+    @code
+    SAFEARRAYBOUND bounds[2]; // 2 dimensions
+    wxSafeArray<VT_VARIANT> safeArray;
+    unsigned rowCount = 1000;
+    unsigned colCount = 20;
+
+    bounds[0].lLbound = 0; // elements start at 0
+    bounds[0].cElements = rowCount;
+    bounds[1].lLbound = 0; // elements start at 0
+    bounds[1].cElements = colCount;
+
+    if ( !safeArray.Create(bounds, 2) )
+        return false;
+
+    long indices[2];
+
+    for ( unsigned row = 0; row < rowCount; row++ )
+    {
+        indices[0] = row;
+        for ( unsigned col = 0; col < colCount; col++ )
+        {
+            indices[1] = col;
+            if ( !safeArray.SetElement(indices, wxString::Format("R%ud C%ud", i+1, j+1)) )(
+               return false;
+        }
+    }
+    range.PutProperty("Value", wxVariant(new wxVariantDataSafeArray(sa.Detach())));
+    @endcode
+
+    If you you received wxVariantDataSafeArray as a result of wxAutomationObject method call:
+    (1) Get the data out of the array.
+    (2) Destroy the array.
+    @code
+    wxVariant result;
+    result = range.GetProperty("Value");
+    if ( result.GetType() == "safearray" )
+    {
+        wxSafeArray<VT_VARIANT> safeArray;
+        wxVariantDataSafeArray* const
+            sa = wxStaticCastVariantData(variant.GetData(), wxVariantDataSafeArray);
+
+        if ( !safeArray.Attach(sa.GetValue() )
+        {
+            if ( !safeArray.HasArray() )
+                SafeArrayDestroy(sa.GetValue()); // we have to dispose the SAFEARRAY ourselves
+            return false;
+        }
+
+        // get the data from the SAFEARRAY using wxSafeArray::GetElement()
+        // SAFEARRAY will be disposed by safeArray's dtor
+    }
+    @endcode
+
+    @onlyfor{wxmsw}
+    @since 2.9.5
+
+    @library{wxcore}
+    @category{data}
+
+    @see wxAutomationObject, wxVariant, wxVariantData, wxVariantDataErrorCode
+
+    @header{wx/msw/ole/oleutils.h}
+*/
+class wxVariantDataSafeArray : public wxVariantData
+{
+public:
+    /**
+        Constructor initializes the object to @a value.
+    */
+    explicit wxVariantDataSafeArray(SAFEARRAY* value = NULL);
+
+    /**
+        Returns the stored array.
+    */
+    SAFEARRAY* GetValue() const;
+
+    /**
+        Set the stored array.
+    */
+    void SetValue(SAFEARRAY* value);
+
+    /**
+        Returns true if @a data is of wxVariantDataErrorCode type
+        and contains the same SCODE value.
+    */
+    virtual bool Eq(wxVariantData& data) const;
+
+    /**
+        Fills the provided string with the textual representation of this
+        object.
+
+        The error code is just a number, so it's output as such.
+    */
+    virtual bool Write(wxString& str) const;
+
+    /**
+        Returns a copy of itself.
+    */
+    wxVariantData* Clone() const;
+
+    /**
+        Returns "safearray".
+    */
+    virtual wxString GetType() const;
+
+    /**
+        Converts the value of this object to wxAny.
+    */
+    virtual bool GetAsAny(wxAny* any) const;
+};
 
 /**
     @class wxAutomationObject
@@ -245,7 +372,7 @@ public:
     @library{wxcore}
     @category{data}
 
-    @see wxVariant, wxVariantDataCurrency, wxVariantDataErrorCode
+    @see wxVariant, wxVariantDataCurrency, wxVariantDataErrorCode, wxVariantDataSafeArray
 */
 class wxAutomationObject : public wxObject
 {
diff --git a/interface/wx/variant.h b/interface/wx/variant.h
index ee3f8db494..9730565dd2 100644
--- a/interface/wx/variant.h
+++ b/interface/wx/variant.h
@@ -26,9 +26,9 @@
     the wxVariantData object, unlike the case for basic data types where
     convenience functions such as GetLong() can be used.
 
-    Under Microsoft Windows, two additional wxVariantData-derived classes --
-    wxVariantDataCurrency and wxVariantDataErrorCode -- are available for
-    interoperation with OLE VARIANT when using wxAutomationObject.
+    Under Microsoft Windows, three additional wxVariantData-derived classes --
+    wxVariantDataCurrency, wxVariantDataErrorCode and wxVariantDataSafeArray --
+    are available for interoperation with OLE VARIANT when using wxAutomationObject.
 
     Pointers to any wxObject derived class can also easily be stored in a
     wxVariant. wxVariant will then use wxWidgets' built-in RTTI system to set
diff --git a/src/msw/ole/automtn.cpp b/src/msw/ole/automtn.cpp
index 9c3600dd12..369dfec16f 100644
--- a/src/msw/ole/automtn.cpp
+++ b/src/msw/ole/automtn.cpp
@@ -222,6 +222,12 @@ bool wxAutomationObject::Invoke(const wxString& member, int action,
             {
                 vReturn.pdispVal = NULL;
             }
+            // Mustn't free the SAFEARRAY if it is contained in the retValue
+            if ((vReturn.vt & VT_ARRAY) &&
+                    retValue.GetType() == wxS("safearray"))
+            {
+                vReturn.parray = NULL;
+            }
         }
     }
     return true;
diff --git a/src/msw/ole/oleutils.cpp b/src/msw/ole/oleutils.cpp
index 30623186cf..293b4e68ba 100644
--- a/src/msw/ole/oleutils.cpp
+++ b/src/msw/ole/oleutils.cpp
@@ -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_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 )
     {
diff --git a/src/msw/ole/safearray.cpp b/src/msw/ole/safearray.cpp
new file mode 100644
index 0000000000..c4061e75ab
--- /dev/null
+++ b/src/msw/ole/safearray.cpp
@@ -0,0 +1,134 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        msw/ole/safearray.cpp
+// Purpose:     Implementation of wxSafeArrayBase class.
+// Author:      PB
+// Created:     2012-09-23
+// RCS-ID:      $Id$
+// Copyright:   (c) 2012 wxWidgets development team
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// for compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+    #include "wx/variant.h"
+#endif // WX_PRECOMP
+
+#include "wx/msw/ole/safearray.h"
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxSafeArrayBase
+// ----------------------------------------------------------------------------
+
+void wxSafeArrayBase::Destroy()
+{
+    if ( m_array )
+    {
+        Unlock();
+        HRESULT hr = SafeArrayDestroy(m_array);
+        if ( FAILED(hr) )
+        {
+            wxLogApiError(wxS("SafeArrayDestroy()"), hr);
+        }
+        m_array = NULL;
+    }
+}
+
+SAFEARRAY* wxSafeArrayBase::Detach()
+{
+    wxCHECK_MSG( m_array, NULL, wxS("Uninitialized safe array") );
+
+    Unlock();
+    SAFEARRAY* array = m_array;
+    m_array = NULL;
+    return array;
+}
+
+size_t wxSafeArrayBase::GetDim() const
+{
+    wxASSERT( m_array );
+
+    return SafeArrayGetDim(m_array);
+}
+
+bool wxSafeArrayBase::GetLBound(size_t dim, long& bound) const
+{
+    wxCHECK_MSG( m_array, false, wxS("Uninitialized safe array") );
+    wxCHECK_MSG( dim > 0, false, wxS("Invalid dimension index") );
+
+    HRESULT hr = SafeArrayGetLBound(m_array, dim, &bound);
+    if ( FAILED(hr) )
+    {
+        wxLogApiError(wxS("SafeArrayGetLBound()"), hr);
+        return false;
+    }
+    return true;
+}
+
+bool wxSafeArrayBase::GetUBound(size_t dim, long& bound) const
+{
+    wxCHECK_MSG( m_array, false, wxS("Uninitialized safe array") );
+    wxCHECK_MSG( dim > 0, false, wxS("Invalid dimension index") );
+
+    HRESULT hr = SafeArrayGetUBound(m_array, dim, &bound);
+    if ( FAILED(hr) )
+    {
+        wxLogApiError(wxS("SafeArrayGetUBound()"), hr);
+        return false;
+    }
+    return true;
+}
+
+size_t wxSafeArrayBase::GetCount(size_t dim) const
+{
+    long lBound, uBound;
+
+    if ( GetLBound(dim, lBound) && GetUBound(dim, uBound) )
+        return uBound - lBound + 1;
+    return 0;
+}
+
+bool wxSafeArrayBase::Lock()
+{
+    wxCHECK_MSG( m_array, false, wxS("Uninitialized safe array") );
+
+    HRESULT hr = SafeArrayLock(m_array);
+    if ( FAILED(hr) )
+    {
+        wxLogApiError(wxS("SafeArrayLock()"), hr);
+        return false;
+    }
+    return true;
+}
+
+bool wxSafeArrayBase::Unlock()
+{
+    wxCHECK_MSG( m_array, false, wxS("Uninitialized safe array") );
+
+    HRESULT hr = SafeArrayUnlock(m_array);
+    if ( FAILED(hr) )
+    {
+        wxLogApiError(wxS("SafeArrayUnlock()"), hr);
+        return false;
+    }
+    return true;
+}
+
+
-- 
2.47.2