user127665
user127665

Reputation: 105

Process.Start() and the Process Tree

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

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.

(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.)

Upvotes: 9

Views: 13498

Answers (5)

Gomes
Gomes

Reputation: 3330

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.

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

Upvotes: 0

noctonura
noctonura

Reputation: 13131

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.

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.

Upvotes: 19

Eric Rosenberger
Eric Rosenberger

Reputation: 9117

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

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.


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:

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

And override the separate process's form's 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.)

Upvotes: 2

Remy Lebeau
Remy Lebeau

Reputation: 597036

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().

Upvotes: 5

Remy Lebeau
Remy Lebeau

Reputation: 597036

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.

Upvotes: 0

Related Questions