If Windows explorer is open at a specific path, do not create a new instance
Asked Answered
T

4

3

I am using the following code so that when the user clicks on a button, an instance of Windows Explorer is opened at a specific path. But this causes a new instance of the Explorer to be opened.

I want to change it so that, if Explorer is already open in the same path, the program does not create a new process and instead bring the open instance to front.

private void button_Click(object sender, EventArgs e)
{
    if (Directory.Exists(myPath))
        Process filesFolder =  Process.Start("explorer.exe", Conf.FilesLocation);               
}
Thirlage answered 20/11, 2015 at 12:32 Comment(3)
Then don't start a new instance, find the existing one's window and bring it to the foregroundVander
@PanagiotisKanavos That's the question. How do I know if it's already open or not?Thirlage
@disasterkid, see my answer to know if it's already open or not.Hepza
S
6

You can use the "open" verb, which will open directories in explorer and re-use an an existing explorer.exe if you pass it a directory that it already has open: So, assuming Conf.FilesLocation is a directory:

        var proc = new ProcessStartInfo();
        proc.FileName = Conf.FilesLocation;
        proc.Verb = "open";
        proc.WindowStyle = ProcessWindowStyle.Hidden;
        Process.Start(proc );
Selection answered 20/11, 2015 at 12:51 Comment(1)
The line with proc.WindowStyle = ProcessWindowStyle.Hidden; causes this to fail opening explorer.exe, must be removed.Ens
Z
3

What I have found to work as well, is to use the file:// protocol, when you do this Windows seems to give focus to the folder if it is already open, rather than opening another window

Process.Start("file://" + Conf.FilesLocation);
Zsa answered 3/5, 2018 at 20:58 Comment(0)
H
2

Although @nos's answer works well, mostly (sometimes, in a not deterministically way it creates another explorer windows even though it may already exists), I became unsatisfied with the time spent by the Process.Start(proc) to open an existing window, sometimes 2 to 4 seconds.

So, adapting some VB.NET code I achieve a very fast way of reusing a existing explorer window that is pointing to a desired folder:

First, add COM references:

using Shell32;//Shell32.dll for ShellFolderView

using SHDocVw;//Microsoft Internet Controls for IShellWindows

    [DllImport("user32.dll")]
    public static extern int ShowWindow(IntPtr Hwnd, int iCmdShow);
    [DllImport("user32.dll")]
    public static extern bool IsIconic(IntPtr Hwnd);

    public static bool ShowInExplorer(string folderName) 
    {
        var SW_RESTORE = 9;
        var exShell = (IShellDispatch2)Activator.CreateInstance(                                           
                            Type.GetTypeFromProgID("Shell.Application"));
        
        foreach (ShellBrowserWindow w in (IShellWindows) exShell.Windows())
        {
              

            if (w.Document is ShellFolderView)
                {
                    var expPath = w.Document.FocusedItem.Path;
                    if (!Directory.Exists(Path.GetDirectoryName(expPath)) ||
                        Path.GetDirectoryName(expPath) != folderName) continue;
                    if (IsIconic(new IntPtr(w.HWND)))
                    {
                        w.Visible = false;
                        w.Visible = true;
                        ShowWindow(new IntPtr(w.HWND),SW_RESTORE);
                        break;
                    }
                    else
                    {
                        w.Visible = false;
                        w.Visible = true;
                        break;
                    }
                }
         }
    }

Although we are interested in ShellFolderView objects, and foreach (ShellBrowserWindow w in (ShellFolderView) exShell.Windows()) was more logical, unfortunately ShellFolderView does not implement IEnumerable, so, no foreach :(

Anyway, these is a very fast (200 ms) way of select and blink the correct already opened explorer window.

Hepza answered 26/11, 2020 at 4:50 Comment(0)
U
2

For me, none of the solutions here work in Win10. For Marcelo's solution exShell.Windows() is always empty, Josh's solution doesn't work for directories, you'll get file does not exist error, and nos' solution throws access denied error.

So here's my working solution:

    [DllImport("user32.dll")]
    private static extern bool SetForegroundWindow(IntPtr Hwnd);

    [DllImport("user32.dll")]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    public static void ShowInExplorer(string filePath) {
        IntPtr hWnd = FindWindow("CabinetWClass", Path.GetDirectoryName(filePath));
        if(hWnd != IntPtr.Zero) {
            SetForegroundWindow(hWnd);
        } else {
            Process.Start("explorer.exe", Path.GetDirectoryName(filePath));
        }
    }

Windows Explorer has window class CabinetWClass and sets title to the browsed directory.

So the above code checks to see if an explorer window with a specific directory exists.

If it does exist, the window is brought to the front, otherwise a new instance of explorer is started with the specified directory. Do note that you need to specifically start explorer.exe with the path given as argument, otherwise it'll throw access denied error.

Uncovenanted answered 30/6, 2021 at 11:6 Comment(1)
This solution worked wonder for me. Also, I don't know to which extend, but there could be another type of window class name Explorer­WClass according to this blog post, but that is just for old windows versions: devblogs.microsoft.com/oldnewthing/20150619-00/?p=45341 Still this is the most simple working solution I foundHe

© 2022 - 2025 — McMap. All rights reserved.