2007-02-08 Jonathan Chambers <joncham@gmail.com>
authorJonathan Chambers <joncham@gmail.com>
Thu, 8 Feb 2007 19:17:49 +0000 (19:17 -0000)
committerJonathan Chambers <joncham@gmail.com>
Thu, 8 Feb 2007 19:17:49 +0000 (19:17 -0000)
        Add support for COM Callable Wrappers.

svn path=/trunk/mcs/; revision=72505

mcs/class/corlib/Mono.Interop/ChangeLog
mcs/class/corlib/Mono.Interop/ComInteropProxy.cs
mcs/class/corlib/System.Runtime.InteropServices/ChangeLog
mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
mcs/class/corlib/System/ChangeLog
mcs/class/corlib/System/__ComObject.cs

index da416597ed7648ebf15c714d01c6510c653dc8f6..00457a7a7b59ace52aac7a0861fb355dd213fc75 100644 (file)
@@ -1,3 +1,7 @@
+2007-02-08  Jonathan Chambers  <joncham@gmail.com>
+
+       * ComInteropProxy.cs: Moved some code to unmanaged and cleanup some things.
+       
 2006-10-18  Jonathan Chambers  <joncham@gmail.com>
 
        * IUnknown.cs: Added.
index 62fd313c283d89ac77afc8534939f3b34c0f44ed..c2ea56ffc437997438918e3fc80dac98f4d30895 100644 (file)
@@ -40,30 +40,19 @@ using System.Runtime.InteropServices;
 
 namespace Mono.Interop
 {
-       internal struct ComInteropProxyEntry
-       {
-               public int refcount;
-               public WeakReference weakref;
-
-               public ComInteropProxyEntry (int refcount, WeakReference weak)
-               {
-                       this.refcount = refcount;
-                       this.weakref = weak;
-               }
-       }
-
        internal class ComInteropProxy : RealProxy, IRemotingTypeInfo
     {
-        #region Sync with object-internals.h
-               private __ComObject com_object;
+        #region Sync with object-internals.h\r
+               private __ComObject com_object;\r
+               int ref_count = 1; // wrapper ref count
         #endregion
-               private string type_name;
-               static Hashtable iunknown_hashtable;
-
-               static ComInteropProxy ()
-               {
-                       iunknown_hashtable = new Hashtable ();
-               }
+               private string type_name;\r
+\r
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]\r
+               private extern static void AddProxy (IntPtr pItf, ComInteropProxy proxy);\r
+\r
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]\r
+               internal extern static ComInteropProxy FindProxy (IntPtr pItf);
 
                public ComInteropProxy (Type t)
                        : base (t)
@@ -76,8 +65,8 @@ namespace Mono.Interop
                internal void CacheProxy ()
                {
                        // called from unmanaged code after .ctor is invoked
-                       // we need .ctor to create unmanaged object and thus IUnknown property value
-                       iunknown_hashtable.Add (com_object.IUnknown, new ComInteropProxyEntry (1, new WeakReference (this)));
+                       // we need .ctor to create unmanaged object and thus IUnknown property value\r
+                       AddProxy (com_object.IUnknown, this);
                }
 
         internal ComInteropProxy (IntPtr pUnk)
@@ -88,31 +77,8 @@ namespace Mono.Interop
                internal ComInteropProxy (IntPtr pUnk, Type t)
                        : base (t)
                {
-                       com_object = new __ComObject (pUnk);
-                       iunknown_hashtable.Add (com_object.IUnknown, new ComInteropProxyEntry (1, new WeakReference (this)));
-               }
-
-               internal static int ReleaseComObject (__ComObject co)
-               {
-                       if (co == null)
-                               throw new ArgumentNullException ("co");
-                       int refcount = -1;
-                       IntPtr pUnk = co.IUnknown;
-                       object obj = iunknown_hashtable[pUnk];
-                       if (obj != null) {
-                               ComInteropProxyEntry entry = (ComInteropProxyEntry)obj;
-                               refcount = entry.refcount - 1;
-                               if (refcount == 0) {
-                                       iunknown_hashtable.Remove (pUnk);
-                                       ComInteropProxy proxy = (ComInteropProxy)entry.weakref.Target;
-                                       if (proxy != null && proxy.com_object != null)
-                                               proxy.com_object.Finalizer ();
-                               }
-                               else {
-                                       iunknown_hashtable[pUnk] = new ComInteropProxyEntry (refcount, entry.weakref);
-                               }
-                       }
-                       return refcount;
+                       com_object = new __ComObject (pUnk);\r
+                       CacheProxy ();
                }
 
                internal static ComInteropProxy GetProxy (IntPtr pItf, Type t)
@@ -120,26 +86,21 @@ namespace Mono.Interop
                        IntPtr ppv;
                        Guid iid = __ComObject.IID_IUnknown;
                        int hr = Marshal.QueryInterface (pItf, ref iid, out ppv);
-                       Marshal.ThrowExceptionForHR (hr);
-                       object obj = iunknown_hashtable[ppv];
+                       Marshal.ThrowExceptionForHR (hr);\r
+                       ComInteropProxy obj = FindProxy (ppv);
                        if (obj == null) {
                                return new ComInteropProxy (ppv);
                        }
-                       else {
-                               ComInteropProxyEntry entry = ((ComInteropProxyEntry)obj);
-                               WeakReference weak_ref = entry.weakref;
-                               object target = weak_ref.Target;
-                               if (target == null) {
-                                       return new ComInteropProxy (ppv);
-                               }
-                               iunknown_hashtable[ppv] = new ComInteropProxyEntry (entry.refcount + 1, weak_ref);
-                               return ((ComInteropProxy)target);
+                       else {\r
+                               System.Threading.Interlocked.Increment (ref obj.ref_count);\r
+                               return obj;
                        }
                }
 
                public override IMessage Invoke (IMessage msg)
                {
                        Console.WriteLine ("Invoke");
+            Console.WriteLine (System.Environment.StackTrace);
 
                        throw new Exception ("The method or operation is not implemented.");
                }
index c2a914119b1a9dc1fef0b483b07ac0f119ebcde3..b65dd4dd018ce3a4581be2906f1c816d2b78cc0f 100644 (file)
@@ -1,3 +1,13 @@
+2007-02-08  Jonathan Chambers  <joncham@gmail.com>
+
+       * Marshal.cs: Throw exceptions for AddRef, Release,
+       and QueryInterface in managed code. Implement GetComInterfaceForObject,
+       GetIDispatchForObject, GetIUnknownForObject, GetObjectForIUnknown, 
+       GetObjectsForNativeVariants, IsComObject, ReleaseComObject, and 
+       FinalReleaseComObject. Unimplement GetComObjectData and SetComObjectData
+       for now to save space and simplify __ComObject for now. MSDN states the 
+       user should never call these methods anyway.
+       
 2007-01-29  Marek Habersack  <grendello@gmail.com>
 
        * Marshal.cs: Implement a missing Marshal.Copy overload.
index f57828c67a64774603358d844eb3d9cc68f93f4a..947081265a4a9de591b53bd8d468b43092ea9054 100644 (file)
@@ -31,6 +31,7 @@
 //
 
 using Mono.Interop;
+using System.Collections;
 using System.Runtime.CompilerServices;
 using System;
 using System.Security;
@@ -67,7 +68,14 @@ namespace System.Runtime.InteropServices
 #endif
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern static int AddRef (IntPtr pUnk);
+               private extern static int AddRefInternal (IntPtr pUnk);
+
+               public static int AddRef (IntPtr pUnk)
+               {
+                       if (pUnk == IntPtr.Zero)
+                               throw new ArgumentException ("Value cannot be null.", "pUnk");
+                       return AddRefInternal (pUnk);
+               }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                public extern static IntPtr AllocCoTaskMem (int cb);
@@ -286,16 +294,22 @@ namespace System.Runtime.InteropServices
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static IntPtr GetCCW (object o, Type T);
+
+               private static IntPtr GetComInterfaceForObjectInternal (object o, Type T)
+               {
+                       if (IsComObject (o))
+                               return ((__ComObject)o).GetInterface (T);
+                       else
+                               return GetCCW (o, T);
+               }
+
                public static IntPtr GetComInterfaceForObject (object o, Type T)
                {
-                       __ComObject co = o as __ComObject;
-                       if (co == null)
-                               throw new NotSupportedException ("Only RCWs are currently supported");
-                       
-                       IntPtr pUnk = co.GetInterface (T);
-                       AddRef (pUnk);
-                       return pUnk;
+                       IntPtr pItf = GetComInterfaceForObjectInternal (o, T);
+                       AddRef (pItf);
+                       return pItf;
                }
 
 #if NET_2_0
@@ -306,18 +320,10 @@ namespace System.Runtime.InteropServices
                }
 #endif
 
+               [MonoNotSupportedAttribute ("MSDN states user code should never need to call this method.")]
                public static object GetComObjectData (object obj, object key)
                {
-                       if (obj == null)
-                               throw new ArgumentNullException ("obj");
-                       if (key == null)
-                               throw new ArgumentNullException ("key");
-
-                       __ComObject com_object = obj as __ComObject;
-                       if (com_object == null)
-                               throw new ArgumentException ("obj is not a COM object", "obj");
-
-                       return com_object.Hashtable[key];
+                       throw new NotSupportedException ("MSDN states user code should never need to call this method.");
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -370,17 +376,15 @@ namespace System.Runtime.InteropServices
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static IntPtr GetIDispatchForObjectInternal (object o);
+
                public static IntPtr GetIDispatchForObject (object o)
                {
-                       // only handle case of RCW objects for now
-                       __ComObject co = o as __ComObject;
-                       if (co != null) {
-                               IntPtr pUnk = co.IDispatch;
-                               AddRef (pUnk);
-                               return pUnk;
-                       }
-                       throw new NotImplementedException ();
+                       IntPtr pUnk = GetIDispatchForObjectInternal (o);
+                       // Internal method does not AddRef
+                       AddRef (pUnk);
+                       return pUnk;
                }
 
 #if NET_2_0
@@ -397,17 +401,15 @@ namespace System.Runtime.InteropServices
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static IntPtr GetIUnknownForObjectInternal (object o);
+
                public static IntPtr GetIUnknownForObject (object o)
                {
-                       // only handle case of RCW objects for now
-                       __ComObject co = o as __ComObject;
-                       if (co != null) {
-                               IntPtr pUnk = co.IUnknown;
-                               AddRef (pUnk);
-                               return pUnk;
-                       }
-                       throw new NotImplementedException ();
+                       IntPtr pUnk = GetIUnknownForObjectInternal (o);
+                       // Internal method does not AddRef
+                       AddRef (pUnk);
+                       return pUnk;
                }
 
 #if NET_2_0
@@ -443,10 +445,18 @@ namespace System.Runtime.InteropServices
                        Marshal.StructureToPtr(vt, pDstNativeVariant, false);
                }
 
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private static extern object GetObjectForCCW (IntPtr pUnk);
+
                public static object GetObjectForIUnknown (IntPtr pUnk)
                {
-                       ComInteropProxy proxy = ComInteropProxy.GetProxy (pUnk, typeof(__ComObject));
-                       return proxy.GetTransparentProxy ();
+                       object obj = GetObjectForCCW (pUnk);
+                       // was not a CCW
+                       if (obj == null) {
+                               ComInteropProxy proxy = ComInteropProxy.GetProxy (pUnk, typeof (__ComObject));
+                               obj = proxy.GetTransparentProxy ();
+                       }
+                       return obj;
                }
 
                public static object GetObjectForNativeVariant (IntPtr pSrcNativeVariant)
@@ -455,10 +465,15 @@ namespace System.Runtime.InteropServices
                        return vt.GetValue();
                }
 
-               [MonoTODO]
                public static object[] GetObjectsForNativeVariants (IntPtr aSrcNativeVariant, int cVars)
                {
-                       throw new NotImplementedException ();
+                       if (cVars < 0)
+                               throw new ArgumentOutOfRangeException ("cVars", "cVars cannot be a negative number.");
+                       object[] objects = new object[cVars];
+                       for (int i = 0; i < cVars; i++)
+                               objects[i] = GetObjectForNativeVariant ((IntPtr)(aSrcNativeVariant.ToInt64 () +
+                                       i * SizeOf (typeof(Variant))));
+                       return objects;
                }
 
                [MonoTODO]
@@ -570,12 +585,8 @@ namespace System.Runtime.InteropServices
                        throw new NotImplementedException ();
                }
 
-               public static bool IsComObject (object o)
-               {
-                       Type t = o.GetType ();
-                       object[] attrs = t.GetCustomAttributes (typeof (ComImportAttribute), true);
-                       return (attrs != null && attrs.Length > 0);
-               }
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               public extern static bool IsComObject (object o);
 
                [MonoTODO]
                public static bool IsTypeVisibleFromCom (Type t)
@@ -632,7 +643,14 @@ namespace System.Runtime.InteropServices
                public extern static object PtrToStructure (IntPtr ptr, Type structureType);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern static int QueryInterface (IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+               private extern static int QueryInterfaceInternal (IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+
+               public static int QueryInterface (IntPtr pUnk, ref Guid iid, out IntPtr ppv)
+               {
+                       if (pUnk == IntPtr.Zero)
+                               throw new ArgumentException ("Value cannot be null.", "pUnk");
+                       return QueryInterfaceInternal (pUnk, ref iid, out ppv);
+               }
 
                public static byte ReadByte (IntPtr ptr)
                {
@@ -741,16 +759,25 @@ namespace System.Runtime.InteropServices
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
 #endif
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern static int Release (IntPtr pUnk);
+               private extern static int ReleaseInternal (IntPtr pUnk);
+
+               public static int Release (IntPtr pUnk)
+               {
+                       if (pUnk == IntPtr.Zero)
+                               throw new ArgumentException ("Value cannot be null.", "pUnk");
+                       return ReleaseInternal (pUnk);
+               }
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static int ReleaseComObjectInternal (object co);
 
                public static int ReleaseComObject (object o)
                {
                        if (o == null)
-                               throw new ArgumentException ("o");
-                       __ComObject co = o as __ComObject;
-                       if (co == null)
-                               throw new ArgumentException ("o");
-                       return ComInteropProxy.ReleaseComObject (co);
+                               throw new ArgumentException ("Value cannot be null.", "o");
+                       if (!IsComObject (o))
+                               throw new ArgumentException ("Value must be a Com object.", "o");
+                       return ReleaseComObjectInternal (o);
                }
 
 #if NET_2_0
@@ -762,19 +789,10 @@ namespace System.Runtime.InteropServices
                        throw new NotImplementedException ();
                }
 
+               [MonoNotSupportedAttribute ("MSDN states user code should never need to call this method.")]
                public static bool SetComObjectData (object obj, object key, object data)
                {
-                       if (obj == null)
-                               throw new ArgumentNullException ("obj");
-                       if (key == null)
-                               throw new ArgumentNullException ("key");
-
-                       __ComObject com_object = obj as __ComObject;
-                       if (com_object == null)
-                               throw new ArgumentException ("obj is not a COM object", "obj");
-
-                       com_object.Hashtable[key] = data;
-                       return true;
+                       throw new NotSupportedException ("MSDN states user code should never need to call this method.");
                }
 
                public static int SizeOf (object structure)
@@ -1035,10 +1053,10 @@ namespace System.Runtime.InteropServices
                }
 
 #if NET_2_0
-               [MonoTODO]
                public static int FinalReleaseComObject (object o)
                {
-                       throw new NotImplementedException ();
+                       while (ReleaseComObject (o) != 0);
+                       return 0;
                }
 
                [MonoTODO]
index 88d3b3d8dcf271ceafa6c6d099d1f8f2b7729378..c470bb9f99235b00225e0de9191bed39e1c3f941 100644 (file)
@@ -1,3 +1,7 @@
+2007-02-08  Jonathan Chambers  <joncham@gmail.com>
+
+       * __ComObject.cs: Add IUnknown field to object. Cleanup icalls.
+       
 2007-02-03  Zoltan Varga  <vargaz@gmail.com>
 
        * BitConverter.cs (ToDouble): Fix this on big-endian machines.
index 54a76adc1db1767071833d65ae0b7c89ec83e00a..7e439be739c59226131633c688bce0b69b709070 100644 (file)
@@ -53,23 +53,28 @@ 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 extern void Finalizer ();
+               internal static extern __ComObject CreateRCW (Type t);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private static extern void AddInterface (__ComObject co, Type t, IntPtr pItf);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private static extern IntPtr FindInterface (__ComObject co, Type t);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern void ReleaseInterfaces ();
 
                ~__ComObject ()
                {
-                       ComInteropProxy.ReleaseComObject (this);
-                       Finalizer ();
+                       ReleaseInterfaces ();
                }
 
                public __ComObject ()
@@ -80,14 +85,9 @@ namespace System
                                coinitialized = true;
                        }
 
-                       hashtable = new Hashtable ();
-
-                       IntPtr ppv;
                        Type t = GetType ();
-                       int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
+                       int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
                        Marshal.ThrowExceptionForHR (hr);
-
-                       SetIUnknown (ppv);
                }
 
                internal __ComObject (Type t)
@@ -98,16 +98,18 @@ namespace System
                                coinitialized = true;
                        }
 
-                       hashtable = new Hashtable ();
-
-                       IntPtr ppv;
-                       int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
+                       int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
                        Marshal.ThrowExceptionForHR (hr);
+               }
 
-                       SetIUnknown (ppv);
+               internal __ComObject (IntPtr pItf)
+               {
+                       Guid iid = IID_IUnknown;
+                       int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown);
+                       Marshal.ThrowExceptionForHR (hr);
                }
 
-               private Guid GetCLSID (Type t)
+               private static Guid GetCLSID (Type t)
                {
                        if (t.IsImport)
                                return t.GUID;
@@ -122,65 +124,35 @@ 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 ();
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern IntPtr FindInterface (Type t);
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern void CacheInterface (Type t, IntPtr pItf);
-
                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);
+                       CheckIUnknown ();
+                       IntPtr pItf = FindInterface (this, t);
                        if (pItf != IntPtr.Zero) {
                                return pItf;
                        }
 
                        Guid iid = t.GUID;
                        IntPtr ppv;
-                       int hr = Marshal.QueryInterface (pUnk, ref iid, out ppv);
+                       int hr = Marshal.QueryInterface (iunknown, ref iid, out ppv);
                        Marshal.ThrowExceptionForHR (hr);
-                       CacheInterface (t, ppv);
+                       AddInterface (this, 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;
                        }
                }
 
@@ -213,21 +185,22 @@ namespace System
 
                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)]