随笔 - 840  文章 - 5 评论 - 951 trackbacks - 19

这是个我在C#调用批处理文件时遇到的问题。首先我通过Process.Start方法调用一个批处理文件,那个批处理文件里面则调用了一大堆程序。当退出C#程序时,我在程序中结束杀掉了那个批处理文件的Process,但是,那个批处理所调用的子进程却无法像直接调用批处理文件那样随着批处理文件的进程一起被杀掉,而是自动向上提升成为了独立的进程。

在网上查了一下,可以通过NtQueryInformationProcess函数查询子进程的信息,并同时也查到了一段杀掉进程及所有子进程的C#代码,有需要的朋友可以参考一下。

代码
static class ProcessExtend
    {
        
// [StructLayout(LayoutKind.Sequential)]
        private struct ProcessBasicInformation
        {
            
public int ExitStatus;
            
public int PebBaseAddress;
            
public int AffinityMask;
            
public int BasePriority;
            
public uint UniqueProcessId;
            
public uint InheritedFromUniqueProcessId;
        }

        [DllImport(
"ntdll.dll")]
        
static extern int NtQueryInformationProcess(
           IntPtr hProcess,
           
int processInformationClass /* 0 */,
           
ref ProcessBasicInformation processBasicInformation,
           
uint processInformationLength,
           
out uint returnLength
        );

        
public static void KillProcessTree(this Process parent)
        {
            var processes 
= Process.GetProcesses();
            
foreach (var p in processes)
            {
                var pbi 
= new ProcessBasicInformation();
                
try
                {
                    
uint bytesWritten;
                    
if (NtQueryInformationProcess(p.Handle, 0ref pbi, (uint)Marshal.SizeOf(pbi), out bytesWritten) == 0// == 0 is OK
                        if (pbi.InheritedFromUniqueProcessId == parent.Id)
                            
using (var newParent = Process.GetProcessById((int)pbi.UniqueProcessId))
                                newParent.KillProcessTree();
                }
                
catch { }
            }
            parent.Kill();
        }
    }

 

PS:今天发现NtQueryInformationProcess函数在x64位程序上运行无效, 具体原因不明,Google了一下也没有找到答案,反而找到了另一种解决方案,通过WMI来实现的。在x86和x64下都可以使用。

View Code
static void KillProcessAndChildren(int pid)
{
    ManagementObjectSearcher searcher 
= new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
    ManagementObjectCollection moc 
= searcher.Get();
    
foreach (ManagementObject mo in moc)
    {
        KillProcessAndChildren(Convert.ToInt32(mo[
"ProcessID"]));
    }
    
try
    {
        Process proc 
= Process.GetProcessById(pid);
        Console.WriteLine(pid);
        proc.Kill();
    }
    
catch (ArgumentException)
    { 
        
/* process already exited */
    }
}

 

posted on 2010-05-19 22:13  天方  阅读(5024)  评论(3编辑  收藏