2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / ComTypeDesc.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Microsoft Public License, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Microsoft Public License.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15 using System; using Microsoft;
16
17
18 #if !SILVERLIGHT // ComObject
19
20 using System.Collections;
21 using System.Collections.Generic;
22 using System.Runtime.InteropServices.ComTypes;
23 using System.Security;
24 using System.Threading;
25 using ComTypes = System.Runtime.InteropServices.ComTypes;
26
27 #if CODEPLEX_40
28 namespace System.Dynamic {
29 #else
30 namespace Microsoft.Scripting {
31 #endif
32
33     internal class ComTypeDesc {
34         private string _typeName;
35         private string _documentation;
36         private Guid _guid;
37
38         //Hashtable is threadsafe for multiple readers single writer. 
39         //Enumerating and writing is mutually exclusive so require locking.
40         private Hashtable _funcs;
41         private Hashtable _puts;
42         private Hashtable _putRefs;
43         private ComMethodDesc _getItem;
44         private ComMethodDesc _setItem;
45
46         private Dictionary<string, ComEventDesc> _events;
47
48         private static readonly Dictionary<string, ComEventDesc> _EmptyEventsDict = new Dictionary<string, ComEventDesc>();
49
50         internal ComTypeDesc(ITypeInfo typeInfo) {
51             if (typeInfo != null) {
52                 ComRuntimeHelpers.GetInfoFromType(typeInfo, out _typeName, out _documentation);
53             }
54         }
55
56         [SecurityCritical]
57         internal static ComTypeDesc FromITypeInfo(ComTypes.ITypeInfo typeInfo, ComTypes.TYPEATTR typeAttr) {
58             if (typeAttr.typekind == ComTypes.TYPEKIND.TKIND_COCLASS) {
59                 return new ComTypeClassDesc(typeInfo);
60             } else if (typeAttr.typekind == ComTypes.TYPEKIND.TKIND_ENUM) {
61                 return new ComTypeEnumDesc(typeInfo);
62             } else if ((typeAttr.typekind == ComTypes.TYPEKIND.TKIND_DISPATCH) ||
63                   (typeAttr.typekind == ComTypes.TYPEKIND.TKIND_INTERFACE)) {
64
65                 return new ComTypeDesc(typeInfo);
66             } else {
67                 throw Error.UnsupportedEnumType();
68             }
69         }
70
71         internal static ComTypeDesc CreateEmptyTypeDesc() {
72             ComTypeDesc typeDesc = new ComTypeDesc(null);
73             typeDesc._funcs = new Hashtable();
74             typeDesc._puts = new Hashtable();
75             typeDesc._putRefs = new Hashtable();
76             typeDesc._events = _EmptyEventsDict;
77
78             return typeDesc;
79         }
80
81         internal static Dictionary<string, ComEventDesc> EmptyEvents {
82             get { return _EmptyEventsDict; }
83         }
84
85         internal Hashtable Funcs {
86             get { return _funcs; }
87             set { _funcs = value; }
88         }
89
90         internal Hashtable Puts {
91             set { _puts = value; }
92         }
93
94         internal Hashtable PutRefs {
95             set { _putRefs = value; }
96         }
97
98         internal Dictionary<string, ComEventDesc> Events {
99             get { return _events; }
100             set { _events = value; }
101         }
102
103         internal bool TryGetFunc(string name, out ComMethodDesc method) {
104             name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
105             if (_funcs.ContainsKey(name)) {
106                 method = _funcs[name] as ComMethodDesc;
107                 return true;
108             }
109             method = null;
110             return false;
111         }
112
113         internal void AddFunc(string name, ComMethodDesc method) {
114             name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
115             lock (_funcs) {
116                 _funcs[name] = method;
117             }
118         }
119
120         internal bool TryGetPut(string name, out ComMethodDesc method) {
121             name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
122             if (_puts.ContainsKey(name)) {
123                 method = _puts[name] as ComMethodDesc;
124                 return true;
125             }
126             method = null;
127             return false;
128         }
129
130         internal void AddPut(string name, ComMethodDesc method) {
131             name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
132             lock (_puts) {
133                 _puts[name] = method;
134             }
135         }
136
137         internal bool TryGetPutRef(string name, out ComMethodDesc method) {
138             name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
139             if (_putRefs.ContainsKey(name)) {
140                 method = _putRefs[name] as ComMethodDesc;
141                 return true;
142             }
143             method = null;
144             return false;
145         }
146         internal void AddPutRef(string name, ComMethodDesc method) {
147             name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
148             lock (_putRefs) {
149                 _putRefs[name] = method;
150             }
151         }
152
153         internal bool TryGetEvent(string name, out ComEventDesc @event) {
154             name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
155             return _events.TryGetValue(name, out @event);
156         }
157
158         internal string[] GetMemberNames(bool dataOnly) {
159             var names = new Dictionary<string, object>();
160
161             lock (_funcs) {
162                 foreach (ComMethodDesc func in _funcs.Values) {
163                     if (!dataOnly || func.IsDataMember) {
164                         names.Add(func.Name, null);
165                     }
166                 }
167             }
168
169             if (!dataOnly) {
170                 lock (_puts) {
171                     foreach (ComMethodDesc func in _puts.Values) {
172                         if (!names.ContainsKey(func.Name)) {
173                             names.Add(func.Name, null);
174                         }
175                     }
176                 }
177
178                 lock (_putRefs) {
179                     foreach (ComMethodDesc func in _putRefs.Values) {
180                         if (!names.ContainsKey(func.Name)) {
181                             names.Add(func.Name, null);
182                         }
183                     }
184                 }
185
186                 if (_events != null && _events.Count > 0) {
187                     foreach (string name in _events.Keys) {
188                         if (!names.ContainsKey(name)) {
189                             names.Add(name, null);
190                         }
191                     }
192                 }
193             }
194
195             string[] result = new string[names.Keys.Count];
196             names.Keys.CopyTo(result, 0);
197             return result;
198         }
199
200         internal string TypeName {
201             get { return _typeName; }
202         }
203
204         internal Guid Guid {
205             get { return _guid; }
206             set { _guid = value; }
207         }
208
209         internal ComMethodDesc GetItem {
210             get { return _getItem; }
211         }
212
213         internal void EnsureGetItem(ComMethodDesc candidate) {
214             Interlocked.CompareExchange(ref _getItem, candidate, null);
215         }
216
217         internal ComMethodDesc SetItem {
218             get { return _setItem; }
219         }
220
221         internal void EnsureSetItem(ComMethodDesc candidate) {
222             Interlocked.CompareExchange(ref _setItem, candidate, null);
223         }
224     }
225 }
226
227 #endif