Link to home
Start Free TrialLog in
Avatar of richelieu7778
richelieu7778

asked on

Forcing a process to the be topmost process

I am running a keyboard hook that, when required, launches a process.  That process is a simple C# Windows form with a form on which there is a listview . . . nothing fancy.

It is desired that this form immediately have the focus so the user can begin using the keyboard UP/DOWN arrow keys without having to first "activate" the form.  I want to remove the requirement that the user first have to left click on the form to give it the focus before they can begin using the UP/DOWN keys.

It seems that no matter what I try, the form is never the topmost window. The user is always forced to have to left click on this window first.

I've tried the following:

Setting the "Topmost" property of the form to "true" in the form's Design mode.
Calling the following in the form's Load() event:
      SetFocus(this.Handle)
      SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
      
      AllowSetForegroundWindow(System.Diagnostics.Process.GetCurrentProcess().Id);//cb#27
      SetForegroundWindow((int)this.Handle);

I've even tried elevating the Priority to "RealTime" when it's launched.

I launch the process using the following:



            ProcessStartInfo Prog2 = new ProcessStartInfo();
            Prog2.UseShellExecute = false;
            Prog2.FileName = "c:\someapp.exe";
            Prog2.Arguments = "1";

            Process p2 = Process.Start(Prog2);
            p2.PriorityBoostEnabled = true;
            p2.PriorityClass = ProcessPriorityClass.RealTime;
            p2.WaitForExit();



QUESTION:

The TaskManager has a "SwitchTo" button which always works on any process running.  Is there any way to programatically simulate the "Switch To" functionality within the calling program?

Thanks in advance,

Avatar of lazyberezovsky
lazyberezovsky
Flag of Belarus image

Just set focus to desired control on Shown event of Form:
private void Form_Shown(object sender, EventArgs e)
{
    textBox1.Focus();
}

Open in new window

Avatar of richelieu7778
richelieu7778

ASKER

That didn't help. I had already set the focus to item #1 in the listview control.  Setting the focus to the listview itself, as you suggested, didn't help.

Pressing the "Switch To" button on the Task Manager *always* works.

There's go to be some property / method in the Process class where you can force that process to be the topmost process . . . . i.e. exactly what the "Switch To" command does in the Task Manager. . . . . there's got to be one . . . . I just can't find it. . . .something like:

        Process p2 = Process.Start(Prog2);
        p2.Topmost = true;

I can't find it . . .
ASKER CERTIFIED SOLUTION
Avatar of lazyberezovsky
lazyberezovsky
Flag of Belarus image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It works, but not under unique circumstances, i.e. when the process is launched from another process . . .

All I need is the code which programatically executes whatever Task Manager executes when its "Switch To" button is pressed.  That's all I need.  That works *every* time under *all* circumstances, unique or not.

I hope somebody knows what that is. . . .it can't be that complicated . . . but who knows. . . . it might be a secret held by Microsoft.
SOLUTION
Avatar of Daniel Van Der Werken
Daniel Van Der Werken
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Whoooo Hoooo!!!  It *looks* like Dan7el might have it.  I was not aware of the "ShowWindowAsync" method.

I can't try it right now. . . . but I'll try it later today and report back . . .

Man, I tried launching app from other process. All works just fine:
Process.Start(appPath);

As mentioned above:
1) I subscribed to Shown event of form and set focus to ListView there
2) form itself TopMost = true (you can set this from designer)

           
Well. . . . I can't get either method to work.  "ShowWindowAsync()" works just fine when and only when VS.NET 2008 is running from the debugger but not in an EXE. I'm wondering if it's process priority thing . . . .  It seems that not matter what I do, tompost is ignored.
Thad definitely works:
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

// Use like this:
string appName = "WindowsApplication1";
Process[] processes = Process.GetProcessesByName(appName);

if (processes.Length > 0)
{
   Process app = processes[0];
   SetForegroundWindow(app.MainWindowHandle);
}

Open in new window

Already tried that-- . . . . it didn't work . . it’s not that easy in my case.

I've discovered that a complication arises when the calling process (my keyboard hook, in my case)  either:

     1) has no Windows Form,

     2) has a windows form but it's Visible propery is set to False, or

     3) even it it has a Windows form, and it's Visible property is set to true but the Windows form doesn't have the current focus at the instant the new process (which does has a Form) is launched.

In other words, a Form of a spawned process is not allowed to have the current focus if the Form from which the process is spawned does *not* have current focus.  I think I read somewhere that it is a “feature”, or limitation, depending on how you look at it, of the SetForegroundWindow().  That’s why the AllowSetForegroundWindow() exists; to allow, under *limited* circumstances, a process which would not normally be allowed to call SetForegroundWindow(), to be allowed to call it

But, in my case, AllowSetForegroundWindow() *STILL* didn’t work.

The *only* thing I found, that consistently works, so far in my investigation, is to call the following in the spawned process (the code in between the “extra stuff required” comment is the new stuff:

        [STAThread]
        static void Main()
        {
   
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);


      //start of extra stuff required
                frmSomeForm frm = new frmSomeForm();
                frm.Show();
                frm.WindowState = FormWindowState.Minimized;
                frm.WindowState = FormWindowState.Normal;
                frm.TopLevel = true;
                frm.TopMost = true;
       //end of extra stuff requried

                Application.Run(new frmSomeForm ());

        }

It flickers a little when first launched, but I can live with that, for now.  As I learn more I can pare down the unnecessary stuff.
To clarify:  the keyboard hook *never* has focus since it is just that--a background process which handles keyboard combinations.  Since it didn't have focus, the form of the process it launched couldn't have focus (at least without the workaround I stated above).
Although my situation was so unique, and nobody provided a solution which worked consistently, for *my situation* both of you tried to help.

I'll split the points.