5 // Sebastien Pouliot <sebastien@ximian.com>
6 // Kornél Pál <http://www.kornelpal.hu/>
7 // Jonathan Chambers <joncham@gmail.com>
9 // Copyright (C) 2004 Novell (http://www.novell.com)
10 // Copyright (C) 2005 Kornél Pál
11 // Copyright (C) 2006 Jonathan Chambers
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Collections;
38 using System.Runtime.InteropServices;
39 using System.Runtime.CompilerServices;
40 using System.Threading;
44 // This is a private class that is used as a generic wrapper class
45 // for COM objects that have no specific wrapper class.
47 // It has no public methods, it's functionality is exposed trough
48 // System.Runtime.InteropServices.Marshal class and can be casted to
49 // any interface that is implemented by the wrapped COM object.
51 // This class is referenced in .NET Framework SDK Documentation so
52 // many times that obj.GetType().FullName == "System.__ComObject" and
53 // Type.GetType("System.__ComObject") may be used.
55 [StructLayout (LayoutKind.Sequential)]
56 internal class __ComObject : MarshalByRefObject
58 #pragma warning disable 169
59 #region Sync with object-internals.h
62 SynchronizationContext synchronization_context;
64 #pragma warning restore 169
66 // keep a reference to the proxy so it doesn't get garbage collected before the RCW
67 ComInteropProxy proxy;
69 [MethodImplAttribute (MethodImplOptions.InternalCall)]
70 internal static extern __ComObject CreateRCW (Type t);
72 [MethodImplAttribute (MethodImplOptions.InternalCall)]
73 private extern void ReleaseInterfaces ();
77 if (hash_table != IntPtr.Zero) {
78 if (synchronization_context != null)
79 synchronization_context.Post ((state) => ReleaseInterfaces (), this);
88 Initialize (GetType ());
91 internal __ComObject (Type t) {
95 internal __ComObject (IntPtr pItf, ComInteropProxy p)
98 InitializeApartmentDetails ();
99 Guid iid = IID_IUnknown;
100 int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown);
101 Marshal.ThrowExceptionForHR (hr);
104 internal void Initialize (IntPtr pUnk, ComInteropProxy p)
107 InitializeApartmentDetails ();
111 internal void Initialize (Type t)
113 InitializeApartmentDetails ();
114 // Guard multiple invocation.
115 if (iunknown != IntPtr.Zero)
118 iunknown = CreateIUnknown (t);
121 internal static IntPtr CreateIUnknown(Type t)
123 System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (t.TypeHandle);
126 ObjectCreationDelegate ocd = ExtensibleClassFactory.GetObjectCreationCallback (t);
128 iunknown = ocd (IntPtr.Zero);
129 if (iunknown == IntPtr.Zero)
130 throw new COMException (string.Format("ObjectCreationDelegate for type {0} failed to return a valid COM object", t));
133 int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
134 Marshal.ThrowExceptionForHR (hr);
140 private void InitializeApartmentDetails ()
142 // Only synchronization_context if thread is STA.
143 if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
146 synchronization_context = SynchronizationContext.Current;
148 // Check whether the current context is a plain SynchronizationContext object
149 // and handle this as if no context was set at all.
150 if (synchronization_context != null &&
151 synchronization_context.GetType () == typeof(SynchronizationContext))
152 synchronization_context = null;
155 private static Guid GetCLSID (Type t)
160 // look at supertypes
161 Type super = t.BaseType;
162 while (super != typeof (object)) {
165 super = super.BaseType;
167 throw new COMException ("Could not find base COM type for type " + t.ToString());
170 [MethodImplAttribute (MethodImplOptions.InternalCall)]
171 internal extern IntPtr GetInterfaceInternal (Type t, bool throwException);
173 internal IntPtr GetInterface (Type t, bool throwException) {
175 return GetInterfaceInternal (t, throwException);
178 internal IntPtr GetInterface(Type t)
180 return GetInterface (t, true);
183 private void CheckIUnknown ()
185 if (iunknown == IntPtr.Zero)
186 throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
189 internal IntPtr IUnknown
193 if (iunknown == IntPtr.Zero)
194 throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
199 internal IntPtr IDispatch
203 IntPtr pUnk = GetInterface (typeof (IDispatch));
204 if (pUnk == IntPtr.Zero)
205 throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
210 internal static Guid IID_IUnknown
214 return new Guid("00000000-0000-0000-C000-000000000046");
218 internal static Guid IID_IDispatch
222 return new Guid ("00020400-0000-0000-C000-000000000046");
226 public override bool Equals (object obj)
232 __ComObject co = obj as __ComObject;
233 if ((object)co == null)
235 return (iunknown == co.IUnknown);
238 public override int GetHashCode ()
241 // not what MS seems to do,
242 // but IUnknown is identity in COM
243 return iunknown.ToInt32 ();
246 [DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, PreserveSig = true)]
247 static extern int CoCreateInstance (
248 [In, MarshalAs (UnmanagedType.LPStruct)] Guid rclsid,
251 [In, MarshalAs (UnmanagedType.LPStruct)] Guid riid,
258 // this is a shim class so we can AOT during aot_only build without --enable-minimal=com
259 internal class __ComObject
263 throw new NotSupportedException ();