Killing multiple processes that were started from nested threads… C#

别等时光非礼了梦想. 提交于 2019-12-11 06:28:53

问题


I'm new to programming. I have a form application that launches a thread. Form there 4 new threads are launched. Each of these threads performs a series of command line processes like the following:

ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.WorkingDirectory ="C:\\BLA\\bin_windows";
        startInfo.UseShellExecute = false;
        startInfo.RedirectStandardOutput = true;
        startInfo.CreateNoWindow = true;

            startInfo.FileName = "SomeProcess"
            Process p = Process.Start(startInfo);
        p.WaitForExit();

When the form application is closed it aborts the first thread (not the 4 separate ones). Now my question is how to force the processes "p" to quit when I close the form?? I tried the following:

    foreach (Process p in System.Diagnostics.Process.GetProcessesByName("SomeProcess"))
    {
        try
        {
            p.Kill();
            p.WaitForExit(); // possibly with a timeout
        }
        catch
        { continue; }
    } 

However, this approach seems a little brutal to me and does not always work well... Is there a way that I can identify only the processes that Ive launched myself and then terminate them? Any suggestions greatly appreciated. Thanks


回答1:


You have very little control of processes you have run. Killing them is one way. If the process is a windowed application (i.e. has a window) you can try sending it a WM_CLOSE message which is equivalent of clicking a close button on the window. Again, application must have a window, either visible or hidden and because of that it will not work on every application. Most applications do have windows though even if not visible.

const uint WM_CLOSE = 0x10;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, uint uMsg, int wParam, int lParam);

Process p = Process.GetProcessesByName("notepad").FirstOrDefault();
if(p != null)
{
    IntPtr hWnd = p.MainWindowHandle;
    SendMessage(hWnd, WM_CLOSE, 0, 0);
}

To kill/close only processes you have spawned just keep their Process objects or at least p.MainWindowHandle if you want to use approach I gave you. For that, have a public property of type ConcurrentBag<Process> (or ConcurrentBag<IntPtr>) in your class. It is already thread safe.

EDIT

As someone pointed out you can do this to close process' main window:

p.CloseMainWindow()



回答2:


If your program is not supposed to be runed twice a time you could use some kind of process manager on singleton:

internal sealed class ProcessManager
{
    private readonly IList<Process> processes;

    #region Singleton

    private static readonly object locker = new object();
    private static volatile ProcessManager instance;

    private ProcessManager()
    {
        processes = new List<Process>();
    }

    public static ProcessManager Instance
    {
        get
        {
            if (instance == null)
            {
                lock (locker)
                {
                    if (instance == null)
                    {
                        instance = new ProcessManager();
                    }
                }
            }

            return instance;
        }
    }

    #endregion

    public void AddProcess(Process process)
    {
        lock(processes)
        {
            processes.Add(process);
        }
    }

    public void TerminateAll()
    {
        lock(processes)
        {
            foreach (Process p in processes)
            {
                try
                {
                    p.Kill();
                    p.WaitForExit(); // possibly with a timeout
                }
                catch
                {
                     continue;
                }
            }
        }
    }
}

Usage:

ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.WorkingDirectory ="C:\\BLA\\bin_windows";
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.CreateNoWindow = true;

        startInfo.FileName = "SomeProcess"
        Process p = Process.Start(startInfo);
        ProcessManager.Instance.AddProcess(p);
    p.WaitForExit();

If you don`t wish static things in your prog (for example, you can have some instances of it), you can use this class, but without singleton and give its single instance to every thread.




回答3:


If you want to close the process, there's no need to P/Invoke and send a WM_CLOSE message, just call the CloseMainWindow() method on your Process instance (which will send a WM_CLOSE for you). You can then follow it up with the Close() method to release your local view of it.

Keeping track of the processes you've started is fairly easy as well.

public static ConcurrentBag<Process> processes = new ConcurrentBag<Process>();

Store your processes as you create them.

Process process = ... //Create your process
processes.Add(process);

And then cycle through and close them.

foreach (var process in processes)
{
    if (!process.HasExited)
    {
        process.CloseMainWindow();
        process.Close();
    }
}


来源:https://stackoverflow.com/questions/10252155/killing-multiple-processes-that-were-started-from-nested-threads-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!