System.Diagnostics.Process, any way to terminate the specified process AND any child processes which

Discussion in 'Microsoft Dot NET Framework' started by Guest, Apr 14, 2004.

  1. Guest

    Guest Guest

    We have some C# code on Windows 2000/XP/2003 that launches a process via the classes in System.Diagnostics, namely ProcessInfo and Process class. The process can get stuck and after a certain timeout we make a call t
    System.Diagnostics.Process.Kill(
    to terminate the process. However, the process launches other child processes and the Process.Kill() leaves those child processes running. In particular the process we are trying to manage occassionally crashes with Windows exception memory read error and that pops up another dialog box. If you just kill the crashed process, the application popup remains but if you kill process and child processes the application popup also goes away along with the crashed app

    In C# code want to terminate the specified process AND any child processes which were started by it, similar to what can be accomplished from the commandline with taskkill.exe (and similarly with windows 2000 era resource kit file rkill.exe)
    taskkill.exe /PID 1234 /F /
    The same kind of thing can be done with the Task Manager taskmgr.exe in which one can right click on a process in the Processes tab and choose "End Process Tree" instead of "End Process

    There is a function NtQueryInformationProcess in the NTDLL.dll with the struct PROCESSINFOCLASS that can be called in such a way as to get InheritedFromUniqueProcessId from the PROCESS_BASIC_INFORMATION
    http://www.codeguru.com/Cpp/W-P/win32/article.php/c1437
    That gives a "Parent" process ID that can then be used to walk through all processes and kill a tree of processes, that is the information we are looking for that would enable us to locate all child processes and terminate those as well

    Is that the only way to obtain the information under Windows (2000, XP, 2003)
    Any idea how to make such calls from C#? We are able to make basic calls but calls such as this one that have OUT parameters we have trouble getting to work in C#

    Thanks
    Fran
     
    Guest, Apr 14, 2004
    #1
    1. Advertisements

  2. Hi Frank,

    Thanks for your post. NtQueryInformationProcess is supported in Windows
    XP/2000/2003. Based on my experience and research, I did not find other
    method to achieve this.

    In C#, you can use P/Invoke to call unmanaged APIs. Please refer to the
    following MSDN article:

    Consuming Unmanaged DLL Functions
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
    l/cpconConsumingUnmanagedDLLFunctions.asp

    The article below give several samples on passing structures as In/Out
    parameters in P/Invoke:

    Marshaling Classes, Structures, and Unions
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
    l/cpconmarshalingclassesstructuresunions.asp

    If you have any problems, please feel free to let me know.

    Have a nice day!

    Regards,

    HuangTM
    Microsoft Online Partner Support
    MCSE/MCSD

    Get Secure! -- www.microsoft.com/security
    This posting is provided "as is" with no warranties and confers no rights.
     
    Tian Min Huang, Apr 15, 2004
    #2
    1. Advertisements

  3. Guest

    Guest

    There is an MSDN article in October 2004 MSDN magazine entitled
    "Examine Running Processes Using Both Managed and Unmanaged Code".
    http://msdn.microsoft.com/msdnmag/issues/04/10/NETProcessBrowser/default.aspx

    The code download includes a wrapper class, wrapper.cs.

    The Wrapper.cs contains examples of calling NtQueryInformationProcess
    to get InheritedFromUniqueProcessId which is equivalent to the Parent
    Process ID.

    Basically the calling code from .NET would look like this:

    [DllImport("KERNEL32.DLL")] private static extern int
    OpenProcess(eDesiredAccess dwDesiredAccess, bool bInheritHandle, int
    dwProcessId);

    [DllImport("KERNEL32.DLL")] private static extern int CloseHandle(int
    hObject);

    [DllImport("NTDLL.DLL")] private static extern int
    NtQueryInformationProcess(int hProcess, PROCESSINFOCLASS pic, ref
    PROCESS_BASIC_INFORMATION pbi, int cb, ref int pSize);

    enum PROCESSINFOCLASS : int
    {
    ProcessBasicInformation = 0,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers, // Note: this is kernel mode only
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    MaxProcessInfoClass
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_BASIC_INFORMATION
    {
    public int ExitStatus;
    public int PebBaseAddress;
    public int AffinityMask;
    public int BasePriority;
    public int UniqueProcessId;
    public int InheritedFromUniqueProcessId;

    public int Size
    {
    get { return(6*4); }
    }
    };

    enum eDesiredAccess : int
    {
    DELETE = 0x00010000,
    READ_CONTROL = 0x00020000,
    WRITE_DAC = 0x00040000,
    WRITE_OWNER = 0x00080000,
    SYNCHRONIZE = 0x00100000,
    STANDARD_RIGHTS_ALL = 0x001F0000,

    PROCESS_TERMINATE = 0x0001,
    PROCESS_CREATE_THREAD = 0x0002,
    PROCESS_SET_SESSIONID = 0x0004,
    PROCESS_VM_OPERATION = 0x0008,
    PROCESS_VM_READ = 0x0010,
    PROCESS_VM_WRITE = 0x0020,
    PROCESS_DUP_HANDLE = 0x0040,
    PROCESS_CREATE_PROCESS = 0x0080,
    PROCESS_SET_QUOTA = 0x0100,
    PROCESS_SET_INFORMATION = 0x0200,
    PROCESS_QUERY_INFORMATION = 0x0400,
    PROCESS_ALL_ACCESS = SYNCHRONIZE | 0xFFF
    }


    public static int GetParentProcessId(int PID)
    {
    int ParentID = 0;

    try
    {
    int hProcess =
    OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, PID);
    if (hProcess != 0)
    {
    PROCESS_BASIC_INFORMATION pbi = new
    PROCESS_BASIC_INFORMATION();
    int pSize = 0;
    if (-1 != NtQueryInformationProcess(hProcess,
    PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, pbi.Size, ref
    pSize))
    {
    ParentID = pbi.InheritedFromUniqueProcessId;
    }

    CloseHandle(hProcess);
    }
    }
    catch(Exception e)
    {
    Trace.WriteLine("Error in GetParentProcessId(): {0}", e.Message);
    }

    return(ParentID);
    }
     
    , Oct 18, 2004
    #3
  4. Guest

    Guest

    Here is one such implementation of a TreeKill and a GetChildProcessIds
    and GetParentProcessId based on the NtQueryInformationProcess and the
    PROCESS_BASIC_INFORMATION struct property InheritedFromUniqueProcessId.


    ----------------------


    using System.Collections;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    /// <summary>
    /// Summary description for ProcessTreeKillable.
    /// </summary>
    public class ProcessUtility
    {
    public static void KillTree(int processToKillId)
    {
    // Kill each child process
    foreach (int childProcessId in GetChildProcessIds(processToKillId))
    {
    using (Process child = Process.GetProcessById(childProcessId))
    {
    child.Kill();
    }
    }

    // Then kill this process
    using (Process thisProcess = Process.GetProcessById(processToKillId))
    {
    thisProcess.Kill();
    }
    }


    public static int GetParentProcessId(int processId)
    {
    int ParentID = 0;

    int hProcess = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION,
    false, processId);

    if (hProcess != 0)
    {
    try
    {
    PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
    int pSize = 0;
    if (-1 != NtQueryInformationProcess(hProcess,
    PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, pbi.Size, ref
    pSize))
    {
    ParentID = pbi.InheritedFromUniqueProcessId;
    }
    }
    finally
    {
    CloseHandle(hProcess);
    }
    }

    return (ParentID);
    }

    public static int[] GetChildProcessIds(int parentProcessId)
    {
    ArrayList myChildren = new ArrayList();

    foreach (Process proc in Process.GetProcesses())
    {
    int currentProcessId = proc.Id;
    proc.Dispose();

    if (parentProcessId == GetParentProcessId(currentProcessId))
    {
    // Add this one
    myChildren.Add(currentProcessId);

    // Add any of its children
    myChildren.AddRange(GetChildProcessIds(currentProcessId));
    }
    }


    return (int[]) myChildren.ToArray(typeof (int));
    }

    #region PInvokes

    [DllImport("KERNEL32.DLL")]
    private static extern int OpenProcess(eDesiredAccess dwDesiredAccess,
    bool bInheritHandle, int dwProcessId);

    [DllImport("KERNEL32.DLL")]
    private static extern int CloseHandle(int hObject);

    [DllImport("NTDLL.DLL")]
    private static extern int NtQueryInformationProcess(int hProcess,
    PROCESSINFOCLASS pic, ref PROCESS_BASIC_INFORMATION pbi, int cb, ref
    int pSize);

    private enum PROCESSINFOCLASS : int
    {
    ProcessBasicInformation = 0,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers, // Note: this is kernel mode only
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    MaxProcessInfoClass
    } ;

    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_BASIC_INFORMATION
    {
    public int ExitStatus;
    public int PebBaseAddress;
    public int AffinityMask;
    public int BasePriority;
    public int UniqueProcessId;
    public int InheritedFromUniqueProcessId;

    public int Size
    {
    get { return (6*4); }
    }
    } ;

    private enum eDesiredAccess : int
    {
    DELETE = 0x00010000,
    READ_CONTROL = 0x00020000,
    WRITE_DAC = 0x00040000,
    WRITE_OWNER = 0x00080000,
    SYNCHRONIZE = 0x00100000,
    STANDARD_RIGHTS_ALL = 0x001F0000,

    PROCESS_TERMINATE = 0x0001,
    PROCESS_CREATE_THREAD = 0x0002,
    PROCESS_SET_SESSIONID = 0x0004,
    PROCESS_VM_OPERATION = 0x0008,
    PROCESS_VM_READ = 0x0010,
    PROCESS_VM_WRITE = 0x0020,
    PROCESS_DUP_HANDLE = 0x0040,
    PROCESS_CREATE_PROCESS = 0x0080,
    PROCESS_SET_QUOTA = 0x0100,
    PROCESS_SET_INFORMATION = 0x0200,
    PROCESS_QUERY_INFORMATION = 0x0400,
    PROCESS_ALL_ACCESS = SYNCHRONIZE | 0xFFF
    }

    #endregion
    }
     
    , Oct 19, 2004
    #4
    1. Advertisements

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. M. D'Costa

    Reading processes using System.Diagnostics.Prcocess class

    M. D'Costa, Jan 21, 2005, in forum: Microsoft Dot NET Framework
    Replies:
    0
    Views:
    194
    M. D'Costa
    Jan 21, 2005
  2. Lloyd Gomes via .NET 247

    Shutting down child processes started using System.Diagnostic.Process

    Lloyd Gomes via .NET 247, Mar 7, 2005, in forum: Microsoft Dot NET Framework
    Replies:
    1
    Views:
    292
    Alvin Bruney [ASP.NET MVP]
    Mar 8, 2005
  3. Bob Trabucco
    Replies:
    3
    Views:
    772
    Guest
    May 25, 2005
  4. Daniel
    Replies:
    1
    Views:
    1,151
    Lau Lei Cheong
    Apr 13, 2006
  5. Guest

    Terminate a child process when parent process is killed

    Guest, Jul 9, 2007, in forum: Microsoft Dot NET Framework
    Replies:
    3
    Views:
    3,033
    Sheng Jiang[MVP]
    Jul 9, 2007
Loading...

Share This Page