-
Notifications
You must be signed in to change notification settings - Fork 296
/
ComCoClass.cs
96 lines (76 loc) · 3.85 KB
/
ComCoClass.cs
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
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Rubberduck.Parsing.Symbols;
using Rubberduck.VBEditor.Utility;
using TYPEATTR = System.Runtime.InteropServices.ComTypes.TYPEATTR;
using IMPLTYPEFLAGS = System.Runtime.InteropServices.ComTypes.IMPLTYPEFLAGS;
using TYPEFLAGS = System.Runtime.InteropServices.ComTypes.TYPEFLAGS;
namespace Rubberduck.Parsing.ComReflection
{
public class ComCoClass : ComType, IComTypeWithMembers
{
private readonly Dictionary<ComInterface, bool> _interfaces = new Dictionary<ComInterface, bool>();
private readonly List<ComInterface> _events = new List<ComInterface>();
public bool IsControl { get; }
public bool IsExtensible => _interfaces.Keys.Any(i => i.IsExtensible);
public ComInterface DefaultInterface { get; private set; }
public IEnumerable<ComInterface> EventInterfaces => _events;
public IEnumerable<ComInterface> ImplementedInterfaces => _interfaces.Keys;
public IEnumerable<ComField> Properties => ImplementedInterfaces.Where(x => !_events.Contains(x)).SelectMany(i => i.Properties);
public IEnumerable<ComInterface> VisibleInterfaces => _interfaces.Where(i => !i.Value).Select(i => i.Key);
public IEnumerable<ComMember> Members => ImplementedInterfaces.Where(x => !_events.Contains(x)).SelectMany(i => i.Members);
public ComMember DefaultMember => DefaultInterface.DefaultMember;
public IEnumerable<ComMember> SourceMembers => _events.SelectMany(i => i.Members);
public bool WithEvents => _events.Count > 0;
public void AddInterface(ComInterface intrface, bool restricted = false)
{
Debug.Assert(intrface != null);
if (!_interfaces.ContainsKey(intrface))
{
_interfaces.Add(intrface, restricted);
}
}
public ComCoClass(ITypeLib typeLib, ITypeInfo info, TYPEATTR attrib, int index) : base (typeLib, attrib, index)
{
Type = DeclarationType.ClassModule;
GetImplementedInterfaces(info, attrib);
IsControl = attrib.wTypeFlags.HasFlag(TYPEFLAGS.TYPEFLAG_FCONTROL);
Debug.Assert(attrib.cFuncs == 0);
}
private void GetImplementedInterfaces(ITypeInfo info, TYPEATTR typeAttr)
{
for (var implIndex = 0; implIndex < typeAttr.cImplTypes; implIndex++)
{
info.GetRefTypeOfImplType(implIndex, out int href);
info.GetRefTypeInfo(href, out ITypeInfo implemented);
implemented.GetTypeAttr(out IntPtr attribPtr);
using (DisposalActionContainer.Create(attribPtr, info.ReleaseTypeAttr))
{
var attribs = Marshal.PtrToStructure<TYPEATTR>(attribPtr);
ComProject.KnownTypes.TryGetValue(attribs.guid, out ComType inherited);
var intface = inherited as ComInterface ?? new ComInterface(implemented, attribs);
ComProject.KnownTypes.TryAdd(attribs.guid, intface);
IMPLTYPEFLAGS flags = 0;
try
{
info.GetImplTypeFlags(implIndex, out flags);
}
catch (COMException) { }
if (flags.HasFlag(IMPLTYPEFLAGS.IMPLTYPEFLAG_FSOURCE))
{
_events.Add(intface);
}
else
{
DefaultInterface = flags.HasFlag(IMPLTYPEFLAGS.IMPLTYPEFLAG_FDEFAULT) ? intface : DefaultInterface;
}
_interfaces.Add(intface, flags.HasFlag(IMPLTYPEFLAGS.IMPLTYPEFLAG_FRESTRICTED));
}
}
}
}
}