2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / ComTypeLibDesc.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.Generic;
21 using System.Globalization;
22 using System.Security;
23 using ComTypes = System.Runtime.InteropServices.ComTypes;
24
25 #if CODEPLEX_40
26 namespace System.Dynamic {
27 #else
28 namespace Microsoft.Scripting {
29 #endif
30
31     internal sealed class ComTypeLibDesc {
32
33         // typically typelibs contain very small number of coclasses
34         // so we will just use the linked list as it performs better
35         // on small number of entities
36         LinkedList<ComTypeClassDesc> _classes;
37         Dictionary<string, ComTypeEnumDesc> _enums;
38         string _typeLibName;
39
40         private static readonly Dictionary<Guid, ComTypeLibDesc> _CachedTypeLibDesc = new Dictionary<Guid, ComTypeLibDesc>();
41
42         private ComTypeLibDesc() {
43             _enums = new Dictionary<string, ComTypeEnumDesc>();
44             _classes = new LinkedList<ComTypeClassDesc>();
45         }
46
47         public override string ToString() {
48             return String.Format(CultureInfo.CurrentCulture, "<type library {0}>", _typeLibName);
49         }
50
51         [SecurityCritical]
52         internal static ComTypeLibDesc GetFromTypeLib(ComTypes.ITypeLib typeLib) {
53             // check whether we have already loaded this type library
54             ComTypes.TYPELIBATTR typeLibAttr = ComRuntimeHelpers.GetTypeAttrForTypeLib(typeLib);
55             ComTypeLibDesc typeLibDesc;
56             lock (_CachedTypeLibDesc) {
57                 if (_CachedTypeLibDesc.TryGetValue(typeLibAttr.guid, out typeLibDesc)) {
58                     return typeLibDesc;
59                 }
60             }
61
62             typeLibDesc = new ComTypeLibDesc();
63
64             typeLibDesc._typeLibName = ComRuntimeHelpers.GetNameOfLib(typeLib);
65
66             int countTypes = typeLib.GetTypeInfoCount();
67             for (int i = 0; i < countTypes; i++) {
68                 ComTypes.TYPEKIND typeKind;
69                 typeLib.GetTypeInfoType(i, out typeKind);
70
71                 ComTypes.ITypeInfo typeInfo;
72                 if (typeKind == ComTypes.TYPEKIND.TKIND_COCLASS) {
73                     typeLib.GetTypeInfo(i, out typeInfo);
74                     ComTypeClassDesc classDesc = new ComTypeClassDesc(typeInfo);
75                     typeLibDesc._classes.AddLast(classDesc);
76                 } else if (typeKind == ComTypes.TYPEKIND.TKIND_ENUM) {
77                     typeLib.GetTypeInfo(i, out typeInfo);
78                     ComTypeEnumDesc enumDesc = new ComTypeEnumDesc(typeInfo);
79                     typeLibDesc._enums.Add(enumDesc.TypeName, enumDesc);
80                 }
81             }
82
83             // cache the typelib using the guid as the dictionary key
84             lock (_CachedTypeLibDesc) {
85                 //check if we are late and somebody already added the key.
86                 ComTypeLibDesc curLibDesc;
87                 if (_CachedTypeLibDesc.TryGetValue(typeLibAttr.guid, out curLibDesc)) {
88                     return curLibDesc;
89                 }
90
91                 _CachedTypeLibDesc.Add(typeLibAttr.guid, typeLibDesc);
92             }
93
94             return typeLibDesc;
95         }
96
97         internal ComTypeClassDesc GetCoClassForInterface(string itfName) {
98             foreach (ComTypeClassDesc coclass in _classes) {
99                 if (coclass.Implements(itfName, false)) {
100                     return coclass;
101                 }
102             }
103
104             return null;
105         }
106     }
107 }
108
109 #endif