如何使用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中,只是屏幕保护程序过程结束。)
答案 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);
}