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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With