2007-07-06 Jonathan Chambers <joncham@gmail.com>
[mono.git] / mcs / class / corlib / System / __ComObject.cs
index 83e372b86a10e5b5b695fa86fc3881c3bbf3c115..acfd093db968365cbec830b1e400fd07465fda5d 100644 (file)
@@ -53,61 +53,56 @@ namespace System
        internal class __ComObject : MarshalByRefObject
        {
                #region Sync with object-internals.h
+               IntPtr iunknown;
                IntPtr hash_table;
                #endregion
 
-               // this is used internally and for the the methods
-               // Marshal.GetComObjectData and Marshal.SetComObjectData
-               Hashtable hashtable;
-
-               [ThreadStatic]
-               static bool coinitialized;
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               internal static extern __ComObject CreateRCW (Type t);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               internal extern void Finalizer ();
+               private extern void ReleaseInterfaces ();
 
                ~__ComObject ()
                {
-                       ComInteropProxy.ReleaseComObject (this);
-                       Finalizer ();
+                       ReleaseInterfaces ();
                }
 
                public __ComObject ()
                {
-                       // call CoInitialize once per thread
-                       if (!coinitialized) {
-                               CoInitialize (IntPtr.Zero);
-                               coinitialized = true;
-                       }
-
-                       hashtable = new Hashtable ();
-
-                       IntPtr ppv;
                        Type t = GetType ();
-                       int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
-                       Marshal.ThrowExceptionForHR (hr);
-
-                       SetIUnknown (ppv);
+                       ObjectCreationDelegate ocd = ExtensibleClassFactory.GetObjectCreationCallback (t);
+                       if (ocd != null) {
+                               iunknown = ocd (IntPtr.Zero);
+                               if (iunknown == IntPtr.Zero)
+                                       throw new COMException (string.Format("ObjectCreationDelegate for type {0} failed to return a valid COM object", t));
+                       } else {
+                               int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
+                               Marshal.ThrowExceptionForHR (hr);
+                       }
                }
 
-               internal __ComObject (Type t)
-               {
-                       // call CoInitialize once per thread
-                       if (!coinitialized) {
-                               CoInitialize (IntPtr.Zero);
-                               coinitialized = true;
+               internal __ComObject (Type t) {
+                       ObjectCreationDelegate ocd = ExtensibleClassFactory.GetObjectCreationCallback (t);
+                       if (ocd != null) {
+                               iunknown = ocd (IntPtr.Zero);
+                               if (iunknown == IntPtr.Zero)
+                                       throw new COMException (string.Format("ObjectCreationDelegate for type {0} failed to return a valid COM object", t));
                        }
+                       else {
+                               int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
+                               Marshal.ThrowExceptionForHR (hr);
+                       }
+               }
 
-                       hashtable = new Hashtable ();
-
-                       IntPtr ppv;
-                       int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
+               internal __ComObject (IntPtr pItf)
+               {
+                       Guid iid = IID_IUnknown;
+                       int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown);
                        Marshal.ThrowExceptionForHR (hr);
-
-                       SetIUnknown (ppv);
                }
 
-               private Guid GetCLSID (Type t)
+               private static Guid GetCLSID (Type t)
                {
                        if (t.IsImport)
                                return t.GUID;
@@ -122,65 +117,32 @@ namespace System
                        throw new COMException ("Could not find base COM type for type " + t.ToString());
                }
 
-               internal __ComObject (IntPtr pItf)
-               {
-                       hashtable = new Hashtable ();
-                       IntPtr ppv;
-                       Guid iid = IID_IUnknown;
-                       int hr = Marshal.QueryInterface (pItf, ref iid, out ppv);
-                       Marshal.ThrowExceptionForHR (hr);
-                       SetIUnknown (ppv);
-        }
-
-               public Hashtable Hashtable
-               {
-                       get
-                       {
-                               return hashtable;
-                       }
-               }
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               internal static extern __ComObject CreateRCW (Type t);
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern void SetIUnknown (IntPtr t);
-
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern IntPtr GetIUnknown ();
+               internal extern IntPtr GetInterfaceInternal (Type t, bool throwException);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern IntPtr FindInterface (Type t);
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern void CacheInterface (Type t, IntPtr pItf);
+               internal IntPtr GetInterface (Type t, bool throwException) {
+                       CheckIUnknown ();
+                       return GetInterfaceInternal (t, throwException);
+               }
 
                internal IntPtr GetInterface(Type t)
                {
-                       // this is needed later and checks to see if we are
-                       // a valid RCW
-                       IntPtr pUnk = IUnknown;
-                       IntPtr pItf = FindInterface (t);
-                       if (pItf != IntPtr.Zero) {
-                               return pItf;
-                       }
+                       return GetInterface (t, true);
+               }
 
-                       Guid iid = t.GUID;
-                       IntPtr ppv;
-                       int hr = Marshal.QueryInterface (pUnk, ref iid, out ppv);
-                       Marshal.ThrowExceptionForHR (hr);
-                       CacheInterface (t, ppv);
-                       return ppv;
+               private void CheckIUnknown ()
+               {
+                       if (iunknown == IntPtr.Zero)
+                               throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
                }
 
                internal IntPtr IUnknown
                {
                        get
                        {
-                               IntPtr pUnk = GetIUnknown();
-                               if (pUnk == IntPtr.Zero)
+                               if (iunknown == IntPtr.Zero)
                                        throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
-                               return pUnk;
+                               return iunknown;
                        }
                }
 
@@ -188,7 +150,7 @@ namespace System
                {
                        get
                        {
-                               IntPtr pUnk = GetInterface (typeof (IDispatchMono));
+                               IntPtr pUnk = GetInterface (typeof (IDispatch));
                                if (pUnk == IntPtr.Zero)
                                        throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
                                return pUnk;
@@ -211,33 +173,26 @@ namespace System
                        }
                }
 
-               [Guid ("00020400-0000-0000-C000-000000000046")]
-               internal interface IDispatchMono
-               {
-               }
-
                public override bool Equals (object obj)
                {
+                       CheckIUnknown ();
                        if (obj == null)
                                return false;
 
                        __ComObject co = obj as __ComObject;
                        if ((object)co == null)
                                return false;
-
-                       return (IUnknown == co.IUnknown);
+                       return (iunknown == co.IUnknown);
                }
 
                public override int GetHashCode ()
                {
+                       CheckIUnknown ();
                        // not what MS seems to do, 
                        // but IUnknown is identity in COM
-                       return IUnknown.ToInt32 ();
+                       return iunknown.ToInt32 ();
                }
 
-               [DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall)]
-               static extern int CoInitialize (IntPtr pvReserved);
-
                [DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, PreserveSig = true)]
                static extern int CoCreateInstance (
                   [In, MarshalAs (UnmanagedType.LPStruct)] Guid rclsid,