X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fcominterop.c;h=bfb0dd5bf5725927291d67119323d99e6a459d33;hb=a5f3c441eef82a7e0e38bbe30e3b5577eebcaf77;hp=3fe0a74e6196616ee41a8f94c58a839bd1c23539;hpb=cc5fe380f28e4f9c9668d8a8b8269b299d183a20;p=mono.git diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c index 3fe0a74e619..bfb0dd5bf57 100644 --- a/mono/metadata/cominterop.c +++ b/mono/metadata/cominterop.c @@ -66,7 +66,7 @@ enum { 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 @@ -81,7 +81,7 @@ typedef struct { guint32 ref_count; guint32 gc_handle; GHashTable* vtable_hash; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 gpointer free_marshaler; #endif } MonoCCW; @@ -125,11 +125,18 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf); 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: @@ -153,7 +160,7 @@ cominterop_method_signature (MonoMethod* method) 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 @@ -188,7 +195,7 @@ cominterop_method_signature (MonoMethod* method) 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; @@ -270,18 +277,28 @@ cominterop_get_com_slot_begin (MonoClass* klass) 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; } @@ -289,7 +306,8 @@ cominterop_get_method_interface (MonoMethod* method) } } - g_assert (ic); + if (!ic) + g_assert (ic); g_assert (MONO_CLASS_IS_INTERFACE (ic)); return ic; @@ -310,10 +328,17 @@ cominterop_get_com_slot_for_method (MonoMethod* method) /* 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); @@ -355,6 +380,7 @@ static gboolean cominterop_com_visible (MonoClass* klass) { static MonoClass *ComVisibleAttribute = NULL; + MonoError error; MonoCustomAttrInfo *cinfo; GPtrArray *ifaces; MonoBoolean visible = 0; @@ -375,7 +401,8 @@ cominterop_com_visible (MonoClass* klass) 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) { @@ -455,7 +482,7 @@ cominterop_get_hresult_for_exception (MonoException* exc) } 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); @@ -496,6 +523,13 @@ mono_cominterop_init (void) 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 @@ -567,7 +601,7 @@ mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, 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) { @@ -826,6 +860,7 @@ mono_cominterop_get_native_wrapper (MonoMethod *method) 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); @@ -1066,7 +1101,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, 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) @@ -1247,8 +1282,11 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, 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 */ @@ -1256,7 +1294,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, 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) @@ -1299,7 +1337,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, 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) @@ -1507,7 +1545,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoO 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) @@ -1550,7 +1592,7 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type) * 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; } @@ -1742,7 +1784,7 @@ cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method) /* 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; @@ -1787,12 +1829,14 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) 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) { @@ -1819,7 +1863,7 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) 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); @@ -1833,7 +1877,9 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) } 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); } @@ -1915,6 +1961,12 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) 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++; } } @@ -1980,6 +2032,7 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) 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; @@ -2088,11 +2141,13 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method) 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)) @@ -2108,32 +2163,46 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method) 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); @@ -2209,7 +2278,7 @@ cominterop_ccw_release (MonoCCWInterface* ccwe) /* 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 @@ -2219,16 +2288,16 @@ cominterop_ccw_release (MonoCCWInterface* ccwe) 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; @@ -2252,11 +2321,13 @@ cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpoin 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); @@ -2287,24 +2358,32 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p 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); @@ -2346,14 +2425,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) { @@ -2392,6 +2483,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; } @@ -2401,7 +2527,7 @@ mono_string_to_bstr (MonoString *string_obj) { 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) { @@ -2437,7 +2563,7 @@ mono_string_from_bstr (gpointer bstr) { 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) { @@ -2463,7 +2589,7 @@ mono_free_bstr (gpointer bstr) { if (!bstr) return; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 SysFreeString ((BSTR)bstr); #else if (com_provider == MONO_COM_DEFAULT) { @@ -2477,6 +2603,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 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=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 @@ -2500,4 +2921,24 @@ mono_marshal_free_ccw (MonoObject* object) 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 */