public void Stop()
 {// attempt to gracefully exit threads
     TimeoutCancelled = true;
     HasAcquired      = false;
     MonitorTimer.Change(Timeout.Infinite, Timeout.Infinite);
     SearchTimer.Change(Timeout.Infinite, Timeout.Infinite);
 }
 public void Restart()
 {
     TimeoutCancelled = false;
     HasAcquired      = false;
     MonitorTimer.Change(0, Interval);
     SearchTimer.Change(Timeout.Infinite, Timeout.Infinite);
 }
        private void OnProcessAcquired(ProcessMonitor m, ProcessEventArgs e)
        {
            ProcessUtils.Logger($"MONITOR@{ProcessName}",
                                $"Process acquired in {ProcessUtils.ElapsedToString(e.Elapsed)}: {e.ProcessName}.exe [{e.TargetProcess.Id}]");

            HasAcquired = true;
            MonitorTimer.Change(Timeout.Infinite, Timeout.Infinite);
            SearchTimer.Change(0, Interval);
            ProcessAcquired?.Invoke(m, e);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (Disposed)
            {
                return;
            }

            if (disposing)
            {
                MonitorTimer.Change(Timeout.Infinite, Timeout.Infinite);
                SearchTimer.Change(Timeout.Infinite, Timeout.Infinite);
                MonitorTimer.Dispose();
                SearchTimer.Dispose();
                MonitorLock.Dispose();
            }
            Disposed = true;
        }
        private void OnProcessSoftExit(ProcessMonitor m, ProcessEventArgs e)
        {// attempt to gracefully switch modes (monitor -> search)
            if (HasAcquired && !string.IsNullOrWhiteSpace(e.ProcessName))
            {
                ProcessUtils.Logger($"MONITOR@{ProcessName}", $"Process exited, attempting to reacquire within {e.Timeout}s: {e.ProcessName}.exe");
            }
            else if (HasAcquired)  // can't get process details?
            {
                ProcessUtils.Logger($"MONITOR@{ProcessName}", $"Process exited, attempting to reacquire within {e.Timeout}s");
            }

            HasAcquired = false;
            // transition from monitoring -> searching
            MonitorTimer.Change(Timeout.Infinite, Timeout.Infinite);
            SearchTimer.Change(0, Interval);

            ProcessSoftExit?.Invoke(m, e);
        }
        /// <summary>
        /// TimerCallback delegate for threaded timer to reacquire a valid process by name
        /// </summary>
        private async void SearchProcess(object stateInfo)
        {// used when searching for a valid process within a timeout
            await MonitorLock.WaitAsync();

            try
            {// monitor with a shorter timeout for the search
                if (!TimeoutCancelled)
                {
                    await TimeoutWatcher(InnerTimeout);
                }
                else
                {
                    SearchTimer.Change(Timeout.Infinite, Timeout.Infinite);
                }
            }
            catch (Win32Exception) { }
            finally
            {
                MonitorLock.Release();
            }
        }