X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem%2F__ComObject.cs;h=18f0c43ec49761d5097b6a32b97c2910c4031816;hb=f91af83b92d7ed1858f419bb5bc5d0d4cab5429c;hp=83e372b86a10e5b5b695fa86fc3881c3bbf3c115;hpb=93703b4ef8bdcf1d6cf336e14f534454221730c5;p=mono.git diff --git a/mcs/class/corlib/System/__ComObject.cs b/mcs/class/corlib/System/__ComObject.cs index 83e372b86a1..18f0c43ec49 100644 --- a/mcs/class/corlib/System/__ComObject.cs +++ b/mcs/class/corlib/System/__ComObject.cs @@ -32,10 +32,12 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +#if !FULL_AOT_RUNTIME using Mono.Interop; using System.Collections; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using System.Threading; namespace System { @@ -50,64 +52,85 @@ namespace System // many times that obj.GetType().FullName == "System.__ComObject" and // Type.GetType("System.__ComObject") may be used. + [StructLayout (LayoutKind.Sequential)] internal class __ComObject : MarshalByRefObject { +#pragma warning disable 169 #region Sync with object-internals.h + IntPtr iunknown; IntPtr hash_table; + SynchronizationContext synchronization_context; #endregion +#pragma warning restore 169 - // 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 (); + { + if (synchronization_context != null) + synchronization_context.Post ((state) => ReleaseInterfaces (), this); + else + ReleaseInterfaces (); } public __ComObject () { - // call CoInitialize once per thread - if (!coinitialized) { - CoInitialize (IntPtr.Zero); - coinitialized = true; - } + Initialize (GetType ()); + } - hashtable = new Hashtable (); + internal __ComObject (Type t) { + Initialize (t); + } - IntPtr ppv; - Type t = GetType (); - int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv); + internal __ComObject (IntPtr pItf) + { + InitializeApartmentDetails (); + Guid iid = IID_IUnknown; + int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown); Marshal.ThrowExceptionForHR (hr); - - SetIUnknown (ppv); } - internal __ComObject (Type t) + internal void Initialize (Type t) { - // call CoInitialize once per thread - if (!coinitialized) { - CoInitialize (IntPtr.Zero); - coinitialized = true; + InitializeApartmentDetails (); + // Guard multiple invocation. + if (iunknown != IntPtr.Zero) + return; + + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (t.TypeHandle); + + 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); - Marshal.ThrowExceptionForHR (hr); - - SetIUnknown (ppv); + private void InitializeApartmentDetails () + { + // Only synchronization_context if thread is STA. + if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) + return; + + synchronization_context = SynchronizationContext.Current; + + // Check whether the current context is a plain SynchronizationContext object + // and handle this as if no context was set at all. + if (synchronization_context != null && + synchronization_context.GetType () == typeof(SynchronizationContext)) + synchronization_context = null; } - private Guid GetCLSID (Type t) + private static Guid GetCLSID (Type t) { if (t.IsImport) return t.GUID; @@ -122,65 +145,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 +178,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 +201,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, @@ -247,3 +230,4 @@ namespace System out IntPtr pUnk); } } +#endif