How to set focus back to form after opening up a process (Notepad)?

30,581

Solution 1

I tried almost everything on internet (so sure about it :)). At best I could get my form on top of all other forms, but without focus (going by @Hans Passant's method). Going by heavy blocks of codes all over, I somehow felt this aint gonna be easy. So I always used SetForegroundWindow() with chunks of other code. Never thought merely SetForegroundWindow() would do the trick.

This worked.

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

At times this method yields in a focus on the parent form (in cases where my desired form is a modal child form of its parent form); in such cases, just add this.Focus() to the last line..

Even this worked:

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

Solution provided by here

Solution 2

I had the same problem, i eventually wound up with programmatically calling 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);
}

//EDIT: You should use process.MainWindowHandle instead ofcourse

Solution 3

If you want to start a process and focus back to the form, then start that process with minimized state, like this:

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

Solution 4

Windows prevents apps from shoving their window into the user's face, you are seeing this at work. The exact rules when an app may steal the focus are documented in the MSDN docs for AllowSetForegroundWindow().

A back-door around this restriction is the AttachThreadInput() function. This code worked well, I did take a shortcut on finding the thread ID for the thread that owns the foreground window. Good enough for Notepad, possibly not for other apps. Do beware that Raymond Chen does not approve of this kind of hack.

    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();
Share:
30,581

Related videos on Youtube

nawfal
Author by

nawfal

You should accept the answer if it helped you by selecting the green tick mark on the top left of the answer. That's the encouraged practice at SO. Not only it helps future visitors, it encourages users to answer your questions. You should post what you have tried and tell us where you're stuck. That gives us more detail, and we can quickly give an answer by copy-pasting the code with minor modifications. Questions like I-need-this,-give-me-code doesnt work in SO. In the current format the question will be closed. You may read http://stackoverflow.com/faq additionally before posting. Do a good search on SO to ensure you're not asking a duplicated question, or else your question will be closed. Quick tag search

Updated on July 09, 2022

Comments

  • nawfal
    nawfal almost 2 years

    I open up a notepad from my program using Process.Start() but the new opened notepad covers the screen. But I do want my application to maintain its focus.

    I similarly (using the same Process.Start) open up MS Excel and Word but to get focus back to my form all I need to write is:

    this.Focus();
    

    But quirk with Notepad: I open notepad (and all other processes like this)

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

    Now notepad takes the focus.

    I tried these:

    1. this.Activate(), this.Focus(), needless to mention

    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. Another lengthier solution got from here.

    All which still keeps the focus on notepad. Why is it so difficult to merely get focus to a window, that too application's own window?

    EDIT: At best I can open the notepad minimized, but it still wouldn't give the focus to the form after trying all the above codes. Notepad opens minimized, but focus will be still on notepad (something that sometimes we see in windows xp) and form will be out of focused.

  • nawfal
    nawfal over 12 years
    Thanks. But I'm in doubt that if BringToFront really works here. Isn't it just a measure to make the control be visible above another control? Is it not that .Activate is a better choice here?
  • nawfal
    nawfal over 12 years
    Also who is Raymond Chen? To approve this? :o
  • user1703401
    user1703401 over 12 years
    Form.BringToFront() calls SetForegroundWindow(), easily seen by just trying to code. Raymond Chen is a Microsoft programmer with a popular blog. Posts answers here too, I don't want to piss him off. blogs.msdn.com/b/oldnewthing
  • nawfal
    nawfal over 12 years
    Hans this code lets my form to be shown on top of the notepad, but now the focus is neither on form nor on notepad. I tried this.Activate and this.Focus but still focus doesnt come on the app. This is a serious requirement for our client..
  • nawfal
    nawfal about 11 years
    How is this answering the question?
  • mklement0
    mklement0 over 5 years
    This works, and answers the question as asked, but a preferable solution is to prevent the launched process from stealing focus in the first place rather than the caller regaining focus after losing it. See stackoverflow.com/q/2121911/45375
  • mklement0
    mklement0 over 5 years
    Actually, I missed that your second command already does what I suggested in my previous comment, courtesy of Microsoft.VisualBasic.Interaction.Shell() and its AppWinStyle flags.

Related