从浏览器进程获取句柄

时间:2016-11-16 08:59:04

标签: c# process dllimport

我需要在默认浏览器中打开一个网站。然后我想在第二个屏幕上显示浏览器。因此,我尝试以下方法:

private void button1_Click(object sender, EventArgs e)
{
    var externalApplication = new Process();
    externalApplication.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
    externalApplication.StartInfo.FileName = "http://www.example.com/";
    externalApplication.Start();
    externalApplication.WaitForInputIdle();

    var handle = externalApplication.MainWindowHandle;
    Console.Write(handle);
    Program.MoveWindow(handle, 0, 0, 1500, 1, true);
}

[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

现在我的问题是,WaitForInputIdle()MainWindowHandle()似乎都不起作用。他们都扔了InvalidOperationException: No process is associated with this object

1 个答案:

答案 0 :(得分:0)

我通过使用@Simon Mourier to get the parent

的答案获得父母句柄解决了这个问题

并以这种方式更改代码:

private void OpenUrl(string url)
{
    var oldProcessIds = Process.GetProcesses().Select(pr => pr.Id);

    IntPtr handle = OpenApplication(url);
    if (handle==IntPtr.Zero)
    {
        // Find out what Process is new
        var processes = Process.GetProcesses();
        var newProcess = processes.Where(pr => !oldProcessIds.Contains(pr.Id));
        var parent = ParentProcessUtilities.GetParentProcess(newProcess.First().Handle);
        Program.MoveWindow(parent.MainWindowHandle, 0, 500, 500, 300, true);
    }
    else
    {
        Program.MoveWindow(handle, 0, 0, 1500, 100, true);
    }
}

private IntPtr OpenApplication(string application)
{
    var externalApplication = new Process();
    externalApplication.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
    externalApplication.StartInfo.FileName = "http://www.example.com";
    externalApplication.Start();    
    externalApplication.Refresh();
    try
    {
        externalApplication.WaitForInputIdle();
        return externalApplication.MainWindowHandle;
    } catch 
    {
        // Cannot get Handle. Application managaes multiple Threads
        return IntPtr.Zero;
    }
}

检索父级的代码:

 [StructLayout(LayoutKind.Sequential)]
    public struct ParentProcessUtilities
    {
        // These members must match PROCESS_BASIC_INFORMATION
        internal IntPtr Reserved1;
        internal IntPtr PebBaseAddress;
        internal IntPtr Reserved2_0;
        internal IntPtr Reserved2_1;
        internal IntPtr UniqueProcessId;
        internal IntPtr InheritedFromUniqueProcessId;

        [DllImport("ntdll.dll")]
        private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);

        /// <summary>
        /// Gets the parent process of the current process.
        /// </summary>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess()
        {
            return GetParentProcess(Process.GetCurrentProcess().Handle);
        }

        /// <summary>
        /// Gets the parent process of specified process.
        /// </summary>
        /// <param name="id">The process id.</param>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess(int id)
        {
            Process process = Process.GetProcessById(id);
            return GetParentProcess(process.Handle);
        }

        /// <summary>
        /// Gets the parent process of a specified process.
        /// </summary>
        /// <param name="handle">The process handle.</param>
        /// <returns>An instance of the Process class or null if an error occurred.</returns>
        public static Process GetParentProcess(IntPtr handle)
        {
            ParentProcessUtilities pbi = new ParentProcessUtilities();
            int returnLength;
            int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
            if (status != 0)
                return null;

            try
            {
                return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
            }
            catch (ArgumentException)
            {
                // not found
                return null;
            }
        }

说明:

在打开URL之前,程序会记住之前存在的进程。因此,在创建之后,可以抓住新流程。从进程中搜索父进程,该进程应该是主进程。然后,该进程的MainWindowHandle将移动窗口。

注意:

到目前为止,这是一个“粗略”的第一个解决方案(更像是POC)。缺少错误处理例程,并乐观地假设没有其他进程同时启动。