Added support for marshalling COM RCWs.
svn path=/trunk/mono/; revision=63102
+2006-07-28 Jonathan Chambers <joncham@gmail.com>
+
+ * object.c (mono_remote_class_vtable): Need to create proxy vtable
+ entries for __ComObject type in addition to ComImport types.
+ * marshal.c: Added support for marshalling COM RCWs. Fixed warning
+ about hash table.
Fri Jul 28 19:04:34 CEST 2006 Paolo Molaro <lupus@ximian.com>
{
MonoMethod *res;
GHashTable *cache;
+ MonoMethodBuilder *mb;
+ MonoMethodSignature *sig, *csig;
+
g_assert (method);
cache = method->klass->image->cominterop_wrapper_cache;
if ((res = mono_marshal_find_in_cache (cache, method)))
return res;
+ sig = mono_method_signature (method);
+ mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
+
/* if method klass is import, that means method
* is really a com call. let interop system emit it.
*/
if (MONO_CLASS_IS_IMPORT(method->klass)) {
- MonoMethodBuilder *mb;
- MonoMethodSignature *sig, *csig;
-
- sig = mono_method_signature (method);
- mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
-
/* FIXME: we have to call actual class .ctor
* instead of just __ComObject .ctor.
*/
mono_mb_emit_byte (mb, CEE_RET);
}
- csig = signature_dup (method->klass->image, sig);
- csig->pinvoke = 0;
- res = mono_mb_create_and_cache (cache, method,
- mb, csig, csig->param_count + 16);
- mono_mb_free (mb);
- return res;
+
}
/* Does this case ever get hit? */
else {
- g_assert(0);
- return NULL;
+ char *msg = g_strdup ("non imported interfaces on \
+ imported classes is not yet implemented.");
+ mono_mb_emit_exception (mb, "NotSupportedException", msg);
}
+ csig = signature_dup (method->klass->image, sig);
+ csig->pinvoke = 0;
+ res = mono_mb_create_and_cache (cache, method,
+ mb, csig, csig->param_count + 16);
+ mono_mb_free (mb);
+ return res;
}
/**
else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
spec->native == MONO_NATIVE_IDISPATCH ||
spec->native == MONO_NATIVE_INTERFACE)) {
- char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
- mono_mb_emit_exception_marshal_directive (mb, msg);
+ mono_mb_emit_ptr (mb, 0);
+ mono_mb_emit_stloc (mb, conv_arg);
+
+ if (t->byref) {
+ /* we dont need any conversions for out parameters */
+ if (t->attrs & PARAM_ATTRIBUTE_OUT)
+ break;
+ else {
+ char *msg = g_strdup_printf ("non out object references are no implemented");
+ MonoException *exc = mono_get_exception_not_implemented (msg);
+ g_warning (msg);
+ g_free (msg);
+ mono_raise_exception (exc);
+
+ }
+ } else {
+ static MonoMethod* GetInterface = NULL;
+
+ if (!GetInterface)
+ GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+ /* load the RCW from the ComInteropProxy*/
+ 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);
+ mono_mb_emit_stloc (mb, conv_arg);
+ }
}
else if (klass->delegate) {
g_assert (!t->byref);
if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
spec->native == MONO_NATIVE_IDISPATCH ||
spec->native == MONO_NATIVE_INTERFACE)) {
- char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
- mono_mb_emit_exception_marshal_directive (mb, msg);
- break;
+ if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
+ static MonoClass* com_interop_proxy_class = NULL;
+ 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);
+
+ real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
+
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
+ mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
+ mono_mb_emit_stloc (mb, real_proxy);
+
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc (mb, real_proxy);
+ mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
+ if (klass && klass != mono_defaults.object_class) {
+ mono_mb_emit_byte (mb, CEE_CASTCLASS);
+ mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
+ }
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ }
+ break;
}
if (klass == mono_defaults.stringbuilder_class) {
gboolean need_free;
ves_icall_System_ComObject_Finalizer(MonoComObject* obj)
{
g_assert(obj);
- g_assert(obj->itf_hash);
- g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL);
+ if (obj->itf_hash)
+ g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL);
+ obj->itf_hash = NULL;
}
#define MONO_IUNKNOWN_INTERFACE_SLOT 0
klass = mono_class_from_mono_type (type->type);
- return g_hash_table_lookup (obj->itf_hash, klass->interface_id);
+ return g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER (klass->interface_id));
}
void
klass = mono_class_from_mono_type (type->type);
- g_hash_table_insert (obj->itf_hash, klass->interface_id, pItf);
+ g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER (klass->interface_id), pItf);
}
gpointer
ves_icall_System_ComObject_GetIUnknown (MonoComObject* obj)
{
g_assert(obj);
- g_assert(obj->itf_hash);
+ if (!obj->itf_hash)
+ return NULL;
return g_hash_table_lookup (obj->itf_hash, MONO_IUNKNOWN_INTERFACE_SLOT);
}
MonoClass *klass;
type = ((MonoReflectionType *)rp->class_to_proxy)->type;
klass = mono_class_from_mono_type (type);
- if (MONO_CLASS_IS_IMPORT(klass) && !mono_class_vtable (mono_domain_get (), klass)->remote)
+ if ((MONO_CLASS_IS_IMPORT(klass) || 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);
+2006-07-28 Jonathan Chambers <joncham@gmail.com>
+
+ * cominterop.cs: Added COM Interop object marshalling tests;
+ enabled on windows only.
+ * libtest.c: Added COM Interop object marshalling tests;
+ enabled on windows only.
+
2006-07-27 Zoltan Varga <vargaz@gmail.com>
* libtest.c: Add a newline at the EOF.
[DllImport ("libtest")]
public static extern int mono_test_marshal_com_object_ref_count (IntPtr pUnk);
- public static int Main() {
+ public static int Main ()
+ {
+ int i = Main2 ();
+ Console.WriteLine (i);
+ return i;
+ }
+ public static int Main2() {
bool isWindows = !(((int)Environment.OSVersion.Platform == 4) ||
((int)Environment.OSVersion.Platform == 128));
- if (isWindows) {
- #region BSTR Tests
-
- string str;
- if (mono_test_marshal_bstr_in ("mono_test_marshal_bstr_in") != 0)
- return 1;
- if (mono_test_marshal_bstr_out (out str) != 0 || str != "mono_test_marshal_bstr_out")
- return 2;
-
- #endregion // BSTR Tests
-
- #region VARIANT Tests
-
- object obj;
- if (mono_test_marshal_variant_in_sbyte ((sbyte)100) != 0)
- return 3;
- if (mono_test_marshal_variant_in_byte ((byte)100) != 0)
- return 4;
- if (mono_test_marshal_variant_in_short ((short)314) != 0)
- return 5;
- if (mono_test_marshal_variant_in_ushort ((ushort)314) != 0)
- return 6;
- if (mono_test_marshal_variant_in_int ((int)314) != 0)
- return 7;
- if (mono_test_marshal_variant_in_uint ((uint)314) != 0)
- return 8;
- if (mono_test_marshal_variant_in_long ((long)314) != 0)
- return 9;
- if (mono_test_marshal_variant_in_ulong ((ulong)314) != 0)
- return 10;
- if (mono_test_marshal_variant_in_float ((float)3.14) != 0)
- return 11;
- if (mono_test_marshal_variant_in_double ((double)3.14) != 0)
- return 12;
- if (mono_test_marshal_variant_in_bstr ("PI") != 0)
- return 13;
- if (mono_test_marshal_variant_out_sbyte (out obj) != 0 || (sbyte)obj != 100)
- return 14;
- if (mono_test_marshal_variant_out_byte (out obj) != 0 || (byte)obj != 100)
- return 15;
- if (mono_test_marshal_variant_out_short (out obj) != 0 || (short)obj != 314)
- return 16;
- if (mono_test_marshal_variant_out_ushort (out obj) != 0 || (ushort)obj != 314)
- return 17;
- if (mono_test_marshal_variant_out_int (out obj) != 0 || (int)obj != 314)
- return 18;
- if (mono_test_marshal_variant_out_uint (out obj) != 0 || (uint)obj != 314)
- return 19;
- if (mono_test_marshal_variant_out_long (out obj) != 0 || (long)obj != 314)
- return 20;
- if (mono_test_marshal_variant_out_ulong (out obj) != 0 || (ulong)obj != 314)
- return 21;
- if (mono_test_marshal_variant_out_float (out obj) != 0 || ((float)obj - 3.14) / 3.14 > .001)
- return 22;
- if (mono_test_marshal_variant_out_double (out obj) != 0 || ((double)obj - 3.14) / 3.14 > .001)
- return 23;
- if (mono_test_marshal_variant_out_bstr (out obj) != 0 || (string)obj != "PI")
- return 24;
-
- #endregion // VARIANT Tests
- }
-#if NOT_YET
- #region Marshal COM Interop Tests
-
- IntPtr pUnk;
- if (mono_test_marshal_com_object_create (out pUnk) != 0)
- return 25;
-
- if (mono_test_marshal_com_object_ref_count (pUnk) != 1)
- return 26;
-
- if (Marshal.AddRef(pUnk) != 2)
- return 27;
-
- if (mono_test_marshal_com_object_ref_count (pUnk) != 2)
- return 28;
-
- if (Marshal.Release (pUnk) != 1)
- return 29;
-
- if (mono_test_marshal_com_object_ref_count (pUnk) != 1)
- return 30;
-
- object com_obj = Marshal.GetObjectForIUnknown (pUnk);
-
- if (com_obj == null)
- return 31;
-
- IMath imath = com_obj as IMath;
-
- if (imath == null)
- return 32;
-
- if (imath.Add(20, 10) != 30)
- return 33;
-
- if (imath.Subtract (20, 10) != 10)
- return 34;
-
- //if (mono_test_marshal_com_object_destroy (pUnk) != 0)
- // return 31;
-
- #endregion // Marshal COM Interop Tests
-#endif
+ if (isWindows) {
+ #region BSTR Tests
+
+ string str;
+ if (mono_test_marshal_bstr_in ("mono_test_marshal_bstr_in") != 0)
+ return 1;
+ if (mono_test_marshal_bstr_out (out str) != 0 || str != "mono_test_marshal_bstr_out")
+ return 2;
+
+ #endregion // BSTR Tests
+
+ #region VARIANT Tests
+
+ object obj;
+ if (mono_test_marshal_variant_in_sbyte ((sbyte)100) != 0)
+ return 3;
+ if (mono_test_marshal_variant_in_byte ((byte)100) != 0)
+ return 4;
+ if (mono_test_marshal_variant_in_short ((short)314) != 0)
+ return 5;
+ if (mono_test_marshal_variant_in_ushort ((ushort)314) != 0)
+ return 6;
+ if (mono_test_marshal_variant_in_int ((int)314) != 0)
+ return 7;
+ if (mono_test_marshal_variant_in_uint ((uint)314) != 0)
+ return 8;
+ if (mono_test_marshal_variant_in_long ((long)314) != 0)
+ return 9;
+ if (mono_test_marshal_variant_in_ulong ((ulong)314) != 0)
+ return 10;
+ if (mono_test_marshal_variant_in_float ((float)3.14) != 0)
+ return 11;
+ if (mono_test_marshal_variant_in_double ((double)3.14) != 0)
+ return 12;
+ if (mono_test_marshal_variant_in_bstr ("PI") != 0)
+ return 13;
+ if (mono_test_marshal_variant_out_sbyte (out obj) != 0 || (sbyte)obj != 100)
+ return 14;
+ if (mono_test_marshal_variant_out_byte (out obj) != 0 || (byte)obj != 100)
+ return 15;
+ if (mono_test_marshal_variant_out_short (out obj) != 0 || (short)obj != 314)
+ return 16;
+ if (mono_test_marshal_variant_out_ushort (out obj) != 0 || (ushort)obj != 314)
+ return 17;
+ if (mono_test_marshal_variant_out_int (out obj) != 0 || (int)obj != 314)
+ return 18;
+ if (mono_test_marshal_variant_out_uint (out obj) != 0 || (uint)obj != 314)
+ return 19;
+ if (mono_test_marshal_variant_out_long (out obj) != 0 || (long)obj != 314)
+ return 20;
+ if (mono_test_marshal_variant_out_ulong (out obj) != 0 || (ulong)obj != 314)
+ return 21;
+ if (mono_test_marshal_variant_out_float (out obj) != 0 || ((float)obj - 3.14) / 3.14 > .001)
+ return 22;
+ if (mono_test_marshal_variant_out_double (out obj) != 0 || ((double)obj - 3.14) / 3.14 > .001)
+ return 23;
+ if (mono_test_marshal_variant_out_bstr (out obj) != 0 || (string)obj != "PI")
+ return 24;
+
+ #endregion // VARIANT Tests
+
+ #region Marshal COM Interop Tests
+
+ IntPtr pUnk;
+ if (mono_test_marshal_com_object_create (out pUnk) != 0)
+ return 25;
+
+ if (mono_test_marshal_com_object_ref_count (pUnk) != 1)
+ return 26;
+
+ if (Marshal.AddRef (pUnk) != 2)
+ return 27;
+
+ if (mono_test_marshal_com_object_ref_count (pUnk) != 2)
+ return 28;
+
+ if (Marshal.Release (pUnk) != 1)
+ return 29;
+
+ if (mono_test_marshal_com_object_ref_count (pUnk) != 1)
+ return 30;
+
+ object com_obj = Marshal.GetObjectForIUnknown (pUnk);
+
+ if (com_obj == null)
+ return 31;
+
+ IMath imath = com_obj as IMath;
+
+ if (imath == null)
+ return 32;
+
+ if (imath.Add (20, 10) != 30)
+ return 33;
+
+ if (imath.Subtract (20, 10) != 10)
+ return 34;
+
+ IMath same1, same2;
+ imath.Same (out same1);
+ imath.Same (out same2);
+ if (same1 != same2)
+ return 35;
+
+ if (!same1.Equals (same2))
+ return 36;
+
+ IMath diff1, diff2;
+ imath.Different (out diff1);
+ imath.Different (out diff2);
+ if (diff1 == diff2)
+ return 37;
+
+ if (diff1.Equals (diff2))
+ return 38;
+
+ // same1 & same2 share a RCW
+ if (Marshal.ReleaseComObject (same1) != 1)
+ return 39;
+
+ if (Marshal.ReleaseComObject (same2) != 0)
+ return 40;
+
+
+ if (Marshal.ReleaseComObject (diff1) != 0 ||
+ Marshal.ReleaseComObject (diff2) != 0)
+ return 41;
+
+
+ //if (mono_test_marshal_com_object_destroy (pUnk) != 0)
+ // return 31;
+ #endregion // Marshal COM Interop Tests
+ }
return 0;
}
[MethodImplAttribute (MethodImplOptions.InternalCall,MethodCodeType=MethodCodeType.Runtime)]
int Add (int a, int b);
[MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
- int Subtract (int a, int b);
+ int Subtract (int a, int b);
+ [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ int Same ([MarshalAs(UnmanagedType.Interface)] out IMath imath);
+ [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+ int Different ([MarshalAs (UnmanagedType.Interface)] out IMath imath);
}
-}
\ No newline at end of file
+}
return 0;
}
-#endif
-
-#ifdef NOT_YET
-
#ifdef _MSC_VER
#define COM_STDCALL __stdcall
#else
int (COM_STDCALL *Release)(MonoComObject* pUnk);
int (COM_STDCALL *Add)(MonoComObject* pUnk, int a, int b, int* c);
int (COM_STDCALL *Subtract)(MonoComObject* pUnk, int a, int b, int* c);
+ int (COM_STDCALL *Same)(MonoComObject* pUnk, MonoComObject* *pOut);
+ int (COM_STDCALL *Different)(MonoComObject* pUnk, MonoComObject* *pOut);
} MonoIUnknown;
struct MonoComObject
return 0;
}
-STDCALL int
-mono_test_marshal_com_object_create(MonoComObject* *pUnk)
+static void create_com_object (MonoComObject** pOut);
+static MonoComObject* same_com_object = NULL;
+
+int COM_STDCALL Same(MonoComObject* pUnk, MonoComObject** pOut)
+{
+ if (!same_com_object)
+ create_com_object (&same_com_object);
+ *pOut = same_com_object;
+ return 0;
+}
+
+int COM_STDCALL Different(MonoComObject* pUnk, MonoComObject** pOut)
{
- *pUnk = g_new0 (MonoComObject, 1);
- (*pUnk)->vtbl = g_new0 (MonoIUnknown, 1);
+ create_com_object (pOut);
+ return 0;
+}
- (*pUnk)->m_ref = 1;
- (*pUnk)->vtbl->QueryInterface = MonoQueryInterface;
- (*pUnk)->vtbl->AddRef = MonoAddRef;
- (*pUnk)->vtbl->Release = MonoRelease;
- (*pUnk)->vtbl->Add = Add;
- (*pUnk)->vtbl->Subtract = Subtract;
+static void create_com_object (MonoComObject** pOut)
+{
+ *pOut = g_new0 (MonoComObject, 1);
+ (*pOut)->vtbl = g_new0 (MonoIUnknown, 1);
+ (*pOut)->m_ref = 1;
+ (*pOut)->vtbl->QueryInterface = MonoQueryInterface;
+ (*pOut)->vtbl->AddRef = MonoAddRef;
+ (*pOut)->vtbl->Release = MonoRelease;
+ (*pOut)->vtbl->Add = Add;
+ (*pOut)->vtbl->Subtract = Subtract;
+ (*pOut)->vtbl->Same = Same;
+ (*pOut)->vtbl->Different = Different;
+}
+
+STDCALL int
+mono_test_marshal_com_object_create(MonoComObject* *pUnk)
+{
+ create_com_object (pUnk);
return 0;
}