/// <devdoc>
/// <para>
/// Frees any resources associated with this component.
/// </para>
/// </devdoc>
public void Close()
{
if (Associated)
{
// We need to lock to ensure we don't run concurrently with CompletionCallback.
// Without this lock we could reset _raisedOnExited which causes CompletionCallback to
// raise the Exited event a second time for the same process.
lock (this)
{
// This sets _waitHandle to null which causes CompletionCallback to not emit events.
StopWatchingForExit();
}
if (_haveProcessHandle)
{
_processHandle.Dispose();
_processHandle = null;
_haveProcessHandle = false;
}
_haveProcessId = false;
_isRemoteMachine = false;
_machineName = ".";
_raisedOnExited = false;
// Only call close on the streams if the user cannot have a reference on them.
// If they are referenced it is the user's responsibility to dispose of them.
try
{
if (_standardOutput != null && (_outputStreamReadMode == StreamReadMode.AsyncMode || _outputStreamReadMode == StreamReadMode.Undefined))
{
if (_outputStreamReadMode == StreamReadMode.AsyncMode)
{
_output?.CancelOperation();
_output?.Dispose();
}
_standardOutput.Close();
}
if (_standardError != null && (_errorStreamReadMode == StreamReadMode.AsyncMode || _errorStreamReadMode == StreamReadMode.Undefined))
{
if (_errorStreamReadMode == StreamReadMode.AsyncMode)
{
_error?.CancelOperation();
_error?.Dispose();
}
_standardError.Close();
}
if (_standardInput != null && !_standardInputAccessed)
{
_standardInput.Close();
}
}
finally
{
_standardOutput = null;
_standardInput = null;
_standardError = null;
_output = null;
_error = null;
CloseCore();
Refresh();
}
}
}