cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
/**
- * signature_cominterop:
- * @image: a image
- * @sig: managed method signature
+ * cominterop_method_signature:
+ * @method: a method
*
* Returns: the corresponding unmanaged method signature for a managed COM
* method.
*/
static MonoMethodSignature*
-signature_cominterop (MonoImage *image, MonoMethodSignature *sig)
+cominterop_method_signature (MonoMethod* method)
{
MonoMethodSignature *res;
+ MonoImage *image = method->klass->image;
+ MonoMethodSignature *sig = mono_method_signature (method);
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
int sigsize;
int i;
int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
param_count++;
sigsize = sizeof (MonoMethodSignature) + ((param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
// first arg is interface pointer
res->params[0] = &mono_defaults.int_class->byval_arg;
- // last arg is return type
- if (!MONO_TYPE_IS_VOID (sig->ret)) {
- res->params[param_count-1] = mono_metadata_type_dup_mp (image, sig->ret);
- res->params[param_count-1]->byref = 1;
- res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
+ if (preserve_sig) {
+ res->ret = sig->ret;
+ }
+ else {
+ // last arg is return type
+ if (!MONO_TYPE_IS_VOID (sig->ret)) {
+ res->params[param_count-1] = mono_metadata_type_dup_mp (image, sig->ret);
+ res->params[param_count-1]->byref = 1;
+ res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
+ }
+
+ // return type is always int32 (HRESULT)
+ res->ret = &mono_defaults.int32_class->byval_arg;
}
// no pinvoke
// set param_count
res->param_count = param_count;
- // return type is always int32 (HRESULT)
- res->ret = &mono_defaults.int32_class->byval_arg;
-
// STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
#ifdef PLATFORM_WIN32
res->call_convention = MONO_CALL_STDCALL;
cominterop_get_com_slot_for_method (MonoMethod* method)
{
guint32 slot = method->slot;
- GPtrArray *ifaces;
- MonoClass *ic = NULL;
- int i;
+ MonoClass *ic = method->klass;
- ifaces = mono_class_get_implemented_interfaces (method->klass);
- if (ifaces) {
- int offset;
- for (i = 0; i < ifaces->len; ++i) {
- ic = g_ptr_array_index (ifaces, i);
- offset = method->klass->interface_offsets[ic->interface_id];
- if (method->slot >= offset && method->slot < offset + ic->method.count) {
- slot -= offset;
- break;
+ /* 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);
+ if (ifaces) {
+ int i;
+ for (i = 0; i < ifaces->len; ++i) {
+ int offset;
+ 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) {
+ slot -= offset;
+ break;
+ }
+ ic = NULL;
}
+ g_ptr_array_free (ifaces, TRUE);
}
- g_ptr_array_free (ifaces, TRUE);
}
- if (!ic)
- ic = method->klass;
-
g_assert (ic);
g_assert (MONO_CLASS_IS_INTERFACE (ic));
static MonoReflectionType*
cominterop_get_method_interface (MonoMethod* method)
{
- GPtrArray *ifaces;
MonoType* t = NULL;
- MonoClass *ic = NULL;
- int i;
MonoReflectionType* rt = NULL;
+ MonoClass *ic = method->klass;
- ifaces = mono_class_get_implemented_interfaces (method->klass);
- if (ifaces) {
- int offset;
- for (i = 0; i < ifaces->len; ++i) {
- ic = g_ptr_array_index (ifaces, i);
- offset = method->klass->interface_offsets[ic->interface_id];
- if (method->slot >= offset && method->slot < offset + ic->method.count)
- break;
- ic = NULL;
+ /* 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);
+ if (ifaces) {
+ int i;
+ for (i = 0; i < ifaces->len; ++i) {
+ int offset;
+ 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)
+ break;
+ ic = NULL;
+ }
+ g_ptr_array_free (ifaces, TRUE);
}
- g_ptr_array_free (ifaces, TRUE);
}
- if (!ic)
- ic = method->klass;
-
g_assert (ic);
g_assert (MONO_CLASS_IS_INTERFACE (ic));
mono_mb_emit_byte (mb, CEE_STIND_REF);
break;
case MONO_MARSHAL_CONV_STR_LPTSTR:
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+#ifdef PLATFORM_WIN32
+ mono_mb_emit_icall (mb, mono_string_from_utf16);
+#else
+ mono_mb_emit_icall (mb, mono_string_new_wrapper);
+#endif
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ break;
case MONO_MARSHAL_CONV_STR_LPSTR:
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
case MONO_MARSHAL_CONV_LPSTR_STR:
return mono_string_new_wrapper;
case MONO_MARSHAL_CONV_STR_LPTSTR:
+#ifdef PLATFORM_WIN32
+ return mono_marshal_string_to_utf16;
+#else
+ return mono_string_to_lpstr;
+#endif
case MONO_MARSHAL_CONV_STR_LPSTR:
return mono_string_to_lpstr;
case MONO_MARSHAL_CONV_STR_BSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
return mono_string_to_ansibstr;
case MONO_MARSHAL_CONV_SB_LPSTR:
+ return mono_string_builder_to_utf8;
case MONO_MARSHAL_CONV_SB_LPTSTR:
+#ifdef PLATFORM_WIN32
+ return mono_string_builder_to_utf16;
+#else
return mono_string_builder_to_utf8;
+#endif
case MONO_MARSHAL_CONV_SB_LPWSTR:
return mono_string_builder_to_utf16;
case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
case MONO_MARSHAL_CONV_FTN_DEL:
return mono_ftnptr_to_delegate;
case MONO_MARSHAL_CONV_LPSTR_SB:
+ return mono_string_utf8_to_builder;
case MONO_MARSHAL_CONV_LPTSTR_SB:
+#ifdef PLATFORM_WIN32
+ return mono_string_utf16_to_builder;
+#else
return mono_string_utf8_to_builder;
+#endif
case MONO_MARSHAL_CONV_LPWSTR_SB:
return mono_string_utf16_to_builder;
case MONO_MARSHAL_FREE_ARRAY:
case MONO_MARSHAL_CONV_HANDLEREF: {
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
+ mono_mb_emit_byte (mb, CEE_ADD);
mono_mb_emit_byte (mb, CEE_LDIND_I);
mono_mb_emit_byte (mb, CEE_STIND_I);
break;
// create unmanaged wrapper
mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
- sig_native = signature_cominterop (method->klass->image, sig);
+ sig_native = cominterop_method_signature (method);
mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
// first arg is IntPtr for interface
mspecs[1] = NULL;
- // move return spec to last param
- if (!MONO_TYPE_IS_VOID (sig->ret))
- mspecs[sig_native->param_count] = mspecs[0];
+ if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
+ // move return spec to last param
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mspecs[sig_native->param_count] = mspecs[0];
- mspecs[0] = NULL;
+ mspecs[0] = NULL;
+ }
mono_marshal_emit_native_wrapper(mono_defaults.corlib, mb_native, sig_native, piinfo, mspecs, piinfo->addr);
static MonoMethod * ThrowExceptionForHR = NULL;
static MonoMethod * GetInterface = NULL;
MonoMethod *adjusted_method;
- int hr;
int retval = 0;
int ptr_this;
int i;
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
if (!GetInterface)
GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
// add local variables
- hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
if (!MONO_TYPE_IS_VOID (sig->ret))
retval = mono_mb_add_local (mb, sig->ret);
mono_mb_emit_ldarg (mb, i);
// push managed return value as byref last argument
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
mono_mb_emit_ldloc_addr (mb, retval);
adjusted_method = cominterop_get_native_wrapper_adjusted (method);
mono_mb_emit_managed_call (mb, adjusted_method, NULL);
- // store HRESULT to check
- mono_mb_emit_stloc (mb, hr);
-
- if (!ThrowExceptionForHR)
- ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
- mono_mb_emit_ldloc (mb, hr);
- mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
+ if (!preserve_sig) {
+ if (!ThrowExceptionForHR)
+ ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
+ mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
- // load return value managed is expecting
- if (!MONO_TYPE_IS_VOID (sig->ret))
- mono_mb_emit_ldloc (mb, retval);
+ // load return value managed is expecting
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mono_mb_emit_ldloc (mb, retval);
+ }
mono_mb_emit_byte (mb, CEE_RET);
}
MonoMethodBuilder *mb;
MonoMethod *res;
GHashTable *cache;
- int pos0, pos1;
+ int pos0;
char *name;
g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
mono_mb_emit_byte (mb, CEE_LDIND_I );
mono_mb_emit_op (mb, CEE_CALLI, sig);
- pos1 = mono_mb_emit_branch (mb, CEE_BR);
+ mono_mb_emit_byte (mb, CEE_RET);
/* else [target == null] call this->method_ptr static */
mono_mb_patch_branch (mb, pos0);
mono_mb_emit_byte (mb, CEE_LDIND_I );
mono_mb_emit_op (mb, CEE_CALLI, static_sig);
- /* return */
- mono_mb_patch_branch (mb, pos1);
mono_mb_emit_byte (mb, CEE_RET);
res = mono_mb_create_and_cache (cache, sig,
"HandleRefs can not be returned from unmanaged code (or passed by ref)");
break;
}
- mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
+ mono_mb_emit_ldarg_addr (mb, argnum);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
+ mono_mb_emit_byte (mb, CEE_ADD);
mono_mb_emit_byte (mb, CEE_LDIND_I);
mono_mb_emit_stloc (mb, conv_arg);
break;
g_free (ptr [i]);
}
-void *
-mono_marshal_realloc (gpointer ptr, gpointer size)
-{
- MONO_ARCH_SAVE_REGS;
-
- return g_try_realloc (ptr, (gulong)size);
-}
-
void *
mono_marshal_string_to_utf16 (MonoString *s)
{
return (*(MonoIUnknown**)pUnk)->Release(pUnk);
}
-void*
+static void*
cominterop_get_idispatch_for_object (MonoObject* object)
{
if (!object)
case MONO_MARSHAL_CONV_STR_LPWSTR:
/* We assume this field points inside a MonoString */
break;
- case MONO_MARSHAL_CONV_STR_LPSTR:
case MONO_MARSHAL_CONV_STR_LPTSTR:
+#ifdef PLATFORM_WIN32
+ /* We assume this field points inside a MonoString
+ * on Win32 */
+ break;
+#endif
+ case MONO_MARSHAL_CONV_STR_LPSTR:
case MONO_MARSHAL_CONV_STR_BSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
case MONO_MARSHAL_CONV_STR_TBSTR:
return res;
}
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, int size)
+{
+ gpointer res;
+
+ if (ptr == NULL) {
+ mono_gc_out_of_memory ((gulong)size);
+ return NULL;
+ }
+
+#ifdef PLATFORM_WIN32
+ res = GlobalReAlloc (ptr, (gulong)size, 0);
+#else
+ res = g_try_realloc (ptr, (gulong)size);
+#endif
+ if (!res)
+ mono_gc_out_of_memory ((gulong)size);
+
+ return res;
+}
+
void
ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
{
/* FIXME: which to use? */
csig = signature_dup (method->klass->image, sig);
/* csig = mono_metadata_signature_dup (sig); */
+
+ /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
+#ifdef PLATFORM_WIN32
csig->call_convention = MONO_CALL_STDCALL;
+#else
+ csig->call_convention = MONO_CALL_C;
+#endif
csig->hasthis = 0;
csig->pinvoke = 1;
ccw_list->data = ccw;
}
else
- g_list_append (ccw_list, ccw);
+ ccw_list = g_list_append (ccw_list, ccw);
g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
/* register for finalization to clean up ccw */
mono_object_register_finalizer (object);
MonoMethod *method = iface->methods [i];
MonoMethodSignature* sig_adjusted;
MonoMethodSignature* sig = mono_method_signature (method);
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
mspecs [1] = NULL;
/* move return spec to last param */
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
mspecs [sig_adjusted->param_count] = mspecs [0];
mspecs [0] = NULL;
MonoMethodBuilder *mb;
MonoMarshalSpec **mspecs;
MonoMethodSignature *sig, *sig_native;
- MonoExceptionClause *main_clause;
+ MonoExceptionClause *main_clause = NULL;
MonoMethodHeader *header;
int pos_leave;
- int hr;
+ int hr = 0;
int i;
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
if (!get_hr_for_exception)
get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
/* create unmanaged wrapper */
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
- sig_native = signature_cominterop (method->klass->image, sig);
+ sig_native = cominterop_method_signature (method);
mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
mspecs [1] = NULL;
/* move return spec to last param */
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
mspecs [sig_native->param_count] = mspecs [0];
mspecs [0] = NULL;
- hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+ 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 = mb->pos;
+ /* try */
+ main_clause = g_new0 (MonoExceptionClause, 1);
+ main_clause->try_offset = mb->pos;
+ }
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ /* 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_ldarg (mb, sig_native->param_count-1);
/* the CCW -> object conversion */
mono_mb_emit_managed_call (mb, method, NULL);
- /* store result if we have one */
- if (!MONO_TYPE_IS_VOID (sig->ret))
- mono_mb_emit_byte (mb, CEE_STIND_REF);
+ 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));
- 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 = mb->pos - main_clause->try_offset;
- main_clause->data.catch_class = mono_defaults.object_class;
-
- /* handler code */
- main_clause->handler_offset = mb->pos;
- 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 = mb->pos - main_clause->handler_offset;
- /* end catch */
+ /* Main exception catch */
+ main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
+ main_clause->try_len = mb->pos - main_clause->try_offset;
+ main_clause->data.catch_class = mono_defaults.object_class;
+
+ /* handler code */
+ main_clause->handler_offset = mb->pos;
+ 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 = mb->pos - main_clause->handler_offset;
+ /* end catch */
- mono_mb_patch_addr (mb, pos_leave, mb->pos - (pos_leave + 4));
+ mono_mb_patch_addr (mb, pos_leave, mb->pos - (pos_leave + 4));
+
+ mono_mb_emit_ldloc (mb, hr);
+ }
- /* FIXME: need to emit try/catch block and return failure code if exception */
- mono_mb_emit_ldloc (mb, hr);
mono_mb_emit_byte (mb, CEE_RET);
mono_loader_lock ();
mono_metadata_free_marshal_spec (mspecs [i]);
g_free (mspecs);
- header = ((MonoMethodNormal *)res)->header;
- header->num_clauses = 1;
- header->clauses = main_clause;
+ if (!preserve_sig) {
+ header = ((MonoMethodNormal *)res)->header;
+ header->num_clauses = 1;
+ header->clauses = main_clause;
+ }
return res;
}
* Converts the standard string representation of a GUID
* to a 16 byte Microsoft GUID.
*/
-void
+static void
cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
gunichar2 * chars = mono_string_chars (string);
int i = 0;
g_assert (ccw);
g_assert (ccw->gc_handle);
g_assert (ccw->ref_count >= 0);
- ref_count = InterlockedIncrement (&ccw->ref_count);
+ ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
if (ref_count == 1) {
guint32 oldhandle = ccw->gc_handle;
g_assert (oldhandle);
MonoCCW* ccw = ccwe->ccw;
g_assert (ccw);
g_assert (ccw->ref_count > 0);
- ref_count = InterlockedDecrement (&ccw->ref_count);
+ ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
if (ref_count == 0) {
/* allow gc of object */
guint32 oldhandle = ccw->gc_handle;