merged Sys.Web.Services 2.0 support in my branch:
[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 using Mono.Interop;
36 using System.Collections;
37 using System.Runtime.InteropServices;
38 using System.Runtime.CompilerServices;
39
40 namespace System
41 {
42         // This is a private class that is used as a generic wrapper class
43         // for COM objects that have no specific wrapper class.
44         //
45         // It has no public methods, it's functionality is exposed trough
46         // System.Runtime.InteropServices.Marshal class and can be casted to
47         // any interface that is implemented by the wrapped COM object.
48         //
49         // This class is referenced in .NET Framework SDK Documentation so
50         // many times that obj.GetType().FullName == "System.__ComObject" and
51         // Type.GetType("System.__ComObject") may be used.
52
53         internal class __ComObject : MarshalByRefObject
54         {
55                 #region Sync with object-internals.h
56                 IntPtr hash_table;
57                 #endregion
58
59                 // this is used internally and for the the methods
60                 // Marshal.GetComObjectData and Marshal.SetComObjectData
61                 Hashtable hashtable;
62
63                 [ThreadStatic]
64                 static bool coinitialized;
65
66                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
67                 internal extern void Finalizer ();
68
69                 ~__ComObject ()
70                 {
71                         ComInteropProxy.ReleaseComObject (this);
72                         Finalizer ();
73                 }
74
75                 public __ComObject ()
76                 {
77                         // call CoInitialize once per thread
78                         if (!coinitialized) {
79                                 CoInitialize (IntPtr.Zero);
80                                 coinitialized = true;
81                         }
82
83                         hashtable = new Hashtable ();
84
85                         IntPtr ppv;
86                         Type t = GetType ();
87                         int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
88                         Marshal.ThrowExceptionForHR (hr);
89
90                         SetIUnknown (ppv);
91                 }
92
93                 internal __ComObject (Type t)
94                 {
95                         // call CoInitialize once per thread
96                         if (!coinitialized) {
97                                 CoInitialize (IntPtr.Zero);
98                                 coinitialized = true;
99                         }
100
101                         hashtable = new Hashtable ();
102
103                         IntPtr ppv;
104                         int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
105                         Marshal.ThrowExceptionForHR (hr);
106
107                         SetIUnknown (ppv);
108                 }
109
110                 private Guid GetCLSID (Type t)
111                 {
112                         if (t.IsImport)
113                                 return t.GUID;
114
115                         // look at supertypes
116                         Type super = t.BaseType;
117                         while (super != typeof (object)) {
118                                 if (super.IsImport)
119                                         return super.GUID;
120                                 super = super.BaseType;
121                         }
122                         throw new COMException ("Could not find base COM type for type " + t.ToString());
123                 }
124
125                 internal __ComObject (IntPtr pItf)
126                 {
127                         hashtable = new Hashtable ();
128                         IntPtr ppv;
129                         Guid iid = IID_IUnknown;
130                         int hr = Marshal.QueryInterface (pItf, ref iid, out ppv);
131                         Marshal.ThrowExceptionForHR (hr);
132                         SetIUnknown (ppv);
133         }
134
135                 public Hashtable Hashtable
136                 {
137                         get
138                         {
139                                 return hashtable;
140                         }
141                 }
142
143                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
144                 internal static extern __ComObject CreateRCW (Type t);
145
146                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
147                 extern void SetIUnknown (IntPtr t);
148
149                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
150                 extern IntPtr GetIUnknown ();
151
152                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
153                 extern IntPtr FindInterface (Type t);
154
155                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
156                 extern void CacheInterface (Type t, IntPtr pItf);
157
158                 internal IntPtr GetInterface(Type t)
159                 {
160                         // this is needed later and checks to see if we are
161                         // a valid RCW
162                         IntPtr pUnk = IUnknown;
163                         IntPtr pItf = FindInterface (t);
164                         if (pItf != IntPtr.Zero) {
165                                 return pItf;
166                         }
167
168                         Guid iid = t.GUID;
169                         IntPtr ppv;
170                         int hr = Marshal.QueryInterface (pUnk, ref iid, out ppv);
171                         Marshal.ThrowExceptionForHR (hr);
172                         CacheInterface (t, ppv);
173                         return ppv;
174                 }
175
176                 internal IntPtr IUnknown
177                 {
178                         get
179                         {
180                                 IntPtr pUnk = GetIUnknown();
181                                 if (pUnk == IntPtr.Zero)
182                                         throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
183                                 return pUnk;
184                         }
185                 }
186
187                 internal IntPtr IDispatch
188                 {
189                         get
190                         {
191                                 IntPtr pUnk = GetInterface (typeof (IDispatch));
192                                 if (pUnk == IntPtr.Zero)
193                                         throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
194                                 return pUnk;
195                         }
196                 }
197
198                 internal static Guid IID_IUnknown
199                 {
200                         get
201                         {
202                                 return new Guid("00000000-0000-0000-C000-000000000046");
203                         }
204                 }
205
206                 internal static Guid IID_IDispatch
207                 {
208                         get
209                         {
210                                 return new Guid ("00020400-0000-0000-C000-000000000046");
211                         }
212                 }
213
214                 public override bool Equals (object obj)
215                 {
216                         if (obj == null)
217                                 return false;
218
219                         __ComObject co = obj as __ComObject;
220                         if ((object)co == null)
221                                 return false;
222
223                         return (IUnknown == co.IUnknown);
224                 }
225
226                 public override int GetHashCode ()
227                 {
228                         // not what MS seems to do, 
229                         // but IUnknown is identity in COM
230                         return IUnknown.ToInt32 ();
231                 }
232
233                 [DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall)]
234                 static extern int CoInitialize (IntPtr pvReserved);
235
236                 [DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, PreserveSig = true)]
237                 static extern int CoCreateInstance (
238                    [In, MarshalAs (UnmanagedType.LPStruct)] Guid rclsid,
239                    IntPtr pUnkOuter,
240                    uint dwClsContext,
241                   [In, MarshalAs (UnmanagedType.LPStruct)] Guid riid,
242                         out IntPtr pUnk);
243         }
244 }