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

时间:2018-12-10 12:51:39

标签: c# .net winforms winapi

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

以下设置:

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

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

出现第一个问题是因为我没有清楚地了解difference between those属性(焦点,活动,已选择,TopMost)是什么。

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

我阅读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);
}

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

  • 像这样设置StartInfo进程的server(这样,新进程就不会占据gui的焦点)
    myProcess.StartInfo.UseShellExecute = false;
    myProcess.StartInfo.CreateNoWindow = true;
    myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
  • 启动server过程和WaitForInputIdle(如描述的here),以确保server确实准备就绪
  • 还可以在RegainFocus()应用中使用gui
  • server的DLL中,我创建一个新的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();
    
  • TopMost=true的作用是将对话框置于gui的前面
  • dialog_Activated()方法使用FocusControl()将焦点设置在第一个输入控件上。这行得通。

此操作的结果是在我的gui上方的一个窗口,该窗口的光标在第一个输入控件中闪烁,但是未选中/处于不活动状态。当我按下<TAB>时,我可以看到在后台的gui中选择了另一个控件。

我也尝试在表单中喷射RegainFocus()调用,但是没有用。

我还无法实现的其他想法:

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

谢谢您的帮助和帮助!

1 个答案:

答案 0 :(得分:2)

我有一个似乎可以在Windows 10和Windows 7上运行的解决方案。

失去焦点后,我使用RegainFocus()功能重新获得焦点(并激活了窗口),请参阅问题。注意:不要混用进程HANDLEMainWindowHandle。隐藏对象后,其MainWindowHandle可能就是0

我删除了

    myProcess.StartInfo.UseShellExecute = false;
    myProcess.StartInfo.CreateNoWindow = true;
    myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

在开始server进程时,为了不影响可见性状态。我还是保留了[WaitForInputIdle][1]

在Windows 7上,这还不够,并且创建的进程上的AllowSetForegroundWindow无法正常工作(尽管要感谢评论),而不是将窗口taskbar was flashing置于最前面。这里的解决方案是对set the registry value

\HKEY_CURRENT_USER\Control Panel\Desktop\ForegroundLockTimeout 

0并重新启动机器。然后,对于Windows 7和10,代码的行为相同。有了正确的权限,甚至可以是done programatically

由于此问题有很多不同的答案和解决方案,因此我认为它取决于许多因素(例如Windows版本,注册表设置,可能的UAC和主题设置,框架和运行时,某些more conditions,... ),这就是为什么我想提及我发现的其他方法的原因。