Skip to content

Commit fdb782a

Browse files
committed
Address PR comments
Enhance the base to provide a useful default behavior (accessing VBComponent.Properties) Require VBE for ctor for all hosts (necessary for useful default behavior) Update all host implementation to pass in VBE in the ctor, preserving the original preferences of loading via reflection or via VBE
1 parent f0a2101 commit fdb782a

File tree

16 files changed

+281
-137
lines changed

16 files changed

+281
-137
lines changed

Rubberduck.Core/Navigation/CodeExplorer/CodeExplorerComponentViewModel.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Runtime.InteropServices;
66
using System.Windows.Media.Imaging;
7+
using NLog;
78
using Rubberduck.Parsing.Symbols;
89
using Rubberduck.VBEditor;
910
using Rubberduck.Parsing.Annotations;
@@ -68,14 +69,19 @@ public CodeExplorerComponentViewModel(CodeExplorerItemViewModel parent, Declarat
6869
switch (qualifiedModuleName.ComponentType)
6970
{
7071
case ComponentType.Document:
71-
string parenthesizedName;
72+
var parenthesizedName = string.Empty;
73+
var state = DocumentState.Inaccessible;
7274
using (var app = _vbe.HostApplication())
7375
{
74-
var document = app.GetDocument(qualifiedModuleName);
75-
parenthesizedName = document.Name ?? string.Empty;
76+
if (app != null)
77+
{
78+
var document = app.GetDocument(qualifiedModuleName);
79+
parenthesizedName = document?.ModuleName ?? string.Empty;
80+
state = document?.State ?? DocumentState.Inaccessible;
81+
}
7682
}
7783

78-
if (ContainsBuiltinDocumentPropertiesProperty())
84+
if (state == DocumentState.DesignView && ContainsBuiltinDocumentPropertiesProperty())
7985
{
8086
CodeExplorerItemViewModel node = this;
8187
while (node.Parent != null)
@@ -87,7 +93,10 @@ public CodeExplorerComponentViewModel(CodeExplorerItemViewModel parent, Declarat
8793
}
8894
else
8995
{
90-
_name += " (" + parenthesizedName + ")";
96+
if (!string.IsNullOrWhiteSpace(parenthesizedName))
97+
{
98+
_name += " (" + parenthesizedName + ")";
99+
}
91100
}
92101
break;
93102

Rubberduck.VBEEditor/SafeComWrappers/Abstract/HostApplicationBase.cs

Lines changed: 119 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ namespace Rubberduck.VBEditor.SafeComWrappers.Abstract
88
public abstract class HostApplicationBase<TApplication> : SafeComWrapper<TApplication>, IHostApplication
99
where TApplication : class
1010
{
11-
protected HostApplicationBase(string applicationName)
12-
:base(ApplicationFromComReflection(applicationName))
13-
{
14-
ApplicationName = applicationName;
15-
}
11+
protected readonly IVBE Vbe;
1612

17-
protected HostApplicationBase(IVBE vbe, string applicationName)
18-
:base(ApplicationFromVbe(vbe, applicationName))
13+
protected HostApplicationBase(IVBE vbe, string applicationName, bool useComReflection = false)
14+
: base(useComReflection
15+
? ApplicationFromComReflection(applicationName)
16+
: ApplicationFromVbe(vbe, applicationName))
1917
{
18+
Vbe = vbe;
2019
ApplicationName = applicationName;
2120
}
2221

@@ -30,20 +29,21 @@ private static TApplication ApplicationFromComReflection(string applicationName)
3029
catch (COMException exception)
3130
{
3231
_logger.Error(exception, $"Unexpected COM exception while acquiring the host application object for application {applicationName} via COM reflection.");
33-
application = null; // We currently really only use the name anyway.
32+
application = null;
3433
}
3534
catch (InvalidCastException exception)
3635
{
3736
//TODO: Find out why this ever happens.
3837
_logger.Error(exception, $"Unable to cast the host application object for application {applicationName} acquired via COM reflection to its PIA type.");
39-
application = null; //We currently really only use the name anyway.
38+
application = null;
4039
}
4140
catch (Exception exception)
4241
{
4342
//note: We catch all exceptions because we currently really do not need application object and there can be exceptions for unexpected system setups.
4443
_logger.Error(exception, $"Unexpected exception while acquiring the host application object for application {applicationName} from a document module.");
45-
application = null; //We currently really only use the name anyway.
44+
application = null;
4645
}
46+
4747
return application;
4848
}
4949

@@ -68,18 +68,18 @@ private static TApplication ApplicationFromVbe(IVBE vbe, string applicationName)
6868
catch (COMException exception)
6969
{
7070
_logger.Error(exception, $"Unexpected COM exception while acquiring the host application object for application {applicationName} from a document module.");
71-
application = null; // We currently really only use the name anyway.
71+
application = null;
7272
}
7373
catch (InvalidCastException exception)
7474
{
7575
_logger.Error(exception, $"Unable to cast the host application object for application {applicationName} acquiered from a document module to its PIA type.");
76-
application = null; //We currently really only use the name anyway.
76+
application = null;
7777
}
7878
catch (Exception exception)
7979
{
8080
//note: We catch all exceptions because we currently really do not need application object and there can be exceptions for unexpected system setups.
8181
_logger.Error(exception, $"Unexpected exception while acquiring the host application object for application {applicationName} from a document module.");
82-
application = null; //We currently really only use the name anyway.
82+
application = null;
8383
}
8484
return application;
8585
}
@@ -89,50 +89,41 @@ private static IProperty ApplicationPropertyFromDocumentModule(IVBE vbe)
8989
using (var projects = vbe.VBProjects)
9090
{
9191
foreach (var project in projects)
92+
using (project)
9293
{
93-
try
94+
if (project.Protection == ProjectProtection.Locked)
9495
{
95-
if (project.Protection == ProjectProtection.Locked)
96-
{
97-
continue;
98-
}
99-
using (var components = project.VBComponents)
96+
continue;
97+
}
98+
99+
using (var components = project.VBComponents)
100+
{
101+
foreach (var component in components)
102+
using (component)
100103
{
101-
foreach (var component in components)
104+
if (component.Type != ComponentType.Document)
102105
{
103-
try
106+
continue;
107+
}
108+
109+
using (var properties = component.Properties)
110+
{
111+
if (properties.Count <= 1)
104112
{
105-
if (component.Type != ComponentType.Document)
106-
{
107-
continue;
108-
}
109-
using (var properties = component.Properties)
110-
{
111-
if (properties.Count <= 1)
112-
{
113-
continue;
114-
}
115-
foreach (var property in properties)
116-
{
117-
if (property.Name == "Application")
118-
{
119-
return property;
120-
}
121-
property.Dispose();
122-
}
123-
}
113+
continue;
124114
}
125-
finally
115+
116+
foreach (var property in properties)
117+
using(property)
126118
{
127-
component.Dispose();
119+
if (property.Name == "Application")
120+
{
121+
return property;
122+
}
128123
}
129124
}
130125
}
131126
}
132-
finally
133-
{
134-
project?.Dispose();
135-
}
136127
}
137128
return null;
138129
}
@@ -142,9 +133,89 @@ private static IProperty ApplicationPropertyFromDocumentModule(IVBE vbe)
142133

143134
public string ApplicationName { get; }
144135

145-
public virtual IEnumerable<HostDocument> GetDocuments() => null;
136+
private const string ComponentName = "VBIDE.VBComponent";
137+
138+
public virtual IEnumerable<HostDocument> GetDocuments()
139+
{
140+
var result = new List<HostDocument>();
141+
142+
foreach (var document in DocumentComponents())
143+
{
144+
var moduleName = new QualifiedModuleName(document);
145+
var name = GetName(document);
146+
147+
result.Add(new HostDocument(moduleName, name, ComponentName, DocumentState.DesignView, null));
148+
}
149+
return result;
150+
}
151+
152+
public virtual HostDocument GetDocument(QualifiedModuleName moduleName)
153+
{
154+
using (var projects = Vbe.VBProjects)
155+
{
156+
foreach (var project in projects)
157+
using(project)
158+
{
159+
if (moduleName.ProjectName != project.Name || moduleName.ProjectId != project.HelpFile)
160+
{
161+
continue;
162+
}
163+
164+
using (var components = project.VBComponents)
165+
using (var component = components[moduleName.ComponentName])
166+
{
167+
var name = GetName(component);
168+
return new HostDocument(moduleName, name, ComponentName, DocumentState.DesignView, null);
169+
}
170+
}
171+
}
172+
173+
return null;
174+
}
175+
176+
private static string GetName(IVBComponent component)
177+
{
178+
var name = string.Empty;
179+
try
180+
{
181+
using (var properties = component.Properties)
182+
using (var nameProperty = properties["Name"])
183+
{
184+
name = nameProperty?.Value.ToString() ?? string.Empty;
185+
}
186+
}
187+
catch (Exception ex)
188+
{
189+
_logger.Trace(ex, "Handled an expection with accessing VBComponent.Properties.");
190+
}
146191

147-
public virtual HostDocument GetDocument(QualifiedModuleName moduleName) => null;
192+
if (string.IsNullOrWhiteSpace(name))
193+
{
194+
name = component.Name;
195+
}
196+
197+
return name;
198+
}
199+
200+
protected IEnumerable<IVBComponent> DocumentComponents()
201+
{
202+
using (var projects = Vbe.VBProjects)
203+
{
204+
foreach (var project in projects)
205+
using (project)
206+
using (var components = project.VBComponents)
207+
{
208+
foreach (var component in components)
209+
using (component)
210+
{
211+
if (component.Type == ComponentType.Document)
212+
{
213+
yield return component;
214+
}
215+
}
216+
}
217+
}
218+
}
148219

149220
public override bool Equals(ISafeComWrapper<TApplication> other)
150221
{

Rubberduck.VBEEditor/SafeComWrappers/SafeIDispatchWrapper.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ public override bool Equals(ISafeComWrapper<dynamic> other)
3838
return false;
3939
}
4040

41-
var otherPtr = GetPointer(other);
42-
43-
return IDispatchPointer == otherPtr;
41+
return IDispatchPointer == GetPointer(other);
4442
}
4543

4644
public override int GetHashCode()

Rubberduck.VBEEditor/SafeComWrappers/VB/Abstract/HostDocument.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ namespace Rubberduck.VBEditor.SafeComWrappers.Abstract
1717
public enum DocumentState
1818
{
1919
/// <summary>
20-
/// The document is not open and its accompanying <see cref="IVBComponent"/> is not available.
20+
/// The document is not accessible. It might be closed or otherwise unavailable. In this case
21+
/// it should be presumed it is not safe to use the <see cref="IVBComponent"/> of that document.
2122
/// </summary>
22-
Closed,
23+
Inaccessible,
2324
/// <summary>
2425
/// The document is open in design mode.
2526
/// </summary>
@@ -32,7 +33,8 @@ public enum DocumentState
3233

3334
public interface IHostDocument
3435
{
35-
string Name { get; }
36+
QualifiedModuleName QualifiedName { get; }
37+
string ModuleName { get; }
3638
string ClassName { get; }
3739
DocumentState State { get; }
3840
bool TryGetTarget(out SafeIDispatchWrapper iDispatch);
@@ -42,16 +44,18 @@ public class HostDocument : IHostDocument
4244
{
4345
private readonly Func<SafeIDispatchWrapper> _getTargetFunc;
4446

45-
public HostDocument(string name, string className, DocumentState state, Func<SafeIDispatchWrapper> getTargetFunc)
47+
public HostDocument(QualifiedModuleName qualifedName, string name, string className, DocumentState state, Func<SafeIDispatchWrapper> getTargetFunc)
4648
{
47-
Name = name;
49+
QualifiedName = qualifedName;
50+
ModuleName = name;
4851
ClassName = className;
4952
State = state;
5053

5154
_getTargetFunc = getTargetFunc;
5255
}
5356

54-
public string Name { get; }
57+
public QualifiedModuleName QualifiedName { get; }
58+
public string ModuleName { get; }
5559
public string ClassName { get; }
5660
public DocumentState State { get; }
5761

0 commit comments

Comments
 (0)