简体   繁体   English

如果 Windows 资源管理器在特定路径打开,则不要创建新实例

[英]If Windows explorer is open at a specific path, do not create a new instance

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.我正在使用以下代码,以便当用户单击按钮时,会在特定路径上打开Windows 资源管理器的实例。 But this causes a new instance of the Explorer to be opened.但这会导致打开一个新的Explorer实例。

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);               
}

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:您可以使用“打开”动词,它将在资源管理器中打开目录并重新使用现有的 explorer.exe,如果您向它传递一个已经打开的目录:因此,假设Conf.FilesLocation是一个目录:

        var proc = new ProcessStartInfo();
        proc.FileName = Conf.FilesLocation;
        proc.Verb = "open";
        proc.WindowStyle = ProcessWindowStyle.Hidden;
        Process.Start(proc );

我发现也可以使用file://协议,当您执行此操作时,Windows 似乎将焦点放在已打开的文件夹上,而不是打开另一个窗口

Process.Start("file://" + Conf.FilesLocation);

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.尽管@nos 的回答效果很好,但大多数情况下(有时,它会以不确定的方式创建另一个资源管理器窗口,即使它可能已经存在),但我对Process.Start(proc)打开现有窗口所花费的时间感到不满意,有时2到4秒。

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:因此,通过调整一些VB.NET 代码,我实现了一种非常快速的重用指向所需文件夹的现有资源管理器窗口的方法:

First, add COM references:首先,添加 COM 引用:

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 :(虽然我们对 ShellFolderView 对象感兴趣,并且foreach (ShellBrowserWindow w in (ShellFolderView) exShell.Windows())合乎逻辑,但不幸的是 ShellFolderView 没有实现 IEnumerable,所以,没有 foreach :(

Anyway, these is a very fast (200 ms) way of select and blink the correct already opened explorer window.无论如何,这是一种非常快速(200 毫秒)的选择和闪烁正确的已打开资源管理器窗口的方式。

For me, none of the solutions here work in Win10.对我来说,这里的解决方案都不适用于 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.对于 Marcelo 的解决方案exShell.Windows()始终为空,Josh 的解决方案不适用于目录,您将收到file does not exist错误,并且 nos 的解决方案引发access denied错误。

So here's my working solution:所以这是我的工作解决方案:

    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. Windows 资源管理器具有窗口类CabinetWClass并将标题设置为浏览的目录。

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.请注意,您需要使用作为参数给出的路径专门启动explorer.exe ,否则它会抛出access denied错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM