Process.Start()和Process Tree

时间:2009-06-23 21:03:52

标签: c# .net

如何使用Process.Start(),但启动的进程与启动过程不在同一个进程树中?

考虑这个示例控制台应用程序:

using System;
using System.Diagnostics;
using System.Threading;

internal class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine("Starting ie...");
        Process.Start("c:\\Program Files\\Internet Explorer\\iexplore.exe", "http://www.google.com");
        Console.WriteLine("Waiting for 15 seconds");
        Thread.Sleep(15000);
        Console.WriteLine("Exiting...");
    }
}

当此程序正常退出时,Internet Explorer将继续运行。但是,如果在15秒睡眠期间您转到任务管理器并选择此程序并选择“结束进程树”,Internet Explorer也将关闭。

(这与my question from earlier today直接相关,目前还没有回复。在Windows XP中,当屏幕保护程序结束时,它似乎结束了进程树,而在Vista中,只是屏幕保护程序过程结束。)

5 个答案:

答案 0 :(得分:15)

Eric是正确的:Windows不公开任何更改进程父级的方法。但是,如果父母去世,则没有回到祖父母的链接,因此您可以通过启动孩子的中间过程来实现目标,然后死亡。

所以:Proc A启动proc B,然后proc B启动proc C并立即死亡。当proc B死掉时,proc C将成为进程树上的根节点 - proc B将在proc B死后不在proc A的树中。

答案 1 :(得分:3)

在调用Process.Start()之前,尝试将Process.StartInfo.UseShellExecute设置为False(默认为True)。这样,CreateProcess()在内部使用,而不是ShellExecute()。

答案 2 :(得分:2)

我不相信Windows公开(通过.NET或其他方式)任何更改进程父级的方法。

作为替代方案,您可以在系统启动时运行单独的进程(例如,通过“SOFTWARE / Microsoft / Windows / CurrentVersion / Run”注册表项),并让触发应用程序(您的屏幕保护程序)使用进程间通信(SendMessage之类)告诉单独的进程启动浏览器。然后单独的进程将成为父进程,并且当屏幕保护程序的进程树被杀死时,浏览器不会被杀死。


这是一些示例代码。请注意,这不会进行任何错误检查,我没有在实际屏幕保护程序的上下文中对其进行测试,但它应该让您了解所涉及的内容:

在屏幕保护程序类中:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);

[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);   

private uint message;

在屏幕保护程序的初始化代码中:

message = RegisterWindowMessage("LaunchBrowser");

在屏幕保护程序的浏览器启动代码中:

SendMessage(FindWindow(null, "BrowserLauncher"), message, UIntPtr.Zero, IntPtr.Zero);

在单独进程的表单类中:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);

private uint message;

在单独进程的Form_Load代码中:

message = RegisterWindowMessage("LaunchBrowser");
Text = "BrowserLauncher";

覆盖单独进程的表单WndProc:

protected override void WndProc(ref Message m)
{
    if (m.Msg == message)
    {
        Process.Start("iexplore.exe", "http://www.google.com");
    }

    base.WndProc(ref m);
}

(当然,你需要隐藏单独进程的表单。)

答案 3 :(得分:0)

据我所知,Process.Start()不支持您的要求。您必须使用PInvoke直接调用Win32 API CreateProcess()函数,以便您可以在其dwCreationFlags参数中指定DETACHED_PROCESS标志。

答案 4 :(得分:0)

您必须分离子进程。不知道如何在c#中进行操作,但考虑下面的C ++代码,您可以使用/ P:invoke在.net中实现相同的代码。

BOOL fSuccess = CreateProcess(..., &pi);
if (fSuccess) {

// Allow the system to destroy the process & thread kernel
// objects as soon as the child process terminates.
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}