2006-07-28 Jonathan Chambers <joncham@gmail.com>
authorJonathan Chambers <joncham@gmail.com>
Fri, 28 Jul 2006 19:11:23 +0000 (19:11 -0000)
committerJonathan Chambers <joncham@gmail.com>
Fri, 28 Jul 2006 19:11:23 +0000 (19:11 -0000)
Added support for marshalling COM RCWs.

svn path=/trunk/mono/; revision=63102

mono/metadata/ChangeLog
mono/metadata/marshal.c
mono/metadata/object.c
mono/tests/ChangeLog
mono/tests/cominterop.cs
mono/tests/libtest.c

index f552b8ef17e685f4084cd5b3f4b97c96bf6c2fd0..ce5680672b0ce0f64077c4b651ce805e82775967 100644 (file)
@@ -1,3 +1,9 @@
+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>
 
index fe8af85253838eed881729bc4602c4bee3ff0f08..7b65c420c13e1feeccb0a15f85c41257ba06e07c 100644 (file)
@@ -2865,22 +2865,22 @@ cominterop_get_native_wrapper (MonoMethod *method)
 {
        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.
                 */
@@ -2947,18 +2947,20 @@ cominterop_get_native_wrapper (MonoMethod *method)
                        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;
 }
 
 /**
@@ -5714,8 +5716,39 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                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);
@@ -5828,9 +5861,34 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                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;
@@ -9136,8 +9194,9 @@ void
 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
@@ -9151,7 +9210,7 @@ ves_icall_System_ComObject_FindInterface (MonoComObject* obj, MonoReflectionType
 
        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
@@ -9163,14 +9222,15 @@ ves_icall_System_ComObject_CacheInterface (MonoComObject* obj, MonoReflectionTyp
 
        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);
 }
 
index a9ff237589a894e8df4223ee3720f09dc9a0ea75..f7152ca8cad5ca1ae1dfffd7e01c61012709b78e 100644 (file)
@@ -1278,7 +1278,7 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
                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);
index 8780a91da8a3712d7f8519aa32acc1ea8d89617d..2236bc78ce8faf4ee4c4a44bcd7f3c07679d5885 100644 (file)
@@ -1,3 +1,10 @@
+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.
index f86ca2b213c13f1ff21f0f263a60b0e375bf7883..329f88d3a988fc0d67a6ad9578af078d757dc24b 100644 (file)
@@ -92,114 +92,149 @@ public class Tests
     [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;
        }
@@ -212,6 +247,10 @@ public class Tests
         [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
+}
index f2ffc9a996eaeb0481c071c96b2a3fea39989429..27ed6ec81af5617fe9facf1d9d1dfa40c80eb4fb 100644 (file)
@@ -2040,10 +2040,6 @@ mono_test_marshal_variant_out_bstr(VARIANT* variant)
        return 0;
 }
 
-#endif
-
-#ifdef NOT_YET
-
 #ifdef _MSC_VER
 #define COM_STDCALL __stdcall
 #else
@@ -2059,6 +2055,8 @@ typedef struct
        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
@@ -2095,19 +2093,42 @@ int COM_STDCALL Subtract(MonoComObject* pUnk, int a, int b, int* c)
        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;
 }