Open files faster with CustomPlaces

2021 JAN 06

Back to index

While working I usually start by browsing to a project directory using Windows Explorer. From there I open files and start programs. Mostly double clicking files to edit. This works great for most text files. Not so great for other types of files.

Sometimes it is necessary to create a new file or open an existing file from within a program using Window’s OpenFileDialog. This is the dialog that shows up when you press File > Open... Unfortunately, this dialog has a habit of starting in the wrong directory. It always starts in Documents, Desktop, or some other folder used severals days ago. I end up having to navigate to my projects directory again. Perhaps severals times if multiple programs are involved.

It would be great if OpenFileDialog had a shortcut to my projects directory. It would be even greater if OpenFileDialog had a shortcut to all Explorer windows that are currently open.

We can make it so using FileDialog.CustomPlaces and shell programming.

Inspiration

The poor implementation in Microsoft Visual Studio 2017 inspired this idea. It inserts a shortcut to repos:

Use of CustomPlaces in Microsoft Visual Studio 2017

CustomPlaces

It is trivial to add CustomPlaces to OpenFileDialog and SaveFileDialog. A custom place is a shortcut to a folder; for our intents and purposes at-least.

The following example demonstrates how to add a shortcut to C:\

using System;
using System.Windows.Forms;

namespace Example
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            var dialog = new OpenFileDialog();
            dialog.CustomPlaces.Add("C:\\");
            dialog.ShowDialog();
        }
    }
}
OpenFileDialog with a shortcut to C:\

Enumerating Explorer locations

How about adding useful paths? Such as locations already open in Explorer. Turns out it is almost trivial (thanks to the help of Luc Morin.)

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Example
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            var dialog = new OpenFileDialog();

            // Add shortcuts to all locations open in Windows Explorer.
            var paths = GetExplorerPaths();
            paths.ForEach(dialog.CustomPlaces.Add);

            dialog.ShowDialog();
        }

        // Returns a list of all locations open in Windows Explorer.
        static List<string> GetExplorerPaths()
        {
            var paths = new List<string>();

            // Based on code by Luc Morin
            // https://stackoverflow.com/a/20961047
            
            // Use the Windows Shell to get a list of all Explorer locations.
            dynamic shell = null;
            try
            {
                var t = Type.GetTypeFromProgID("Shell.Application");
                shell = Activator.CreateInstance(t);

                // Enumerate all InternetExplorer shell objects. These include 
                // Internet Explorer and regular file Explorer.
                // https://docs.microsoft.com/en-us/windows/win32/shell/shellwindows
                var windows = shell.Windows();
                for (int i = 0; i < windows.Count; i++)
                {
                    var explorer = windows.Item(i);
                    if (explorer == null)
                    {
                        continue;
                    }

                    // Don't include locations from Internet Explorer.
                    var processFileName = Path.GetFileName((string)explorer.FullName);
                    if (0 == string.Compare(processFileName, "explorer.exe", true))
                    {
                        // LocationURL is null if Explorer is showing "This PC".
                        if (!string.IsNullOrEmpty(explorer.LocationURL))
                        {
                            var location = new Uri(explorer.LocationURL);
                            paths.Add(location.LocalPath);
                        }
                    }
                }
            }
            finally
            {
                Marshal.FinalReleaseComObject(shell);
            }
            // TODO: catch (Exception ex) { ... }

            return paths;
        }
    }
}

The result is an OpenFileDialog with CustomPlaces pointing to all location currently open in Window Explorer. This should help our users find the files they are looking for a little faster:

OpenFileDialog with shortcuts to all locations open in Explorer
A close up of CustomPlaces added to OpenFileDialog

Next time your are implementing an OpenFileDialog or a SaveFileDialog consider employing this trick.

For C++ programmers there is a similar API under IFileDialog::AddPlace. Partial example here.

Future projects

In a future article we will explore the possibility to add this feature to all OpenFileDialog and SaveFileDialog regardless if we create them or not:

info@wronex.com