Skip to content

Commit 82ca648

Browse files
authored
Merge pull request #226 from rubberduck-vba/next
sync with main repo
2 parents 7b70a38 + 50e6014 commit 82ca648

File tree

4 files changed

+134
-3
lines changed

4 files changed

+134
-3
lines changed

RetailCoder.VBE/Root/RubberduckModule.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public override void Load()
8282
ApplyDefaultInterfacesConvention(assemblies);
8383
ApplyConfigurationConvention(assemblies);
8484
ApplyAbstractFactoryConvention(assemblies);
85+
Rebind<IFolderBrowserFactory>().To<DialogFactory>().InSingletonScope();
8586

8687
BindCommandsToMenuItems();
8788

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@
467467
<Compile Include="UI\CodeExplorer\Commands\AddClassModuleCommand.cs" />
468468
<Compile Include="UI\CodeExplorer\Commands\AddStdModuleCommand.cs" />
469469
<Compile Include="UI\CodeExplorer\Commands\AddTestModuleCommand.cs" />
470+
<Compile Include="UI\ModernFolderBrowser.cs" />
470471
<Compile Include="VersionCheck\IVersionCheck.cs" />
471472
<Compile Include="UI\Command\MenuItems\CommandBars\AppCommandBarBase.cs" />
472473
<Compile Include="UI\Command\MenuItems\CommandBars\ContextSelectionLabelMenuItem.cs" />

RetailCoder.VBE/UI/FileBrowserDialogFactory.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,27 @@ IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton,
1414

1515
public class DialogFactory : IFolderBrowserFactory
1616
{
17+
private static readonly bool OldSchool = Environment.OSVersion.Version.Major < 6;
18+
1719
public IFolderBrowser CreateFolderBrowser(string description)
1820
{
19-
return new FolderBrowser(description);
21+
return !OldSchool
22+
? new ModernFolderBrowser(description) as IFolderBrowser
23+
: new FolderBrowser(description);
2024
}
2125

2226
public IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton)
2327
{
24-
return new FolderBrowser(description, showNewFolderButton);
28+
return !OldSchool
29+
? new ModernFolderBrowser(description, showNewFolderButton) as IFolderBrowser
30+
: new FolderBrowser(description, showNewFolderButton);
2531
}
2632

2733
public IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton, Environment.SpecialFolder rootFolder)
2834
{
29-
return new FolderBrowser(description, showNewFolderButton, rootFolder);
35+
return !OldSchool
36+
? new ModernFolderBrowser(description, showNewFolderButton, rootFolder) as IFolderBrowser
37+
: new FolderBrowser(description, showNewFolderButton, rootFolder);
3038
}
3139
}
3240
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
using System.Windows.Forms;
5+
using FileDialog = System.Windows.Forms.FileDialog;
6+
7+
namespace Rubberduck.UI
8+
{
9+
public class ModernFolderBrowser : IFolderBrowser
10+
{
11+
// ReSharper disable InconsistentNaming
12+
private const BindingFlags DefaultBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
13+
14+
private static readonly AssemblyName FormsAssemblyName =
15+
Assembly.GetExecutingAssembly()
16+
.GetReferencedAssemblies()
17+
.FirstOrDefault(a => a.FullName.StartsWith("System.Windows.Forms"));
18+
19+
private static readonly Assembly FormsAssembly = Assembly.Load(FormsAssemblyName);
20+
private static readonly Type IFileDialog = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("IFileDialog"));
21+
private static readonly MethodInfo OpenFileDialogCreateVistaDialog = typeof(System.Windows.Forms.OpenFileDialog).GetMethod("CreateVistaDialog", DefaultBindingFlags);
22+
private static readonly MethodInfo OpenFileDialogOnBeforeVistaDialog = typeof(System.Windows.Forms.OpenFileDialog).GetMethod("OnBeforeVistaDialog", DefaultBindingFlags);
23+
private static readonly MethodInfo FileDialogGetOptions = typeof(FileDialog).GetMethod("GetOptions", DefaultBindingFlags);
24+
private static readonly MethodInfo IFileDialogSetOptions = IFileDialog.GetMethod("SetOptions", DefaultBindingFlags);
25+
private static readonly MethodInfo IFileDialogShow = IFileDialog.GetMethod("Show", DefaultBindingFlags);
26+
private static readonly Type FOS = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("FOS"));
27+
private static readonly uint FOS_PICKFOLDERS = (uint)FOS.GetField("FOS_PICKFOLDERS").GetValue(null);
28+
private static readonly Type VistaDialogEvents = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("VistaDialogEvents"));
29+
private static readonly ConstructorInfo VistaDialogEventsCtor = VistaDialogEvents.GetConstructors().SingleOrDefault();
30+
private static readonly MethodInfo IFileDialogAdvise = IFileDialog.GetMethod("Advise", DefaultBindingFlags);
31+
private static readonly MethodInfo IFileDialogUnadvise = IFileDialog.GetMethod("Unadvise", DefaultBindingFlags);
32+
33+
// ReSharper restore InconsistentNaming
34+
35+
private readonly System.Windows.Forms.OpenFileDialog _dialog;
36+
private readonly object _newDialog;
37+
38+
// ReSharper disable once UnusedParameter.Local
39+
public ModernFolderBrowser(string description, bool showNewFolderButton, Environment.SpecialFolder rootFolder)
40+
{
41+
_root = rootFolder;
42+
_dialog = new System.Windows.Forms.OpenFileDialog
43+
{
44+
Title = description,
45+
InitialDirectory = Environment.GetFolderPath(_root),
46+
// ReSharper disable once LocalizableElement
47+
Filter = "Folders|\n",
48+
AddExtension = false,
49+
CheckFileExists = false,
50+
DereferenceLinks = true,
51+
Multiselect = false
52+
};
53+
_newDialog = OpenFileDialogCreateVistaDialog.Invoke(_dialog, new object[] { });
54+
OpenFileDialogOnBeforeVistaDialog.Invoke(_dialog, new[] { _newDialog });
55+
var options = (uint)FileDialogGetOptions.Invoke(_dialog, new object[] { }) | FOS_PICKFOLDERS;
56+
IFileDialogSetOptions.Invoke(_newDialog, new object[] { options });
57+
}
58+
59+
public ModernFolderBrowser(string description, bool showNewFolderButton)
60+
: this(description, showNewFolderButton, Environment.SpecialFolder.MyDocuments)
61+
{ }
62+
63+
public ModernFolderBrowser(string description) : this(description, true) { }
64+
65+
public string Description
66+
{
67+
get { return _dialog.Title; }
68+
set { _dialog.Title = value; }
69+
}
70+
71+
public bool ShowNewFolderButton
72+
{
73+
get { return true; }
74+
// ReSharper disable once ValueParameterNotUsed
75+
set { }
76+
}
77+
78+
private Environment.SpecialFolder _root;
79+
public Environment.SpecialFolder RootFolder
80+
{
81+
get { return _root; }
82+
set
83+
{
84+
_root = value;
85+
_dialog.InitialDirectory = Environment.GetFolderPath(_root);
86+
}
87+
}
88+
89+
public string SelectedPath
90+
{
91+
get { return _dialog.FileName; }
92+
set { _dialog.FileName = value; }
93+
}
94+
95+
public DialogResult ShowDialog()
96+
{
97+
var sink = VistaDialogEventsCtor.Invoke(new object[] { _dialog });
98+
var cookie = 0u;
99+
var parameters = new[] { sink, cookie };
100+
IFileDialogAdvise.Invoke(_newDialog, parameters);
101+
//This is the cookie returned as a ref parameter in the call above.
102+
cookie = (uint)parameters[1];
103+
int returnValue;
104+
try
105+
{
106+
returnValue = (int)IFileDialogShow.Invoke(_newDialog, new object[] { IntPtr.Zero });
107+
}
108+
finally
109+
{
110+
IFileDialogUnadvise.Invoke(_newDialog, new object[] { cookie });
111+
GC.KeepAlive(sink);
112+
}
113+
return returnValue == 0 ? DialogResult.OK : DialogResult.Cancel;
114+
}
115+
116+
public void Dispose()
117+
{
118+
_dialog.Dispose();
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)