如何激活由另一个进程启动的窗口

BNT*_*BNT 2 .net c# winapi winforms

我想这可能是不可能的。请证明我错了。

以下设置:

  • 我的带有 GUI 的 .NET C# 应用程序(让我们称之为它gui)通过创建一个来打开另一个应用程序(让我们称之为它servernew Process()
  • server由其他人开发)以一个参数启动以隐藏其 GUI
  • 等待gui用户进行一些输入
  • thengui命令server执行一些任务
  • 这些任务是在我提供给的程序集/DLL 中定义的server
  • 其中一项任务是打开表单/对话框并向用户询问更多问题

现在,由于整个用户体验需要针对重复操作进行优化,因此打开的 GUI 元素(窗口/表单/对话框)需要预先选择/聚焦/活动。

第一个问题的出现是因为我没有找到这些属性(Focus、Active、Selected、TopMost)之间差异的明确解释。

现在真正的问题是,我如何确保所有 GUI 元素都处于活动状态并被选中,无论它们是由我的gui进程还是由server进程启动?

使用 WINAPI 可以更强大我读到所以我定义了以下内容

// required to use WINAPI for RegainFocus();
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SetActiveWindow(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

static private void RegainFocus()
{
    // set focus back to and show application for faster input
    // SW_RESTORE = 9
    ShowWindow(Process.GetCurrentProcess().MainWindowHandle, 9);
    SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle);
    SetActiveWindow(Process.GetCurrentProcess().MainWindowHandle);
}
Run Code Online (Sandbox Code Playgroud)

那么到目前为止我尝试过的是:

  • 像这样设置StartInfo进程的server(这样新进程就不会抢走焦点gui
    myProcess.StartInfo.UseShellExecute = false;
    myProcess.StartInfo.CreateNoWindow = true;
    myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
    Run Code Online (Sandbox Code Playgroud)
  • 启动该server过程WaitForInputIdle(如此处所述以确保server真正准备好
  • 也可以RegainFocus()gui应用程序中使用
  • 在 DLL 中,server我创建一个新的Form()并尝试(将窗口置于前面并选择它)
    myForm = new Form();
    myForm.Activated += dialog_Activated;
    myForm.PerformLayout();
    myForm.TopMost = true;
    myForm.Activate();
    myForm.BringToFront();
    myForm.Focus();
    myForm.Select();
    DialogResult result = myForm.ShowDialog();
    
    Run Code Online (Sandbox Code Playgroud)
  • TopMost=true将对话框放在前面的工作gui
  • dialog_Activated()方法使用 将焦点设置在第一个输入控件上FocusControl()。这有效。

其结果是在我的顶部出现一个窗口gui,其中光标在第一个输入控件中闪烁,但已取消选择/不活动。当我点击时,我可以看到在后台<TAB>选择了不同的控件。gui

我也尝试RegainFocus()在表单中喷洒电话,但没有成功。

我有更多想法但无法实现:

目标框架是.NET 4.5,目标操作系统是Windows 7和Windows 10。

感谢您的任何帮助和意见/提示!

BNT*_*BNT 5

我得到了一个似乎适用于 Windows 10 和 Windows 7 的解决方案。

在我失去焦点后,我使用该RegainFocus()功能重新获得焦点(并激活窗口),请参阅问题。注意:不要将 processHANDLEMainWindowHandle. 当一个对象被隐藏时,它MainWindowHandle很可能是隐藏的0

我删除了

    myProcess.StartInfo.UseShellExecute = false;
    myProcess.StartInfo.CreateNoWindow = true;
    myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Run Code Online (Sandbox Code Playgroud)

当启动server进程时,为了不弄乱可见性状态。但我还是保留了[WaitForInputIdle][1]

在Windows 7上,这仍然不够,并且创建的进程上的AllowSetForegroundWindow不起作用(不过感谢您的评论),任务栏不是将窗口带到前面,而是闪烁。这里的解决方案是设置注册表

\HKEY_CURRENT_USER\Control Panel\Desktop\ForegroundLockTimeout 
Run Code Online (Sandbox Code Playgroud)

0重新启动机器。然后,代码在 Windows 7 和 10 上的行为相同。如果有正确的权限,甚至可以通过编程来完成此操作。

由于这个问题有很多不同的答案和解决方案,我认为它取决于许多因素(如 Windows 版本、注册表设置、可能 UAC 和主题设置、框架和运行时、更多条件,...),这就是为什么我我还想提一下我发现的其他方法。


归档时间:

查看次数:

3509 次

最近记录:

6 年,11 月 前