【问题标题】:start and close instance of explorer.exe启动和关闭 explorer.exe 的实例
【发布时间】:2017-11-30 13:22:36
【问题描述】:

当我尝试像这样从 c# 启动 explorer.exe 时,我有一个奇怪的行为:

ProcessStartInfo info = new ProcessStartInfo("explorer.exe", "E:");
info.WindowStyle = ProcessWindowStyle.Hidden;
Process process = new Process();
process.StartInfo = info;
process.Start();
Thread.Sleep(2000);
bool res = process.CloseMainWindow(); // InvalidOperationException -> already exited
process.Close();
process.WaitForExit(5000);

问题是:

这个异常似乎是正确的,因为此时HasExited 已经返回true。尽管如此,在任务管理器中创建的资源管理器实例仍然存在。

所以我不明白我的电话是做什么的。我原以为它会直接启动资源管理器的一个实例,但似乎没有,或者资源管理器以某种不同的方式工作。

我的第二个问题是:如何以编程方式启动并在此之后立即停止资源管理器的新特定实例?

编辑 回答一些问题:

  • 资源管理器选项 Launch Folder Windows in a separate process 设置为 true
  • 创建的process.Id 不在任务管理器中。例如:taskmanager 中显示的新资源管理器实例的 PID 为 4968,而调试器显示 10752 作为已创建(和退出)进程的 ID。

编辑:这里是任务管理器在运行约 12 次调试后的屏幕截图

【问题讨论】:

  • the created instance of explorer is still present.确定它是资源管理器的created instance,还是只是默认的一直在运行?
  • process.Close(); process.WaitForExit(5000); 为什么会有 process.Close() 那里
  • @mjwills 是的,我确定,它是创建的实例。
  • @MethodMan 来自 MSDN 示例
  • 不要被任务管理器误导,资源管理器会为其主窗口中的每个选项卡创建一个进程。 Explorer 是一个单实例进程。如果您再次启动它,它只会要求第一个实例显示 URL。并退出。功能,而不是错误。使用 IShellWindows 接口查找正在运行的实例。

标签: c# windows-10 windows-explorer


【解决方案1】:

这可能是因为有问题的 explorer.exe 进程已退出。 Windows 使用多个资源管理器窗口会做一些奇怪的事情,这取决于您设置的选项。默认情况下,如果我没记错的话,所有窗口最终都会在一个进程中运行。

我要做的是为您刚刚生成的进程输出 processid:

Console.WriteLine($"{process.Id} has exited {process.HasExited}");

然后查看任务管理器,看看能不能找到对应的进程。我想 HasExited 是真的,所以你不会找到进程,但窗口会打开。

您可能必须将process.EnableRaisingEvents 设置为true 才能从process.HasExited 获得有效答案,我想不起来了。

还可以通过文件夹选项检查资源管理器中的设置,看看您是否在视图选项卡上启用了Launch Folder Windows in a separate process

如果您确实找到了您的进程,您可以随时终止该进程并查看您的窗口是否关闭。如果是这样,那么可能是 explorer.exe 没有创建您可以使用 Spy++ 检查的主窗口句柄


编辑了更多信息

此外,@Hans Passant 上面提到 shell 窗口的工作方式不同。所以实际发生的是,explorer.exe (1234) 联系根explorer.exe (321),然后创建一个新窗口(如果 Launch separate 为 false)或产生一个子进程 explorer.exe (3445)。你的进程explorer.exe (1234) 完成了它的工作,然后退出。您的进程从未创建任何窗口,因此CloseMainWindow() 将找不到要关闭的窗口和错误。

如何关闭特定的资源管理器窗口

为此,您需要使用 ShellWindows,请参阅 Is there a way to close a particular instance of explorer with C#?

作为参考,这里使用的代码是:

ShellWindows _shellWindows = new SHDocVw.ShellWindows();
string processType;

foreach (InternetExplorer ie in _shellWindows)
{
    //this parses the name of the process
    processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();

    //this could also be used for IE windows with processType of "iexplore"
    if (processType.Equals("explorer") && ie.LocationURL.Contains(@"C:/Users/Bob"))
        {
            ie.Quit();
        }    
}

请注意,您需要注意不要关闭用户想要打开的窗口。是否有关闭窗口的理由?

【讨论】:

  • 查看我的编辑:创建的任务不会显示在任务管理器中,而是一个具有不同 PID 的新资源管理器实例
  • 那么我认为就像@Hans Passant 在他上面的评论中所建议的那样。您的进程正在生成,并与根 explorer.exe 进程联系,然后该进程又创建了自己的子进程。
  • 好的,谢谢。有什么建议如何获取子进程的 PID 以便我可以关闭它?
  • 我已经更新了我的答案,为您提供一些参考。
  • 这对我有用,非常感谢 :-) 是的,我会注意的。我想把它关起来整理一下。我只需要资源管理器打开特定路径(断开连接的网络驱动器),然后仅此而已。这也是我将其创建为隐藏的原因,因此用户永远看不到它。
【解决方案2】:

问题在于has UI Interface 的概念,根据定义:

通过发送关闭消息来关闭具有用户界面的进程 到它的主窗口。

但是explorer.exe 远比使用 UI 的简单过程复杂得多。 例如,如果您使用另一个更简单的应用程序(例如记事本),则不会引发异常:

 ProcessStartInfo info = new ProcessStartInfo("notepad.exe");
            info.WindowStyle = ProcessWindowStyle.Maximized;
            Process process = new Process();
            process.StartInfo = info;
            process.Start();
            Thread.Sleep(2000);
            bool res = process.CloseMainWindow(); // InvalidOperationException -> already exited
            process.Close();

【讨论】:

    猜你喜欢
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 2019-09-12
    • 2022-01-19
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多