Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I open a process so that it doesn't have focus?

I'm trying to write some automation to open a close a series of windows (non-hidden, non-malicious) and I don't want them to steal focus as they open. The problem is that when each window opens, it steals focus preventing me from working while it runs in the background. Here's the code that I execute in a loop to open the various windows:

using (Process proc = new Process())
{
    proc.StartInfo.FileName = filename;
    proc.StartInfo.Arguments = arguments;
    proc.Start();

    Thread.Sleep(1000);

    if (!proc.HasExited)
    {
        proc.Kill();
    }
}

How do I make these open without focus so I can do other things while this automation runs?

Addenda: The program that is executing the above code is a simple console app. The processes I'm starting are GUI apps. For testing/designing purposes, I'm currently attempting this with repeated instances of Internet Explorer (iexplore.exe) with different arguments.

I will be running this and carrying on with other unrelated work while this runs in the background. I don't want focus returned to the parent app, either. Essentially, I'll run this .exe when I get to my desk, and switch to other windows to do other work, ignoring the original program and its child processes until it's finished.

like image 972
chaosTechnician Avatar asked Sep 25 '12 16:09

chaosTechnician


People also ask

What is stealing my focus?

In computing, focus stealing is a mode error occurring when a program not in focus (e.g. minimized or operating in background) places a window in the foreground and redirects all keyboard input to that window.


2 Answers

This is possible but only via pinvoke, which unfortunately requires about 70 lines of code:

[StructLayout(LayoutKind.Sequential)]
struct STARTUPINFO
{
    public Int32 cb;
    public string lpReserved;
    public string lpDesktop;
    public string lpTitle;
    public Int32 dwX;
    public Int32 dwY;
    public Int32 dwXSize;
    public Int32 dwYSize;
    public Int32 dwXCountChars;
    public Int32 dwYCountChars;
    public Int32 dwFillAttribute;
    public Int32 dwFlags;
    public Int16 wShowWindow;
    public Int16 cbReserved2;
    public IntPtr lpReserved2;
    public IntPtr hStdInput;
    public IntPtr hStdOutput;
    public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
    public IntPtr hProcess;
    public IntPtr hThread;
    public int dwProcessId;
    public int dwThreadId;
}

[DllImport("kernel32.dll")]
static extern bool CreateProcess(
    string lpApplicationName,
    string lpCommandLine,
    IntPtr lpProcessAttributes,
    IntPtr lpThreadAttributes,
    bool bInheritHandles,
    uint dwCreationFlags,
    IntPtr lpEnvironment,
    string lpCurrentDirectory,
    [In] ref STARTUPINFO lpStartupInfo,
    out PROCESS_INFORMATION lpProcessInformation
);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

const int STARTF_USESHOWWINDOW = 1;
const int SW_SHOWNOACTIVATE = 4; 
const int SW_SHOWMINNOACTIVE = 7; 


public static void StartProcessNoActivate(string cmdLine)
{
    STARTUPINFO si = new STARTUPINFO();
    si.cb = Marshal.SizeOf(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOWMINNOACTIVE;

    PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

    CreateProcess(null, cmdLine, IntPtr.Zero, IntPtr.Zero, true,
        0, IntPtr.Zero, null, ref si, out pi);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

Set si.wShowWindow to SW_SHOWNOACTIVATE to show the window normally but without stealing focus, and SW_SHOWMINNOACTIVE to start the app minimised, again without stealing focus.

A full list of options is available here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx

like image 169
benrwb Avatar answered Oct 24 '22 20:10

benrwb


You can move focus to your app

    [DllImport("User32")]
    private static extern int SetForegroundWindow(IntPtr hwnd);
    [DllImportAttribute("User32.DLL")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);


 Process.Start("");
        Thread.Sleep(100);
        var myWindowHandler = Process.GetCurrentProcess().MainWindowHandle;
        ShowWindow(myWindowHandler, 5);
        SetForegroundWindow(myWindowHandler);

SetForegroundWindow

ShowWindow

like image 32
Sebastian Ðymel Avatar answered Oct 24 '22 22:10

Sebastian Ðymel