Adding support for get test results in TestDriver.
[mono.git] / mcs / class / corlib / System / __ComObject.cs
1 //
2 // System.__ComObject
3 //
4 // Authors:
5 //   Sebastien Pouliot <sebastien@ximian.com>
6 //   Kornél Pál <http://www.kornelpal.hu/>
7 //   Jonathan Chambers <joncham@gmail.com>
8 //
9 // Copyright (C) 2004 Novell (http://www.novell.com)
10 // Copyright (C) 2005 Kornél Pál
11 // Copyright (C) 2006 Jonathan Chambers
12 //
13
14 //
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:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
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.
33 //
34
35 #if !FULL_AOT_RUNTIME
36 using Mono.Interop;
37 using System.Collections;
38 using System.Runtime.InteropServices;
39 using System.Runtime.CompilerServices;
40 using System.Threading;
41
42 namespace System
43 {
44         // This is a private class that is used as a generic wrapper class
45         // for COM objects that have no specific wrapper class.
46         //
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.
50         //
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.
54
55         [StructLayout (LayoutKind.Sequential)]
56         internal class __ComObject : MarshalByRefObject
57         {
58 #pragma warning disable 169     
59                 #region Sync with object-internals.h
60                 IntPtr iunknown;
61                 IntPtr hash_table;
62                 SynchronizationContext synchronization_context;
63                 #endregion
64 #pragma warning restore 169
65
66                 // keep a reference to the proxy so it doesn't get garbage collected before the RCW
67                 ComInteropProxy proxy;
68
69                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
70                 internal static extern __ComObject CreateRCW (Type t);
71
72                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
73                 private extern void ReleaseInterfaces ();
74
75                 ~__ComObject ()
76                 {       
77                         if (hash_table != IntPtr.Zero) {
78                                 if (synchronization_context != null)
79                                         synchronization_context.Post ((state) => ReleaseInterfaces (), this);
80                                 else
81                                         ReleaseInterfaces ();
82                         }
83                         proxy = null;
84                 }
85
86                 public __ComObject ()
87                 {
88                         Initialize (GetType ());
89                 }
90
91                 internal __ComObject (Type t) {
92                         Initialize (t);
93                 }
94
95                 internal __ComObject (IntPtr pItf, ComInteropProxy p)
96                 {
97                         proxy = p;
98                         InitializeApartmentDetails ();
99                         Guid iid = IID_IUnknown;
100                         int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown);
101                         Marshal.ThrowExceptionForHR (hr);
102                 }
103
104                 internal void Initialize (IntPtr pUnk, ComInteropProxy p)
105                 {
106                         proxy = p;
107                         InitializeApartmentDetails ();
108                         iunknown = pUnk;
109                 }
110
111                 internal void Initialize (Type t)
112                 {
113                         InitializeApartmentDetails ();
114                         // Guard multiple invocation.
115                         if (iunknown != IntPtr.Zero)
116                                 return;
117
118                         iunknown = CreateIUnknown (t);
119                 }
120
121                 internal static IntPtr CreateIUnknown(Type t)
122                 {
123                         System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (t.TypeHandle);
124
125                         IntPtr iunknown;
126                         ObjectCreationDelegate ocd = ExtensibleClassFactory.GetObjectCreationCallback (t);
127                         if (ocd != null) {
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));
131                         }
132                         else {
133                                 int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
134                                 Marshal.ThrowExceptionForHR (hr);
135                         }
136
137                         return iunknown;
138                 }
139
140                 private void InitializeApartmentDetails ()
141                 {
142                         // Only synchronization_context if thread is STA.
143                         if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
144                                 return;
145                         
146                         synchronization_context = SynchronizationContext.Current;
147
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;                 
153                 }
154
155                 private static Guid GetCLSID (Type t)
156                 {
157                         if (t.IsImport)
158                                 return t.GUID;
159
160                         // look at supertypes
161                         Type super = t.BaseType;
162                         while (super != typeof (object)) {
163                                 if (super.IsImport)
164                                         return super.GUID;
165                                 super = super.BaseType;
166                         }
167                         throw new COMException ("Could not find base COM type for type " + t.ToString());
168                 }
169
170                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
171                 internal extern IntPtr GetInterfaceInternal (Type t, bool throwException);
172
173                 internal IntPtr GetInterface (Type t, bool throwException) {
174                         CheckIUnknown ();
175                         return GetInterfaceInternal (t, throwException);
176                 }
177
178                 internal IntPtr GetInterface(Type t)
179                 {
180                         return GetInterface (t, true);
181                 }
182
183                 private void CheckIUnknown ()
184                 {
185                         if (iunknown == IntPtr.Zero)
186                                 throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
187                 }
188
189                 internal IntPtr IUnknown
190                 {
191                         get
192                         {
193                                 if (iunknown == IntPtr.Zero)
194                                         throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
195                                 return iunknown;
196                         }
197                 }
198
199                 internal IntPtr IDispatch
200                 {
201                         get
202                         {
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.");
206                                 return pUnk;
207                         }
208                 }
209
210                 internal static Guid IID_IUnknown
211                 {
212                         get
213                         {
214                                 return new Guid("00000000-0000-0000-C000-000000000046");
215                         }
216                 }
217
218                 internal static Guid IID_IDispatch
219                 {
220                         get
221                         {
222                                 return new Guid ("00020400-0000-0000-C000-000000000046");
223                         }
224                 }
225
226                 public override bool Equals (object obj)
227                 {
228                         CheckIUnknown ();
229                         if (obj == null)
230                                 return false;
231
232                         __ComObject co = obj as __ComObject;
233                         if ((object)co == null)
234                                 return false;
235                         return (iunknown == co.IUnknown);
236                 }
237
238                 public override int GetHashCode ()
239                 {
240                         CheckIUnknown ();
241                         // not what MS seems to do, 
242                         // but IUnknown is identity in COM
243                         return iunknown.ToInt32 ();
244                 }
245
246                 [DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, PreserveSig = true)]
247                 static extern int CoCreateInstance (
248                    [In, MarshalAs (UnmanagedType.LPStruct)] Guid rclsid,
249                    IntPtr pUnkOuter,
250                    uint dwClsContext,
251                   [In, MarshalAs (UnmanagedType.LPStruct)] Guid riid,
252                         out IntPtr pUnk);
253         }
254 }
255 #else
256 namespace System
257 {
258         // this is a shim class so we can AOT during mobile_static build without --enable-minimal=com
259         internal class __ComObject
260         {
261                 __ComObject ()
262                 {
263                         throw new NotSupportedException ();
264                 }
265         }
266 }
267 #endif