14

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

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

    Thread.Sleep(1000);

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

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

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

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

4

6 回答 6

14

这是可能的,但只能通过 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.wShowWindowSW_SHOWNOACTIVATE正常显示窗口但不窃取焦点,并SW_SHOWMINNOACTIVE最小化启动应用程序,再次不窃取焦点。

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

于 2013-09-27T11:44:37.277 回答
3

您可以将焦点转移到您的应用程序

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

设置前景窗口

展示窗口

于 2012-09-25T16:34:18.380 回答
1

解决了。

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

于 2012-10-15T08:06:30.430 回答
0

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();
    }
}
于 2012-09-25T16:36:37.707 回答
-2

使用Process.StartInfo.CreateNoWindow = true和的组合Process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden

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

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

于 2012-09-25T16:31:43.660 回答
-3

我没有尝试过,但我相信如果你设置proc.StartInfo.WindowStyle = WindowStyle.Minimized 应该可以解决问题。

于 2012-09-25T16:25:47.393 回答