如何在打开一个进程(记事本)后将焦点重新设置回forms?

我使用Process.Start()从程序中打开一个记事本,但新打开的记事本覆盖了屏幕。 但我确实希望我的应用程序保持其重点。

我同样(使用相同的Process.Start)打开MS Excel和Word,但要将焦点重新放回到我的表单,我需要写的是:

 this.Focus(); 

但是用记事本怪起来:我打开记事本(以及所有其他这样的过程)

 Process process = new Process(); process.StartInfo.UseShellExecute = true; process.EnableRaisingEvents = true; process.StartInfo.FileName = @"abc.log"; process.Start(); 

现在记事本成为焦点。

我试过这些:

  1. this.Activate()this.Focus() ,不用说了

  2.  [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] public static extern IntPtr SetFocus(HandleRef hWnd); { IntPtr hWnd = myProcess.Handle; SetFocus(new HandleRef(null, hWnd)); } 
  3.  [DllImport("User32")] private static extern int SetForegroundWindow(IntPtr hwnd); [DllImportAttribute("User32.DLL")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private const int SW_SHOW = 5; private const int SW_MINIMIZE = 6; private const int SW_RESTORE = 9; { ShowWindow(Process.GetCurrentProcess().MainWindowHandle, SW_RESTORE); SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle); } 
  4. 另一个更长的解决方案来自这里 。

所有这些仍然把重点放在记事本上。 为什么仅仅将焦点集中到一个窗口是如此困难,那也是应用程序自己的窗口?

编辑:充其量我可以打开记事本最小化,但它仍然不会在尝试所有上述代码后将焦点放在表单上。 记事本打开最小化,但焦点仍然在记事本(有时我们在windows xp中看到的东西)和表单将失去焦点。

我在互联网上尝试了几乎所有的东西(所以肯定:))。 充其量我可以把我的forms放在所有其他forms之上,但没有焦点(通过@Hans Passant的方法)。 经过大量的代码,我不知怎的感觉这很容易。 所以我总是使用SetForegroundWindow()和其他代码块。 从来没有想过只有SetForegroundWindow()可以做到这一点。

这很有效。

 [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetForegroundWindow(IntPtr hWnd); private void button1_Click(object sender, EventArgs e) { Process process = new Process(); process.StartInfo.FileName = @...\abc.log"; process.Start(); process.WaitForInputIdle(); //this is the key!! SetForegroundWindow(this.Handle); } 

有时这种方法会聚焦于父表格(如果我想要的表格是其父表格的模态子表格); 在这种情况下,只需将this.Focus()添加到最后一行..

即便如此:

 Microsoft.VisualBasic.Interaction.Shell(@"notepad.exe D:\abc.log", Microsoft.VisualBasic.AppWinStyle.NormalNoFocus); 

解决方案由这里提供

我有同样的问题,我最终以编程方式调用alt-tab结束:

 [DllImport("user32.dll")] static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam); private void alttab() { uint WM_SYSCOMMAND = 0x0112; int SC_PREVWINDOW = 0xF050; PostMessage(Process.GetCurrentProcess().MainWindowHandle, WM_SYSCOMMAND, SC_PREVWINDOW, 0); } 

//编辑:你应该使用process.MainWindowHandle代替课程

Windows可以防止应用程序将窗口推入用户的脸部,您可以看到这一点。 应用程序可能窃取焦点的确切规则记录在AllowSetForegroundWindow()的MSDN文档中。

这个限制的后门是AttachThreadInput()函数。 这段代码工作得很好,我确实找到了拥有前台窗口的线程的线程ID的快捷方式。 适用于记事本,可能不适用于其他应用程序。 请注意Raymond Chen不赞成这种黑客攻击。

  private void button1_Click(object sender, EventArgs e) { var prc = Process.Start("notepad.exe"); prc.WaitForInputIdle(); int tid = GetCurrentThreadId(); int tidTo = prc.Threads[0].Id; if (!AttachThreadInput(tid, tidTo, true)) throw new Win32Exception(); this.BringToFront(); AttachThreadInput(tid, tidTo, false); } [DllImport("user32.dll", SetLastError = true)] private static extern bool AttachThreadInput(int tid, int tidTo, bool attach); [DllImport("kernel32.dll")] private static extern int GetCurrentThreadId(); 

试试这个:

 public partial class MainForm : Form { private ShowForm showForm; public MainForm() { InitializeComponent(); } private void showButton_Click(object sender, EventArgs e) { this.showForm = new ShowForm(); this.showForm.FormClosed += showForm_FormClosed; this.showForm.Show(this); } private void showForm_FormClosed(object sender, FormClosedEventArgs e) { this.Focus(); } }