/* SAFEARRAY marshalling */
static gboolean
-mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty);
+mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
static gpointer
mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
static void
mono_marshal_safearray_end (gpointer safearray, gpointer indices);
+static gboolean
+mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
+
+static void
+mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
+
+static void
+mono_marshal_safearray_free_indices (gpointer indices);
+
/**
* cominterop_method_signature:
* @method: a method
static void
-cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid);
+cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
static gboolean
cominterop_class_guid (MonoClass* klass, guint8* guid)
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_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", 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);
+ register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
+ register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
+ register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
}
void
* to a 16 byte Microsoft GUID.
*/
static void
-cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
+cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
gunichar2 * chars = mono_string_chars (string);
int i = 0;
static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
static SysStringLenFunc sys_string_len_ms = NULL;
static SysFreeStringFunc sys_free_string_ms = NULL;
+#ifndef HOST_WIN32
+
+typedef struct tagSAFEARRAYBOUND {
+ ULONG cElements;
+ LONG lLbound;
+}SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
+#define VT_VARIANT 12
+
+#endif
+
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);
+typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
+typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
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 SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
+static SafeArrayCreateFunc safe_array_create_ms = NULL;
static gboolean
init_com_provider_ms (void)
return FALSE;
}
+ error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
+ if (error_msg) {
+ g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
+ g_assert_not_reached ();
+ return FALSE;
+ }
+
+ error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
+ if (error_msg) {
+ g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
+ g_assert_not_reached ();
+ return FALSE;
+ }
+
initialized = TRUE;
return TRUE;
}
switch (action) {
- case MARSHAL_ACTION_CONV_OUT: {
+ case MARSHAL_ACTION_CONV_IN: {
+
+ if (t->attrs & PARAM_ATTRIBUTE_IN) {
+
+ /* Generates IL code for the following algorithm:
+
+ SafeArray safearray; // safearray_var
+ IntPtr indices; // indices_var
+ int empty; // empty_var
+ if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
+ if (!empty) {
+ int index=0; // index_var
+ do { // label3
+ variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
+ mono_marshal_safearray_set_value (safearray, indices, elem);
+ ++index;
+ }
+ while (mono_marshal_safearray_next (safearray, indices));
+ } // label2
+ mono_marshal_safearray_free_indices (indices);
+ } // label1
+ */
+
+ int safearray_var, indices_var, empty_var, elem_var, index_var;
+ guint32 label1 = 0, label2 = 0, label3 = 0;
+ static MonoMethod *get_native_variant_for_object = NULL;
+ static MonoMethod *get_value_impl = NULL;
+ static MonoMethod *variant_clear = NULL;
+
+ conv_arg = safearray_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);
+
+ if (t->byref) {
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ } else
+ mono_mb_emit_ldarg (mb, argnum);
+
+ mono_mb_emit_ldloc_addr (mb, safearray_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_create);
+
+ 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);
+
+ if (!get_value_impl)
+ get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
+ g_assert (get_value_impl);
+
+ if (t->byref) {
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ } else
+ mono_mb_emit_ldarg (mb, argnum);
+
+ mono_mb_emit_ldloc (mb, index_var);
+
+ mono_mb_emit_managed_call (mb, get_value_impl, NULL);
+
+ if (!get_native_variant_for_object)
+ get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
+ g_assert (get_native_variant_for_object);
+
+ elem_var = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
+ mono_mb_emit_ldloc_addr (mb, elem_var);
+
+ mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+
+ mono_mb_emit_ldloc (mb, safearray_var);
+ mono_mb_emit_ldloc (mb, indices_var);
+ mono_mb_emit_ldloc_addr (mb, elem_var);
+ mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
+
+ if (!variant_clear)
+ variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
+
+ mono_mb_emit_ldloc_addr (mb, elem_var);
+ mono_mb_emit_managed_call (mb, variant_clear, NULL);
+
+ mono_mb_emit_add_to_local (mb, index_var, 1);
+
+ mono_mb_emit_ldloc (mb, safearray_var);
+ 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, indices_var);
+ mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
+
+ mono_mb_patch_short_branch (mb, label1);
+ }
+ break;
+ }
+
+ case MARSHAL_ACTION_PUSH:
+ if (t->byref)
+ mono_mb_emit_ldloc_addr (mb, conv_arg);
+ else
+ mono_mb_emit_ldloc (mb, conv_arg);
+ break;
- if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
+ case MARSHAL_ACTION_CONV_OUT: {
+ if (t->attrs & PARAM_ATTRIBUTE_OUT) {
/* 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)) {
+ bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
+ if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
if (!empty) {
int index=0; // index_var
do { // label3
- object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
- result.SetValueImpl(elem, index);
+ if (!byValue || (index < parameter.Length)) {
+ 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
+ if (!byValue)
+ return result;
*/
int result_var, indices_var, empty_var, elem_var, index_var;
- guint32 label1 = 0, label2 = 0, label3 = 0;
+ guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
static MonoMethod *get_object_for_native_variant = NULL;
static MonoMethod *set_value_impl = NULL;
+ gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
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);
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_ldarg (mb, argnum);
+ if (byValue)
+ mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+ else
+ mono_mb_emit_byte (mb, CEE_LDC_I4_1);
mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
label3 = mono_mb_get_label (mb);
+ if (byValue) {
+ mono_mb_emit_ldloc (mb, index_var);
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_LDLEN);
+ label4 = mono_mb_emit_branch (mb, CEE_BGE);
+ }
+
mono_mb_emit_ldloc (mb, conv_arg);
mono_mb_emit_ldloc (mb, indices_var);
mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
mono_mb_emit_ldloc (mb, index_var);
mono_mb_emit_managed_call (mb, set_value_impl, NULL);
+ if (byValue)
+ mono_mb_patch_short_branch (mb, label4);
+
mono_mb_emit_add_to_local (mb, index_var, 1);
mono_mb_emit_ldloc (mb, conv_arg);
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);
+ if (!byValue) {
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc (mb, result_var);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ }
}
break;
}
}
static gboolean
-mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty)
+mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
{
int dim;
- mono_array_size_t *sizes;
- mono_array_size_t *bounds;
+ uintptr_t *sizes;
+ intptr_t *bounds;
MonoClass *aklass;
int i;
gboolean bounded = FALSE;
}
#endif
- dim = mono_marshal_safearray_get_dim (safearray);
+ (*(int*)empty) = TRUE;
- *indices = g_malloc (dim * sizeof(int));
+ if (safearray != NULL) {
- sizes = alloca (dim * sizeof(mono_array_size_t));
- bounds = alloca (dim * sizeof(mono_array_size_t));
+ dim = mono_marshal_safearray_get_dim (safearray);
- (*(int*)empty) = TRUE;
- for (i=0; i<dim; ++i) {
- glong lbound, ubound;
- int cursize;
- int hr;
+ if (dim > 0) {
- 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;
+ *indices = g_malloc (dim * sizeof(int));
- ((int*)*indices) [i] = lbound;
+ sizes = alloca (dim * sizeof(uintptr_t));
+ bounds = alloca (dim * sizeof(intptr_t));
- if (cursize != 0)
- (*(int*)empty) = FALSE;
- }
+ 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;
- aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
- *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
+ ((int*)*indices) [i] = lbound;
+ if (cursize != 0)
+ (*(int*)empty) = FALSE;
+ }
+
+ if (allocateNewArray) {
+ aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
+ *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
+ } else {
+ *result = parameter;
+ }
+ }
+ }
return TRUE;
}
#endif
}
+static gboolean
+mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
+{
+ int dim;
+ SAFEARRAYBOUND *bounds;
+ int i;
+ int max_array_length;
+
+#ifndef HOST_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
+
+ max_array_length = mono_array_length (input);
+ dim = ((MonoObject *)input)->vtable->klass->rank;
+
+ *indices = g_malloc (dim * sizeof (int));
+ bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
+ (*(int*)empty) = (max_array_length == 0);
+
+ if (dim > 1) {
+ for (i=0; i<dim; ++i) {
+ ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
+ bounds [i].cElements = input->bounds [i].length;
+ }
+ } else {
+ ((int*)*indices) [0] = 0;
+ bounds [0].cElements = max_array_length;
+ bounds [0].lLbound = 0;
+ }
+
+#ifdef HOST_WIN32
+ *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
+#else
+ *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
+#endif
+
+ return TRUE;
+}
+
+static
+void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
+{
+#ifdef HOST_WIN32
+ int hr = SafeArrayPutElement (safearray, indices, value);
+ if (hr < 0)
+ cominterop_raise_hr_exception (hr);
+#else
+ if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+ int hr = safe_array_put_element_ms (safearray, indices, value);
+ if (hr < 0) {
+ cominterop_raise_hr_exception (hr);
+ }
+ } else
+ g_assert_not_reached ();
+#endif
+}
+
+static
+void mono_marshal_safearray_free_indices (gpointer indices)
+{
+ g_free (indices);
+}
+
#else /* DISABLE_COM */
void