Skip to content

Commit 3586a84

Browse files
committed
Massive refactor of COM reflection. Much tech debt paid.
1 parent 21a3dbc commit 3586a84

29 files changed

+1385
-658
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Runtime.InteropServices.ComTypes;
4+
using Rubberduck.Parsing.Symbols;
5+
using FUNCDESC = System.Runtime.InteropServices.ComTypes.FUNCDESC;
6+
7+
namespace Rubberduck.Parsing.ComReflection
8+
{
9+
public interface IComBase
10+
{
11+
Guid Guid { get; }
12+
int Index { get; }
13+
ComDocumentation Documentation { get; }
14+
string Name { get; }
15+
DeclarationType Type { get; }
16+
}
17+
18+
public abstract class ComBase : IComBase
19+
{
20+
public Guid Guid { get; protected set; }
21+
public int Index { get; protected set; }
22+
public ComDocumentation Documentation { get; protected set; }
23+
public string Name
24+
{
25+
get { return Documentation == null ? string.Empty : Documentation.Name; }
26+
}
27+
28+
public DeclarationType Type { get; protected set; }
29+
30+
protected ComBase(ITypeLib typeLib, int index)
31+
{
32+
Index = index;
33+
Documentation = new ComDocumentation(typeLib, index);
34+
}
35+
36+
protected ComBase(ITypeInfo info)
37+
{
38+
ITypeLib typeLib;
39+
int index;
40+
info.GetContainingTypeLib(out typeLib, out index);
41+
Index = index;
42+
Debug.Assert(typeLib != null);
43+
Documentation = new ComDocumentation(typeLib, index);
44+
}
45+
46+
protected ComBase(ITypeInfo info, FUNCDESC funcDesc)
47+
{
48+
Index = funcDesc.memid;
49+
Documentation = new ComDocumentation(info, funcDesc.memid);
50+
}
51+
}
52+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Linq;
5+
using System.Runtime.InteropServices;
6+
using System.Runtime.InteropServices.ComTypes;
7+
using Rubberduck.Parsing.Symbols;
8+
using TYPEATTR = System.Runtime.InteropServices.ComTypes.TYPEATTR;
9+
using IMPLTYPEFLAGS = System.Runtime.InteropServices.ComTypes.IMPLTYPEFLAGS;
10+
11+
namespace Rubberduck.Parsing.ComReflection
12+
{
13+
public class ComCoClass : ComType, IComTypeWithMembers
14+
{
15+
private readonly Dictionary<ComInterface, bool> _interfaces = new Dictionary<ComInterface, bool>();
16+
private readonly List<ComInterface> _events = new List<ComInterface>();
17+
18+
public ComInterface DefaultInterface { get; private set; }
19+
20+
public IEnumerable<ComInterface> EventInterfaces
21+
{
22+
get { return _events; }
23+
}
24+
public IEnumerable<ComInterface> ImplementedInterfaces
25+
{
26+
get { return _interfaces.Keys; }
27+
}
28+
29+
public IEnumerable<ComInterface> VisibleInterfaces
30+
{
31+
get { return _interfaces.Where(i => !i.Value).Select(i => i.Key); }
32+
}
33+
34+
public IEnumerable<ComMember> Members
35+
{
36+
get { return ImplementedInterfaces.SelectMany(i => i.Members); }
37+
}
38+
39+
public bool WithEvents
40+
{
41+
get { return _events.Count > 0; }
42+
}
43+
44+
public ComCoClass(ITypeLib typeLib, ITypeInfo info, TYPEATTR attrib, int index) : base (typeLib, attrib, index)
45+
{
46+
Type = DeclarationType.ClassModule;
47+
GetImplementedInterfaces(info, attrib);
48+
Debug.Assert(attrib.cFuncs == 0);
49+
}
50+
51+
private void GetImplementedInterfaces(ITypeInfo info, TYPEATTR typeAttr)
52+
{
53+
for (var implIndex = 0; implIndex < typeAttr.cImplTypes; implIndex++)
54+
{
55+
int href;
56+
info.GetRefTypeOfImplType(implIndex, out href);
57+
58+
ITypeInfo implemented;
59+
info.GetRefTypeInfo(href, out implemented);
60+
61+
IntPtr attribPtr;
62+
implemented.GetTypeAttr(out attribPtr);
63+
var attribs = (TYPEATTR)Marshal.PtrToStructure(attribPtr, typeof(TYPEATTR));
64+
65+
ComType inherited;
66+
ComProject.KnownTypes.TryGetValue(attribs.guid, out inherited);
67+
var intface = inherited as ComInterface ?? new ComInterface(implemented, attribs);
68+
ComProject.KnownTypes.TryAdd(attribs.guid, intface);
69+
70+
IMPLTYPEFLAGS flags = 0;
71+
try
72+
{
73+
info.GetImplTypeFlags(implIndex, out flags);
74+
}
75+
catch (COMException) { }
76+
77+
DefaultInterface = flags.HasFlag(IMPLTYPEFLAGS.IMPLTYPEFLAG_FDEFAULT) ? intface : DefaultInterface;
78+
if (flags.HasFlag(IMPLTYPEFLAGS.IMPLTYPEFLAG_FSOURCE))
79+
{
80+
_events.Add(intface);
81+
}
82+
_interfaces.Add(intface, flags.HasFlag(IMPLTYPEFLAGS.IMPLTYPEFLAG_FRESTRICTED));
83+
info.ReleaseTypeAttr(attribPtr);
84+
}
85+
}
86+
}
87+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Runtime.InteropServices.ComTypes;
2+
3+
namespace Rubberduck.Parsing.ComReflection
4+
{
5+
public class ComDocumentation
6+
{
7+
public string Name { get; private set; }
8+
public string DocString { get; private set; }
9+
public string HelpFile { get; private set; }
10+
public int HelpContext { get; private set; }
11+
12+
public ComDocumentation(ITypeLib typeLib, int index)
13+
{
14+
LoadDocumentation(typeLib, null, index);
15+
}
16+
17+
public ComDocumentation(ITypeInfo info, int index)
18+
{
19+
LoadDocumentation(null, info, index);
20+
}
21+
22+
private void LoadDocumentation(ITypeLib typeLib, ITypeInfo info, int index)
23+
{
24+
string name;
25+
string docString;
26+
int helpContext;
27+
string helpFile;
28+
29+
if (info == null)
30+
{
31+
typeLib.GetDocumentation(index, out name, out docString, out helpContext, out helpFile);
32+
}
33+
else
34+
{
35+
info.GetDocumentation(index, out name, out docString, out helpContext, out helpFile);
36+
}
37+
38+
//See http://chat.stackexchange.com/transcript/message/30119269#30119269
39+
Name = name.Equals("LONG_PTR") ? "LongPtr" : name;
40+
DocString = docString;
41+
HelpContext = helpContext;
42+
HelpFile = helpFile;
43+
}
44+
}
45+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.InteropServices;
4+
using System.Runtime.InteropServices.ComTypes;
5+
using Rubberduck.Parsing.Symbols;
6+
using TYPEATTR = System.Runtime.InteropServices.ComTypes.TYPEATTR;
7+
using VARDESC = System.Runtime.InteropServices.ComTypes.VARDESC;
8+
9+
namespace Rubberduck.Parsing.ComReflection
10+
{
11+
public class ComEnumeration : ComType
12+
{
13+
public List<ComEnumerationMember> Members { get; set; }
14+
15+
public ComEnumeration(ITypeLib typeLib, ITypeInfo info, TYPEATTR attrib, int index) : base(typeLib, attrib, index)
16+
{
17+
Members = new List<ComEnumerationMember>();
18+
Type = DeclarationType.Enumeration;
19+
GetEnumerationMembers(info, attrib);
20+
ComProject.KnownEnumerations.TryAdd(Guid, this);
21+
}
22+
23+
private void GetEnumerationMembers(ITypeInfo info, TYPEATTR attrib)
24+
{
25+
var count = attrib.cVars;
26+
for (var index = 0; index < count; index++)
27+
{
28+
IntPtr varPtr;
29+
info.GetVarDesc(index, out varPtr);
30+
var desc = (VARDESC)Marshal.PtrToStructure(varPtr, typeof(VARDESC));
31+
Members.Add(new ComEnumerationMember(info, desc));
32+
info.ReleaseVarDesc(varPtr);
33+
}
34+
}
35+
}
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Diagnostics;
2+
using System.Runtime.InteropServices;
3+
using System.Runtime.InteropServices.ComTypes;
4+
using VARDESC = System.Runtime.InteropServices.ComTypes.VARDESC;
5+
6+
namespace Rubberduck.Parsing.ComReflection
7+
{
8+
[DebuggerDisplay("{Name} = {Value} ({ValueType})")]
9+
public class ComEnumerationMember
10+
{
11+
public string Name { get; private set; }
12+
public int Value { get; private set; }
13+
public VarEnum ValueType { get; private set; }
14+
15+
public ComEnumerationMember(ITypeInfo info, VARDESC varDesc)
16+
{
17+
var value = new ComVariant(varDesc.desc.lpvarValue);
18+
Value = (int)value.Value;
19+
ValueType = value.VariantType;
20+
21+
var names = new string[255];
22+
int count;
23+
info.GetNames(varDesc.memid, names, 1, out count);
24+
Debug.Assert(count == 1);
25+
Name = names[0];
26+
}
27+
}
28+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Diagnostics;
2+
using System.Runtime.InteropServices;
3+
using System.Runtime.InteropServices.ComTypes;
4+
using VARDESC = System.Runtime.InteropServices.ComTypes.VARDESC;
5+
using VARFLAGS = System.Runtime.InteropServices.ComTypes.VARFLAGS;
6+
7+
namespace Rubberduck.Parsing.ComReflection
8+
{
9+
[DebuggerDisplay("{Name}")]
10+
public class ComField
11+
{
12+
public string Name { get; set; }
13+
public int Index { get; set; }
14+
public bool IsConstant { get; set; }
15+
public object DefaultValue { get; set; }
16+
public VarEnum DefaultValueType { get; set; }
17+
public VARFLAGS Flags { get; set; }
18+
19+
public ComField(ITypeInfo info, VARDESC varDesc, int index)
20+
{
21+
Index = index;
22+
23+
var names = new string[255];
24+
int length;
25+
info.GetNames(varDesc.memid, names, 255, out length);
26+
Debug.Assert(length >= 1);
27+
Name = names[0];
28+
29+
IsConstant = varDesc.varkind.HasFlag(VARKIND.VAR_CONST);
30+
Flags = (VARFLAGS)varDesc.wVarFlags;
31+
32+
if (IsConstant)
33+
{
34+
var value = new ComVariant(varDesc.desc.lpvarValue);
35+
DefaultValue = value.Value;
36+
DefaultValueType = value.VariantType;
37+
}
38+
}
39+
}
40+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Runtime.InteropServices;
5+
using System.Runtime.InteropServices.ComTypes;
6+
using Rubberduck.Parsing.Symbols;
7+
using TYPEATTR = System.Runtime.InteropServices.ComTypes.TYPEATTR;
8+
using FUNCDESC = System.Runtime.InteropServices.ComTypes.FUNCDESC;
9+
using CALLCONV = System.Runtime.InteropServices.ComTypes.CALLCONV;
10+
11+
namespace Rubberduck.Parsing.ComReflection
12+
{
13+
[DebuggerDisplay("{Name}")]
14+
public class ComInterface : ComType, IComTypeWithMembers
15+
{
16+
private readonly List<ComInterface> _inherited = new List<ComInterface>();
17+
private readonly List<ComMember> _members = new List<ComMember>();
18+
19+
public IEnumerable<ComInterface> InheritedInterfaces
20+
{
21+
get { return _inherited; }
22+
}
23+
24+
public IEnumerable<ComMember> Members
25+
{
26+
get { return _members; }
27+
}
28+
29+
public ComInterface(ITypeInfo info, TYPEATTR attrib) : base(info, attrib)
30+
{
31+
GetImplementedInterfaces(info, attrib);
32+
GetComMembers(info, attrib);
33+
}
34+
35+
public ComInterface(ITypeLib typeLib, ITypeInfo info, TYPEATTR attrib, int index) : base(typeLib, attrib, index)
36+
{
37+
Type = DeclarationType.ClassModule;
38+
GetImplementedInterfaces(info, attrib);
39+
GetComMembers(info, attrib);
40+
}
41+
42+
private void GetImplementedInterfaces(ITypeInfo info, TYPEATTR typeAttr)
43+
{
44+
for (var implIndex = 0; implIndex < typeAttr.cImplTypes; implIndex++)
45+
{
46+
int href;
47+
info.GetRefTypeOfImplType(implIndex, out href);
48+
49+
ITypeInfo implemented;
50+
info.GetRefTypeInfo(href, out implemented);
51+
52+
IntPtr attribPtr;
53+
implemented.GetTypeAttr(out attribPtr);
54+
var attribs = (TYPEATTR)Marshal.PtrToStructure(attribPtr, typeof(TYPEATTR));
55+
56+
ComType inherited;
57+
ComProject.KnownTypes.TryGetValue(attribs.guid, out inherited);
58+
var intface = inherited as ComInterface ?? new ComInterface(implemented, attribs);
59+
_inherited.Add(intface);
60+
ComProject.KnownTypes.TryAdd(attribs.guid, intface);
61+
62+
info.ReleaseTypeAttr(attribPtr);
63+
}
64+
}
65+
66+
private void GetComMembers(ITypeInfo info, TYPEATTR attrib)
67+
{
68+
for (var index = 0; index < attrib.cFuncs; index++)
69+
{
70+
IntPtr memberPtr;
71+
info.GetFuncDesc(index, out memberPtr);
72+
var member = (FUNCDESC)Marshal.PtrToStructure(memberPtr, typeof(FUNCDESC));
73+
if (member.callconv != CALLCONV.CC_STDCALL)
74+
{
75+
continue;
76+
}
77+
_members.Add(new ComMember(info, member));
78+
info.ReleaseFuncDesc(memberPtr);
79+
}
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)