问题
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