Process.Start()和Process Tree

我如何使用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也将关闭。

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

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

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

我不相信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); } 

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

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

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

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