Ensure basic console logging

pull/726/head
NextTurn 2020-09-06 00:00:00 +08:00 committed by Next Turn
parent 12525cc8fc
commit 2ab79083d4
34 changed files with 282 additions and 296 deletions

View File

@ -102,7 +102,7 @@ namespace WinSW
private static int SingleIntElement(XmlNode parent, string tagName, int defaultValue) private static int SingleIntElement(XmlNode parent, string tagName, int defaultValue)
{ {
XmlNode? e = parent.SelectSingleNode(tagName); var e = parent.SelectSingleNode(tagName);
return e is null ? defaultValue : int.Parse(e.InnerText, NumberFormatInfo.InvariantInfo); return e is null ? defaultValue : int.Parse(e.InnerText, NumberFormatInfo.InvariantInfo);
} }
@ -128,13 +128,13 @@ namespace WinSW
private string? SingleElementOrNull(string tagName) private string? SingleElementOrNull(string tagName)
{ {
XmlNode? n = this.root.SelectSingleNode(tagName); var n = this.root.SelectSingleNode(tagName);
return n is null ? null : Environment.ExpandEnvironmentVariables(n.InnerText); return n is null ? null : Environment.ExpandEnvironmentVariables(n.InnerText);
} }
private bool SingleBoolElementOrDefault(string tagName, bool defaultValue) private bool SingleBoolElementOrDefault(string tagName, bool defaultValue)
{ {
XmlNode? e = this.root.SelectSingleNode(tagName); var e = this.root.SelectSingleNode(tagName);
return e is null ? defaultValue : bool.Parse(e.InnerText); return e is null ? defaultValue : bool.Parse(e.InnerText);
} }
@ -208,14 +208,14 @@ namespace WinSW
{ {
get get
{ {
XmlNode? argumentNode = this.ExtensionsConfiguration; var argumentNode = this.ExtensionsConfiguration;
XmlNodeList? extensions = argumentNode?.SelectNodes("extension"); var extensions = argumentNode?.SelectNodes("extension");
if (extensions is null) if (extensions is null)
{ {
return new List<string>(0); return new List<string>(0);
} }
List<string> result = new List<string>(extensions.Count); var result = new List<string>(extensions.Count);
for (int i = 0; i < extensions.Count; i++) for (int i = 0; i < extensions.Count; i++)
{ {
result.Add(XmlHelper.SingleAttribute<string>((XmlElement)extensions[i]!, "id")); result.Add(XmlHelper.SingleAttribute<string>((XmlElement)extensions[i]!, "id"));
@ -239,7 +239,7 @@ namespace WinSW
string? mode = null; string? mode = null;
// first, backward compatibility with older configuration // first, backward compatibility with older configuration
XmlElement? e = (XmlElement?)this.root.SelectSingleNode("logmode"); var e = (XmlElement?)this.root.SelectSingleNode("logmode");
if (e != null) if (e != null)
{ {
mode = e.InnerText; mode = e.InnerText;
@ -272,7 +272,7 @@ namespace WinSW
{ {
get get
{ {
XmlElement? e = (XmlElement?)this.root.SelectSingleNode("logmode"); var e = (XmlElement?)this.root.SelectSingleNode("logmode");
// this is more modern way, to support nested elements as configuration // this is more modern way, to support nested elements as configuration
e ??= (XmlElement?)this.root.SelectSingleNode("log")!; // WARNING: NRE e ??= (XmlElement?)this.root.SelectSingleNode("log")!; // WARNING: NRE
@ -293,13 +293,13 @@ namespace WinSW
return new RollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern); return new RollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern);
case "roll-by-time": case "roll-by-time":
XmlNode? patternNode = e.SelectSingleNode("pattern"); var patternNode = e.SelectSingleNode("pattern");
if (patternNode is null) if (patternNode is null)
{ {
throw new InvalidDataException("Time Based rolling policy is specified but no pattern can be found in configuration XML."); throw new InvalidDataException("Time Based rolling policy is specified but no pattern can be found in configuration XML.");
} }
var pattern = patternNode.InnerText; string? pattern = patternNode.InnerText;
int period = SingleIntElement(e, "period", 1); int period = SingleIntElement(e, "period", 1);
return new TimeBasedRollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, pattern, period); return new TimeBasedRollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, pattern, period);
@ -313,18 +313,18 @@ namespace WinSW
case "roll-by-size-time": case "roll-by-size-time":
sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * RollingSizeTimeLogAppender.BytesPerKB; sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * RollingSizeTimeLogAppender.BytesPerKB;
XmlNode? filePatternNode = e.SelectSingleNode("pattern"); var filePatternNode = e.SelectSingleNode("pattern");
if (filePatternNode is null) if (filePatternNode is null)
{ {
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but no pattern can be found in configuration XML."); throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but no pattern can be found in configuration XML.");
} }
XmlNode? autoRollAtTimeNode = e.SelectSingleNode("autoRollAtTime"); var autoRollAtTimeNode = e.SelectSingleNode("autoRollAtTime");
TimeSpan? autoRollAtTime = null; TimeSpan? autoRollAtTime = null;
if (autoRollAtTimeNode != null) if (autoRollAtTimeNode != null)
{ {
// validate it // validate it
if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out TimeSpan autoRollAtTimeValue)) if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out var autoRollAtTimeValue))
{ {
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but autoRollAtTime does not match the TimeSpan format HH:mm:ss found in configuration XML."); throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but autoRollAtTime does not match the TimeSpan format HH:mm:ss found in configuration XML.");
} }
@ -332,7 +332,7 @@ namespace WinSW
autoRollAtTime = autoRollAtTimeValue; autoRollAtTime = autoRollAtTimeValue;
} }
XmlNode? zipolderthannumdaysNode = e.SelectSingleNode("zipOlderThanNumDays"); var zipolderthannumdaysNode = e.SelectSingleNode("zipOlderThanNumDays");
int? zipolderthannumdays = null; int? zipolderthannumdays = null;
if (zipolderthannumdaysNode != null) if (zipolderthannumdaysNode != null)
{ {
@ -345,7 +345,7 @@ namespace WinSW
zipolderthannumdays = zipolderthannumdaysValue; zipolderthannumdays = zipolderthannumdaysValue;
} }
XmlNode? zipdateformatNode = e.SelectSingleNode("zipDateFormat"); var zipdateformatNode = e.SelectSingleNode("zipDateFormat");
string zipdateformat = zipdateformatNode is null ? "yyyyMM" : zipdateformatNode.InnerText; string zipdateformat = zipdateformatNode is null ? "yyyyMM" : zipdateformatNode.InnerText;
return new RollingSizeTimeLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, sizeThreshold, filePatternNode.InnerText, autoRollAtTime, zipolderthannumdays, zipdateformat); return new RollingSizeTimeLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, sizeThreshold, filePatternNode.InnerText, autoRollAtTime, zipolderthannumdays, zipdateformat);
@ -363,7 +363,7 @@ namespace WinSW
{ {
get get
{ {
XmlNodeList? nodeList = this.root.SelectNodes("depend"); var nodeList = this.root.SelectNodes("depend");
if (nodeList is null) if (nodeList is null)
{ {
return base.ServiceDependencies; return base.ServiceDependencies;
@ -404,7 +404,7 @@ namespace WinSW
} }
catch (ArgumentException e) catch (ArgumentException e)
{ {
StringBuilder builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("Start mode in XML must be one of the following:"); builder.AppendLine("Start mode in XML must be one of the following:");
foreach (string sm in Enum.GetNames(typeof(ServiceStartMode))) foreach (string sm in Enum.GetNames(typeof(ServiceStartMode)))
{ {
@ -457,13 +457,13 @@ namespace WinSW
{ {
get get
{ {
XmlNodeList? nodeList = this.root.SelectNodes("download"); var nodeList = this.root.SelectNodes("download");
if (nodeList is null) if (nodeList is null)
{ {
return base.Downloads; return base.Downloads;
} }
List<Download> result = new List<Download>(nodeList.Count); var result = new List<Download>(nodeList.Count);
for (int i = 0; i < nodeList.Count; i++) for (int i = 0; i < nodeList.Count; i++)
{ {
if (nodeList[i] is XmlElement element) if (nodeList[i] is XmlElement element)
@ -480,25 +480,25 @@ namespace WinSW
{ {
get get
{ {
XmlNodeList? childNodes = this.root.SelectNodes("onfailure"); var childNodes = this.root.SelectNodes("onfailure");
if (childNodes is null) if (childNodes is null)
{ {
return Array.Empty<SC_ACTION>(); return Array.Empty<SC_ACTION>();
} }
SC_ACTION[] result = new SC_ACTION[childNodes.Count]; var result = new SC_ACTION[childNodes.Count];
for (int i = 0; i < childNodes.Count; i++) for (int i = 0; i < childNodes.Count; i++)
{ {
XmlNode node = childNodes[i]!; var node = childNodes[i]!;
string action = node.Attributes!["action"]?.Value ?? throw new InvalidDataException("'action' is missing"); string action = node.Attributes!["action"]?.Value ?? throw new InvalidDataException("'action' is missing");
SC_ACTION_TYPE type = action switch var type = action switch
{ {
"restart" => SC_ACTION_TYPE.SC_ACTION_RESTART, "restart" => SC_ACTION_TYPE.SC_ACTION_RESTART,
"none" => SC_ACTION_TYPE.SC_ACTION_NONE, "none" => SC_ACTION_TYPE.SC_ACTION_NONE,
"reboot" => SC_ACTION_TYPE.SC_ACTION_REBOOT, "reboot" => SC_ACTION_TYPE.SC_ACTION_REBOOT,
_ => throw new Exception("Invalid failure action: " + action) _ => throw new Exception("Invalid failure action: " + action)
}; };
XmlAttribute? delay = node.Attributes["delay"]; var delay = node.Attributes["delay"];
result[i] = new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero); result[i] = new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero);
} }
@ -510,11 +510,11 @@ namespace WinSW
protected string? GetServiceAccountPart(string subNodeName) protected string? GetServiceAccountPart(string subNodeName)
{ {
XmlNode? node = this.root.SelectSingleNode("serviceaccount"); var node = this.root.SelectSingleNode("serviceaccount");
if (node != null) if (node != null)
{ {
XmlNode? subNode = node.SelectSingleNode(subNodeName); var subNode = node.SelectSingleNode(subNodeName);
if (subNode != null) if (subNode != null)
{ {
return subNode.InnerText; return subNode.InnerText;
@ -583,11 +583,11 @@ namespace WinSW
private Dictionary<string, string> LoadEnvironmentVariables() private Dictionary<string, string> LoadEnvironmentVariables()
{ {
XmlNodeList nodeList = this.root.SelectNodes("env")!; var nodeList = this.root.SelectNodes("env")!;
Dictionary<string, string> environment = new Dictionary<string, string>(nodeList.Count); var environment = new Dictionary<string, string>(nodeList.Count);
for (int i = 0; i < nodeList.Count; i++) for (int i = 0; i < nodeList.Count; i++)
{ {
XmlNode node = nodeList[i]!; var node = nodeList[i]!;
string key = node.Attributes!["name"]?.Value ?? throw new InvalidDataException("'name' is missing"); string key = node.Attributes!["name"]?.Value ?? throw new InvalidDataException("'name' is missing");
string value = Environment.ExpandEnvironmentVariables(node.Attributes["value"]?.Value ?? throw new InvalidDataException("'value' is missing")); string value = Environment.ExpandEnvironmentVariables(node.Attributes["value"]?.Value ?? throw new InvalidDataException("'value' is missing"));
environment[key] = value; environment[key] = value;
@ -600,7 +600,7 @@ namespace WinSW
private ProcessCommand GetProcessCommand(string name) private ProcessCommand GetProcessCommand(string name)
{ {
XmlNode? node = this.root.SelectSingleNode(name); var node = this.root.SelectSingleNode(name);
return node is null ? default : new ProcessCommand return node is null ? default : new ProcessCommand
{ {
Executable = GetInnerText(Names.Executable), Executable = GetInnerText(Names.Executable),

View File

@ -121,10 +121,10 @@ namespace WinSW
/// </exception> /// </exception>
public async Task PerformAsync() public async Task PerformAsync()
{ {
WebRequest request = WebRequest.Create(this.From); var request = WebRequest.Create(this.From);
if (!string.IsNullOrEmpty(this.Proxy)) if (!string.IsNullOrEmpty(this.Proxy))
{ {
CustomProxyInformation proxyInformation = new CustomProxyInformation(this.Proxy!); var proxyInformation = new CustomProxyInformation(this.Proxy!);
if (proxyInformation.Credentials != null) if (proxyInformation.Credentials != null)
{ {
request.Proxy = new WebProxy(proxyInformation.ServerAddress, false, null, proxyInformation.Credentials); request.Proxy = new WebProxy(proxyInformation.ServerAddress, false, null, proxyInformation.Credentials);
@ -166,9 +166,9 @@ namespace WinSW
string tmpFilePath = this.To + ".tmp"; string tmpFilePath = this.To + ".tmp";
try try
{ {
using (WebResponse response = await request.GetResponseAsync().ConfigureAwait(false)) using (var response = await request.GetResponseAsync().ConfigureAwait(false))
using (Stream responseStream = response.GetResponseStream()) using (var responseStream = response.GetResponseStream())
using (FileStream tmpStream = new FileStream(tmpFilePath, FileMode.Create)) using (var tmpStream = new FileStream(tmpFilePath, FileMode.Create))
{ {
if (supportsIfModifiedSince) if (supportsIfModifiedSince)
{ {

View File

@ -25,7 +25,7 @@ namespace WinSW.Extensions
try try
{ {
Type? t = Type.GetType(className); var t = Type.GetType(className);
if (t is null) if (t is null)
{ {
throw new ExtensionException(id, "Class " + className + " does not exist"); throw new ExtensionException(id, "Class " + className + " does not exist");
@ -154,8 +154,8 @@ namespace WinSW.Extensions
throw new ExtensionException(id, "Extension has been already loaded"); throw new ExtensionException(id, "Extension has been already loaded");
} }
XmlNode? extensionsConfig = this.ServiceConfig.ExtensionsConfiguration; var extensionsConfig = this.ServiceConfig.ExtensionsConfiguration;
XmlElement? configNode = extensionsConfig is null ? null : extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement; var configNode = extensionsConfig is null ? null : extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement;
if (configNode is null) if (configNode is null)
{ {
throw new ExtensionException(id, "Cannot get the configuration entry"); throw new ExtensionException(id, "Cannot get the configuration entry");
@ -164,7 +164,7 @@ namespace WinSW.Extensions
var descriptor = WinSWExtensionDescriptor.FromXml(configNode); var descriptor = WinSWExtensionDescriptor.FromXml(configNode);
if (descriptor.Enabled) if (descriptor.Enabled)
{ {
IWinSWExtension extension = CreateExtensionInstance(descriptor.Id, descriptor.ClassName); var extension = CreateExtensionInstance(descriptor.Id, descriptor.ClassName);
extension.Descriptor = descriptor; extension.Descriptor = descriptor;
try try
{ {

View File

@ -243,10 +243,10 @@ namespace WinSW
/// </summary> /// </summary>
private async Task CopyStreamWithDateRotationAsync(StreamReader reader, string ext) private async Task CopyStreamWithDateRotationAsync(StreamReader reader, string ext)
{ {
PeriodicRollingCalendar periodicRollingCalendar = new PeriodicRollingCalendar(this.Pattern, this.Period); var periodicRollingCalendar = new PeriodicRollingCalendar(this.Pattern, this.Period);
periodicRollingCalendar.Init(); periodicRollingCalendar.Init();
StreamWriter writer = this.CreateWriter(new FileStream(this.BaseLogFileName + "_" + periodicRollingCalendar.Format + ext, FileMode.Append)); var writer = this.CreateWriter(new FileStream(this.BaseLogFileName + "_" + periodicRollingCalendar.Format + ext, FileMode.Append));
string? line; string? line;
while ((line = await reader.ReadLineAsync()) != null) while ((line = await reader.ReadLineAsync()) != null)
{ {
@ -302,7 +302,7 @@ namespace WinSW
/// </summary> /// </summary>
private async Task CopyStreamWithRotationAsync(StreamReader reader, string ext) private async Task CopyStreamWithRotationAsync(StreamReader reader, string ext)
{ {
StreamWriter writer = this.CreateWriter(new FileStream(this.BaseLogFileName + ext, FileMode.Append)); var writer = this.CreateWriter(new FileStream(this.BaseLogFileName + ext, FileMode.Append));
long fileLength = new FileInfo(this.BaseLogFileName + ext).Length; long fileLength = new FileInfo(this.BaseLogFileName + ext).Length;
string? line; string? line;
@ -426,20 +426,20 @@ namespace WinSW
private async Task CopyStreamWithRotationAsync(StreamReader reader, string extension) private async Task CopyStreamWithRotationAsync(StreamReader reader, string extension)
{ {
// lock required as the timer thread and the thread that will write to the stream could try and access the file stream at the same time // lock required as the timer thread and the thread that will write to the stream could try and access the file stream at the same time
var fileLock = new object(); object? fileLock = new object();
var baseDirectory = Path.GetDirectoryName(this.BaseLogFileName)!; string? baseDirectory = Path.GetDirectoryName(this.BaseLogFileName)!;
var baseFileName = Path.GetFileName(this.BaseLogFileName); string? baseFileName = Path.GetFileName(this.BaseLogFileName);
var logFile = this.BaseLogFileName + extension; string? logFile = this.BaseLogFileName + extension;
var writer = this.CreateWriter(new FileStream(logFile, FileMode.Append)); var writer = this.CreateWriter(new FileStream(logFile, FileMode.Append));
var fileLength = new FileInfo(logFile).Length; long fileLength = new FileInfo(logFile).Length;
// We auto roll at time is configured then we need to create a timer and wait until time is elasped and roll the file over // We auto roll at time is configured then we need to create a timer and wait until time is elasped and roll the file over
if (this.AutoRollAtTime is TimeSpan autoRollAtTime) if (this.AutoRollAtTime is TimeSpan autoRollAtTime)
{ {
// Run at start // Run at start
var tickTime = this.SetupRollTimer(autoRollAtTime); double tickTime = this.SetupRollTimer(autoRollAtTime);
var timer = new System.Timers.Timer(tickTime); var timer = new System.Timers.Timer(tickTime);
timer.Elapsed += (_, _) => timer.Elapsed += (_, _) =>
{ {
@ -451,8 +451,8 @@ namespace WinSW
writer.Dispose(); writer.Dispose();
var now = DateTime.Now.AddDays(-1); var now = DateTime.Now.AddDays(-1);
var nextFileNumber = this.GetNextFileNumber(extension, baseDirectory, baseFileName, now); int nextFileNumber = this.GetNextFileNumber(extension, baseDirectory, baseFileName, now);
var nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(this.FilePattern), nextFileNumber, extension)); string? nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(this.FilePattern), nextFileNumber, extension));
File.Move(logFile, nextFileName); File.Move(logFile, nextFileName);
writer = this.CreateWriter(new FileStream(logFile, FileMode.Create)); writer = this.CreateWriter(new FileStream(logFile, FileMode.Create));
@ -488,8 +488,8 @@ namespace WinSW
{ {
// roll file // roll file
var now = DateTime.Now; var now = DateTime.Now;
var nextFileNumber = this.GetNextFileNumber(extension, baseDirectory, baseFileName, now); int nextFileNumber = this.GetNextFileNumber(extension, baseDirectory, baseFileName, now);
var nextFileName = Path.Combine( string? nextFileName = Path.Combine(
baseDirectory, baseDirectory,
string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(this.FilePattern), nextFileNumber, extension)); string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(this.FilePattern), nextFileNumber, extension));
File.Move(logFile, nextFileName); File.Move(logFile, nextFileName);
@ -589,21 +589,21 @@ namespace WinSW
private int GetNextFileNumber(string ext, string baseDirectory, string baseFileName, DateTime now) private int GetNextFileNumber(string ext, string baseDirectory, string baseFileName, DateTime now)
{ {
var nextFileNumber = 0; int nextFileNumber = 0;
var files = Directory.GetFiles(baseDirectory, string.Format("{0}.{1}.#*{2}", baseFileName, now.ToString(this.FilePattern), ext)); string[]? files = Directory.GetFiles(baseDirectory, string.Format("{0}.{1}.#*{2}", baseFileName, now.ToString(this.FilePattern), ext));
if (files.Length == 0) if (files.Length == 0)
{ {
nextFileNumber = 1; nextFileNumber = 1;
} }
else else
{ {
foreach (var f in files) foreach (string? f in files)
{ {
try try
{ {
var filenameOnly = Path.GetFileNameWithoutExtension(f); string? filenameOnly = Path.GetFileNameWithoutExtension(f);
var hashIndex = filenameOnly.IndexOf('#'); int hashIndex = filenameOnly.IndexOf('#');
var lastNumberAsString = filenameOnly.Substring(hashIndex + 1, 4); string? lastNumberAsString = filenameOnly.Substring(hashIndex + 1, 4);
if (int.TryParse(lastNumberAsString, out int lastNumber)) if (int.TryParse(lastNumberAsString, out int lastNumber))
{ {
if (lastNumber > nextFileNumber) if (lastNumber > nextFileNumber)

View File

@ -20,7 +20,7 @@ namespace WinSW.Native
IntPtr.Zero, IntPtr.Zero,
ref inBufferSize); ref inBufferSize);
IntPtr inBuffer = Marshal.AllocCoTaskMem(inBufferSize); var inBuffer = Marshal.AllocCoTaskMem(inBufferSize);
try try
{ {
if (!CredPackAuthenticationBuffer( if (!CredPackAuthenticationBuffer(
@ -33,7 +33,7 @@ namespace WinSW.Native
Throw.Command.Win32Exception("Failed to pack auth buffer."); Throw.Command.Win32Exception("Failed to pack auth buffer.");
} }
CREDUI_INFO info = new CREDUI_INFO var info = new CREDUI_INFO
{ {
Size = Marshal.SizeOf(typeof(CREDUI_INFO)), Size = Marshal.SizeOf(typeof(CREDUI_INFO)),
CaptionText = caption, CaptionText = caption,
@ -47,7 +47,7 @@ namespace WinSW.Native
ref authPackage, ref authPackage,
inBuffer, inBuffer,
inBufferSize, inBufferSize,
out IntPtr outBuffer, out var outBuffer,
out uint outBufferSize, out uint outBufferSize,
ref save, ref save,
CREDUIWIN_GENERIC); CREDUIWIN_GENERIC);

View File

@ -11,24 +11,24 @@ namespace WinSW.Native
/// <exception cref="CommandException" /> /// <exception cref="CommandException" />
internal static unsafe bool UpdateCompanyName(string path, string outputPath, string companyName) internal static unsafe bool UpdateCompanyName(string path, string outputPath, string companyName)
{ {
IntPtr module = LoadLibraryW(path); var module = LoadLibraryW(path);
try try
{ {
IntPtr verInfo = FindResourceW(module, VS_VERSION_INFO, RT_VERSION); var verInfo = FindResourceW(module, VS_VERSION_INFO, RT_VERSION);
if (verInfo == IntPtr.Zero) if (verInfo == IntPtr.Zero)
{ {
Exit(); Exit();
} }
IntPtr resData = LoadResource(module, verInfo); var resData = LoadResource(module, verInfo);
if (resData == IntPtr.Zero) if (resData == IntPtr.Zero)
{ {
Exit(); Exit();
} }
IntPtr resAddr = LockResource(resData); var resAddr = LockResource(resData);
IntPtr address = resAddr; var address = resAddr;
int offset = 0; int offset = 0;
short length = ((short*)address)[0]; short length = ((short*)address)[0];
@ -81,7 +81,7 @@ namespace WinSW.Native
int newLength = companyName.Length + 1; int newLength = companyName.Length + 1;
Debug.Assert(newLength > 12 && newLength <= 16); Debug.Assert(newLength > 12 && newLength <= 16);
IntPtr newAddress = Marshal.AllocHGlobal(length); var newAddress = Marshal.AllocHGlobal(length);
try try
{ {
Buffer.MemoryCopy((void*)resAddr, (void*)newAddress, length, length); Buffer.MemoryCopy((void*)resAddr, (void*)newAddress, length, length);
@ -94,7 +94,7 @@ namespace WinSW.Native
File.Copy(path, outputPath, true); File.Copy(path, outputPath, true);
IntPtr update = BeginUpdateResourceW(outputPath, false); var update = BeginUpdateResourceW(outputPath, false);
if (update == IntPtr.Zero) if (update == IntPtr.Zero)
{ {
Exit(); Exit();

View File

@ -11,7 +11,7 @@ namespace WinSW.Native
/// <exception cref="Win32Exception" /> /// <exception cref="Win32Exception" />
internal static void AddServiceLogonRight(ref string userName) internal static void AddServiceLogonRight(ref string userName)
{ {
IntPtr sid = GetAccountSid(ref userName); var sid = GetAccountSid(ref userName);
try try
{ {
@ -36,7 +36,7 @@ namespace WinSW.Native
_ = LookupAccountName(null, accountName, IntPtr.Zero, ref sidSize, null, ref domainNameLength, out _); _ = LookupAccountName(null, accountName, IntPtr.Zero, ref sidSize, null, ref domainNameLength, out _);
IntPtr sid = Marshal.AllocHGlobal(sidSize); var sid = Marshal.AllocHGlobal(sidSize);
try try
{ {
string? domainName = domainNameLength == 0 ? null : new string('\0', domainNameLength - 1); string? domainName = domainNameLength == 0 ? null : new string('\0', domainNameLength - 1);
@ -64,7 +64,7 @@ namespace WinSW.Native
/// <exception cref="Win32Exception" /> /// <exception cref="Win32Exception" />
private static void AddAccountRight(IntPtr sid, string rightName) private static void AddAccountRight(IntPtr sid, string rightName)
{ {
uint status = LsaOpenPolicy(IntPtr.Zero, default, PolicyAccess.ALL_ACCESS, out IntPtr policyHandle); uint status = LsaOpenPolicy(IntPtr.Zero, default, PolicyAccess.ALL_ACCESS, out var policyHandle);
if (status != 0) if (status != 0)
{ {
throw new Win32Exception(LsaNtStatusToWinError(status)); throw new Win32Exception(LsaNtStatusToWinError(status));
@ -72,7 +72,7 @@ namespace WinSW.Native
try try
{ {
LSA_UNICODE_STRING userRight = new LSA_UNICODE_STRING var userRight = new LSA_UNICODE_STRING
{ {
Buffer = rightName, Buffer = rightName,
Length = (ushort)(rightName.Length * sizeof(char)), Length = (ushort)(rightName.Length * sizeof(char)),

View File

@ -58,7 +58,7 @@ namespace WinSW.Native
/// <exception cref="CommandException" /> /// <exception cref="CommandException" />
internal static ServiceManager Open(ServiceManagerAccess access = ServiceManagerAccess.All) internal static ServiceManager Open(ServiceManagerAccess access = ServiceManagerAccess.All)
{ {
IntPtr handle = OpenSCManager(null, null, access); var handle = OpenSCManager(null, null, access);
if (handle == IntPtr.Zero) if (handle == IntPtr.Zero)
{ {
Throw.Command.Win32Exception("Failed to open the service control manager database."); Throw.Command.Win32Exception("Failed to open the service control manager database.");
@ -77,7 +77,7 @@ namespace WinSW.Native
string? username, string? username,
string? password) string? password)
{ {
IntPtr handle = ServiceApis.CreateService( var handle = ServiceApis.CreateService(
this.handle, this.handle,
serviceName, serviceName,
displayName, displayName,
@ -113,7 +113,7 @@ namespace WinSW.Native
out _, out _,
ref resume); ref resume);
IntPtr services = Marshal.AllocHGlobal(bytesNeeded); var services = Marshal.AllocHGlobal(bytesNeeded);
try try
{ {
if (!EnumServicesStatus( if (!EnumServicesStatus(
@ -141,7 +141,7 @@ namespace WinSW.Native
/// <exception cref="CommandException" /> /// <exception cref="CommandException" />
internal unsafe Service OpenService(char* serviceName, ServiceAccess access = ServiceAccess.All) internal unsafe Service OpenService(char* serviceName, ServiceAccess access = ServiceAccess.All)
{ {
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, access); var serviceHandle = ServiceApis.OpenService(this.handle, serviceName, access);
if (serviceHandle == IntPtr.Zero) if (serviceHandle == IntPtr.Zero)
{ {
Throw.Command.Win32Exception("Failed to open the service."); Throw.Command.Win32Exception("Failed to open the service.");
@ -153,7 +153,7 @@ namespace WinSW.Native
/// <exception cref="CommandException" /> /// <exception cref="CommandException" />
internal Service OpenService(string serviceName, ServiceAccess access = ServiceAccess.All) internal Service OpenService(string serviceName, ServiceAccess access = ServiceAccess.All)
{ {
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, access); var serviceHandle = ServiceApis.OpenService(this.handle, serviceName, access);
if (serviceHandle == IntPtr.Zero) if (serviceHandle == IntPtr.Zero)
{ {
Throw.Command.Win32Exception("Failed to open the service."); Throw.Command.Win32Exception("Failed to open the service.");
@ -164,7 +164,7 @@ namespace WinSW.Native
internal bool ServiceExists(string serviceName) internal bool ServiceExists(string serviceName)
{ {
IntPtr serviceHandle = ServiceApis.OpenService(this.handle, serviceName, ServiceAccess.All); var serviceHandle = ServiceApis.OpenService(this.handle, serviceName, ServiceAccess.All);
if (serviceHandle == IntPtr.Zero) if (serviceHandle == IntPtr.Zero)
{ {
return false; return false;
@ -202,7 +202,7 @@ namespace WinSW.Native
0, 0,
out int bytesNeeded); out int bytesNeeded);
IntPtr config = Marshal.AllocHGlobal(bytesNeeded); var config = Marshal.AllocHGlobal(bytesNeeded);
try try
{ {
if (!QueryServiceConfig( if (!QueryServiceConfig(
@ -231,7 +231,7 @@ namespace WinSW.Native
if (!QueryServiceStatusEx( if (!QueryServiceStatusEx(
this.handle, this.handle,
ServiceStatusType.ProcessInfo, ServiceStatusType.ProcessInfo,
out SERVICE_STATUS_PROCESS status, out var status,
sizeof(SERVICE_STATUS_PROCESS), sizeof(SERVICE_STATUS_PROCESS),
out _)) out _))
{ {
@ -247,7 +247,7 @@ namespace WinSW.Native
{ {
get get
{ {
if (!QueryServiceStatus(this.handle, out SERVICE_STATUS status)) if (!QueryServiceStatus(this.handle, out var status))
{ {
Throw.Command.Win32Exception("Failed to query service status."); Throw.Command.Win32Exception("Failed to query service status.");
} }
@ -282,7 +282,7 @@ namespace WinSW.Native
/// <exception cref="CommandException" /> /// <exception cref="CommandException" />
internal void SetStatus(IntPtr statusHandle, ServiceControllerStatus state) internal void SetStatus(IntPtr statusHandle, ServiceControllerStatus state)
{ {
if (!QueryServiceStatus(this.handle, out SERVICE_STATUS status)) if (!QueryServiceStatus(this.handle, out var status))
{ {
Throw.Command.Win32Exception("Failed to query service status."); Throw.Command.Win32Exception("Failed to query service status.");
} }

View File

@ -199,7 +199,7 @@ namespace WinSW.Native
var serviceName = new ReadOnlySpan<char>(this.ServiceName, new ReadOnlySpan<char>(this.ServiceName, 256).IndexOf('\0')); var serviceName = new ReadOnlySpan<char>(this.ServiceName, new ReadOnlySpan<char>(this.ServiceName, 256).IndexOf('\0'));
var displayName = new ReadOnlySpan<char>(this.DisplayName, new ReadOnlySpan<char>(this.DisplayName, 256).IndexOf('\0')); var displayName = new ReadOnlySpan<char>(this.DisplayName, new ReadOnlySpan<char>(this.DisplayName, 256).IndexOf('\0'));
#if NETCOREAPP #if NET
return string.Concat(displayName, " (", serviceName, ")"); return string.Concat(displayName, " (", serviceName, ")");
#else #else
return string.Concat(displayName.ToString(), " (", serviceName.ToString(), ")"); return string.Concat(displayName.ToString(), " (", serviceName.ToString(), ")");

View File

@ -51,7 +51,7 @@ namespace WinSW.Native
internal static void Win32Exception(int error, string message) internal static void Win32Exception(int error, string message)
{ {
Debug.Assert(error != 0); Debug.Assert(error != 0);
Win32Exception inner = new Win32Exception(error); var inner = new Win32Exception(error);
Debug.Assert(message.EndsWith(".")); Debug.Assert(message.EndsWith("."));
throw new CommandException(message + ' ' + inner.Message, inner); throw new CommandException(message + ' ' + inner.Message, inner);
} }
@ -61,7 +61,7 @@ namespace WinSW.Native
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Win32Exception() internal static void Win32Exception()
{ {
Win32Exception inner = new Win32Exception(); var inner = new Win32Exception();
Debug.Assert(inner.NativeErrorCode != 0); Debug.Assert(inner.NativeErrorCode != 0);
throw new CommandException(inner); throw new CommandException(inner);
} }
@ -70,7 +70,7 @@ namespace WinSW.Native
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Win32Exception(string message) internal static void Win32Exception(string message)
{ {
Win32Exception inner = new Win32Exception(); var inner = new Win32Exception();
Debug.Assert(inner.NativeErrorCode != 0); Debug.Assert(inner.NativeErrorCode != 0);
Debug.Assert(message.EndsWith(".")); Debug.Assert(message.EndsWith("."));
throw new CommandException(message + ' ' + inner.Message, inner); throw new CommandException(message + ' ' + inner.Message, inner);

View File

@ -1,7 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
#if !NETCOREAPP #if !NET
namespace System.Diagnostics.CodeAnalysis namespace System.Diagnostics.CodeAnalysis
{ {
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary> /// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>

View File

@ -40,15 +40,15 @@ namespace WinSW
private PeriodicityType DeterminePeriodicityType() private PeriodicityType DeterminePeriodicityType()
{ {
PeriodicRollingCalendar periodicRollingCalendar = new PeriodicRollingCalendar(this.format, this.period); var periodicRollingCalendar = new PeriodicRollingCalendar(this.format, this.period);
DateTime epoch = new DateTime(1970, 1, 1); var epoch = new DateTime(1970, 1, 1);
foreach (PeriodicityType i in ValidOrderedList) foreach (var i in ValidOrderedList)
{ {
string r0 = epoch.ToString(this.format); string r0 = epoch.ToString(this.format);
periodicRollingCalendar.Periodicity = i; periodicRollingCalendar.Periodicity = i;
DateTime next = periodicRollingCalendar.NextTriggeringTime(epoch, 1); var next = periodicRollingCalendar.NextTriggeringTime(epoch, 1);
string r1 = next.ToString(this.format); string r1 = next.ToString(this.format);
if (r0 != r1) if (r0 != r1)
@ -91,7 +91,7 @@ namespace WinSW
{ {
get get
{ {
DateTime now = DateTime.Now; var now = DateTime.Now;
if (now > this.nextRoll) if (now > this.nextRoll)
{ {
this.currentRoll = now; this.currentRoll = now;

View File

@ -1,8 +1,8 @@
#if !NETCOREAPP #if !NET
using System; using System;
#endif #endif
using System.IO; using System.IO;
#if !NETCOREAPP #if !NET
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#endif #endif
@ -12,7 +12,7 @@ namespace WinSW.Util
{ {
public static void MoveOrReplaceFile(string sourceFileName, string destFileName) public static void MoveOrReplaceFile(string sourceFileName, string destFileName)
{ {
#if NETCOREAPP #if NET
File.Move(sourceFileName, destFileName, true); File.Move(sourceFileName, destFileName, true);
#else #else
string sourceFilePath = Path.GetFullPath(sourceFileName); string sourceFilePath = Path.GetFullPath(sourceFileName);
@ -24,7 +24,7 @@ namespace WinSW.Util
} }
#endif #endif
} }
#if !NETCOREAPP #if !NET
private static Exception GetExceptionForLastWin32Error(string path) => Marshal.GetLastWin32Error() switch private static Exception GetExceptionForLastWin32Error(string path) => Marshal.GetLastWin32Error() switch
{ {

View File

@ -18,7 +18,7 @@ namespace WinSW.Util
{ {
StopPrivate(process, millisecondsTimeout); StopPrivate(process, millisecondsTimeout);
foreach (Process child in GetChildren(process)) foreach (var child in GetChildren(process))
{ {
using (child) using (child)
{ {
@ -29,7 +29,7 @@ namespace WinSW.Util
internal static void StopDescendants(this Process process, int millisecondsTimeout) internal static void StopDescendants(this Process process, int millisecondsTimeout)
{ {
foreach (Process child in GetChildren(process)) foreach (var child in GetChildren(process))
{ {
using (child) using (child)
{ {
@ -40,12 +40,12 @@ namespace WinSW.Util
internal static unsafe List<Process> GetChildren(this Process process) internal static unsafe List<Process> GetChildren(this Process process)
{ {
DateTime startTime = process.StartTime; var startTime = process.StartTime;
int processId = process.Id; int processId = process.Id;
var children = new List<Process>(); var children = new List<Process>();
foreach (Process other in Process.GetProcesses()) foreach (var other in Process.GetProcesses())
{ {
try try
{ {
@ -54,12 +54,12 @@ namespace WinSW.Util
goto Next; goto Next;
} }
IntPtr handle = other.Handle; var handle = other.Handle;
if (NtQueryInformationProcess( if (NtQueryInformationProcess(
handle, handle,
PROCESSINFOCLASS.ProcessBasicInformation, PROCESSINFOCLASS.ProcessBasicInformation,
out PROCESS_BASIC_INFORMATION information, out var information,
sizeof(PROCESS_BASIC_INFORMATION)) != 0) sizeof(PROCESS_BASIC_INFORMATION)) != 0)
{ {
goto Next; goto Next;
@ -119,7 +119,7 @@ namespace WinSW.Util
} }
} }
#if NETCOREAPP #if NET
process.Kill(); process.Kill();
#else #else
try try
@ -169,7 +169,7 @@ namespace WinSW.Util
} }
} }
#if NETCOREAPP #if NET
process.Kill(); process.Kill();
#else #else
try try

View File

@ -10,7 +10,7 @@ namespace WinSW.Util
/// <exception cref="CommandException" /> /// <exception cref="CommandException" />
internal static unsafe DateTime GetLastWriteTime(this RegistryKey registryKey) internal static unsafe DateTime GetLastWriteTime(this RegistryKey registryKey)
{ {
int error = RegQueryInfoKeyW(registryKey.Handle, null, null, null, null, null, null, null, null, null, null, out FILETIME lastWriteTime); int error = RegQueryInfoKeyW(registryKey.Handle, null, null, null, null, null, null, null, null, null, null, out var lastWriteTime);
if (error != Errors.ERROR_SUCCESS) if (error != Errors.ERROR_SUCCESS)
{ {
Throw.Command.Win32Exception(error, "Failed to query registry key."); Throw.Command.Win32Exception(error, "Failed to query registry key.");

View File

@ -17,7 +17,7 @@ namespace WinSW.Util
/// <exception cref="InvalidDataException">The required element is missing</exception> /// <exception cref="InvalidDataException">The required element is missing</exception>
public static string? SingleElement(XmlNode node, string tagName, bool optional) public static string? SingleElement(XmlNode node, string tagName, bool optional)
{ {
XmlNode? n = node.SelectSingleNode(tagName); var n = node.SelectSingleNode(tagName);
if (n is null && !optional) if (n is null && !optional)
{ {
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
@ -36,7 +36,7 @@ namespace WinSW.Util
/// <exception cref="InvalidDataException">The required element is missing</exception> /// <exception cref="InvalidDataException">The required element is missing</exception>
public static XmlNode? SingleNode(XmlNode node, string tagName, bool optional) public static XmlNode? SingleNode(XmlNode node, string tagName, bool optional)
{ {
XmlNode? n = node.SelectSingleNode(tagName); var n = node.SelectSingleNode(tagName);
if (n is null && !optional) if (n is null && !optional)
{ {
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");

View File

@ -23,13 +23,13 @@ namespace WinSW.Plugins.SharedDirectoryMapper
public SharedDirectoryMapper(bool enableMapping, string directoryUNC, string driveLabel) public SharedDirectoryMapper(bool enableMapping, string directoryUNC, string driveLabel)
{ {
SharedDirectoryMapperConfig config = new SharedDirectoryMapperConfig(enableMapping, driveLabel, directoryUNC); var config = new SharedDirectoryMapperConfig(enableMapping, driveLabel, directoryUNC);
this.entries.Add(config); this.entries.Add(config);
} }
public override void Configure(XmlServiceConfig config, XmlNode node) public override void Configure(XmlServiceConfig config, XmlNode node)
{ {
XmlNodeList? mapNodes = XmlHelper.SingleNode(node, "mapping", false)!.SelectNodes("map"); var mapNodes = XmlHelper.SingleNode(node, "mapping", false)!.SelectNodes("map");
if (mapNodes != null) if (mapNodes != null)
{ {
for (int i = 0; i < mapNodes.Count; i++) for (int i = 0; i < mapNodes.Count; i++)
@ -44,7 +44,7 @@ namespace WinSW.Plugins.SharedDirectoryMapper
public override void OnWrapperStarted() public override void OnWrapperStarted()
{ {
foreach (SharedDirectoryMapperConfig config in this.entries) foreach (var config in this.entries)
{ {
string label = config.Label; string label = config.Label;
string uncPath = config.UNCPath; string uncPath = config.UNCPath;
@ -72,7 +72,7 @@ namespace WinSW.Plugins.SharedDirectoryMapper
public override void BeforeWrapperStopped() public override void BeforeWrapperStopped()
{ {
foreach (SharedDirectoryMapperConfig config in this.entries) foreach (var config in this.entries)
{ {
string label = config.Label; string label = config.Label;
if (config.EnableMapping) if (config.EnableMapping)
@ -88,7 +88,7 @@ namespace WinSW.Plugins.SharedDirectoryMapper
private void ThrowExtensionException(int error, string message) private void ThrowExtensionException(int error, string message)
{ {
Win32Exception inner = new Win32Exception(error); var inner = new Win32Exception(error);
throw new ExtensionException(this.Descriptor.Id, $"{this.DisplayName}: {message} {inner.Message}", inner); throw new ExtensionException(this.Descriptor.Id, $"{this.DisplayName}: {message} {inner.Message}", inner);
} }

View File

@ -75,7 +75,7 @@ namespace WinSW.Tests
{ {
const string commandName = "unknown"; const string commandName = "unknown";
CommandLineTestResult result = Helper.ErrorTest(new[] { commandName }); var result = Helper.ErrorTest(new[] { commandName });
Assert.Equal($"Unrecognized command or argument '{commandName}'\r\n\r\n", result.Error); Assert.Equal($"Unrecognized command or argument '{commandName}'\r\n\r\n", result.Error);
} }
@ -101,7 +101,7 @@ namespace WinSW.Tests
Assert.Equal(OldCompanyName, FileVersionInfo.GetVersionInfo(inputPath).CompanyName); Assert.Equal(OldCompanyName, FileVersionInfo.GetVersionInfo(inputPath).CompanyName);
// deny write access // deny write access
using FileStream file = File.OpenRead(inputPath); using var file = File.OpenRead(inputPath);
string outputPath = Path.GetTempFileName(); string outputPath = Path.GetTempFileName();
Program.TestExecutablePath = inputPath; Program.TestExecutablePath = inputPath;

View File

@ -1,5 +1,4 @@
using System; using System.IO;
using System.IO;
using System.Xml; using System.Xml;
using WinSW.Tests.Util; using WinSW.Tests.Util;
using Xunit; using Xunit;
@ -15,7 +14,7 @@ namespace WinSW.Tests.Configuration
[Fact] [Fact]
public void AllOptionsConfigShouldDeclareDefaults() public void AllOptionsConfigShouldDeclareDefaults()
{ {
XmlServiceConfig config = Load("complete"); var config = Load("complete");
Assert.Equal("myapp", config.Name); Assert.Equal("myapp", config.Name);
Assert.Equal("%BASE%\\myExecutable.exe", config.Executable); Assert.Equal("%BASE%\\myExecutable.exe", config.Executable);
@ -26,7 +25,7 @@ namespace WinSW.Tests.Configuration
[Fact] [Fact]
public void MinimalConfigShouldDeclareDefaults() public void MinimalConfigShouldDeclareDefaults()
{ {
XmlServiceConfig config = Load("minimal"); var config = Load("minimal");
Assert.Equal("myapp", config.Name); Assert.Equal("myapp", config.Name);
Assert.Equal("%BASE%\\myExecutable.exe", config.Executable); Assert.Equal("%BASE%\\myExecutable.exe", config.Executable);
@ -41,7 +40,7 @@ namespace WinSW.Tests.Configuration
string path = Path.Combine(directory, $@"samples\sample-{exampleName}.xml"); string path = Path.Combine(directory, $@"samples\sample-{exampleName}.xml");
Assert.True(File.Exists(path)); Assert.True(File.Exists(path));
XmlDocument dom = new XmlDocument(); var dom = new XmlDocument();
dom.Load(path); dom.Load(path);
return new XmlServiceConfig(dom); return new XmlServiceConfig(dom);
} }

View File

@ -21,7 +21,7 @@ namespace WinSW.Tests
public void Roundtrip_Defaults() public void Roundtrip_Defaults()
{ {
// Roundtrip data // Roundtrip data
Download d = new Download(From, To); var d = new Download(From, To);
var config = ConfigXmlBuilder.Create(this.output) var config = ConfigXmlBuilder.Create(this.output)
.WithDownload(d) .WithDownload(d)
.ToServiceConfig(true); .ToServiceConfig(true);
@ -39,7 +39,7 @@ namespace WinSW.Tests
public void Roundtrip_BasicAuth() public void Roundtrip_BasicAuth()
{ {
// Roundtrip data // Roundtrip data
Download d = new Download(From, To, true, Download.AuthType.Basic, "aUser", "aPassword", true); var d = new Download(From, To, true, Download.AuthType.Basic, "aUser", "aPassword", true);
var config = ConfigXmlBuilder.Create(this.output) var config = ConfigXmlBuilder.Create(this.output)
.WithDownload(d) .WithDownload(d)
.ToServiceConfig(true); .ToServiceConfig(true);
@ -57,7 +57,7 @@ namespace WinSW.Tests
public void Roundtrip_SSPI() public void Roundtrip_SSPI()
{ {
// Roundtrip data // Roundtrip data
Download d = new Download(From, To, false, Download.AuthType.Sspi); var d = new Download(From, To, false, Download.AuthType.Sspi);
var config = ConfigXmlBuilder.Create(this.output) var config = ConfigXmlBuilder.Create(this.output)
.WithDownload(d) .WithDownload(d)
.ToServiceConfig(true); .ToServiceConfig(true);
@ -105,7 +105,7 @@ namespace WinSW.Tests
[InlineData(false)] [InlineData(false)]
public void Download_FailOnError(bool failOnError) public void Download_FailOnError(bool failOnError)
{ {
Download d = new Download(From, To, failOnError); var d = new Download(From, To, failOnError);
var config = ConfigXmlBuilder.Create(this.output) var config = ConfigXmlBuilder.Create(this.output)
.WithDownload(d) .WithDownload(d)

View File

@ -19,7 +19,7 @@ namespace WinSW.Tests
public DownloadTests() public DownloadTests()
{ {
TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 0); var tcpListener = new TcpListener(IPAddress.Loopback, 0);
tcpListener.Start(); tcpListener.Start();
int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port; int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
string prefix = $"http://localhost:{port}/"; string prefix = $"http://localhost:{port}/";
@ -39,7 +39,7 @@ namespace WinSW.Tests
private async Task TestClientServerAsync(Func<string, string, Task> client, Action<HttpListenerContext> server, AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous, [CallerMemberName] string path = null) private async Task TestClientServerAsync(Func<string, string, Task> client, Action<HttpListenerContext> server, AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous, [CallerMemberName] string path = null)
{ {
HttpListener listener = new HttpListener(); var listener = new HttpListener();
string prefix = $"{this.globalPrefix}{path}/"; string prefix = $"{this.globalPrefix}{path}/";
listener.Prefixes.Add(prefix); listener.Prefixes.Add(prefix);
listener.AuthenticationSchemes = authenticationSchemes; listener.AuthenticationSchemes = authenticationSchemes;
@ -72,7 +72,7 @@ namespace WinSW.Tests
async Task ListenAsync() async Task ListenAsync()
{ {
HttpListenerContext context = await listener.GetContextAsync(); var context = await listener.GetContextAsync();
try try
{ {
server(context); server(context);
@ -136,7 +136,7 @@ namespace WinSW.Tests
}, },
context => context =>
{ {
HttpListenerBasicIdentity identity = (HttpListenerBasicIdentity)context.User.Identity; var identity = (HttpListenerBasicIdentity)context.User.Identity;
if (identity.Name != username || identity.Password != password) if (identity.Name != username || identity.Password != password)
{ {
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
@ -152,8 +152,8 @@ namespace WinSW.Tests
[Fact] [Fact]
public async Task TestHttp_IfModifiedSince_ModifiedAsync() public async Task TestHttp_IfModifiedSince_ModifiedAsync()
{ {
DateTime lastModified = DateTime.Now.TrimToSeconds(); var lastModified = DateTime.Now.TrimToSeconds();
DateTime prevModified = lastModified.AddDays(-1); var prevModified = lastModified.AddDays(-1);
await this.TestClientServerAsync( await this.TestClientServerAsync(
async (source, dest) => async (source, dest) =>
@ -180,7 +180,7 @@ namespace WinSW.Tests
[Fact] [Fact]
public async Task TestHttp_IfModifiedSince_NotModifiedAsync() public async Task TestHttp_IfModifiedSince_NotModifiedAsync()
{ {
DateTime lastModified = DateTime.Now.TrimToSeconds(); var lastModified = DateTime.Now.TrimToSeconds();
await this.TestClientServerAsync( await this.TestClientServerAsync(
async (source, dest) => async (source, dest) =>
@ -210,7 +210,7 @@ namespace WinSW.Tests
await this.TestClientServerAsync( await this.TestClientServerAsync(
async (source, dest) => async (source, dest) =>
{ {
WebException exception = await Assert.ThrowsAsync<WebException>( var exception = await Assert.ThrowsAsync<WebException>(
async () => await new Download(source, dest).PerformAsync()); async () => await new Download(source, dest).PerformAsync());
Assert.Equal(WebExceptionStatus.ProtocolError, exception.Status); Assert.Equal(WebExceptionStatus.ProtocolError, exception.Status);

View File

@ -41,7 +41,7 @@ $@"<service>
[Fact] [Fact]
public void LoadExtensions() public void LoadExtensions()
{ {
WinSWExtensionManager manager = new WinSWExtensionManager(this.serviceConfig); var manager = new WinSWExtensionManager(this.serviceConfig);
manager.LoadExtensions(); manager.LoadExtensions();
Assert.Equal(2, manager.Extensions.Count); Assert.Equal(2, manager.Extensions.Count);
} }
@ -49,7 +49,7 @@ $@"<service>
[Fact] [Fact]
public void StartStopExtension() public void StartStopExtension()
{ {
WinSWExtensionManager manager = new WinSWExtensionManager(this.serviceConfig); var manager = new WinSWExtensionManager(this.serviceConfig);
manager.LoadExtensions(); manager.LoadExtensions();
manager.FireOnWrapperStarted(); manager.FireOnWrapperStarted();
manager.FireBeforeWrapperStopped(); manager.FireBeforeWrapperStopped();

View File

@ -1,4 +1,4 @@
#if NETCOREAPP #if NET
using System; using System;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -14,10 +14,10 @@ namespace WinSW.Tests.Extensions
[ElevatedFact] [ElevatedFact]
public void TestMap() public void TestMap()
{ {
using TestData data = TestData.Create(); using var data = TestData.Create();
const string label = "W:"; const string label = "W:";
SharedDirectoryMapper mapper = new SharedDirectoryMapper(true, $@"\\{Environment.MachineName}\{data.name}", label); var mapper = new SharedDirectoryMapper(true, $@"\\{Environment.MachineName}\{data.name}", label);
mapper.OnWrapperStarted(); mapper.OnWrapperStarted();
Assert.True(Directory.Exists($@"{label}\")); Assert.True(Directory.Exists($@"{label}\"));
@ -28,10 +28,10 @@ namespace WinSW.Tests.Extensions
[ElevatedFact] [ElevatedFact]
public void TestDisableMapping() public void TestDisableMapping()
{ {
using TestData data = TestData.Create(); using var data = TestData.Create();
const string label = "W:"; const string label = "W:";
SharedDirectoryMapper mapper = new SharedDirectoryMapper(enableMapping: false, $@"\\{Environment.MachineName}\{data.name}", label); var mapper = new SharedDirectoryMapper(enableMapping: false, $@"\\{Environment.MachineName}\{data.name}", label);
mapper.OnWrapperStarted(); mapper.OnWrapperStarted();
Assert.False(Directory.Exists($@"{label}\")); Assert.False(Directory.Exists($@"{label}\"));
@ -41,10 +41,10 @@ namespace WinSW.Tests.Extensions
[ElevatedFact] [ElevatedFact]
public void TestMap_PathEndsWithSlash_Throws() public void TestMap_PathEndsWithSlash_Throws()
{ {
using TestData data = TestData.Create(); using var data = TestData.Create();
const string label = "W:"; const string label = "W:";
SharedDirectoryMapper mapper = new SharedDirectoryMapper(true, $@"\\{Environment.MachineName}\{data.name}\", label); var mapper = new SharedDirectoryMapper(true, $@"\\{Environment.MachineName}\{data.name}\", label);
_ = Assert.ThrowsAny<Exception>(() => mapper.OnWrapperStarted()); _ = Assert.ThrowsAny<Exception>(() => mapper.OnWrapperStarted());
Assert.False(Directory.Exists($@"{label}\")); Assert.False(Directory.Exists($@"{label}\"));
@ -54,10 +54,10 @@ namespace WinSW.Tests.Extensions
[ElevatedFact] [ElevatedFact]
public void TestMap_LabelDoesNotEndWithColon_Throws() public void TestMap_LabelDoesNotEndWithColon_Throws()
{ {
using TestData data = TestData.Create(); using var data = TestData.Create();
const string label = "W"; const string label = "W";
SharedDirectoryMapper mapper = new SharedDirectoryMapper(true, $@"\\{Environment.MachineName}\{data.name}", label); var mapper = new SharedDirectoryMapper(true, $@"\\{Environment.MachineName}\{data.name}", label);
_ = Assert.ThrowsAny<Exception>(() => mapper.OnWrapperStarted()); _ = Assert.ThrowsAny<Exception>(() => mapper.OnWrapperStarted());
Assert.False(Directory.Exists($@"{label}\")); Assert.False(Directory.Exists($@"{label}\"));
@ -82,7 +82,7 @@ namespace WinSW.Tests.Extensions
try try
{ {
NativeMethods.SHARE_INFO_2 shareInfo = new NativeMethods.SHARE_INFO_2 var shareInfo = new NativeMethods.SHARE_INFO_2
{ {
netname = name, netname = name,
type = NativeMethods.STYPE_DISKTREE | NativeMethods.STYPE_TEMPORARY, type = NativeMethods.STYPE_DISKTREE | NativeMethods.STYPE_TEMPORARY,

View File

@ -405,7 +405,7 @@ $@"<service>
<arguments>arguments</arguments> <arguments>arguments</arguments>
</service>"; </service>";
XmlServiceConfig config = XmlServiceConfig.FromXml(seedXml); var config = XmlServiceConfig.FromXml(seedXml);
VerifyEqual(prestart, config.Prestart); VerifyEqual(prestart, config.Prestart);
VerifyEqual(poststart, config.Poststart); VerifyEqual(poststart, config.Poststart);

View File

@ -33,11 +33,11 @@ $@"<service>
/// <exception cref="Exception">Command failure</exception> /// <exception cref="Exception">Command failure</exception>
public static string Test(string[] arguments, XmlServiceConfig config = null) public static string Test(string[] arguments, XmlServiceConfig config = null)
{ {
TextWriter tmpOut = Console.Out; var tmpOut = Console.Out;
TextWriter tmpError = Console.Error; var tmpError = Console.Error;
using StringWriter swOut = new StringWriter(); using var swOut = new StringWriter();
using StringWriter swError = new StringWriter(); using var swError = new StringWriter();
Console.SetOut(swOut); Console.SetOut(swOut);
Console.SetError(swError); Console.SetError(swError);
@ -67,11 +67,11 @@ $@"<service>
{ {
Exception exception = null; Exception exception = null;
TextWriter tmpOut = Console.Out; var tmpOut = Console.Out;
TextWriter tmpError = Console.Error; var tmpError = Console.Error;
using StringWriter swOut = new StringWriter(); using var swOut = new StringWriter();
using StringWriter swError = new StringWriter(); using var swError = new StringWriter();
Console.SetOut(swOut); Console.SetOut(swOut);
Console.SetError(swError); Console.SetError(swError);

View File

@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using WinSW.Tests.Extensions;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace WinSW.Tests.Util namespace WinSW.Tests.Util
@ -57,7 +56,7 @@ namespace WinSW.Tests.Util
public string ToXmlString(bool dumpConfig = false) public string ToXmlString(bool dumpConfig = false)
{ {
StringBuilder str = new StringBuilder(); var str = new StringBuilder();
if (this.PrintXmlVersion) if (this.PrintXmlVersion)
{ {
// TODO: The encoding is generally wrong // TODO: The encoding is generally wrong
@ -121,7 +120,7 @@ namespace WinSW.Tests.Util
public ConfigXmlBuilder WithDownload(Download download) public ConfigXmlBuilder WithDownload(Download download)
{ {
StringBuilder xml = new StringBuilder(); var xml = new StringBuilder();
xml.Append($"<download from=\"{download.From}\" to=\"{download.To}\" failOnError=\"{download.FailOnError}\""); xml.Append($"<download from=\"{download.From}\" to=\"{download.To}\" failOnError=\"{download.FailOnError}\"");
// Authentication // Authentication

View File

@ -48,7 +48,7 @@ namespace WinSW.Tests.Util
hr = client.SetEventCallbacks(this); hr = client.SetEventCallbacks(this);
AssertEx.Succeeded(hr); AssertEx.Succeeded(hr);
IntPtr pointer = Marshal.GetIUnknownForObject(client); var pointer = Marshal.GetIUnknownForObject(client);
Assert.Equal(1, Marshal.Release(pointer)); Assert.Equal(1, Marshal.Release(pointer));
target = DataTarget.CreateFromDbgEng(pointer); target = DataTarget.CreateFromDbgEng(pointer);
@ -125,7 +125,7 @@ namespace WinSW.Tests.Util
{ {
using var runtime = this.target.ClrVersions.Single().CreateRuntime(); using var runtime = this.target.ClrVersions.Single().CreateRuntime();
var module = runtime.EnumerateModules().First(module => module.Name == typeof(Program).Assembly.Location); ClrModule module = runtime.EnumerateModules().First(module => module.Name == typeof(Program).Assembly.Location);
var type = module.GetTypeByName(this.trackerType.FullName); var type = module.GetTypeByName(this.trackerType.FullName);
var field = type.GetStaticFieldByName(this.hitsField.Name); var field = type.GetStaticFieldByName(this.hitsField.Name);

View File

@ -39,7 +39,7 @@ namespace WinSW.Tests.Util
internal static string NET461Exe => Path.Combine(ArtifactsDirectory, "publish", "WinSW.NET461.exe"); internal static string NET461Exe => Path.Combine(ArtifactsDirectory, "publish", "WinSW.NET461.exe");
internal static string WinSWExe => internal static string WinSWExe =>
#if NETCOREAPP #if NET
Path.ChangeExtension(typeof(Program).Assembly.Location, ".exe"); Path.ChangeExtension(typeof(Program).Assembly.Location, ".exe");
#else #else
typeof(Program).Assembly.Location; typeof(Program).Assembly.Location;

View File

@ -1,5 +1,4 @@
using System.Reflection; using WinSW.Configuration;
using WinSW.Configuration;
using Xunit; using Xunit;
namespace WinSW.Tests.Util namespace WinSW.Tests.Util

View File

@ -19,7 +19,7 @@ namespace WinSW.Logging
protected override void Append(LoggingEvent loggingEvent) protected override void Append(LoggingEvent loggingEvent)
{ {
IServiceEventLog? eventLog = this.provider.Locate(); var eventLog = this.provider.Locate();
// We write the event iff the provider is ready // We write the event iff the provider is ready
eventLog?.WriteEntry(loggingEvent.RenderedMessage, ToEventLogEntryType(loggingEvent.Level)); eventLog?.WriteEntry(loggingEvent.RenderedMessage, ToEventLogEntryType(loggingEvent.Level));

View File

@ -10,7 +10,7 @@ namespace WinSW.Logging
{ {
Console.ResetColor(); Console.ResetColor();
Level level = loggingEvent.Level; var level = loggingEvent.Level;
Console.ForegroundColor = Console.ForegroundColor =
level >= Level.Error ? ConsoleColor.Red : level >= Level.Error ? ConsoleColor.Red :
level >= Level.Warn ? ConsoleColor.Yellow : level >= Level.Warn ? ConsoleColor.Yellow :

View File

@ -51,7 +51,7 @@ namespace WinSW
return TestExecutablePath; return TestExecutablePath;
} }
using Process current = Process.GetCurrentProcess(); using var current = Process.GetCurrentProcess();
return current.MainModule!.FileName!; return current.MainModule!.FileName!;
} }
} }
@ -90,7 +90,7 @@ namespace WinSW
Console.SetError(new StreamWriter(stderr) { AutoFlush = true }); Console.SetError(new StreamWriter(stderr) { AutoFlush = true });
} }
#if NETCOREAPP #if NET
args = args[4..]; args = args[4..];
#else #else
string[] oldArgs = args; string[] oldArgs = args;
@ -116,15 +116,13 @@ namespace WinSW
XmlServiceConfig config = null!; XmlServiceConfig config = null!;
try try
{ {
config = LoadConfig(pathToConfig); config = LoadConfigAndInitLoggers(pathToConfig, false);
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
Throw.Command.Exception("The specified command or file was not found."); Throw.Command.Exception("The specified command or file was not found.");
} }
InitLoggers(config, enableConsoleLogging: false);
Log.Debug("Starting WinSW in service mode."); Log.Debug("Starting WinSW in service mode.");
AutoRefresh(config); AutoRefresh(config);
@ -141,9 +139,9 @@ namespace WinSW
}), }),
}; };
using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) using (var identity = WindowsIdentity.GetCurrent())
{ {
WindowsPrincipal principal = new WindowsPrincipal(identity); var principal = new WindowsPrincipal(identity);
if (principal.IsInRole(new SecurityIdentifier(WellKnownSidType.ServiceSid, null)) || if (principal.IsInRole(new SecurityIdentifier(WellKnownSidType.ServiceSid, null)) ||
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null)) || principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null)) ||
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null)) || principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null)) ||
@ -420,8 +418,7 @@ namespace WinSW
void Install(string? pathToConfig, bool noElevate, string? username, string? password) void Install(string? pathToConfig, bool noElevate, string? username, string? password)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -431,7 +428,7 @@ namespace WinSW
Log.Info($"Installing service '{config.Format()}'..."); Log.Info($"Installing service '{config.Format()}'...");
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.CreateService); using var scm = ServiceManager.Open(ServiceManagerAccess.CreateService);
if (scm.ServiceExists(config.Name)) if (scm.ServiceExists(config.Name))
{ {
@ -468,7 +465,7 @@ namespace WinSW
Security.AddServiceLogonRight(ref username); Security.AddServiceLogonRight(ref username);
} }
using Service sc = scm.CreateService( using var sc = scm.CreateService(
config.Name, config.Name,
config.DisplayName, config.DisplayName,
config.StartMode, config.StartMode,
@ -483,7 +480,7 @@ namespace WinSW
sc.SetDescription(description); sc.SetDescription(description);
} }
SC_ACTION[] actions = config.FailureActions; var actions = config.FailureActions;
if (actions.Length > 0) if (actions.Length > 0)
{ {
sc.SetFailureActions(config.ResetFailureAfter, actions); sc.SetFailureActions(config.ResetFailureAfter, actions);
@ -545,8 +542,7 @@ namespace WinSW
void Uninstall(string? pathToConfig, bool noElevate) void Uninstall(string? pathToConfig, bool noElevate)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -556,10 +552,10 @@ namespace WinSW
Log.Info($"Uninstalling service '{config.Format()}'..."); Log.Info($"Uninstalling service '{config.Format()}'...");
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect); using var scm = ServiceManager.Open(ServiceManagerAccess.Connect);
try try
{ {
using Service sc = scm.OpenService(config.Name); using var sc = scm.OpenService(config.Name);
if (sc.Status != ServiceControllerStatus.Stopped) if (sc.Status != ServiceControllerStatus.Stopped)
{ {
@ -595,8 +591,7 @@ namespace WinSW
void Start(string? pathToConfig, bool noElevate, bool noWait, CancellationToken ct) void Start(string? pathToConfig, bool noElevate, bool noWait, CancellationToken ct)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -641,8 +636,7 @@ namespace WinSW
void Stop(string? pathToConfig, bool noElevate, bool noWait, bool force, CancellationToken ct) void Stop(string? pathToConfig, bool noElevate, bool noWait, bool force, CancellationToken ct)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -695,8 +689,7 @@ namespace WinSW
void Restart(string? pathToConfig, bool noElevate, bool force, CancellationToken ct) void Restart(string? pathToConfig, bool noElevate, bool force, CancellationToken ct)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -758,7 +751,7 @@ namespace WinSW
if (startedDependentServices != null) if (startedDependentServices != null)
{ {
foreach (ServiceController service in startedDependentServices) foreach (var service in startedDependentServices)
{ {
if (service.Status == ServiceControllerStatus.Stopped) if (service.Status == ServiceControllerStatus.Stopped)
{ {
@ -773,8 +766,7 @@ namespace WinSW
void RestartSelf(string? pathToConfig) void RestartSelf(string? pathToConfig)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -794,7 +786,7 @@ namespace WinSW
IntPtr.Zero, IntPtr.Zero,
null, null,
default, default,
out ProcessApis.PROCESS_INFORMATION processInfo)) out var processInfo))
{ {
Throw.Command.Win32Exception("Failed to invoke restart."); Throw.Command.Win32Exception("Failed to invoke restart.");
} }
@ -805,8 +797,7 @@ namespace WinSW
static int Status(string? pathToConfig) static int Status(string? pathToConfig)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
using var svc = new ServiceController(config.Name); using var svc = new ServiceController(config.Name);
try try
@ -838,8 +829,7 @@ namespace WinSW
void Test(string? pathToConfig, bool noElevate, bool noBreak) void Test(string? pathToConfig, bool noElevate, bool noBreak)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -849,7 +839,7 @@ namespace WinSW
AutoRefresh(config); AutoRefresh(config);
using WrapperService wsvc = new WrapperService(config); using var wsvc = new WrapperService(config);
wsvc.RaiseOnStart(args); wsvc.RaiseOnStart(args);
try try
{ {
@ -860,7 +850,7 @@ namespace WinSW
} }
else else
{ {
using ManualResetEvent evt = new ManualResetEvent(false); using var evt = new ManualResetEvent(false);
Console.WriteLine("Press Ctrl+C to stop the service..."); Console.WriteLine("Press Ctrl+C to stop the service...");
Console.CancelKeyPress += CancelKeyPress; Console.CancelKeyPress += CancelKeyPress;
@ -883,8 +873,7 @@ namespace WinSW
void Refresh(string? pathToConfig, bool noElevate) void Refresh(string? pathToConfig, bool noElevate)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
InitLoggers(config, enableConsoleLogging: true);
if (!elevated) if (!elevated)
{ {
@ -900,7 +889,7 @@ namespace WinSW
if (all) if (all)
{ {
using var scm = ServiceManager.Open(ServiceManagerAccess.EnumerateService); using var scm = ServiceManager.Open(ServiceManagerAccess.EnumerateService);
(IntPtr services, int count) = scm.EnumerateServices(); (var services, int count) = scm.EnumerateServices();
try try
{ {
int prevProcessId = -1; int prevProcessId = -1;
@ -915,7 +904,7 @@ namespace WinSW
{ {
if (prevProcessId >= 0) if (prevProcessId >= 0)
{ {
using Process process = Process.GetProcessById(prevProcessId); using var process = Process.GetProcessById(prevProcessId);
Draw(process, string.Empty, false); Draw(process, string.Empty, false);
} }
} }
@ -926,7 +915,7 @@ namespace WinSW
if (prevProcessId >= 0) if (prevProcessId >= 0)
{ {
using Process process = Process.GetProcessById(prevProcessId); using var process = Process.GetProcessById(prevProcessId);
Draw(process, string.Empty, true); Draw(process, string.Empty, true);
} }
} }
@ -937,15 +926,15 @@ namespace WinSW
} }
else else
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect); using var scm = ServiceManager.Open(ServiceManagerAccess.Connect);
using Service sc = scm.OpenService(config.Name, ServiceAccess.QueryStatus); using var sc = scm.OpenService(config.Name, ServiceAccess.QueryStatus);
int processId = sc.ProcessId; int processId = sc.ProcessId;
if (processId >= 0) if (processId >= 0)
{ {
using Process process = Process.GetProcessById(processId); using var process = Process.GetProcessById(processId);
Draw(process, string.Empty, true); Draw(process, string.Empty, true);
} }
} }
@ -972,11 +961,11 @@ namespace WinSW
Console.WriteLine(process.Format()); Console.WriteLine(process.Format());
List<Process> children = process.GetChildren(); var children = process.GetChildren();
int count = children.Count; int count = children.Count;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
using Process child = children[i]; using var child = children[i];
Draw(child, indentation, i == count - 1); Draw(child, indentation, i == count - 1);
} }
} }
@ -984,7 +973,7 @@ namespace WinSW
void DevKill(string? pathToConfig, bool noElevate) void DevKill(string? pathToConfig, bool noElevate)
{ {
XmlServiceConfig config = LoadConfig(pathToConfig); var config = LoadConfigAndInitLoggers(pathToConfig, true);
if (!elevated) if (!elevated)
{ {
@ -992,13 +981,13 @@ namespace WinSW
return; return;
} }
using ServiceManager scm = ServiceManager.Open(); using var scm = ServiceManager.Open();
using Service sc = scm.OpenService(config.Name); using var sc = scm.OpenService(config.Name);
int processId = sc.ProcessId; int processId = sc.ProcessId;
if (processId >= 0) if (processId >= 0)
{ {
using Process process = Process.GetProcessById(processId); using var process = Process.GetProcessById(processId);
process.StopDescendants(config.StopTimeoutInMs); process.StopDescendants(config.StopTimeoutInMs);
} }
@ -1007,7 +996,7 @@ namespace WinSW
static unsafe void DevList() static unsafe void DevList()
{ {
using var scm = ServiceManager.Open(ServiceManagerAccess.EnumerateService); using var scm = ServiceManager.Open(ServiceManagerAccess.EnumerateService);
(IntPtr services, int count) = scm.EnumerateServices(); (var services, int count) = scm.EnumerateServices();
try try
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@ -1058,7 +1047,7 @@ namespace WinSW
" " + (stderrName ?? NoPipe) + " " + (stderrName ?? NoPipe) +
commandLine.Remove(commandLine.IndexOf(exe), exe.Length).TrimStart('"'); commandLine.Remove(commandLine.IndexOf(exe), exe.Length).TrimStart('"');
ProcessStartInfo startInfo = new ProcessStartInfo var startInfo = new ProcessStartInfo
{ {
UseShellExecute = true, UseShellExecute = true,
Verb = "runas", Verb = "runas",
@ -1069,7 +1058,7 @@ namespace WinSW
try try
{ {
using Process elevated = Process.Start(startInfo)!; using var elevated = Process.Start(startInfo)!;
if (stdinName is not null) if (stdinName is not null)
{ {
@ -1106,9 +1095,9 @@ namespace WinSW
return; return;
} }
DateTime fileLastWriteTime = File.GetLastWriteTime(config.FullPath); var fileLastWriteTime = File.GetLastWriteTime(config.FullPath);
using RegistryKey? registryKey = Registry.LocalMachine using var registryKey = Registry.LocalMachine
.OpenSubKey("SYSTEM")? .OpenSubKey("SYSTEM")?
.OpenSubKey("CurrentControlSet")? .OpenSubKey("CurrentControlSet")?
.OpenSubKey("Services")? .OpenSubKey("Services")?
@ -1119,7 +1108,7 @@ namespace WinSW
return; return;
} }
DateTime registryLastWriteTime = registryKey.GetLastWriteTime(); var registryLastWriteTime = registryKey.GetLastWriteTime();
if (fileLastWriteTime > registryLastWriteTime) if (fileLastWriteTime > registryLastWriteTime)
{ {
@ -1129,16 +1118,16 @@ namespace WinSW
static void DoRefresh(XmlServiceConfig config) static void DoRefresh(XmlServiceConfig config)
{ {
using ServiceManager scm = ServiceManager.Open(ServiceManagerAccess.Connect); using var scm = ServiceManager.Open(ServiceManagerAccess.Connect);
try try
{ {
using Service sc = scm.OpenService(config.Name); using var sc = scm.OpenService(config.Name);
sc.ChangeConfig(config.DisplayName, config.StartMode, config.ServiceDependencies); sc.ChangeConfig(config.DisplayName, config.StartMode, config.ServiceDependencies);
sc.SetDescription(config.Description); sc.SetDescription(config.Description);
SC_ACTION[] actions = config.FailureActions; var actions = config.FailureActions;
if (actions.Length > 0) if (actions.Length > 0)
{ {
sc.SetFailureActions(config.ResetFailureAfter, actions); sc.SetFailureActions(config.ResetFailureAfter, actions);
@ -1173,42 +1162,54 @@ namespace WinSW
} }
/// <exception cref="FileNotFoundException" /> /// <exception cref="FileNotFoundException" />
private static XmlServiceConfig LoadConfig(string? path) private static XmlServiceConfig LoadConfigAndInitLoggers(string? path, bool enableConsoleLogging)
{ {
if (TestConfig != null) if (TestConfig != null)
{ {
return TestConfig; return TestConfig;
} }
if (path != null)
{
return new XmlServiceConfig(path);
}
path = Path.ChangeExtension(ExecutablePath, ".xml");
if (!File.Exists(path))
{
throw new FileNotFoundException("Unable to locate " + Path.GetFileNameWithoutExtension(path) + ".xml file within executable directory.");
}
return new XmlServiceConfig(path);
}
private static void InitLoggers(XmlServiceConfig config, bool enableConsoleLogging)
{
if (XmlServiceConfig.TestConfig != null)
{
return;
}
// TODO: Make logging levels configurable // TODO: Make logging levels configurable
Level fileLogLevel = Level.Debug; var fileLogLevel = Level.Debug;
// TODO: Debug should not be printed to console by default. Otherwise commands like 'status' will be pollutted // TODO: Debug should not be printed to console by default. Otherwise commands like 'status' will be pollutted
// This is a workaround till there is a better command line parsing, which will allow determining // This is a workaround till there is a better command line parsing, which will allow determining
Level consoleLogLevel = Level.Info; var consoleLogLevel = Level.Info;
Level eventLogLevel = Level.Warn; var eventLogLevel = Level.Warn;
List<IAppender> appenders = new List<IAppender>(); // console log
if (enableConsoleLogging)
{
var consoleAppender = new WinSWConsoleAppender
{
Name = "Wrapper console log",
Threshold = consoleLogLevel,
Layout = new PatternLayout("%date{ABSOLUTE} - %message%newline"),
};
consoleAppender.ActivateOptions();
BasicConfigurator.Configure(
#if NET
LogManager.GetRepository(Assembly.GetExecutingAssembly()),
#endif
consoleAppender);
}
XmlServiceConfig config;
if (path != null)
{
config = new XmlServiceConfig(path);
}
else
{
path = Path.ChangeExtension(ExecutablePath, ".xml");
if (!File.Exists(path))
{
throw new FileNotFoundException("Unable to locate " + Path.GetFileNameWithoutExtension(path) + ".xml file within executable directory.");
}
config = new XmlServiceConfig(path);
}
// .wrapper.log // .wrapper.log
string wrapperLogPath = Path.Combine(config.LogDirectory, config.BaseName + ".wrapper.log"); string wrapperLogPath = Path.Combine(config.LogDirectory, config.BaseName + ".wrapper.log");
@ -1223,20 +1224,6 @@ namespace WinSW
Layout = new PatternLayout("%date %-5level - %message%newline"), Layout = new PatternLayout("%date %-5level - %message%newline"),
}; };
wrapperLog.ActivateOptions(); wrapperLog.ActivateOptions();
appenders.Add(wrapperLog);
// console log
if (enableConsoleLogging)
{
var consoleAppender = new WinSWConsoleAppender
{
Name = "Wrapper console log",
Threshold = consoleLogLevel,
Layout = new PatternLayout("%date{ABSOLUTE} - %message%newline"),
};
consoleAppender.ActivateOptions();
appenders.Add(consoleAppender);
}
// event log // event log
var systemEventLogger = new ServiceEventLogAppender(WrapperService.eventLogProvider) var systemEventLogger = new ServiceEventLogAppender(WrapperService.eventLogProvider)
@ -1245,20 +1232,22 @@ namespace WinSW
Threshold = eventLogLevel, Threshold = eventLogLevel,
}; };
systemEventLogger.ActivateOptions(); systemEventLogger.ActivateOptions();
appenders.Add(systemEventLogger);
BasicConfigurator.Configure( BasicConfigurator.Configure(
#if NETCOREAPP #if NET
LogManager.GetRepository(System.Reflection.Assembly.GetExecutingAssembly()), LogManager.GetRepository(Assembly.GetExecutingAssembly()),
#endif #endif
appenders.ToArray()); wrapperLog,
systemEventLogger);
return config;
} }
/// <exception cref="CommandException" /> /// <exception cref="CommandException" />
internal static bool IsProcessElevated() internal static bool IsProcessElevated()
{ {
IntPtr process = ProcessApis.GetCurrentProcess(); var process = ProcessApis.GetCurrentProcess();
if (!ProcessApis.OpenProcessToken(process, TokenAccessLevels.Read, out IntPtr token)) if (!ProcessApis.OpenProcessToken(process, TokenAccessLevels.Read, out var token))
{ {
Throw.Command.Win32Exception("Failed to open process token."); Throw.Command.Win32Exception("Failed to open process token.");
} }
@ -1270,7 +1259,7 @@ namespace WinSW
if (!SecurityApis.GetTokenInformation( if (!SecurityApis.GetTokenInformation(
token, token,
SecurityApis.TOKEN_INFORMATION_CLASS.TokenElevation, SecurityApis.TOKEN_INFORMATION_CLASS.TokenElevation,
out SecurityApis.TOKEN_ELEVATION elevation, out var elevation,
sizeof(SecurityApis.TOKEN_ELEVATION), sizeof(SecurityApis.TOKEN_ELEVATION),
out _)) out _))
{ {
@ -1288,10 +1277,10 @@ namespace WinSW
private static string ReadPassword() private static string ReadPassword()
{ {
StringBuilder buf = new StringBuilder(); var buf = new StringBuilder();
while (true) while (true)
{ {
ConsoleKeyInfo key = Console.ReadKey(true); var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter) if (key.Key == ConsoleKey.Enter)
{ {
return buf.ToString(); return buf.ToString();

View File

@ -11,7 +11,7 @@ namespace WinSW
/// <exception cref="TimeoutException" /> /// <exception cref="TimeoutException" />
internal static void WaitForStatus(this ServiceController serviceController, ServiceControllerStatus desiredStatus, ServiceControllerStatus pendingStatus, CancellationToken ct) internal static void WaitForStatus(this ServiceController serviceController, ServiceControllerStatus desiredStatus, ServiceControllerStatus pendingStatus, CancellationToken ct)
{ {
TimeSpan timeout = new TimeSpan(TimeSpan.TicksPerSecond); var timeout = new TimeSpan(TimeSpan.TicksPerSecond);
for (; ; ) for (; ; )
{ {
try try

View File

@ -22,7 +22,7 @@ namespace WinSW
private static readonly int additionalStopTimeout = 1_000; private static readonly int additionalStopTimeout = 1_000;
private static readonly ILog Log = LogManager.GetLogger( private static readonly ILog Log = LogManager.GetLogger(
#if NETCOREAPP #if NET
Assembly.GetExecutingAssembly(), Assembly.GetExecutingAssembly(),
#endif #endif
"WinSW"); "WinSW");
@ -71,7 +71,7 @@ namespace WinSW
/// </summary> /// </summary>
private void HandleFileCopies() private void HandleFileCopies()
{ {
var file = this.config.BasePath + ".copies"; string? file = this.config.BasePath + ".copies";
if (!File.Exists(file)) if (!File.Exists(file))
{ {
return; // nothing to handle return; // nothing to handle
@ -128,7 +128,7 @@ namespace WinSW
Directory.CreateDirectory(logDirectory); Directory.CreateDirectory(logDirectory);
} }
LogHandler logAppender = this.config.LogHandler; var logAppender = this.config.LogHandler;
logAppender.EventLogger = this; logAppender.EventLogger = this;
return logAppender; return logAppender;
} }
@ -264,11 +264,11 @@ namespace WinSW
this.HandleFileCopies(); this.HandleFileCopies();
// handle downloads // handle downloads
List<Download> downloads = this.config.Downloads; var downloads = this.config.Downloads;
Task[] tasks = new Task[downloads.Count]; var tasks = new Task[downloads.Count];
for (int i = 0; i < downloads.Count; i++) for (int i = 0; i < downloads.Count; i++)
{ {
Download download = downloads[i]; var download = downloads[i];
string downloadMessage = $"Downloading: {download.From} to {download.To}. failOnError={download.FailOnError.ToString()}"; string downloadMessage = $"Downloading: {download.From} to {download.To}. failOnError={download.FailOnError.ToString()}";
Log.Info(downloadMessage); Log.Info(downloadMessage);
tasks[i] = download.PerformAsync(); tasks[i] = download.PerformAsync();
@ -280,14 +280,14 @@ namespace WinSW
} }
catch (AggregateException e) catch (AggregateException e)
{ {
List<Exception> exceptions = new List<Exception>(e.InnerExceptions.Count); var exceptions = new List<Exception>(e.InnerExceptions.Count);
for (int i = 0; i < tasks.Length; i++) for (int i = 0; i < tasks.Length; i++)
{ {
if (tasks[i].IsFaulted) if (tasks[i].IsFaulted)
{ {
Download download = downloads[i]; var download = downloads[i];
string errorMessage = $"Failed to download {download.From} to {download.To}"; string errorMessage = $"Failed to download {download.From} to {download.To}";
AggregateException exception = tasks[i].Exception!; var exception = tasks[i].Exception!;
Log.Error(errorMessage, exception); Log.Error(errorMessage, exception);
// TODO: move this code into the download logic // TODO: move this code into the download logic
@ -301,13 +301,13 @@ namespace WinSW
throw new AggregateException(exceptions); throw new AggregateException(exceptions);
} }
ProcessCommand prestart = this.config.Prestart; var prestart = this.config.Prestart;
string? prestartExecutable = prestart.Executable; string? prestartExecutable = prestart.Executable;
if (prestartExecutable != null) if (prestartExecutable != null)
{ {
try try
{ {
using Process process = this.StartProcess(prestartExecutable, prestart.Arguments, prestart.CreateLogHandler()); using var process = this.StartProcess(prestartExecutable, prestart.Arguments, prestart.CreateLogHandler());
this.WaitForProcessToExit(process); this.WaitForProcessToExit(process);
this.LogExited($"Pre-start process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode); this.LogExited($"Pre-start process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode);
process.StopDescendants(additionalStopTimeout); process.StopDescendants(additionalStopTimeout);
@ -326,17 +326,17 @@ namespace WinSW
this.ExtensionManager.LoadExtensions(); this.ExtensionManager.LoadExtensions();
this.ExtensionManager.FireOnWrapperStarted(); this.ExtensionManager.FireOnWrapperStarted();
LogHandler executableLogHandler = this.CreateExecutableLogHandler(); var executableLogHandler = this.CreateExecutableLogHandler();
this.process = this.StartProcess(this.config.Executable, startArguments, executableLogHandler, this.OnMainProcessExited); this.process = this.StartProcess(this.config.Executable, startArguments, executableLogHandler, this.OnMainProcessExited);
this.ExtensionManager.FireOnProcessStarted(this.process); this.ExtensionManager.FireOnProcessStarted(this.process);
ProcessCommand poststart = this.config.Poststart; var poststart = this.config.Poststart;
string? poststartExecutable = poststart.Executable; string? poststartExecutable = poststart.Executable;
if (poststartExecutable != null) if (poststartExecutable != null)
{ {
try try
{ {
using Process process = StartProcessLocked(); using var process = StartProcessLocked();
this.WaitForProcessToExit(process); this.WaitForProcessToExit(process);
this.LogExited($"Post-start process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode); this.LogExited($"Post-start process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode);
process.StopDescendants(additionalStopTimeout); process.StopDescendants(additionalStopTimeout);
@ -362,13 +362,13 @@ namespace WinSW
/// </summary> /// </summary>
private void DoStop() private void DoStop()
{ {
ProcessCommand prestop = this.config.Prestop; var prestop = this.config.Prestop;
string? prestopExecutable = prestop.Executable; string? prestopExecutable = prestop.Executable;
if (prestopExecutable != null) if (prestopExecutable != null)
{ {
try try
{ {
using Process process = StartProcessLocked(prestopExecutable, prestop.Arguments, prestop.CreateLogHandler()); using var process = StartProcessLocked(prestopExecutable, prestop.Arguments, prestop.CreateLogHandler());
this.WaitForProcessToExit(process); this.WaitForProcessToExit(process);
this.LogExited($"Pre-stop process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode); this.LogExited($"Pre-stop process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode);
process.StopDescendants(additionalStopTimeout); process.StopDescendants(additionalStopTimeout);
@ -387,7 +387,7 @@ namespace WinSW
string? stopArguments = this.config.StopArguments; string? stopArguments = this.config.StopArguments;
if (stopExecutable is null && stopArguments is null) if (stopExecutable is null && stopArguments is null)
{ {
Process process = this.process; var process = this.process;
Log.Debug("ProcessKill " + process.Id); Log.Debug("ProcessKill " + process.Id);
bool? result = process.Stop(this.config.StopTimeoutInMs); bool? result = process.Stop(this.config.StopTimeoutInMs);
this.LogMinimal($"Child process '{process.Format()}' " + result switch this.LogMinimal($"Child process '{process.Format()}' " + result switch
@ -408,7 +408,7 @@ namespace WinSW
try try
{ {
// TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated // TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated
using Process stopProcess = StartProcessLocked(stopExecutable, stopArguments); using var stopProcess = StartProcessLocked(stopExecutable, stopArguments);
Log.Debug("WaitForProcessToExit " + this.process.Id + "+" + stopProcess.Id); Log.Debug("WaitForProcessToExit " + this.process.Id + "+" + stopProcess.Id);
this.WaitForProcessToExit(stopProcess); this.WaitForProcessToExit(stopProcess);
@ -425,13 +425,13 @@ namespace WinSW
} }
} }
ProcessCommand poststop = this.config.Poststop; var poststop = this.config.Poststop;
string? poststopExecutable = poststop.Executable; string? poststopExecutable = poststop.Executable;
if (poststopExecutable != null) if (poststopExecutable != null)
{ {
try try
{ {
using Process process = StartProcessLocked(poststopExecutable, poststop.Arguments, poststop.CreateLogHandler()); using var process = StartProcessLocked(poststopExecutable, poststop.Arguments, poststop.CreateLogHandler());
this.WaitForProcessToExit(process); this.WaitForProcessToExit(process);
this.LogExited($"Post-Stop process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode); this.LogExited($"Post-Stop process '{process.Format()}' exited with code {process.ExitCode}.", process.ExitCode);
process.StopDescendants(additionalStopTimeout); process.StopDescendants(additionalStopTimeout);
@ -477,13 +477,13 @@ namespace WinSW
private void AcceptPreshutdown() private void AcceptPreshutdown()
{ {
const string acceptedCommandsFieldName = const string acceptedCommandsFieldName =
#if NETCOREAPP #if NET
"_acceptedCommands"; "_acceptedCommands";
#else #else
"acceptedCommands"; "acceptedCommands";
#endif #endif
FieldInfo? acceptedCommandsField = typeof(ServiceBase).GetField(acceptedCommandsFieldName, BindingFlags.Instance | BindingFlags.NonPublic); var acceptedCommandsField = typeof(ServiceBase).GetField(acceptedCommandsFieldName, BindingFlags.Instance | BindingFlags.NonPublic);
if (acceptedCommandsField is null) if (acceptedCommandsField is null)
{ {
throw new MissingFieldException(nameof(ServiceBase), acceptedCommandsFieldName); throw new MissingFieldException(nameof(ServiceBase), acceptedCommandsFieldName);
@ -501,8 +501,8 @@ namespace WinSW
private void SignalStopped() private void SignalStopped()
{ {
using ServiceManager scm = ServiceManager.Open(); using var scm = ServiceManager.Open();
using Service sc = scm.OpenService(this.ServiceName, ServiceApis.ServiceAccess.QueryStatus); using var sc = scm.OpenService(this.ServiceName, ServiceApis.ServiceAccess.QueryStatus);
sc.SetStatus(this.ServiceHandle, ServiceControllerStatus.Stopped); sc.SetStatus(this.ServiceHandle, ServiceControllerStatus.Stopped);
} }
@ -549,16 +549,16 @@ namespace WinSW
RedirectStandardError = logHandler?.ErrFileDisabled == false, RedirectStandardError = logHandler?.ErrFileDisabled == false,
}; };
Dictionary<string, string> environment = this.config.EnvironmentVariables; var environment = this.config.EnvironmentVariables;
if (environment.Count > 0) if (environment.Count > 0)
{ {
var newEnvironment = var newEnvironment =
#if NETCOREAPP #if NET
startInfo.Environment; startInfo.Environment;
#else #else
startInfo.EnvironmentVariables; startInfo.EnvironmentVariables;
#endif #endif
foreach (KeyValuePair<string, string> pair in environment) foreach (var pair in environment)
{ {
newEnvironment[pair.Key] = pair.Value; newEnvironment[pair.Key] = pair.Value;
} }
@ -607,7 +607,7 @@ namespace WinSW
{ {
process.Exited += (sender, _) => process.Exited += (sender, _) =>
{ {
Process process = (Process)sender!; var process = (Process)sender!;
if (!process.EnableRaisingEvents) if (!process.EnableRaisingEvents)
{ {