【问题标题】:Focus Windows Explorer From C# App In Task Bar从任务栏中的 C# 应用程序聚焦 Windows 资源管理器
【发布时间】:2013-11-26 18:05:55
【问题描述】:

我们公司有作为任务栏图标运行的应用程序 - 除了任务栏图标之外没有 UI。

某些事件会导致任务栏启动 explorer.exe 以显示目录。用户交互不会导致这种情况,因此我们的应用程序没有焦点。

我可以使用如下代码在 Windows 资源管理器中显示目录:

Process.Start("explorer.exe", "c:\somedirectory");

问题是,文件夹在后台启动,我似乎无法集中注意力。

部分问题是 explorer.exe 进程立即退出,单独启动 explorer.exe 进程。我可以使用Process.processes() 找到启动的窗口,并查看窗口标题和进程的开始时间。

一旦我最终掌握了流程(并等待它打开),我就会努力集中注意力。这是我尝试过的:

//trying to bring the application to the front
form.TopMost = true;
form.Activate();
form.BringToFront();
form.Focus();

Process process = ...;

ShowWindow(process.Handle, WindowShowStyle.ShowNormal);
SetForegroundWindow(process.Handle);
SwitchToThisWindow(process.Handle, true);  

ShowWindow(process.MainWindowHandle, WindowShowStyle.ShowNormal);
SetForegroundWindow(process.MainWindowHandle);
SwitchToThisWindow(process.MainWindowHandle, true);  

这会使窗口在任务栏中闪烁,但仍然没有焦点。

我怎样才能让窗口来到屏幕的前面?

【问题讨论】:

  • 问题是:你想要吗?当您在另一个窗口中输入时弹出一个窗口是非常烦人的。闪烁的图标应该告诉应用程序需要交互。
  • 你读过SetForegroundWindow的文档吗?特别是 Remarks 部分中的要点。执行摘要是该系统旨在阻止您窃取注意力。换句话说,处理这个问题的正确方法是设计你的程序,使它不会试图窃取焦点。
  • 交互是由用户在网络浏览器中发起的——基本上他们需要通过点击内网页面上的链接来启动一个文件夹。确实没有其他选择(我们已经探索了浏览器插件等),这正是用户想要的。任何想法如何聚焦窗口是可能的?
  • 你需要搜索焦点窃取
  • 真正的焦点窃取实际上是在 .NET 中实现的,它使用 Dirty Trick。在大家最喜欢的程序集中,拨打AppActivate() method

标签: c# windows winforms process


【解决方案1】:

您可以使用Shell.Application scripting interface 要求资源管理器创建并显示一个新窗口。我相信使用类型化接口也可以做到这一点,但目前我无法理解。

var shellApplication = Type.GetTypeFromProgID("Shell.Application");
dynamic shell = Activator.CreateInstance(shellApplication);
shell.Open(@"C:\drop\");

这似乎打开了焦点窗口(在 Win 8.1 上测试,使用一个在 30 秒后打开的计时器,然后在有焦点的网络浏览器中导航直到计时器触发)。

【讨论】:

  • 感谢 Mitch - 我尝试了一个使用反射 (.NET 2.0) 的版本。它启动文件夹但不关注它。我认为从非调试、非重点的 winform 应用程序运行是不同的。
  • 我确实确保有另一个窗口聚焦(在本例中为 IE),并且该进程未在调试模式下运行。我不确定为什么它对我有用,而不对你有用,你在什么操作系统上运行?
  • 我在 Windows 7 Ultimate x64 上进行测试 - 我也不知道为什么。我肯定更喜欢 3 LOC,而不是我最终得到的几十个非常黑客的代码。
  • 好奇和好奇...我可以在 W7 和 vista 上重现您的问题,但不能在较新的版本上重现。我想知道为什么它改变了......
【解决方案2】:

要聚焦explorer.exe,应用程序本身需要聚焦。 WinForms 故意让这变得困难,因为它可能被滥用。

Here's how you can steal focus in WinForms。请记住它may have bad consequences

一旦您的应用程序获得焦点,您就可以关注另一个进程:

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

SetForegroundWindow(otherProcess.MainWindowHandle);

这是我如何找到资源管理器进程的。就像我说的,explorer.exe 似乎启动了另一个进程并关闭了,所以最好的选择似乎是找到最近启动的 explorer.exe 进程:

public static Process GetExplorerProcess()
{
    var all = Process.GetProcessesByName("explorer");
    Process process = null;
    foreach (var p in all)
        if (process == null || p.StartTime > process.StartTime)
            process = p;
    return process;
}

另一个不需要窃取焦点的选项是显示来自托盘图标的消息。然后你可以设置一个点击处理程序来打开/聚焦文件夹。应用程序自然会通过点击获得焦点。

trayIcon.ShowBalloonTip(3000, "", msg, ToolTipIcon.Info);

这更符合“不要惹恼用户”,但在我的情况下,用户对不得不点击气泡更加恼火。

更新

查找资源管理器进程需要您的应用具有管理员权限。我发现如果您首先关注自己的应用程序,然后启动文件夹,则文件夹会自动获得关注。也就是说,不需要搜索当前进程并调用SetForegroundWindow

【讨论】:

  • 这与 WinForms 无关。
  • @DavidHeffernan - 什么?
  • 这不是 WinForms 问题。问题是 Win32 焦点窃取。阅读 SetForegroundWindow 的文档。
  • @DavidHeffernan 我已阅读文档。我是第一个承认我对 WinForms 了解不多的人——这就是人们提问的原因,对吧? “窃取焦点”链接的最后一个动作是form.Activate();,我已经确认如果没有那个调用它就不起作用。所以 WinForms 似乎参与其中。也许不是。我不确定你的意思是什么。如果您想写一个答案,如果它正常工作,我会非常乐意投票。
  • 我不会写答案。这本质上是对所有其他焦点窃取问题的欺骗。你甚至在你的答案中链接到一个。阻止焦点窃取的是Win32。不是 WinForms。 WinForms 只是 Win32 的一个薄包装器。它不处理焦点,Win32 处理。这是一个 100% 的 Win32 问题。
猜你喜欢
  • 2016-04-24
  • 2013-12-04
  • 1970-01-01
  • 2020-05-21
  • 2011-07-13
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
相关资源
最近更新 更多