static CRITICAL_SECTION cominterop_mutex;
/* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
#define STDCALL __stdcall
#else
#define STDCALL
guint32 ref_count;
guint32 gc_handle;
GHashTable* vtable_hash;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
gpointer free_marshaler;
#endif
} MonoCCW;
static MonoObject*
cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
-MonoString *
-mono_string_from_bstr (gpointer bstr);
+/* 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);
-void
-mono_free_bstr (gpointer bstr);
+static gboolean
+mono_marshal_safearray_next (gpointer safearray, gpointer indices);
+
+static void
+mono_marshal_safearray_end (gpointer safearray, gpointer indices);
/**
* cominterop_method_signature:
param_count++;
res = mono_metadata_signature_alloc (image, param_count);
- sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
+ sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
memcpy (res, sig, sigsize);
// now move args forward one
res->param_count = param_count;
// STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
res->call_convention = MONO_CALL_STDCALL;
#else
res->call_convention = MONO_CALL_C;
static MonoClass*
cominterop_get_method_interface (MonoMethod* method)
{
+ MonoError error;
MonoClass *ic = method->klass;
/* if method is on a class, we need to look up interface method exists on */
if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
- GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass);
+ GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
+ g_assert (mono_error_ok (&error));
if (ifaces) {
int i;
+ mono_class_setup_vtable (method->klass);
for (i = 0; i < ifaces->len; ++i) {
- int offset;
+ int j, offset;
+ gboolean found = FALSE;
ic = g_ptr_array_index (ifaces, i);
offset = mono_class_interface_offset (method->klass, ic);
- if (method->slot >= offset && method->slot < offset + ic->method.count)
+ for (j = 0; j < ic->method.count; ++j) {
+ if (method->klass->vtable [j + offset] == method) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
break;
ic = NULL;
}
}
}
- g_assert (ic);
+ if (!ic)
+ g_assert (ic);
g_assert (MONO_CLASS_IS_INTERFACE (ic));
return ic;
/* if method is on a class, we need to look up interface method exists on */
if (!MONO_CLASS_IS_INTERFACE(ic)) {
int offset = 0;
+ int i = 0;
ic = cominterop_get_method_interface (method);
offset = mono_class_interface_offset (method->klass, ic);
g_assert(offset >= 0);
- slot -= offset;
+ for(i = 0; i < ic->method.count; ++i) {
+ if (method->klass->vtable [i + offset] == method)
+ {
+ slot = ic->methods[i]->slot;
+ break;
+ }
+ }
}
g_assert (ic);
cominterop_com_visible (MonoClass* klass)
{
static MonoClass *ComVisibleAttribute = NULL;
+ MonoError error;
MonoCustomAttrInfo *cinfo;
GPtrArray *ifaces;
MonoBoolean visible = 0;
return TRUE;
}
- ifaces = mono_class_get_implemented_interfaces (klass);
+ ifaces = mono_class_get_implemented_interfaces (klass, &error);
+ g_assert (mono_error_ok (&error));
if (ifaces) {
int i;
for (i = 0; i < ifaces->len; ++i) {
}
static MonoReflectionType *
-type_from_handle (MonoType *handle)
+cominterop_type_from_handle (MonoType *handle)
{
MonoDomain *domain = mono_domain_get ();
MonoClass *klass = mono_class_from_mono_type (handle);
register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
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
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
- mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_icall (mb, cominterop_type_from_handle);
mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
if (!method->klass->methods)
mono_class_setup_methods (method->klass);
+ g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
sig = mono_method_signature (method);
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
if (klass && klass != mono_defaults.object_class) {
mono_mb_emit_ptr (mb, t);
- mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_icall (mb, cominterop_type_from_handle);
mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
}
else if (spec->native == MONO_NATIVE_IUNKNOWN)
if (!AddRef)
AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+
mono_mb_emit_ldloc (mb, conv_arg);
- /* if null just break, conv arg was already inited to 0 */
pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
/* to store later */
mono_mb_emit_ldloc (mb, conv_arg);
if (klass && klass != mono_defaults.object_class) {
mono_mb_emit_ptr (mb, t);
- mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_icall (mb, cominterop_type_from_handle);
mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
}
else if (spec->native == MONO_NATIVE_IUNKNOWN)
mono_mb_emit_ldloc (mb, ccw_obj);
if (klass && klass != mono_defaults.object_class) {
mono_mb_emit_ptr (mb, t);
- mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_icall (mb, cominterop_type_from_handle);
mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
}
else if (spec->native == MONO_NATIVE_IUNKNOWN)
proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
g_assert (proxy);
+ if (proxy->ref_count == 0)
+ return -1;
+
ref_count = InterlockedDecrement (&proxy->ref_count);
+
g_assert (ref_count >= 0);
if (ref_count == 0)
* is called by the corresponding real proxy to create the real RCW.
* Constructor does not need to be called. Will be called later.
*/
- obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
+ obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
return obj;
}
/* csig = mono_metadata_signature_dup (sig); */
/* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
csig->call_convention = MONO_CALL_STDCALL;
#else
csig->call_convention = MONO_CALL_C;
klass = mono_object_get_class (object);
+ mono_cominterop_lock ();
if (!ccw_hash)
ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
if (!ccw_interface_hash)
ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
+ mono_cominterop_unlock ();
ccw_list_item = ccw_list;
while (ccw_list_item) {
if (!ccw) {
ccw = g_new0 (MonoCCW, 1);
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
ccw->free_marshaler = 0;
#endif
ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
}
else
ccw_list = g_list_append (ccw_list, ccw);
+ mono_cominterop_lock ();
g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
+ mono_cominterop_unlock ();
/* register for finalization to clean up ccw */
mono_object_register_finalizer (object);
}
mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
}
+ } else {
+ /* increase SizeParamIndex since we've added a param */
+ if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
+ sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
+ if (mspecs[mspec_index]->data.array_data.param_num != -1)
+ mspecs[mspec_index]->data.array_data.param_num++;
}
}
static gboolean
mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
{
+ g_hash_table_remove (ccw_interface_hash, value);
g_assert (value);
g_free (value);
return TRUE;
if (!preserve_sig) {
hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
-
- /* try */
- main_clause = g_new0 (MonoExceptionClause, 1);
- main_clause->try_offset = mono_mb_get_label (mb);
}
+ else if (!MONO_TYPE_IS_VOID (sig->ret))
+ hr = mono_mb_add_local (mb, sig->ret);
+
+ /* try */
+ main_clause = g_new0 (MonoExceptionClause, 1);
+ main_clause->try_offset = mono_mb_get_label (mb);
/* load last param to store result if not preserve_sig and not void */
if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
mono_mb_emit_managed_call (mb, method, NULL);
- if (!preserve_sig) {
- /* store result if not preserve_sig and we have one */
- if (!MONO_TYPE_IS_VOID (sig->ret))
- mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
+ if (!MONO_TYPE_IS_VOID (sig->ret)) {
+ if (!preserve_sig) {
+ MonoClass *rclass = mono_class_from_mono_type (sig->ret);
+ if (rclass->valuetype) {
+ mono_mb_emit_op (mb, CEE_STOBJ, rclass);
+ } else {
+ mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
+ }
+ } else
+ mono_mb_emit_stloc (mb, hr);
+ }
- pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
+ pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
- /* Main exception catch */
- main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
- main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
- main_clause->data.catch_class = mono_defaults.object_class;
+ /* Main exception catch */
+ main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
+ main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
+ main_clause->data.catch_class = mono_defaults.object_class;
- /* handler code */
- main_clause->handler_offset = mono_mb_get_label (mb);
+ /* handler code */
+ main_clause->handler_offset = mono_mb_get_label (mb);
+
+ if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
mono_mb_emit_stloc (mb, hr);
- mono_mb_emit_branch (mb, CEE_LEAVE);
- main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
- /* end catch */
+ }
+ else {
+ mono_mb_emit_byte (mb, CEE_POP);
+ }
+
+ mono_mb_emit_branch (mb, CEE_LEAVE);
+ main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
+ /* end catch */
- mono_mb_set_clauses (mb, 1, main_clause);
+ mono_mb_set_clauses (mb, 1, main_clause);
- mono_mb_patch_branch (mb, pos_leave);
+ mono_mb_patch_branch (mb, pos_leave);
+ if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
mono_mb_emit_ldloc (mb, hr);
- }
mono_mb_emit_byte (mb, CEE_RET);
/* allow gc of object */
guint32 oldhandle = ccw->gc_handle;
g_assert (oldhandle);
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
if (ccw->free_marshaler)
ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler);
#endif
return ref_count;
}
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
#endif
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
/* All ccw objects are free threaded */
static int
cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
{
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
if (!ccw->free_marshaler) {
int ret = 0;
gpointer tunk;
static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
{
+ MonoError error;
GPtrArray *ifaces;
MonoClass *itf = NULL;
int i;
MonoCCW* ccw = ccwe->ccw;
MonoClass* klass = NULL;
+ MonoClass* klass_iter = NULL;
MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
g_assert (object);
return MONO_S_OK;
}
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
/* handle IMarshal special */
if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
}
#endif
-
- ifaces = mono_class_get_implemented_interfaces (klass);
- if (ifaces) {
- for (i = 0; i < ifaces->len; ++i) {
- MonoClass *ic = NULL;
- ic = g_ptr_array_index (ifaces, i);
- if (cominterop_class_guid_equal (riid, ic)) {
- itf = ic;
- break;
+ klass_iter = klass;
+ while (klass_iter && klass_iter != mono_defaults.object_class) {
+ ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
+ g_assert (mono_error_ok (&error));
+ if (ifaces) {
+ for (i = 0; i < ifaces->len; ++i) {
+ MonoClass *ic = NULL;
+ ic = g_ptr_array_index (ifaces, i);
+ if (cominterop_class_guid_equal (riid, ic)) {
+ itf = ic;
+ break;
+ }
}
+ g_ptr_array_free (ifaces, TRUE);
}
- g_ptr_array_free (ifaces, TRUE);
+
+ if (itf)
+ break;
+
+ klass_iter = klass_iter->parent;
}
if (itf) {
*ppv = cominterop_get_ccw (object, itf);
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)
{
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;
}
{
if (!string_obj)
return NULL;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
#else
if (com_provider == MONO_COM_DEFAULT) {
{
if (!bstr)
return NULL;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
#else
if (com_provider == MONO_COM_DEFAULT) {
{
if (!bstr)
return;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
SysFreeString ((BSTR)bstr);
#else
if (com_provider == MONO_COM_DEFAULT) {
#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 HOST_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 HOST_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 HOST_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 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
+
+ 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 HOST_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 HOST_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
return FALSE;
}
+gpointer
+mono_string_to_bstr (MonoString *string_obj)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+MonoString *
+mono_string_from_bstr (gpointer bstr)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+void
+mono_free_bstr (gpointer bstr)
+{
+ g_assert_not_reached ();
+}
+
#endif /* DISABLE_COM */