diff --git a/RetailCoder.VBE/Root/RubberduckModule.cs b/RetailCoder.VBE/Root/RubberduckModule.cs index 7b2b42e51a..1436aba97e 100644 --- a/RetailCoder.VBE/Root/RubberduckModule.cs +++ b/RetailCoder.VBE/Root/RubberduckModule.cs @@ -82,6 +82,7 @@ public override void Load() ApplyDefaultInterfacesConvention(assemblies); ApplyConfigurationConvention(assemblies); ApplyAbstractFactoryConvention(assemblies); + Rebind().To().InSingletonScope(); BindCommandsToMenuItems(); diff --git a/RetailCoder.VBE/Rubberduck.csproj b/RetailCoder.VBE/Rubberduck.csproj index 6ac4f1578f..2959822a3a 100644 --- a/RetailCoder.VBE/Rubberduck.csproj +++ b/RetailCoder.VBE/Rubberduck.csproj @@ -467,6 +467,7 @@ + diff --git a/RetailCoder.VBE/UI/FileBrowserDialogFactory.cs b/RetailCoder.VBE/UI/FileBrowserDialogFactory.cs index 118953a510..582235f907 100644 --- a/RetailCoder.VBE/UI/FileBrowserDialogFactory.cs +++ b/RetailCoder.VBE/UI/FileBrowserDialogFactory.cs @@ -14,19 +14,27 @@ IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton, public class DialogFactory : IFolderBrowserFactory { + private static readonly bool OldSchool = Environment.OSVersion.Version.Major < 6; + public IFolderBrowser CreateFolderBrowser(string description) { - return new FolderBrowser(description); + return !OldSchool + ? new ModernFolderBrowser(description) as IFolderBrowser + : new FolderBrowser(description); } public IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton) { - return new FolderBrowser(description, showNewFolderButton); + return !OldSchool + ? new ModernFolderBrowser(description, showNewFolderButton) as IFolderBrowser + : new FolderBrowser(description, showNewFolderButton); } public IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton, Environment.SpecialFolder rootFolder) { - return new FolderBrowser(description, showNewFolderButton, rootFolder); + return !OldSchool + ? new ModernFolderBrowser(description, showNewFolderButton, rootFolder) as IFolderBrowser + : new FolderBrowser(description, showNewFolderButton, rootFolder); } } } diff --git a/RetailCoder.VBE/UI/ModernFolderBrowser.cs b/RetailCoder.VBE/UI/ModernFolderBrowser.cs new file mode 100644 index 0000000000..754ee09d59 --- /dev/null +++ b/RetailCoder.VBE/UI/ModernFolderBrowser.cs @@ -0,0 +1,121 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; +using FileDialog = System.Windows.Forms.FileDialog; + +namespace Rubberduck.UI +{ + public class ModernFolderBrowser : IFolderBrowser + { + // ReSharper disable InconsistentNaming + private const BindingFlags DefaultBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + + private static readonly AssemblyName FormsAssemblyName = + Assembly.GetExecutingAssembly() + .GetReferencedAssemblies() + .FirstOrDefault(a => a.FullName.StartsWith("System.Windows.Forms")); + + private static readonly Assembly FormsAssembly = Assembly.Load(FormsAssemblyName); + private static readonly Type IFileDialog = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("IFileDialog")); + private static readonly MethodInfo OpenFileDialogCreateVistaDialog = typeof(System.Windows.Forms.OpenFileDialog).GetMethod("CreateVistaDialog", DefaultBindingFlags); + private static readonly MethodInfo OpenFileDialogOnBeforeVistaDialog = typeof(System.Windows.Forms.OpenFileDialog).GetMethod("OnBeforeVistaDialog", DefaultBindingFlags); + private static readonly MethodInfo FileDialogGetOptions = typeof(FileDialog).GetMethod("GetOptions", DefaultBindingFlags); + private static readonly MethodInfo IFileDialogSetOptions = IFileDialog.GetMethod("SetOptions", DefaultBindingFlags); + private static readonly MethodInfo IFileDialogShow = IFileDialog.GetMethod("Show", DefaultBindingFlags); + private static readonly Type FOS = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("FOS")); + private static readonly uint FOS_PICKFOLDERS = (uint)FOS.GetField("FOS_PICKFOLDERS").GetValue(null); + private static readonly Type VistaDialogEvents = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("VistaDialogEvents")); + private static readonly ConstructorInfo VistaDialogEventsCtor = VistaDialogEvents.GetConstructors().SingleOrDefault(); + private static readonly MethodInfo IFileDialogAdvise = IFileDialog.GetMethod("Advise", DefaultBindingFlags); + private static readonly MethodInfo IFileDialogUnadvise = IFileDialog.GetMethod("Unadvise", DefaultBindingFlags); + + // ReSharper restore InconsistentNaming + + private readonly System.Windows.Forms.OpenFileDialog _dialog; + private readonly object _newDialog; + + // ReSharper disable once UnusedParameter.Local + public ModernFolderBrowser(string description, bool showNewFolderButton, Environment.SpecialFolder rootFolder) + { + _root = rootFolder; + _dialog = new System.Windows.Forms.OpenFileDialog + { + Title = description, + InitialDirectory = Environment.GetFolderPath(_root), + // ReSharper disable once LocalizableElement + Filter = "Folders|\n", + AddExtension = false, + CheckFileExists = false, + DereferenceLinks = true, + Multiselect = false + }; + _newDialog = OpenFileDialogCreateVistaDialog.Invoke(_dialog, new object[] { }); + OpenFileDialogOnBeforeVistaDialog.Invoke(_dialog, new[] { _newDialog }); + var options = (uint)FileDialogGetOptions.Invoke(_dialog, new object[] { }) | FOS_PICKFOLDERS; + IFileDialogSetOptions.Invoke(_newDialog, new object[] { options }); + } + + public ModernFolderBrowser(string description, bool showNewFolderButton) + : this(description, showNewFolderButton, Environment.SpecialFolder.MyDocuments) + { } + + public ModernFolderBrowser(string description) : this(description, true) { } + + public string Description + { + get { return _dialog.Title; } + set { _dialog.Title = value; } + } + + public bool ShowNewFolderButton + { + get { return true; } + // ReSharper disable once ValueParameterNotUsed + set { } + } + + private Environment.SpecialFolder _root; + public Environment.SpecialFolder RootFolder + { + get { return _root; } + set + { + _root = value; + _dialog.InitialDirectory = Environment.GetFolderPath(_root); + } + } + + public string SelectedPath + { + get { return _dialog.FileName; } + set { _dialog.FileName = value; } + } + + public DialogResult ShowDialog() + { + var sink = VistaDialogEventsCtor.Invoke(new object[] { _dialog }); + var cookie = 0u; + var parameters = new[] { sink, cookie }; + IFileDialogAdvise.Invoke(_newDialog, parameters); + //This is the cookie returned as a ref parameter in the call above. + cookie = (uint)parameters[1]; + int returnValue; + try + { + returnValue = (int)IFileDialogShow.Invoke(_newDialog, new object[] { IntPtr.Zero }); + } + finally + { + IFileDialogUnadvise.Invoke(_newDialog, new object[] { cookie }); + GC.KeepAlive(sink); + } + return returnValue == 0 ? DialogResult.OK : DialogResult.Cancel; + } + + public void Dispose() + { + _dialog.Dispose(); + } + } +}