如何打开流程以使其没有焦点?



我正在尝试编写一些自动化来打开和关闭一系列窗口(非隐藏、非恶意),我不希望它们在打开时窃取焦点。问题是,当每个窗口打开时,它都会偷走焦点,使我无法在后台运行时工作。以下是我在循环中执行的打开各种窗口的代码:

using (Process proc = new Process())
{
proc.StartInfo.FileName = filename;
proc.StartInfo.Arguments = arguments;
proc.Start();
Thread.Sleep(1000);
if (!proc.HasExited)
{
proc.Kill();
}
}

我如何在没有焦点的情况下打开这些,以便在自动化运行时可以做其他事情?

附录:执行上述代码的程序是一个简单的控制台应用程序。我正在启动的进程是GUI应用程序。出于测试/设计目的,我目前正在尝试使用具有不同参数的Internet Explorer(iexplore.exe)的重复实例。

我将运行这个,并继续其他无关的工作,而这是在后台运行。我也不希望焦点回到父应用程序上。从本质上讲,当我到达办公桌时,我会运行这个.exe,并切换到其他窗口来做其他工作,忽略原始程序及其子进程,直到它完成。

这是可能的,但只能通过pinvoke,不幸的是,它需要大约70行代码:

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

si.wShowWindow设置为SW_SHOWNOACTIVATE以正常显示窗口,但不窃取焦点,将SW_SHOWMINNOACTIVE设置为最小化启动应用程序,再次不窃取焦点。

此处提供了完整的选项列表:http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx

您可以将焦点转移到应用

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

设置前景窗口

显示窗口

已解决。

我最终使用的解决方案绕过了任何属性或重新分配了焦点。由于该任务是自动化和独立的,我只使用Windows任务计划程序来运行该应用程序。无论出于何种原因,只要"父"控制台窗口未处于焦点位置,"子"GUI窗口就会正常打开,但不会处于焦点位置—允许我在应用程序运行时继续在另一个窗口中工作。

SetForegroundWindow在控制台应用程序中也能做到这一点

测试代码:

创建一个简单的类:

public class MyClass
{
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
public void doProcess(string filename, string arguments){
using (Process proc = new Process())
{
proc.StartInfo.FileName = filename;
proc.StartInfo.Arguments = arguments;
proc.Start();
SetForegroundWindow(proc.MainWindowHandle);
}
}
}

然后在控制台应用程序的main方法中:

class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
mc.doProcess("iexplore.exe", "http://www.stackoverflow.com");
Console.ReadKey();
}
}

使用Process.StartInfo.CreateNoWindow = trueProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden的组合。

可能还值得使用Process.StartInfo.UseShellExecute = false,并重定向StdIn/StdOut/StdErr。

请参阅http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.aspx

我还没有尝试过,但我相信如果你设置proc。StartInfo.WindowStyle=窗口样式。最小化即可。

最新更新