繁体   English   中英

关闭打开的资源管理器窗口而不终止 explorer.exe

[英]Close open Explorer windows without terminating explorer.exe

我试过搜索,但没有什么真正符合我的需求。

我不希望explorer.exe 被终止或重新启动。 我只想关闭任何打开的资源管理器窗口。

以下替代方法使用Shell 对象的 COM API 来检索和识别文件资源管理器窗口。 它需要添加对以下内容的 COM 引用:

  • Microsoft Shell 控件和自动化
  • 微软互联网控制

Shell.Windows 方法返回的对象是一个 IEnumerable。 集合中的每个对象都是一个 SHDocVw.InternetExplorer 实例。 如果 Document 对象是 Shell32.ShellFolderView,则资源管理器是文件资源管理器。

    private static void CloseExplorerWindows()

        {
        Shell32.Shell shell = new Shell32.Shell();

        // ref: Shell.Windows method
        // https://msdn.microsoft.com/en-us/library/windows/desktop/bb774107(v=vs.85).aspx
        System.Collections.IEnumerable windows = shell.Windows() as System.Collections.IEnumerable;
        if (windows != null)
            {
            // ref: ShellWindows object
            // https://msdn.microsoft.com/en-us/library/windows/desktop/bb773974(v=vs.85).aspx
            foreach (SHDocVw.InternetExplorer window in windows)
                {
                object doc = window.Document;
                if (doc != null && doc is Shell32.ShellFolderView)
                    {
                    window.Quit();  // closes the window
                    }
                }
            }
        }
    [DllImport("user32.dll")]
    private static extern bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lParam);
    [DllImport("user32.dll")]
    private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);
    [DllImport("user32.dll")]
    private static extern uint RealGetWindowClass(IntPtr hwnd, StringBuilder pszType, uint cchType);
    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    static uint WM_CLOSE = 0x10;

    private delegate bool EnumWindowsDelegate(IntPtr hwnd, IntPtr lParam);

    private static bool EnumWindowsCallback(IntPtr hwnd, IntPtr lParam)
    {
        IntPtr pid = new IntPtr();
        GetWindowThreadProcessId(hwnd, out pid);
        var wndProcess = System.Diagnostics.Process.GetProcessById(pid.ToInt32());
        var wndClass = new StringBuilder(255);
        RealGetWindowClass(hwnd, wndClass, 255);
        if (wndProcess.ProcessName == "explorer" && wndClass.ToString() == "CabinetWClass")
        {
            //hello file explorer window...

            SendMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); // ... bye file explorer window
        }
        return (true);
    }

    static void Main()
    {
        EnumWindowsDelegate childProc = new EnumWindowsDelegate(EnumWindowsCallback);

        EnumWindows(childProc, IntPtr.Zero);

        Console.ReadKey();
    }

编辑:
所以我想唯一有趣的事情是回调,它将被窗口为每个枚举窗口调用(hwnd 中所述窗口的句柄)

GetWindowThreadProcessId为我们提供给定窗口句柄的 processid

GetProcessById然后为我们提供一个进程对象来读取进程名称之类的内容

RealGetWindowClass为我们提供给定窗口句柄的注册类名

最后我们可以看看当前窗口的进程是否为资源管理器,窗口类是否为“CabinetWClass”,即普通文件资源管理器窗口的窗口类

最后但并非最不重要的是,如果我们的检查没问题,请发送WM_CLOSE消息以请求窗口自行关闭...

    public static void CloseExplorerWindows() => EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero);

    private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern int GetWindowTextLength(IntPtr hWnd);
    [DllImport("user32.dll")]
    private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
    [DllImport("user32.dll")]
    private static extern bool IsWindowVisible(IntPtr hWnd);
    [DllImport("user32.dll", SetLastError = true)]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    static uint WM_CLOSE = 0x10;

    private static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
    {
        int size = GetWindowTextLength(hWnd);
        if (size++ > 0 && IsWindowVisible(hWnd))
        {
            var sb = new StringBuilder(size);
            GetWindowText(hWnd, sb, size);

            var threadID = GetWindowThreadProcessId(hWnd, out var processID);
            var s = System.Diagnostics.Process.GetProcessById((int)processID).ProcessName;

            if (s == "explorer" && sb.ToString() != "Program Manager")
                SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        }
        return true;
    }

默认情况下,资源管理器作为单个进程运行,任何打开的窗口都只是进程的一个线程。
通常,要关闭程序,您需要向进程发送关闭消息。 在这种情况下,关闭 explorer.exe 将关闭所有资源管理器窗口。

要关闭单个窗口,您需要通过它自己的进程打开每个窗口。 这可以通过注册表设置或在查看->选项->查看->高级设置下启用:“启动...单独进程”来完成

a) 查找要关闭的窗口的 PID(进程 ID)。

通过任务管理器:
1. 在进程列表中,单击“Windows 资源管理器”左侧的箭头
2. 检查窗口名称是否与您要关闭的窗口匹配
3. 右键单击​​“Windows 资源管理器”,单击“转到详细信息”
4.记录pid

通过命令:
tasklist /V /FI "IMAGENAME eq explorer.exe"

如果每个资源管理器窗口都在其自己的进程中打开,则上述命令将在最后一列中显示窗口标题。
否则将显示“N/A”。

所有资源管理器窗口的 pid 将相同。 Explorer.exe 进程有自己的 pid,标题为“N/A”
如果已启用“单独进程”,例如。 通过文件夹视图选项,然后可以通过 taskkill 的进程 ID 和过滤器选项关闭每个窗口。

要关闭,必须首先激活所需的窗口,否则使用 pid 关闭将关闭最后一个活动窗口,或者使用窗口标题过滤器关闭将给出错误:

信息:没有任务以指定的条件运行。

b) taskkill /pid <pid>将关闭最后一个活动窗口。
重复此命令将打开下一个窗口。

taskkill /im explorer.exe /fi "windowtitle eq <window name>"
taskkill /fi "IMAGENAME eq explorer.exe" /fi "windowtitle eq <window name>"

<窗口名称> 不区分大小写
如果在文件夹视图中启用了标题栏中的完整路径,则包括完整路径或通配符。

要关闭所有资源管理器窗口:
taskkill /im explorer.exe

注意事项:

  1. 要激活资源管理器窗口,如果启用了窗口重用,请发出相同的命令来打开窗口。
  2. 资源管理器窗口(ing)进程的pid在响应表的最后一行,在“PID”列中; 可以通过 FOR 循环访问。
  3. 从@HelpingHand 关闭窗口的 vbs 解决方法:
    https://superuser.com/questions/1263315/how-to-close-a-particular-opened-folder-using-cmd-or-batch-file
  4. 激活窗口的 vbs 解决方法:
    http://superuser.com/questions/327676/application-to-automatically-switch-between-two-applications-in-windows

在 Win 10 上测试

暂无
暂无

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

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