// // System.__ComObject // // Authors: // Sebastien Pouliot // Kornél Pál // Jonathan Chambers // // Copyright (C) 2004 Novell (http://www.novell.com) // Copyright (C) 2005 Kornél Pál // Copyright (C) 2006 Jonathan Chambers // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // 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 { // This is a private class that is used as a generic wrapper class // for COM objects that have no specific wrapper class. // // It has no public methods, it's functionality is exposed trough // System.Runtime.InteropServices.Marshal class and can be casted to // any interface that is implemented by the wrapped COM object. // // This class is referenced in .NET Framework SDK Documentation so // 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 // keep a reference to the proxy so it doesn't get garbage collected before the RCW ComInteropProxy proxy; [MethodImplAttribute (MethodImplOptions.InternalCall)] internal static extern __ComObject CreateRCW (Type t); [MethodImplAttribute (MethodImplOptions.InternalCall)] private extern void ReleaseInterfaces (); ~__ComObject () { if (hash_table != IntPtr.Zero) { if (synchronization_context != null) synchronization_context.Post ((state) => ReleaseInterfaces (), this); else ReleaseInterfaces (); } proxy = null; } public __ComObject () { Initialize (GetType ()); } internal __ComObject (Type t) { Initialize (t); } internal __ComObject (IntPtr pItf, ComInteropProxy p) { proxy = p; InitializeApartmentDetails (); Guid iid = IID_IUnknown; int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown); Marshal.ThrowExceptionForHR (hr); } internal void Initialize (IntPtr pUnk, ComInteropProxy p) { proxy = p; InitializeApartmentDetails (); iunknown = pUnk; } internal void Initialize (Type t) { InitializeApartmentDetails (); // Guard multiple invocation. if (iunknown != IntPtr.Zero) return; iunknown = CreateIUnknown (t); } internal static IntPtr CreateIUnknown(Type t) { System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (t.TypeHandle); IntPtr iunknown; 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); } return iunknown; } 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 static Guid GetCLSID (Type t) { if (t.IsImport) return t.GUID; // look at supertypes Type super = t.BaseType; while (super != typeof (object)) { if (super.IsImport) return super.GUID; super = super.BaseType; } throw new COMException ("Could not find base COM type for type " + t.ToString()); } [MethodImplAttribute (MethodImplOptions.InternalCall)] internal extern IntPtr GetInterfaceInternal (Type t, bool throwException); internal IntPtr GetInterface (Type t, bool throwException) { CheckIUnknown (); return GetInterfaceInternal (t, throwException); } internal IntPtr GetInterface(Type t) { return GetInterface (t, true); } 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 { if (iunknown == IntPtr.Zero) throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used."); return iunknown; } } internal IntPtr IDispatch { get { 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; } } internal static Guid IID_IUnknown { get { return new Guid("00000000-0000-0000-C000-000000000046"); } } internal static Guid IID_IDispatch { get { return new Guid ("00020400-0000-0000-C000-000000000046"); } } 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); } public override int GetHashCode () { CheckIUnknown (); // not what MS seems to do, // but IUnknown is identity in COM return iunknown.ToInt32 (); } [DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, PreserveSig = true)] static extern int CoCreateInstance ( [In, MarshalAs (UnmanagedType.LPStruct)] Guid rclsid, IntPtr pUnkOuter, uint dwClsContext, [In, MarshalAs (UnmanagedType.LPStruct)] Guid riid, out IntPtr pUnk); } } #else namespace System { // this is a shim class so we can AOT during full AOT builds without --enable-minimal=com internal class __ComObject { __ComObject () { throw new NotSupportedException (); } } } #endif