2009-06-25 Sylvain Dupont <duposyl@gmail.com>
authorBill Holmes <holmes@mono-cvs.ximian.com>
Thu, 25 Jun 2009 14:06:50 +0000 (14:06 -0000)
committerBill Holmes <holmes@mono-cvs.ximian.com>
Thu, 25 Jun 2009 14:06:50 +0000 (14:06 -0000)
* cominterop.h cominterop.c marshal.c: Added support for marshalling out
  parameters of type SAFEARRAY[VARIANT].

* reflection.c (encode_marshal_blob): Properly generate element type
  (SafeArraySubType marshal attribute option).

* cominterop.cs libtest.c: Added tests for marshalling
  out parameters of type SAFEARRAY[VARIANT].

* CustomAttributeBuilder.cs: Properly handle element type for safe
  arrays (SafeArraySubType marshal attribute option).

Code is contributed under MIT/X11 license.

svn path=/trunk/mono/; revision=136836

mono/metadata/ChangeLog
mono/metadata/cominterop.c
mono/metadata/cominterop.h
mono/metadata/marshal.c
mono/metadata/reflection.c
mono/tests/ChangeLog
mono/tests/cominterop.cs
mono/tests/libtest.c

index 2da297cee0aa9cbd6ba7a11c0e06ab5f36300513..d59d3cc0d896eaf069dbaede7d73960569f0aaf7 100644 (file)
@@ -1,4 +1,14 @@
 
+2009-06-25  Sylvain Dupont <duposyl@gmail.com>
+
+       * cominterop.h cominterop.c marshal.c: Added support for marshalling out 
+         parameters of type SAFEARRAY[VARIANT].
+
+       * reflection.c (encode_marshal_blob): Properly generate element type
+         (SafeArraySubType marshal attribute option).
+
+       Code is contributed under MIT/X11 license.
+
 Thu Jun 25 15:48:09 CEST 2009 Paolo Molaro <lupus@ximian.com>
 
        * reflection.c: in mono_method_clear_object () really ensure all the
index ad29cfb337e4a25ce98ad8981031a743238bf17e..4f6d9cee4723b7c9064b0a0f8383c35bd5249a7f 100644 (file)
@@ -125,6 +125,19 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf);
 static MonoObject*
 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
 
+/* SAFEARRAY marshalling */
+static gboolean
+mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty);
+
+static gpointer
+mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
+
+static gboolean
+mono_marshal_safearray_next (gpointer safearray, gpointer indices);
+
+static void
+mono_marshal_safearray_end (gpointer safearray, gpointer indices);
+
 /**
  * cominterop_method_signature:
  * @method: a method
@@ -491,6 +504,12 @@ mono_cominterop_init (void)
        register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
        register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
        register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
+
+       /* SAFEARRAY marshalling */
+       register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
 }
 
 void
@@ -2373,14 +2392,26 @@ cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
        return MONO_E_NOTIMPL;
 }
 
-typedef gpointer (*SysAllocStringLenFunc)(gunichar* str, guint32 len);
-typedef guint32 (*SysStringLenFunc)(gpointer bstr);
-typedef void (*SysFreeStringFunc)(gunichar* str);
+typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
+typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
+typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
 
 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
 static SysStringLenFunc sys_string_len_ms = NULL;
 static SysFreeStringFunc sys_free_string_ms = NULL;
 
+typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
+typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
+typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
+typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
+typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
+
+static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
+static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
+static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
+static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
+static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
+
 static gboolean
 init_com_provider_ms (void)
 {
@@ -2419,6 +2450,41 @@ init_com_provider_ms (void)
                return FALSE;
        }
 
+       error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
        initialized = TRUE;
        return TRUE;
 }
@@ -2504,6 +2570,301 @@ mono_free_bstr (gpointer bstr)
 #endif
 }
 
+
+/* SAFEARRAY marshalling */
+int
+mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
+                                                                               MonoMarshalSpec *spec,
+                                                                               int conv_arg, MonoType **conv_arg_type,
+                                                                               MarshalAction action)
+{
+       MonoMethodBuilder *mb = m->mb;
+
+       mono_init_com_types ();
+       
+       switch (action) {
+
+       case MARSHAL_ACTION_CONV_OUT: {
+
+               if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
+
+                       /* Generates IL code for the following algorithm:
+
+                                       Array result;   // result_var
+                                       IntPtr indices; // indices_var
+                                       int empty;      // empty_var
+                                       if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty)) {
+                                               if (!empty) {
+                                                       int index=0; // index_var
+                                                       do { // label3
+                                                               object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
+                                                               result.SetValueImpl(elem, index);
+                                                               ++index;
+                                                       } 
+                                                       while (mono_marshal_safearray_next(safearray, indices));
+                                               } // label2
+                                               mono_marshal_safearray_end(safearray, indices);
+                                       } // label1
+                       */
+
+                       int result_var, indices_var, empty_var, elem_var, index_var;
+                       guint32 label1 = 0, label2 = 0, label3 = 0;
+                       static MonoMethod *get_object_for_native_variant = NULL;
+                       static MonoMethod *set_value_impl = NULL;
+
+                       result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+                       indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc_addr (mb, result_var);
+                       mono_mb_emit_ldloc_addr (mb, indices_var);
+                       mono_mb_emit_ldloc_addr (mb, empty_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
+
+                       label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+                       mono_mb_emit_ldloc (mb, empty_var);
+
+                       label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
+
+                       index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                       mono_mb_emit_stloc (mb, index_var);
+
+                       label3 = mono_mb_get_label (mb);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
+
+                       if (!get_object_for_native_variant)
+                               get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
+                       g_assert (get_object_for_native_variant);
+
+                       if (!set_value_impl)
+                               set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
+                       g_assert (set_value_impl);
+
+                       elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+                       mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+                       mono_mb_emit_stloc (mb, elem_var);
+
+                       mono_mb_emit_ldloc (mb, result_var);
+                       mono_mb_emit_ldloc (mb, elem_var);
+                       mono_mb_emit_ldloc (mb, index_var);
+                       mono_mb_emit_managed_call (mb, set_value_impl, NULL);
+
+                       mono_mb_emit_add_to_local (mb, index_var, 1);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_next);
+                       mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
+
+                       mono_mb_patch_short_branch (mb, label2);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_end);
+
+                       mono_mb_patch_short_branch (mb, label1);
+
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_ldloc (mb, result_var);
+                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+               }
+               break;
+       }
+
+       default:
+               g_assert_not_reached ();
+       }
+
+       return conv_arg;
+}
+
+static 
+guint32 mono_marshal_safearray_get_dim (gpointer safearray)
+{
+       guint32 result=0;
+#ifdef PLATFORM_WIN32
+       result = SafeArrayGetDim (safearray);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               result = safe_array_get_dim_ms (safearray);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static 
+int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
+{
+       int result=MONO_S_OK;
+#ifdef PLATFORM_WIN32
+       result = SafeArrayGetLBound (psa, nDim, plLbound);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               result = safe_array_get_lbound_ms (psa, nDim, plLbound);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static 
+int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
+{
+       int result=MONO_S_OK;
+#ifdef PLATFORM_WIN32
+       result = SafeArrayGetUBound (psa, nDim, plUbound);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               result = safe_array_get_ubound_ms (psa, nDim, plUbound);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static gboolean
+mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty)
+{
+       int dim;
+       mono_array_size_t *sizes;
+       mono_array_size_t *bounds;
+       MonoClass *aklass;
+       int i;
+       gboolean bounded = FALSE;
+
+#ifndef PLATFORM_WIN32
+       // If not on windows, check that the MS provider is used as it is 
+       // required for SAFEARRAY support.
+       // If SAFEARRAYs are not supported, returning FALSE from this
+       // function will prevent the other mono_marshal_safearray_xxx functions
+       // from being called.
+       if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
+               return FALSE;
+       }
+#endif
+
+       dim = mono_marshal_safearray_get_dim (safearray);
+
+       *indices = g_malloc (dim * sizeof(int));
+
+       sizes = alloca (dim * sizeof(mono_array_size_t));
+       bounds = alloca (dim * sizeof(mono_array_size_t));
+
+       (*(int*)empty) = TRUE;
+       for (i=0; i<dim; ++i) {
+               glong lbound, ubound;
+               int cursize;
+               int hr;
+
+               hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+               if (lbound != 0)
+                       bounded = TRUE;
+               hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+               cursize = ubound-lbound+1;
+               sizes [i] = cursize;
+               bounds [i] = lbound;
+
+               ((int*)*indices) [i] = lbound;
+
+               if (cursize != 0)
+                       (*(int*)empty) = FALSE;
+       }
+
+       aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
+       *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
+
+       return TRUE;
+}
+
+static 
+gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
+{
+       gpointer result;
+#ifdef PLATFORM_WIN32
+       int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
+       if (hr < 0) {
+               cominterop_raise_hr_exception (hr);
+       }
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static 
+gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
+{
+       int i;
+       int dim = mono_marshal_safearray_get_dim (safearray);
+       gboolean ret= TRUE;
+       int *pIndices = (int*) indices;
+       int hr;
+
+       for (i=dim-1; i>=0; --i)
+       {
+               glong lbound, ubound;
+
+               hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+
+               if (++pIndices[i] <= ubound) {
+                       break;
+               }
+
+               hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+
+               pIndices[i] = lbound;
+
+               if (i == 0)
+                       ret = FALSE;
+       }
+       return ret;
+}
+
+static 
+void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
+{
+       g_free(indices);
+#ifdef PLATFORM_WIN32
+       SafeArrayDestroy (safearray);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               safe_array_destroy_ms (safearray);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+}
+
 #else /* DISABLE_COM */
 
 void
index 653b3dc9c877a3fd491816a9c5758a99fb8fd6ff..d3da2d93f4675af84daaa1843246e117fe898994 100644 (file)
@@ -40,6 +40,13 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
                                                                                        int conv_arg, MonoType **conv_arg_type, 
                                                                                        MarshalAction action) MONO_INTERNAL;
 
+int
+mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum,
+                                                                               MonoType *t,
+                                                                               MonoMarshalSpec *spec, 
+                                                                               int conv_arg, MonoType **conv_arg_type,
+                                                                               MarshalAction action) MONO_INTERNAL;
+
 MonoString * 
 mono_string_from_bstr (gpointer bstr);
 
index b765f6264f311cad1416513d3424289da6060ee1..114307b16c40303fbd204445540bbdbff5211cd7 100644 (file)
@@ -7410,6 +7410,10 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
                        spec->native == MONO_NATIVE_IDISPATCH ||
                        spec->native == MONO_NATIVE_INTERFACE))
                        return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+               if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) && 
+                       (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) && 
+                       (action == MARSHAL_ACTION_CONV_OUT))
+                       return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
 #endif
 
                if (mono_defaults.safehandle_class != NULL && t->data.klass &&
index 4b68dec62d640b6d59750d13bfca8f9e753b1538..d419de1ec291a680276659829ba541a0c853f5ca 100644 (file)
@@ -1785,6 +1785,10 @@ encode_marshal_blob (MonoDynamicImage *assembly, MonoReflectionMarshal *minfo) {
                        }
                }
                break;
+       case MONO_NATIVE_SAFEARRAY:
+               if (minfo->eltype)
+                       sigbuffer_add_value (&buf, minfo->eltype);
+               break;
        case MONO_NATIVE_CUSTOM:
                if (minfo->guid) {
                        str = mono_string_to_utf8 (minfo->guid);
index 40ff030eb84566a6571b42e657b269d82f2854e5..3936a5243f3b5a11bdcbed414ddbec2d3d263261 100644 (file)
@@ -1,3 +1,10 @@
+2009-06-25  Sylvain Dupont <duposyl@gmail.com>
+
+       * cominterop.cs libtest.c: Added tests for marshalling
+         out parameters of type SAFEARRAY[VARIANT].
+
+       Code is contributed under MIT/X11 license.
+
 2009-06-24  Zoltan Varga  <vargaz@gmail.com>
 
        * libtest.c make_imt_test.sh: Applied patch from Romain Tartiere 
index 985e58f29edb1ede5f5147a0de0efa3c314a159e..1614a172aec8928a4411c2d6957bfc54fef247d6 100644 (file)
@@ -211,6 +211,18 @@ public class Tests
        [DllImport ("libtest")]
        public static extern int mono_test_marshal_ccw_itest ([MarshalAs (UnmanagedType.Interface)]ITestPresSig itest);
 
+       [DllImport("libtest")]
+       public static extern int mono_test_marshal_variant_out_safearray_1dim_vt_bstr_empty([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]out Array array);
+
+       [DllImport("libtest")]
+       public static extern int mono_test_marshal_variant_out_safearray_1dim_vt_bstr ([MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]out Array array);
+
+       [DllImport("libtest")]
+       public static extern int mono_test_marshal_variant_out_safearray_2dim_vt_int ([MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]out Array array);
+
+       [DllImport("libtest")]
+       public static extern int mono_test_marshal_variant_out_safearray_4dim_vt_int ([MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]out Array array);
+
        public static int Main() {
 
         bool isWindows = !(((int)Environment.OSVersion.Platform == 4) || 
@@ -423,6 +435,54 @@ public class Tests
                        mono_test_marshal_ccw_itest (test_pres_sig);
 
                        #endregion // COM Callable Wrapper Tests
+
+                       #region SAFEARRAY tests
+
+                       Array array;
+                       if ((mono_test_marshal_variant_out_safearray_1dim_vt_bstr_empty(out array) != 0) || (array.Rank != 1) || (array.Length != 0))
+                               return 62;
+
+                       if ((mono_test_marshal_variant_out_safearray_1dim_vt_bstr (out array) != 0) || (array.Rank != 1) || (array.Length != 10))
+                               return 63;
+                       for (int i = 0; i < 10; ++i) {
+                               if (i != Convert.ToInt32(array.GetValue (i)))
+                                       return 64;
+                       }
+
+                       if ((mono_test_marshal_variant_out_safearray_2dim_vt_int (out array) != 0) || (array.Rank != 2))
+                               return 65;
+                       if (   (array.GetLowerBound (0) != 0) || (array.GetUpperBound (0) != 3)
+                               || (array.GetLowerBound (1) != 0) || (array.GetUpperBound (1) != 2))
+                               return 66;
+                       for (int i = array.GetLowerBound (0); i <= array.GetUpperBound (0); ++i)
+                       {
+                               for (int j = array.GetLowerBound (1); j <= array.GetUpperBound (1); ++j) {
+                                       if ((i + 1) * 10 + (j + 1) != (int)array.GetValue (new long[] { i, j }))
+                                               return 67;
+                               }
+                       }
+
+                       if ((mono_test_marshal_variant_out_safearray_4dim_vt_int (out array) != 0) || (array.Rank != 4))
+                               return 68;
+                       if (   (array.GetLowerBound (0) != 15) || (array.GetUpperBound (0) != 24)
+                               || (array.GetLowerBound (1) != 20) || (array.GetUpperBound (1) != 22)
+                               || (array.GetLowerBound (2) !=  5) || (array.GetUpperBound (2) != 10)
+                               || (array.GetLowerBound (3) != 12) || (array.GetUpperBound (3) != 18) )
+                               return 69;
+
+                       int index = 0;
+                       for (int i = array.GetLowerBound (3); i <= array.GetUpperBound (3); ++i) {
+                               for (int j = array.GetLowerBound (2); j <= array.GetUpperBound (2); ++j) {
+                                       for (int k = array.GetLowerBound (1); k <= array.GetUpperBound (1); ++k) {
+                                               for (int l = array.GetLowerBound (0); l <= array.GetUpperBound (0); ++l) {
+                                                       if (index != (int)array.GetValue (new long[] { l, k, j, i }))
+                                                               return 70;
+                                                       ++index;
+                                               }
+                                       }
+                               }
+                       }
+                       #endregion // SafeArray Tests
                }
 
         return 0;
index ba0c352546f84b49ad52e3aa9c179ec2d8b79ce6..59a338fc2495dc412d8845061fa3e11a48ed9173 100644 (file)
@@ -4045,4 +4045,126 @@ mono_test_managed_marshal_bool_ref (int arg, unsigned int expected, unsigned int
        return 0;
 }
 
+#ifdef WIN32
+
+LIBTEST_API int STDCALL 
+mono_test_marshal_variant_out_safearray_1dim_vt_bstr_empty (SAFEARRAY** safearray)
+{
+       /* Create an empty one-dimensional array of variants */
+       SAFEARRAY *pSA;
+       SAFEARRAYBOUND dimensions [1];
+
+       dimensions [0].lLbound = 0;
+       dimensions [0].cElements = 0;
+
+       pSA= SafeArrayCreate (VT_VARIANT, 1, dimensions);
+       *safearray = pSA;
+       return S_OK;
+}
+
+LIBTEST_API int STDCALL 
+mono_test_marshal_variant_out_safearray_1dim_vt_bstr (SAFEARRAY** safearray)
+{
+       /* Create a one-dimensional array of 10 variants filled with "0" to "9" */
+       SAFEARRAY *pSA;
+       SAFEARRAYBOUND dimensions [1];
+       long i;
+       wchar_t buffer [20];
+       HRESULT hr = S_OK;
+       long indices [1];
+
+       dimensions [0].lLbound = 0;
+       dimensions [0].cElements = 10;
+
+       pSA= SafeArrayCreate (VT_VARIANT, 1, dimensions);
+       for (i= dimensions [0].lLbound; i< (dimensions [0].cElements + dimensions [0].lLbound); i++) {
+               VARIANT vOut;
+               VariantInit (&vOut);
+               vOut.vt = VT_BSTR;
+               _ltow (i,buffer,10);
+               vOut.bstrVal= SysAllocString (buffer);
+               indices [0] = i;
+               if ((hr = SafeArrayPutElement (pSA, indices, &vOut)) != S_OK) {
+                       VariantClear (&vOut);
+                       SafeArrayDestroy (pSA);
+                       return hr;
+               }
+               VariantClear (&vOut);
+       }
+       *safearray = pSA;
+       return hr;
+}
+
+LIBTEST_API int STDCALL 
+mono_test_marshal_variant_out_safearray_2dim_vt_int (SAFEARRAY** safearray)
+{
+       /* Create a two-dimensional array of 4x3 variants filled with 11, 12, 13, etc. */
+       SAFEARRAY *pSA;
+       SAFEARRAYBOUND dimensions [2];
+       long i, j;
+       HRESULT hr = S_OK;
+       long indices [2];
+
+       dimensions [0].lLbound = 0;
+       dimensions [0].cElements = 4;
+       dimensions [1].lLbound = 0;
+       dimensions [1].cElements = 3;
+
+       pSA= SafeArrayCreate(VT_VARIANT, 2, dimensions);
+       for (i= dimensions [0].lLbound; i< (dimensions [0].cElements + dimensions [0].lLbound); i++) {
+               for (j= dimensions [1].lLbound; j< (dimensions [1].cElements + dimensions [1].lLbound); j++) {
+                       VARIANT vOut;
+                       VariantInit (&vOut);
+                       vOut.vt = VT_I4;
+                       vOut.intVal = (i+1)*10+(j+1);
+                       indices [0] = i;
+                       indices [1] = j;
+                       if ((hr = SafeArrayPutElement (pSA, indices, &vOut)) != S_OK) {
+                               VariantClear (&vOut);
+                               SafeArrayDestroy (pSA);
+                               return hr;
+                       }
+                       VariantClear (&vOut);  // does a deep destroy of source VARIANT 
+               }
+       }
+       *safearray = pSA;
+       return hr;
+}
+
+LIBTEST_API int STDCALL 
+mono_test_marshal_variant_out_safearray_4dim_vt_int (SAFEARRAY** safearray)
+{
+       /* Create a four-dimensional array of 10x3x6x7 variants filled with their indices */
+       /* Also use non zero lower bounds                                                 */
+       SAFEARRAY *pSA;
+       SAFEARRAYBOUND dimensions [4];
+       long i;
+       HRESULT hr = S_OK;
+       VARIANT *pData;
+
+       dimensions [0].lLbound = 15;
+       dimensions [0].cElements = 10;
+       dimensions [1].lLbound = 20;
+       dimensions [1].cElements = 3;
+       dimensions [2].lLbound = 5;
+       dimensions [2].cElements = 6;
+       dimensions [3].lLbound = 12;
+       dimensions [3].cElements = 7;
+
+       pSA= SafeArrayCreate (VT_VARIANT, 4, dimensions);
+
+       SafeArrayAccessData (pSA, (void **)&pData);
+
+       for (i= 0; i< 10*3*6*7; i++) {
+               VariantInit(&pData [i]);
+               pData [i].vt = VT_I4;
+               pData [i].intVal = i;
+       }
+       SafeArrayUnaccessData(pSA);
+       *safearray = pSA;
+       return hr;
+}
+
+#endif
+