135 lines
3.5 KiB
C#
135 lines
3.5 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
using Topshelf;
|
|||
|
|
using log4net;
|
|||
|
|
using System.Net.Sockets;
|
|||
|
|
using System.Net;
|
|||
|
|
using System.Collections.Concurrent;
|
|||
|
|
using System.Diagnostics;
|
|||
|
|
using System.IO.Pipes;
|
|||
|
|
|
|||
|
|
namespace kmProcessServer;
|
|||
|
|
|
|||
|
|
internal class ServiceMain : ServiceControl
|
|||
|
|
{
|
|||
|
|
ILog appLog = LogManager.GetLogger(Program.AppName);
|
|||
|
|
ConcurrentBag<Task> tasks = new();
|
|||
|
|
ConcurrentBag<MdlProcess> ChildProcesses = new();
|
|||
|
|
|
|||
|
|
public bool Start(HostControl hostControl)
|
|||
|
|
{
|
|||
|
|
appLog.Info(string.Format("Service successfully started."));
|
|||
|
|
tasks.Add(Task.Run(() => { StartTasks(); }));
|
|||
|
|
return true;
|
|||
|
|
} //Start
|
|||
|
|
|
|||
|
|
public bool Stop(HostControl hostControl)
|
|||
|
|
{
|
|||
|
|
Program.isExiting = true;
|
|||
|
|
Task.WaitAll(tasks.ToArray());
|
|||
|
|
tasks.Clear();
|
|||
|
|
appLog.Debug("++ Service shutdown successful.");
|
|||
|
|
return true;
|
|||
|
|
} //Stop
|
|||
|
|
|
|||
|
|
void StartTasks()
|
|||
|
|
{
|
|||
|
|
var rn = new Random();
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
foreach (var f0 in Directory.GetFiles(Program.AppPath + "Procs", "*.exe"))
|
|||
|
|
{
|
|||
|
|
var px = new MdlProcess()
|
|||
|
|
{
|
|||
|
|
ProgramToRun = f0,
|
|||
|
|
ExecutableName = Path.GetFileName(f0)
|
|||
|
|
};
|
|||
|
|
var si = new ProcessStartInfo()
|
|||
|
|
{
|
|||
|
|
FileName = px.ProgramToRun,
|
|||
|
|
Verb = "OPEN",
|
|||
|
|
WorkingDirectory = Path.GetDirectoryName(f0),
|
|||
|
|
RedirectStandardError = true,
|
|||
|
|
UseShellExecute = false
|
|||
|
|
};
|
|||
|
|
px.theProcess = new Process() { StartInfo = si };
|
|||
|
|
px.theProcess.Start();
|
|||
|
|
px.StartTime = DateTimeOffset.Now;
|
|||
|
|
px.IPCChannel = string.Format("kmProcess_IPCChannel.{0}", px.theProcess.Id);
|
|||
|
|
ChildProcesses.Add(px);
|
|||
|
|
appLog.DebugFormat("++ Launched Process '{0}' having PID of {1}", px.ExecutableName, px.theProcess.Id);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
appLog.Error(ex);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
while (!Program.isExiting)
|
|||
|
|
{
|
|||
|
|
Thread.Sleep(rn.Next(900, 3000));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// First, try to stop them all gracefully...
|
|||
|
|
foreach (var px in ChildProcesses)
|
|||
|
|
{
|
|||
|
|
appLog.DebugFormat("Sending request to shut down process '{0}'...", px.ExecutableName);
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using (var ch = new NamedPipeClientStream(".", px.IPCChannel, PipeDirection.Out))
|
|||
|
|
{
|
|||
|
|
if (ch.ConnectAsync().Wait(3000))
|
|||
|
|
{
|
|||
|
|
using (var w = new StreamWriter(ch))
|
|||
|
|
{
|
|||
|
|
w.WriteLine("EXIT_NOW");
|
|||
|
|
w.Flush();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
appLog.Error(ex);
|
|||
|
|
}
|
|||
|
|
Thread.Sleep(100);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Anyone still running? Use the hammer.
|
|||
|
|
foreach (var px in ChildProcesses)
|
|||
|
|
{
|
|||
|
|
if (px.theProcess != null)
|
|||
|
|
{
|
|||
|
|
if (!px.theProcess.HasExited)
|
|||
|
|
Thread.Sleep(5000); //Give it a little time to gracefully exit
|
|||
|
|
if (!px.theProcess.HasExited)
|
|||
|
|
{
|
|||
|
|
try { px.theProcess.Kill(); }
|
|||
|
|
catch { }
|
|||
|
|
}
|
|||
|
|
try { px.theProcess.Dispose(); }
|
|||
|
|
catch { }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
ChildProcesses.Clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region "Private Models and Such"
|
|||
|
|
class MdlProcess
|
|||
|
|
{
|
|||
|
|
public string ProgramToRun { get; set; } = string.Empty;
|
|||
|
|
public string ExecutableName { get; set; } = string.Empty;
|
|||
|
|
public Process? theProcess { get; set; } = null;
|
|||
|
|
public DateTimeOffset StartTime { get; set; } = DateTimeOffset.Now;
|
|||
|
|
/// <summary>
|
|||
|
|
/// Used for interprocess communications
|
|||
|
|
/// </summary>
|
|||
|
|
public string IPCChannel { get; set; } = string.Empty;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
}
|