-
Notifications
You must be signed in to change notification settings - Fork 168
Expand file tree
/
Copy pathTypeLibHelpers.cs
More file actions
206 lines (174 loc) · 7.71 KB
/
Copy pathTypeLibHelpers.cs
File metadata and controls
206 lines (174 loc) · 7.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using ELEMDESC = System.Runtime.InteropServices.ComTypes.ELEMDESC;
using FUNCDESC = System.Runtime.InteropServices.ComTypes.FUNCDESC;
using TYPEDESC = System.Runtime.InteropServices.ComTypes.TYPEDESC;
using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR;
using VARDESC = System.Runtime.InteropServices.ComTypes.VARDESC;
namespace Microsoft.ClearScript.Util.COM
{
internal static class TypeLibHelpers
{
// GUID_ManagedName (um\cor.h)
private static readonly Guid managedNameGuid = new("{0f21f359-ab84-41e8-9a78-36d110e6d2f9}");
public static string GetName(this ITypeLib typeLib)
{
return typeLib.GetMemberName(-1);
}
public static string GetMemberName(this ITypeLib typeLib, int index)
{
typeLib.GetDocumentation(index, out var name, out _, out _, out _);
return name;
}
public static string GetManagedName(this ITypeLib typeLib)
{
if (typeLib is ITypeLib2 typeLib2)
{
// ReSharper disable EmptyGeneralCatchClause
try
{
var guid = managedNameGuid;
typeLib2.GetCustData(ref guid, out var data);
if (data is string name)
{
name = name.Trim();
if (name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
{
return name.Substring(0, name.Length - 4);
}
return name;
}
}
catch
{
}
// ReSharper restore EmptyGeneralCatchClause
}
return typeLib.GetName();
}
public static Guid GetGuid(this ITypeLib typeLib)
{
using (var attrScope = typeLib.CreateAttrScope())
{
return attrScope.Value.guid;
}
}
public static IScope<TYPELIBATTR> CreateAttrScope(this ITypeLib typeLib)
{
return StructHelpers.CreateScope<TYPELIBATTR>(typeLib.GetLibAttr, typeLib.ReleaseTLibAttr);
}
public static IEnumerable<ITypeInfo> GetReferencedEnums(this ITypeLib typeLib)
{
var processedTypeInfo = new Dictionary<Guid, ITypeInfo>();
var count = typeLib.GetTypeInfoCount();
for (var index = 0; index < count; index++)
{
typeLib.GetTypeInfo(index, out var typeInfo);
foreach (var enumTypeInfo in GetReferencedEnums(typeLib, typeInfo, processedTypeInfo))
{
yield return enumTypeInfo;
}
}
}
private static IEnumerable<ITypeInfo> GetReferencedEnums(ITypeLib typeLib, ITypeInfo typeInfo, Dictionary<Guid, ITypeInfo> processedTypeInfo)
{
if (typeInfo is null)
{
yield break;
}
var guid = typeInfo.GetOrCreateGuid();
// ReSharper disable once CanSimplifyDictionaryLookupWithTryAdd
if (processedTypeInfo.ContainsKey(guid))
{
yield break;
}
processedTypeInfo.Add(guid, typeInfo);
if (typeInfo.IsEnum())
{
yield return typeInfo;
yield break;
}
if (typeInfo.GetContainingTypeLib().GetGuid() != typeLib.GetGuid())
{
yield break;
}
using (var typeAttrScope = typeInfo.CreateAttrScope())
{
for (var funcIndex = 0; funcIndex < typeAttrScope.Value.cFuncs; funcIndex++)
{
using (var funcDescScope = typeInfo.CreateFuncDescScope(funcIndex))
{
foreach (var enumTypeInfo in GetReferencedEnums(typeLib, typeInfo, funcDescScope.Value, processedTypeInfo))
{
yield return enumTypeInfo;
}
}
}
for (var varIndex = 0; varIndex < typeAttrScope.Value.cVars; varIndex++)
{
using (var varDescScope = typeInfo.CreateVarDescScope(varIndex))
{
foreach (var enumTypeInfo in GetReferencedEnums(typeLib, typeInfo, varDescScope.Value, processedTypeInfo))
{
yield return enumTypeInfo;
}
}
}
for (var implTypeIndex = 0; implTypeIndex < typeAttrScope.Value.cImplTypes; implTypeIndex++)
{
typeInfo.GetRefTypeOfImplType(implTypeIndex, out var href);
typeInfo.GetRefTypeInfo(href, out var refTypeInfo);
var refGuid = refTypeInfo.GetGuid();
if ((refGuid == typeof(IDispatch).GUID) || (refGuid == typeof(IDispatchEx).GUID))
{
continue;
}
foreach (var enumTypeInfo in GetReferencedEnums(typeLib, refTypeInfo, processedTypeInfo))
{
yield return enumTypeInfo;
}
}
}
}
private static IEnumerable<ITypeInfo> GetReferencedEnums(ITypeLib typeLib, ITypeInfo typeInfo, FUNCDESC funcDesc, Dictionary<Guid, ITypeInfo> processedTypeInfo)
{
foreach (var enumTypeInfo in GetReferencedEnums(typeLib, typeInfo, funcDesc.elemdescFunc, processedTypeInfo))
{
yield return enumTypeInfo;
}
foreach (var elemDesc in StructHelpers.GetStructsFromArray<ELEMDESC>(funcDesc.lprgelemdescParam, funcDesc.cParams))
{
foreach (var enumTypeInfo in GetReferencedEnums(typeLib, typeInfo, elemDesc, processedTypeInfo))
{
yield return enumTypeInfo;
}
}
}
private static IEnumerable<ITypeInfo> GetReferencedEnums(ITypeLib typeLib, ITypeInfo typeInfo, VARDESC varDesc, Dictionary<Guid, ITypeInfo> processedTypeInfo)
{
return GetReferencedEnums(typeLib, typeInfo, varDesc.elemdescVar, processedTypeInfo);
}
private static IEnumerable<ITypeInfo> GetReferencedEnums(ITypeLib typeLib, ITypeInfo typeInfo, ELEMDESC elemDesc, Dictionary<Guid, ITypeInfo> processedTypeInfo)
{
return GetReferencedEnums(typeLib, typeInfo, elemDesc.tdesc, processedTypeInfo);
}
private static IEnumerable<ITypeInfo> GetReferencedEnums(ITypeLib typeLib, ITypeInfo typeInfo, TYPEDESC typeDesc, Dictionary<Guid, ITypeInfo> processedTypeInfo)
{
if ((typeDesc.vt == (short)VarEnum.VT_PTR) || (typeDesc.vt == (short)VarEnum.VT_CARRAY))
{
return GetReferencedEnums(typeLib, typeInfo, (TYPEDESC)Marshal.PtrToStructure(typeDesc.lpValue, typeof(TYPEDESC)), processedTypeInfo);
}
if (typeDesc.vt == (short)VarEnum.VT_USERDEFINED)
{
typeInfo.GetRefTypeInfo(unchecked((int)typeDesc.lpValue.ToInt64()), out var refTypeInfo);
return GetReferencedEnums(typeLib, refTypeInfo, processedTypeInfo);
}
return Enumerable.Empty<ITypeInfo>();
}
}
}