* class.c (mono_class_setup_parent): setup is_com_object during class initialization.
* object.c (mono_remote_class_vtable/mono_object_new_specific): Changed checks
to use is_com_object instead of MONO_CLASS_IS_IMPORT() macro.
* class-internals.h: add is_com_object to class structure.
* marshal.c: Fixed marshalling for IDispatch and IUnknown, added
null checks to COM object marshalling. Fix .ctor call on RCW.
* icall.c: Added icall implementation for MonoType.IsCOMObjectImpl.
* mini.c: Don't verify COM proxy invoke calls
All code is contributed under the MIT/X11 license.
svn path=/trunk/mono/; revision=63629
+2006-08-10 Jonathan Chambers <joncham@gmail.com>
+
+ * class.c (mono_class_setup_parent): setup is_com_object during class initialization.
+ * object.c (mono_remote_class_vtable/mono_object_new_specific): Changed checks
+ to use is_com_object instead of MONO_CLASS_IS_IMPORT() macro.
+ * class-internals.h: add is_com_object to class structure.
+ * marshal.c: Fixed marshalling for IDispatch and IUnknown, added
+ null checks to COM object marshalling. Fix .ctor call on RCW.
+ * icall.c: Added icall implementation for MonoType.IsCOMObjectImpl.
+
+ All code is contributed under the MIT/X11 license.
+
2006-08-09 Dick Porter <dick@ximian.com>
* monitor.c (mono_monitor_cleanup): mono_monitor_cleanup() is
/* next byte */
guint has_static_refs : 1; /* it has static fields that are GC-tracked */
guint no_special_static_fields : 1; /* has no thread/context static fields */
+ /* directly or indirectly derives from ComImport attributed class.
+ * this means we need to create a proxy for instances of this class
+ * for COM Interop. set this flag on loading so all we need is a quick check
+ * during object creation rather than having to traverse supertypes
+ */
+ guint is_com_object : 1;
guint8 exception_type; /* MONO_EXCEPTION_* */
void* exception_data; /* Additional information about the exception */
if (!MONO_CLASS_IS_INTERFACE (class)) {
/* Imported COM Objects always derive from __ComObject. */
- if (MONO_CLASS_IS_IMPORT (class) && parent == mono_defaults.object_class)
- parent = mono_defaults.com_object_class;
+ if (MONO_CLASS_IS_IMPORT (class)) {
+ if (parent == mono_defaults.object_class)
+ parent = mono_defaults.com_object_class;
+ }
class->parent = parent;
+
if (!parent)
g_assert_not_reached (); /* FIXME */
class->marshalbyref = parent->marshalbyref;
class->contextbound = parent->contextbound;
class->delegate = parent->delegate;
+ if (MONO_CLASS_IS_IMPORT (class))
+ class->is_com_object = 1;
+ else
+ class->is_com_object = parent->is_com_object;
if (system_namespace) {
if (*class->name == 'M' && !strcmp (class->name, "MarshalByRefObject"))
return type->type->byref;
}
+static MonoBoolean
+ves_icall_type_iscomobject (MonoReflectionType *type)
+{
+ MonoClass *klass = mono_class_from_mono_type (type->type);
+ MONO_ARCH_SAVE_REGS;
+
+ return (klass && klass->is_com_object);
+}
+
static MonoReflectionModule*
ves_icall_MonoType_get_Module (MonoReflectionType *type)
{
{"GetPropertiesByName", ves_icall_Type_GetPropertiesByName},
{"InternalGetEvent", ves_icall_MonoType_GetEvent},
{"IsByRefImpl", ves_icall_type_isbyref},
+ {"IsCOMObjectImpl", ves_icall_type_iscomobject},
{"IsPointerImpl", ves_icall_type_ispointer},
{"IsPrimitiveImpl", ves_icall_type_isprimitive},
{"getFullName", ves_icall_System_MonoType_getFullName},
guint32 offset = 7;
guint32 slot = method->slot;
GPtrArray *ifaces;
- MonoClass *ic;
+ MonoClass *ic = method->klass;
int i;
ifaces = mono_class_get_implemented_interfaces (method->klass);
if (!interface_type_attribute)
interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
- cinfo = mono_custom_attrs_from_class (method->klass);
+ cinfo = mono_custom_attrs_from_class (ic);
if (cinfo) {
itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
if (!cinfo->cached)
mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
}
+ if (!strcmp(method->name, ".ctor")) {
+ static MonoClass *com_interop_proxy_class = NULL;
+ static MonoMethod *cache_proxy = NULL;
+
+ if (!com_interop_proxy_class)
+ com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
+ if (!cache_proxy)
+ cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
+
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ mono_mb_emit_managed_call (mb, cache_proxy, NULL);
+ }
+
emit_thread_interrupt_checkpoint (mb);
-
+
mono_mb_emit_byte (mb, CEE_RET);
res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
return method;
/* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */
- if ((MONO_CLASS_IS_IMPORT(method->klass) || method->klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), method->klass)->remote)
+ if ((method->klass->is_com_object || method->klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), method->klass)->remote)
return cominterop_get_invoke(method);
sig = signature_no_pinvoke (method);
}
} else {
- static MonoMethod* GetInterface = NULL;
-
- if (!GetInterface)
- GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+ guint32 pos_failed = 0;
+ mono_mb_emit_ldarg (mb, argnum);
+ // if null just break, conv arg was already inited to 0
+ pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
mono_mb_emit_byte (mb, CEE_LDIND_REF);
mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
mono_mb_emit_byte (mb, CEE_LDIND_REF);
- mono_mb_emit_ptr (mb, t);
- mono_mb_emit_icall (mb, type_from_handle);
- mono_mb_emit_managed_call (mb, GetInterface, NULL);
+ if (klass && klass != mono_defaults.object_class) {
+ static MonoMethod* GetInterface = NULL;
+
+ if (!GetInterface)
+ GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+ mono_mb_emit_ptr (mb, t);
+ mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_managed_call (mb, GetInterface, NULL);
+ }
+ else if (spec->native == MONO_NATIVE_IUNKNOWN) {
+ static MonoProperty* iunknown = NULL;
+
+ if (!iunknown)
+ iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
+ mono_mb_emit_managed_call (mb, iunknown->get, NULL);
+ }
+ else if (spec->native == MONO_NATIVE_IDISPATCH) {
+ static MonoProperty* idispatch = NULL;
+
+ if (!idispatch)
+ idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
+ mono_mb_emit_managed_call (mb, idispatch->get, NULL);
+ }
+ else {
+ }
mono_mb_emit_stloc (mb, conv_arg);
+
+ // case if null
+ mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
}
}
else if (klass->delegate) {
static MonoMethod* com_interop_proxy_get_proxy = NULL;
static MonoMethod* get_transparent_proxy = NULL;
int real_proxy;
- com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
- com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
- get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+ guint32 pos_failed = 0;
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+ mono_mb_emit_ldloc (mb, conv_arg);
+ pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+ if (!com_interop_proxy_class)
+ com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
+ if (!com_interop_proxy_get_proxy)
+ com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
+ if (!get_transparent_proxy)
+ get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
}
mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+ // case if null
+ mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
}
break;
}
{
MonoClass *klass;
MonoDomain *domain;
+ MonoObject *obj;
MONO_ARCH_SAVE_REGS;
* because we want to actually create object. mono_object_new checks
* to see if type is import and creates transparent proxy. this method
* is called by the corresponding real proxy to create the real RCW.
+ * Constructor does not need to be called. Will be called later.
*/
- return mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
+ obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
+ return obj;
}
static gboolean
MonoClass *klass;
type = ((MonoReflectionType *)rp->class_to_proxy)->type;
klass = mono_class_from_mono_type (type);
- if ((MONO_CLASS_IS_IMPORT(klass) || klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), klass)->remote)
+ if ((klass->is_com_object || klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), klass)->remote)
remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
else
remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
MONO_ARCH_SAVE_REGS;
- /* check for MONO_CLASS_IS_IMPORT for COM Interop */
- if (vtable->remote || MONO_CLASS_IS_IMPORT(vtable->klass))
+ /* check for is_com_object for COM Interop */
+ if (vtable->remote || vtable->klass->is_com_object)
{
gpointer pa [1];
MonoMethod *im = vtable->domain->create_proxy_for_type_method;
+2006-08-10 Jonathan Chambers <joncham@gmail.com>
+
+ * mini.c: Don't verify COM proxy invoke calls
+
+
2006-08-10 Dick Porter <dick@ximian.com>
* wapihandles.c (mini_wapi_seminfo): More info, to help track down
dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
+ dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
/* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
+2006-08-09 Jonathan Chambers <joncham@gmail.com>
+
+ * cominterop.cs: Added COM Interop tests for accessing IUnknown and IDispatch.
+ * libtest.c: Implemented QueryInterface correctly.
+
2006-08-08 Zoltan Varga <vargaz@gmail.com>
* vararg.il: Add a test for #79027.
[DllImport ("libtest")]
public static extern int mono_test_marshal_com_object_ref_count (IntPtr pUnk);
- public static int Main ()
- {
- int i = Main2 ();
- Console.WriteLine (i);
- return i;
- }
- public static int Main2() {
+ public static int Main() {
bool isWindows = !(((int)Environment.OSVersion.Platform == 4) ||
((int)Environment.OSVersion.Platform == 128));
Marshal.ReleaseComObject (diff2) != 0)
return 41;
+ IntPtr pUnk2 = Marshal.GetIUnknownForObject (imath);
+ if (pUnk2 == IntPtr.Zero)
+ return 50;
+
+ if (pUnk != pUnk2)
+ return 51;
+
+ IntPtr pDisp = Marshal.GetIDispatchForObject (imath);
+ if (pDisp == IntPtr.Zero)
+ return 52;
+
+ if (pUnk != pDisp)
+ return 53;
+
//if (mono_test_marshal_com_object_destroy (pUnk) != 0)
// return 31;
}
[ComImport()]
- [Guid ("00000000-0000-0000-0000-000000000000")]
+ [Guid ("00000000-0000-0000-0000-000000000001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMath
{
[MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Different ([MarshalAs (UnmanagedType.Interface)] out IMath imath);
}
+
+ [ComImport ()]
+ [Guid ("00000000-0000-0000-0000-000000000002")]
+ public class Foo : IMath
+ {
+ [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ public extern int Add (int a, int b);
+ [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ public extern int Subtract (int a, int b);
+ [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ public extern int Same ([MarshalAs (UnmanagedType.Interface)] out IMath imath);
+ [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ public extern int Different ([MarshalAs (UnmanagedType.Interface)] out IMath imath);
+ }
}
#ifdef WIN32
#include <windows.h>
+#include "initguid.h"
#endif
#ifdef WIN32
int m_ref;
};
+DEFINE_GUID(IID_IMath, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+DEFINE_GUID(IID_IMonoUnknown, 0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
+DEFINE_GUID(IID_IMonoDispatch, 0x00020400, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
+
int COM_STDCALL MonoQueryInterface(MonoComObject* pUnk, gpointer riid, gpointer* ppv)
{
- *ppv = pUnk;
- return 0;
+ *ppv = NULL;
+ if (!memcmp(riid, &IID_IMonoUnknown, sizeof(GUID))) {
+ *ppv = pUnk;
+ return S_OK;
+ }
+ else if (!memcmp(riid, &IID_IMath, sizeof(GUID))) {
+ *ppv = pUnk;
+ return S_OK;
+ }
+ else if (!memcmp(riid, &IID_IMonoDispatch, sizeof(GUID))) {
+ *ppv = pUnk;
+ return S_OK;
+ }
+ return E_NOINTERFACE;
}
int COM_STDCALL MonoAddRef(MonoComObject* pUnk)