Process.Close() Is Not Terminating Created Process,C#

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() and process.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 the Kill method

If CloseMainWindow fails, you can use Kill 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



Leave a reply



Submit