Process.Start()和Process Tree

时间:2021-04-07 20:44:28

How can I use Process.Start(), but have the launched process not in the same process tree as the launching process?

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

Consider this sample console application:

考虑此示例控制台应用程序

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...");
    }
}

When this program exits normally, Internet Explorer will continue to run. However, if during the 15 second sleep period you go to Task Manager and select this program and select "End Process Tree", Internet Explorer will also close.

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

(This is directly related to my question from earlier today that, as yet, has no replies. In Windows XP, when the screen saver process ends, it appears to end the process tree, whereas in Vista, just the screen saver process is ended.)

(这是直接关系到我的问题,从今天早些时候说,到目前为止,还没有任何回复。在Windows XP中,当屏幕保护程序过程结束,这似乎结束进程树,而在Vista中,只是屏幕保护程序结束。)

5 个解决方案

#1


Eric is correct: Windows does not expose any method of changing a processes parent. However, if the parent dies, there is no link back to grandparent so you can achieve your goal with an intermediate process that starts the child, then dies.

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

So: Proc A starts proc B, then proc B starts proc C and immediately dies. When proc B dies, proc C will be a root node on the process tree - proc C will NOT be in proc A's tree after proc B dies.

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

#2


I don't believe Windows exposes (via .NET or otherwise) any method of changing a process's parent.

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

As an alternative, you could run a separate process at system startup (via the "SOFTWARE/Microsoft/Windows/CurrentVersion/Run" registry key for example), and have the triggering application (your screen saver) use inter-process communication (SendMessage or the like) to tell the separate process to launch the browser. Then the separate process would be the parent and the browser wouldn't be killed when the screen saver's process tree is killed.

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


Here's some example code. Note that this doesn't do any error checking, and I haven't tested it in the context of an actual screen saver, but it should give you an idea of what's involved:

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

In the screen saver class:

在屏幕保护程序类中:

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

In the screen saver's initialization code:

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

message = RegisterWindowMessage("LaunchBrowser");

In the screen saver's browser launching code:

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

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

In the separate process's form class:

在单独的进程的表单类中:

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

private uint message;

In the separate process's Form_Load code:

在单独的进程的Form_Load代码中:

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

And override the separate process's form's WndProc:

并覆盖单独进程的窗体的WndProc:

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

    base.WndProc(ref m);
}

(You'll want to make the separate process's form hidden, of course.)

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

#3


Try setting Process.StartInfo.UseShellExecute to False (it is True by default) before calling Process.Start(). That way, CreateProcess() is used internally instead of ShellExecute().

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

#4


As far as I know, Process.Start() does not support what you are asking for. You would have to use PInvoke to call the Win32 API CreateProcess() function directly so that you can specify the DETACHED_PROCESS flag in its dwCreationFlags parameter.

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

#5


You have to detach the child process. Not sure how to go about in c# but consider the below code in C++, with which you can use /P:invoke to implement the same in .net.

您必须分离子进程。不知道如何在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);
}

#1


Eric is correct: Windows does not expose any method of changing a processes parent. However, if the parent dies, there is no link back to grandparent so you can achieve your goal with an intermediate process that starts the child, then dies.

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

So: Proc A starts proc B, then proc B starts proc C and immediately dies. When proc B dies, proc C will be a root node on the process tree - proc C will NOT be in proc A's tree after proc B dies.

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

#2


I don't believe Windows exposes (via .NET or otherwise) any method of changing a process's parent.

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

As an alternative, you could run a separate process at system startup (via the "SOFTWARE/Microsoft/Windows/CurrentVersion/Run" registry key for example), and have the triggering application (your screen saver) use inter-process communication (SendMessage or the like) to tell the separate process to launch the browser. Then the separate process would be the parent and the browser wouldn't be killed when the screen saver's process tree is killed.

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


Here's some example code. Note that this doesn't do any error checking, and I haven't tested it in the context of an actual screen saver, but it should give you an idea of what's involved:

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

In the screen saver class:

在屏幕保护程序类中:

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

In the screen saver's initialization code:

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

message = RegisterWindowMessage("LaunchBrowser");

In the screen saver's browser launching code:

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

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

In the separate process's form class:

在单独的进程的表单类中:

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

private uint message;

In the separate process's Form_Load code:

在单独的进程的Form_Load代码中:

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

And override the separate process's form's WndProc:

并覆盖单独进程的窗体的WndProc:

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

    base.WndProc(ref m);
}

(You'll want to make the separate process's form hidden, of course.)

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

#3


Try setting Process.StartInfo.UseShellExecute to False (it is True by default) before calling Process.Start(). That way, CreateProcess() is used internally instead of ShellExecute().

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

#4


As far as I know, Process.Start() does not support what you are asking for. You would have to use PInvoke to call the Win32 API CreateProcess() function directly so that you can specify the DETACHED_PROCESS flag in its dwCreationFlags parameter.

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

#5


You have to detach the child process. Not sure how to go about in c# but consider the below code in C++, with which you can use /P:invoke to implement the same in .net.

您必须分离子进程。不知道如何在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);
}