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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何激活Window由另一个进程启动相关的知识,希望对你有一定的参考价值。

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

以下设置:

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

现在因为需要针对重复操作优化整体使用体验,所以打开的GUI元素(窗口/窗体/对话框)需要预先选择/聚焦/激活。

第一个问题出现了,因为我没有找到difference between those属性(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);
}

然后我到目前为止尝试的是:

  • 像这样设置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()将Focus设置为第一个输入控件。这有效。

结果是我的gui顶部有一个窗口,它在第一个输入控件中闪烁,但是取消选择/不活动。当我点击<TAB>时,我可以看到在背景中的gui中选择了不同的控件。

我尝试在表格中喷涂RegainFocus()电话,没有用。

我有进一步的想法,但无法实现它们:

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

感谢您的帮助和输入/ tipps!

答案

我得到了一个似乎适用于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,...)这就是我想要的原因提到我发现的其他方法。

以上是关于如何激活Window由另一个进程启动的主要内容,如果未能解决你的问题,请参考以下文章

调试由另一个产生的进程

C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题

LINUX PID 1和SYSTEMD PID 0 是内核的一部分,主要用于内进换页,内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程,PID 为 1,又叫超级进程(代码片段

.net 提示正由另一进程使用,因此该进程无法访问该文件

Winform 拷贝文件到PDA,提示:正由另一进程使时用,因此该进程无法访问该文件。

如何从 IIS 托管的 WCF 服务启动进程?