Process.Close() is not terminating created process,c#
Process.Close() isn't meant to abort the process - it's just meant to release your "local" view on the process, and associated resources.
I think you mean Process.Kill() or Process.CloseMainWindow(). Personally I'd try to find a more graceful way of shutting it down though.
Terminating a Process and any Child Processes with a Timeout
Ok so I believe I've gotten to the ideal solution, many thanks to Remus and Usr. I'm leaving my previous solution up as it's fairly viable for small operations.
The biggest problem is when the lineage chain is broken, terminating all child processes becomes quite difficult. Ie A creates B, B creates C but then B ends - A looses any scope over C.
For my testing I modified my TestApp into something rather horrible, a self-spawning nightmare with a self-terminating flipflop. The nasty code for it is at the bottom of this answer, which I suggest anyone only looks at for reference only.
The only answer it seems to govern this nightmare is via Job Objects. I used the class from this answer (credit to Alexander Yezutov -> Matt Howells -> 'Josh') but had to modify it slight to work (therefore I'm posting it's code). I added this class to my project:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace JobManagement
{
public class Job : IDisposable
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CreateJobObject(IntPtr a, string lpName);
[DllImport("kernel32.dll")]
static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
private IntPtr _handle;
private bool _disposed;
public Job()
{
_handle = CreateJobObject(IntPtr.Zero, null);
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
LimitFlags = 0x2000
};
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
BasicLimitInformation = info
};
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
if (!SetInformationJobObject(_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length))
{
throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error()));
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing) { }
Close();
_disposed = true;
}
public void Close()
{
CloseHandle(_handle);
_handle = IntPtr.Zero;
}
public bool AddProcess(IntPtr processHandle)
{
return AssignProcessToJobObject(_handle, processHandle);
}
public bool AddProcess(int processId)
{
return AddProcess(Process.GetProcessById(processId).Handle);
}
}
#region Helper classes
[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public UInt32 LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public UIntPtr Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public IntPtr lpSecurityDescriptor;
public Int32 bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}
public enum JobObjectInfoType
{
AssociateCompletionPortInformation = 7,
BasicLimitInformation = 2,
BasicUIRestrictions = 4,
EndOfJobTimeInformation = 6,
ExtendedLimitInformation = 9,
SecurityLimitInformation = 5,
GroupInformation = 11
}
#endregion
}
Changed my main method's content to look like this:
var t = new Thread(delegate()
{
try
{
using (var jobHandler = new Job())
{
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + cmd);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
using (Process process = Process.Start(processInfo))
{
DateTime started = process.StartTime;
jobHandler.AddProcess(process.Id); //add the PID to the Job object
process.EnableRaisingEvents = true;
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => WriteToDebugTextBox(e.Data);
process.BeginOutputReadLine();
process.WaitForExit(_postProcessesTimeOut * 1000);
TimeSpan tpt = (DateTime.Now - started);
if (Math.Abs(tpt.TotalMilliseconds) > (_postProcessesTimeOut * 1000))
{
WriteToDebugTextBox("Timeout reached, terminating all child processes"); //jobHandler.Close() will do this, just log that the timeout was reached
}
}
jobHandler.Close(); //this will terminate all spawned processes
}
}
catch (Exception ex)
{
WriteToDebugTextBox("ERROR:" + ex.Message);
}
WriteToDebugTextBox("Finished Post Process");
});
t.Start();
Feedback through the method looks like this (note: it looses scope part way through but TestApp continues to run and propagate):
13:06:31.055 Executing Threaded Post Process 'test.bat'
13:06:31.214 24976 TestApp started
13:06:31.226 24976 Now going to make a horrible mess by calling myself in 1 second...
13:06:32.213 24976 Creating Child Process cmd 'TestApp.exe'
13:06:32.229 24976 Finished Child-Threaded Process
13:06:32.285 24976 TestApp is going to have a little 'sleep' for 10 seconds
13:06:32.336 24976 Created New Process 26936
13:06:32.454 20344 TestApp started
13:06:32.500 20344 Now going to make a horrible mess by calling myself in 1 second...
13:06:32.512 20344 !! I will self terminate after creating a child process to break the lineage chain
13:06:33.521 20344 Creating Child Process cmd 'TestApp.exe'
13:06:33.540 20344 Finished Child-Threaded Process
13:06:33.599 20344 Created New Process 24124
13:06:33.707 19848 TestApp started
13:06:33.759 19848 Now going to make a horrible mess by calling myself in 1 second...
13:06:34.540 20344 !! Topping myself! PID 20344
Scope lost after here
13:06:41.139 Timeout reached, terminating all child processes
Note the PIDs vary because TestApp isn't being directly called, it's being passed through CMD - I was going for extreme here ;)
Here's TestApp, I strongly suggest this is used for reference only as it will run amok creating new instances of itself (it does have a 'kill' argument for clean up if anyone runs it!).
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TestApp
{
class Program
{
/// <summary>
/// TestApp.exe [hangtime(int)] [self-terminate(bool)]
/// TestApp.exe kill --terminate all processes called TestApp
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
int hangTime = 5; //5 second default
bool selfTerminate = true;
Process thisProcess = Process.GetCurrentProcess();
if (args.Length > 0)
{
if (args[0] == "kill")
{
KillAllTestApps(thisProcess);
return;
}
hangTime = int.Parse(args[0]);
if (args.Length > 1)
{
selfTerminate = bool.Parse(args[1]);
}
}
Console.WriteLine("{0} TestApp started", thisProcess.Id);
Console.WriteLine("{0} Now going to make a horrible mess by calling myself in 1 second...", thisProcess.Id);
if (selfTerminate)
{
Console.WriteLine("{0} !! I will self terminate after creating a child process to break the lineage chain", thisProcess.Id);
}
Thread.Sleep(1000);
ExecutePostProcess("TestApp.exe", thisProcess, selfTerminate);
if (selfTerminate)
{
Thread.Sleep(1000);
Console.WriteLine("{0} !! Topping myself! PID {0}", thisProcess.Id);
thisProcess.Kill();
}
Console.WriteLine("{0} TestApp is going to have a little 'sleep' for {1} seconds", thisProcess.Id, hangTime);
Thread.Sleep(hangTime * 1000);
Console.WriteLine("{0} Test App has woken up!", thisProcess.Id);
}
public static void ExecutePostProcess(string cmd, Process thisProcess, bool selfTerminate)
{
Console.WriteLine("{0} Creating Child Process cmd '{1}'", thisProcess.Id, cmd);
var t = new Thread(delegate()
{
try
{
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + cmd + " 10 " + (selfTerminate ? "false" : "true" ));
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
using (Process process = Process.Start(processInfo))
{
Console.WriteLine("{0} Created New Process {1}", thisProcess.Id, process.Id);
process.EnableRaisingEvents = true;
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine(e.Data);
process.BeginOutputReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
t.Start();
Console.WriteLine("{0} Finished Child-Threaded Process", thisProcess.Id);
}
/// <summary>
/// kill all TestApp processes regardless of parent
/// </summary>
private static void KillAllTestApps(Process thisProcess)
{
Process[] processes = Process.GetProcessesByName("TestApp");
foreach(Process p in processes)
{
if (thisProcess.Id != p.Id)
{
Console.WriteLine("Killing {0}:{1}", p.ProcessName, p.Id);
p.Kill();
}
}
}
}
}
Process is not terminating Properly in java (Runtime)
There was .dll
linking error in when I tried to do the same in command prompt with Demo files.By keeping .dll
file and .exe
file in the same directory it solved my purpose program was running Flawlessly with proper exit code (0).
So kept other .dll
file in this path D:\apache-tomcat-7.0.64\temp\
. and is fine.
The thumb rule says .dll
and .exe
should be in the same directoryeory
Carefully closing processes
You need to focus on resource clean-up and graceful exit in the process you've started.
You cannot do it remotely, so what you do in this scheduler app is sufficient to send a message to the started process to make it stop.
The started process should handle the rest. (A graceful exit)
When you stop a process, any managed (and also unmanaged) resources it had utilized will be freed whether you Dispose()
them or not.
There will be no memory leak since the full working set will be freed by your OS.
What you should consider is whether there are ongoing background processing (threads started by you, which are not marked with IsBackground = true will continue running and prevent application close), Tasks that you have started, and you should implement graceful exit for any kind of external connections etc. for these.
If one of the tasks is writing to a file at that exact moment, the file will be partially written. If a thread is doing some Network IO at that moment, that will be interrupted. It will be disconnected from the remote end prematurely. You don't need to worry about memory and handle leaks but should consider graceful-stop for these kinds of processes (file IO, network IO etc.)
Your finalizers will be invoked during termination. This is a good place to handle clean-up.
Also see here for how to use a cancellation token to stop a task when it is about to be cancelled.
Hope this helps.
Program doesn’t terminate when using processes
ProcessStartInfo psi = new ProcessStartInfo("getdiff.exe");
psi.Arguments = "DIFF";
psi.UseShellExecute = false;
psi.RedirectStandardInput = true;
psi.WorkingDirectory = "c:\\test";
Process p = Process.Start(psi);
StreamReader read = p.StandardOutput;
while (read.Peek() >= 0)
Console.WriteLine(read.ReadLine());
Console.WriteLine("Complete");
p.WaitForExit();
p.Close();
What are the differences between kill process and close process?
What are the differences between
Process.Close()
andprocess.Kill()
?
The manual is pretty clear on that:
Process.Close()
:
The Close method causes the process to stop waiting for exit if it was waiting, closes the process handle, and clears process-specific properties. Close does not close the standard output, input, and error readers and writers in case they are being referenced externally. [i.e. the process itself keeps running, you just cannot control it anymore using your
Process
instance]
Process.Kill()
:
Kill forces a termination of the process, while CloseMainWindow only requests a termination. [...] The request to exit the process by calling CloseMainWindow does not force the application to quit. The application can ask for user verification before quitting, or it can refuse to quit. To force the application to quit, use the Kill method. The behavior of CloseMainWindow is identical to that of a user closing an application's main window using the system menu. Therefore, the request to exit the process by closing the main window does not force the application to quit immediately.
Process.CloseMainWindow
:
Closes a process that has a user interface by sending a close message to its main window.
As for your edit:
i asked because i have application who start to capture packet using wireshark with command via command line with Windows = hidden.
Use the WinPcap API or the Pcap.Net library for that, not Wireshark.
Can't close process but kill
According to the documentation of CloseMainWindow
, there is no guarantee that the process will exit upon calling that method. It's possible that the process you're trying to close is displaying a modal dialog. It's also possible that the application which isn't closing does not have a graphical interface (in which case you must use Kill
to terminate it). The relevant documentation is provided below.
The request to exit the process by calling
CloseMainWindow
does not force the application to quit. The application can ask for user verification before quitting, or it can refuse to quit. To force the application to quit, use theKill
methodIf
CloseMainWindow
fails, you can useKill
to terminate the process. Kill is the only way to terminate processes that do not have graphical interfaces.
I noticed that CloseMainWindow
returns a bool
. You may want to attempt to read that value and only WaitForExit
if that was true
. You could also try to remote into the server and hook up a debugger to the relevant process to see why it doesn't close.
Related Topics
How Would I Sort a List of Files by Name to Match How Windows Explorer Displays Them
Is There a Much Better Way to Create Deep and Shallow Clones in C#
How to Interact with Windows Media Player in C#
How to Use System.Net.Httpclient to Post a Complex Type
Nullable Object Must Have a Value
String Interpolation VS String.Format
Setting a Webrequest's Body Data
Using Custom Fonts on a Label on Winforms
The Source Was Not Found, But Some or All Event Logs Could Not Be Searched
Detecting Client Death in Wcf Duplex Contracts
Get Current System.Web.Ui.Page from Httpcontext
How to Make Form1 Label.Text Change When Checkbox on Form2 Is Checked
Split a String That Has White Spaces, Unless They Are Enclosed Within "Quotes"
How to Open a Web Page from My Application
How to to Return an Image with Web API Get Method