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

时间:2012-01-16 13:58:11

标签: c# winforms process focus windows-shell

我使用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. 另一个较长的解决方案来自here

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

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

5 个答案:

答案 0 :(得分:11)

我在互联网上尝试了几乎所有东西(所以肯定:))。充其量我可以把我的形式放在所有其他形式之上,但没有焦点(通过@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);

here

提供的解决方案

答案 1 :(得分:2)

我遇到了同样的问题,我最终以编程方式调用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代替课程

答案 2 :(得分:2)

如果您要启动一个过程并集中到表单上,请以最小化状态启动该过程,如下所示:

Dim psi As New ProcessStartInfo("notepad")
psi.WindowStyle = ProcessWindowStyle.Minimized
Process.Start(psi)

答案 3 :(得分:1)

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();

答案 4 :(得分:-1)

试试这个:

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();
    }
}