从任务栏中的C#应用程序聚焦Windows资源管理器



我们公司有一个作为任务栏图标运行的应用程序,除了任务栏图标之外没有任何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);  

这会使任务栏中的窗口闪烁,但它仍然没有聚焦。

我怎样才能把窗户移到屏幕的前面?

您可以使用Shell.Application脚本接口要求Explorer创建并显示一个新窗口。我相信使用类型化接口也是可能的,但我现在无法理解确切的接口。

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

这似乎打开了有焦点的窗口(在Win 8.1上使用计时器进行测试,计时器在30秒后打开,然后在有焦点的web浏览器中导航,直到计时器启动)。

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

以下是如何在WinForms中窃取焦点。请记住,这可能会产生不良后果。

一旦你的应用程序有了焦点,你就可以关注另一个过程:

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

以下是我如何找到explorer过程的。就像我说的,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

最新更新