Merge pull request #356 from NextTurn/nrt

Annotate for nullable reference types
pull/367/head
Oleg Nenashev 2020-01-20 05:54:50 +01:00 committed by GitHub
commit 33da176920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 370 additions and 328 deletions

View File

@ -7,11 +7,11 @@ namespace winsw.Logging
/// </summary>
public class WrapperServiceEventLogProvider : IServiceEventLogProvider
{
public WrapperService service { get; set; }
public WrapperService? service { get; set; }
public EventLog locate()
public EventLog? locate()
{
WrapperService _service = service;
WrapperService? _service = service;
if (_service != null && !_service.IsShuttingDown)
{
return _service.EventLog;

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
@ -28,7 +29,7 @@ namespace winsw
private readonly Process _process = new Process();
private readonly ServiceDescriptor _descriptor;
private Dictionary<string, string> _envs;
private Dictionary<string, string>? _envs;
internal WinSWExtensionManager ExtensionManager { get; private set; }
@ -52,7 +53,7 @@ namespace winsw
/// <remarks>
/// The version will be taken from <see cref="AssemblyInfo"/>
/// </remarks>
public static Version Version => Assembly.GetExecutingAssembly().GetName().Version;
public static Version Version => Assembly.GetExecutingAssembly().GetName().Version!;
/// <summary>
/// Indicates that the system is shutting down.
@ -92,7 +93,7 @@ namespace winsw
{
using (var tr = new StreamReader(file, Encoding.UTF8))
{
string line;
string? line;
while ((line = tr.ReadLine()) != null)
{
LogEvent("Handling copy: " + line);
@ -223,7 +224,7 @@ namespace winsw
}
}
string startarguments = _descriptor.Startarguments;
string? startarguments = _descriptor.Startarguments;
if (startarguments == null)
{
@ -282,7 +283,7 @@ namespace winsw
/// </summary>
private void StopIt()
{
string stoparguments = _descriptor.Stoparguments;
string? stoparguments = _descriptor.Stoparguments;
LogEvent("Stopping " + _descriptor.Id);
Log.Info("Stopping " + _descriptor.Id);
_orderlyShutdown = true;
@ -307,7 +308,7 @@ namespace winsw
stoparguments += " " + _descriptor.Arguments;
Process stopProcess = new Process();
string executable = _descriptor.StopExecutable;
string? executable = _descriptor.StopExecutable;
if (executable == null)
{
@ -399,10 +400,10 @@ namespace winsw
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
}
private void StartProcess(Process processToStart, string arguments, string executable, LogHandler logHandler, bool redirectStdin)
private void StartProcess(Process processToStart, string arguments, string executable, LogHandler? logHandler, bool redirectStdin)
{
// Define handler of the completed process
ProcessCompletionCallback processCompletionCallback = proc =>
void OnProcessCompleted(Process proc)
{
string msg = processToStart.Id + " - " + processToStart.StartInfo.FileName + " " + processToStart.StartInfo.Arguments;
try
@ -427,16 +428,11 @@ namespace winsw
{
LogEvent("WaitForExit " + ioe.Message);
}
try
finally
{
proc.Dispose();
}
catch (InvalidOperationException ioe)
{
LogEvent("Dispose " + ioe.Message);
}
};
}
// Invoke process and exit
ProcessHelper.StartProcessAndCallbackForExit(
@ -446,7 +442,7 @@ namespace winsw
envVars: _envs,
workingDirectory: _descriptor.WorkingDirectory,
priority: _descriptor.Priority,
callback: processCompletionCallback,
callback: OnProcessCompleted,
logHandler: logHandler,
redirectStdin: redirectStdin,
hideWindow: _descriptor.HideWindow);
@ -475,6 +471,7 @@ namespace winsw
}
}
[DoesNotReturn]
private static void ThrowNoSuchService()
{
throw new WmiException(ReturnValue.NoSuchService);
@ -488,7 +485,7 @@ namespace winsw
/// <param name="descriptor">Service descriptor. If null, it will be initialized within the method.
/// In such case configs will be loaded from the XML Configuration File.</param>
/// <exception cref="Exception">Any unhandled exception</exception>
public static void Run(string[] _args, ServiceDescriptor descriptor = null)
public static void Run(string[] _args, ServiceDescriptor? descriptor = null)
{
bool isCLIMode = _args.Length > 0;
@ -543,8 +540,9 @@ namespace winsw
throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
}
string username = null, password = null;
bool setallowlogonasaserviceright = false;
string? username = null;
string? password = null;
bool setallowlogonasaserviceright = false; // This variable is very readable.
if (args.Count > 1 && args[1] == "/p")
{
// we expected username/password on stdin
@ -573,7 +571,7 @@ namespace winsw
if (setallowlogonasaserviceright)
{
LogonAsAService.AddLogonAsAServiceRight(username);
LogonAsAService.AddLogonAsAServiceRight(username!);
}
svc.Create(
@ -712,8 +710,7 @@ namespace winsw
// run restart from another process group. see README.md for why this is useful.
STARTUPINFO si = default;
bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out PROCESS_INFORMATION pi);
bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out _);
if (!result)
{
throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
@ -731,6 +728,7 @@ namespace winsw
Console.WriteLine("Started");
else
Console.WriteLine("Stopped");
return;
}

View File

@ -0,0 +1,8 @@
#if !NETCOREAPP
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class DoesNotReturnAttribute : Attribute { }
}
#endif

View File

@ -15,7 +15,7 @@ namespace winsw
private static extern bool FreeConsole();
[DllImport(KERNEL32)]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate? HandlerRoutine, bool Add);
// Delegate type to be used as the Handler Routine for SCCH
private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);

View File

@ -3,6 +3,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net20;net40;net461;netcoreapp3.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Version><!-- Populated by AppVeyor --></Version>
<AssemblyTitle>Windows Service Wrapper</AssemblyTitle>
<Description>Allows arbitrary process to run as a Windows service by wrapping it.</Description>

View File

@ -13,36 +13,29 @@ namespace winsw.Configuration
/// </summary>
public sealed class DefaultWinSWSettings : IWinSWConfiguration
{
public string Id => null;
public string Caption => null;
public string Description => null;
public string Executable => null;
public string Id => throw new InvalidOperationException(nameof(Id) + " must be specified.");
public string Caption => throw new InvalidOperationException(nameof(Caption) + " must be specified.");
public string Description => throw new InvalidOperationException(nameof(Description) + " must be specified.");
public string Executable => throw new InvalidOperationException(nameof(Executable) + " must be specified.");
public bool HideWindow => false;
public string ExecutablePath
{
get
{
// this returns the executable name as given by the calling process, so
// it needs to be absolutized.
string p = Environment.GetCommandLineArgs()[0];
return Path.GetFullPath(p);
}
}
// this returns the executable name as given by the calling process, so
// it needs to be absolutized.
public string ExecutablePath => Path.GetFullPath(Environment.GetCommandLineArgs()[0]);
// Installation
public bool AllowServiceAcountLogonRight => false;
public string ServiceAccountPassword => null;
public string? ServiceAccountPassword => null;
public string ServiceAccountUser => "NULL\\NULL";
public List<Native.SC_ACTION> FailureActions => new List<Native.SC_ACTION>();
public List<Native.SC_ACTION> FailureActions => new List<Native.SC_ACTION>(0);
public TimeSpan ResetFailureAfter => TimeSpan.FromDays(1);
// Executable management
public string Arguments => string.Empty;
public string Startarguments => null;
public string StopExecutable => null;
public string Stoparguments => null;
public string WorkingDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public string? Startarguments => null;
public string? StopExecutable => null;
public string? Stoparguments => null;
public string WorkingDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
public ProcessPriorityClass Priority => ProcessPriorityClass.Normal;
public TimeSpan StopTimeout => TimeSpan.FromSeconds(15);
public bool StopParentProcessFirst => false;
@ -56,7 +49,7 @@ namespace winsw.Configuration
public bool Interactive => false;
// Logging
public string LogDirectory => Path.GetDirectoryName(ExecutablePath);
public string LogDirectory => Path.GetDirectoryName(ExecutablePath)!;
public string LogMode => "append";
public bool OutFileDisabled => false;
@ -65,13 +58,13 @@ namespace winsw.Configuration
public string ErrFilePattern => ".err.log";
// Environment
public List<Download> Downloads => new List<Download>();
public Dictionary<string, string> EnvironmentVariables => new Dictionary<string, string>();
public List<Download> Downloads => new List<Download>(0);
public Dictionary<string, string> EnvironmentVariables => new Dictionary<string, string>(0);
// Misc
public bool BeepOnShutdown => false;
// Extensions
public XmlNode ExtensionsConfiguration => null;
public XmlNode? ExtensionsConfiguration => null;
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using WMI;
namespace winsw.Configuration
{
public interface IWinSWConfiguration
@ -18,16 +19,16 @@ namespace winsw.Configuration
// Installation
bool AllowServiceAcountLogonRight { get; }
string ServiceAccountPassword { get; }
string? ServiceAccountPassword { get; }
string ServiceAccountUser { get; }
List<Native.SC_ACTION> FailureActions { get; }
TimeSpan ResetFailureAfter { get; }
// Executable management
string Arguments { get; }
string Startarguments { get; }
string StopExecutable { get; }
string Stoparguments { get; }
string? Startarguments { get; }
string? StopExecutable { get; }
string? Stoparguments { get; }
string WorkingDirectory { get; }
ProcessPriorityClass Priority { get; }
TimeSpan StopTimeout { get; }
@ -53,6 +54,6 @@ namespace winsw.Configuration
bool BeepOnShutdown { get; }
// Extensions
XmlNode ExtensionsConfiguration { get; }
XmlNode? ExtensionsConfiguration { get; }
}
}

View File

@ -23,20 +23,21 @@ namespace winsw
public readonly string From;
public readonly string To;
public readonly AuthType Auth = AuthType.none;
public readonly string Username;
public readonly string Password;
public readonly string? Username;
public readonly string? Password;
public readonly bool UnsecureAuth;
public readonly bool FailOnError;
public string ShortId => $"(download from {From})";
// internal
public Download(
string from,
string to,
bool failOnError = false,
AuthType auth = AuthType.none,
string username = null,
string password = null,
string? username = null,
string? password = null,
bool unsecureAuth = false)
{
From = from;
@ -119,7 +120,7 @@ namespace winsw
break;
case AuthType.basic:
SetBasicAuthHeader(req, Username, Password);
SetBasicAuthHeader(req, Username!, Password!);
break;
default:

View File

@ -1,5 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
@ -15,7 +15,7 @@ namespace DynamicProxy
/// <param name="method">The method info that can be used to invoke the actual method on the object implementation</param>
/// <param name="parameters">Parameters to pass to the method</param>
/// <returns>Object</returns>
object Invoke(object proxy, MethodInfo method, object[] parameters);
object? Invoke(object proxy, MethodInfo method, object[] parameters);
}
/// <summary>
@ -23,7 +23,7 @@ namespace DynamicProxy
/// </summary>
public class MetaDataFactory
{
private static Hashtable typeMap = new Hashtable();
private static readonly Dictionary<string, Type> typeMap = new Dictionary<string, Type>();
/// <summary>
/// Class constructor. Private because this is a static class.
@ -41,12 +41,16 @@ namespace DynamicProxy
{
if (interfaceType != null)
{
lock (typeMap.SyncRoot)
lock (typeMap)
{
if (!typeMap.ContainsKey(interfaceType.FullName))
#if NETCOREAPP
_ = typeMap.TryAdd(interfaceType.FullName!, interfaceType);
#else
if (!typeMap.ContainsKey(interfaceType.FullName!))
{
typeMap.Add(interfaceType.FullName, interfaceType);
typeMap.Add(interfaceType.FullName!, interfaceType);
}
#endif
}
}
}
@ -59,10 +63,10 @@ namespace DynamicProxy
///<returns>MethodInfo</returns>
public static MethodInfo GetMethod(string name, int i)
{
Type type = null;
lock (typeMap.SyncRoot)
Type? type = null;
lock (typeMap)
{
type = (Type)typeMap[name];
type = typeMap[name];
}
return type.GetMethods()[i];
@ -70,10 +74,10 @@ namespace DynamicProxy
public static PropertyInfo GetProperty(string name, int i)
{
Type type = null;
lock (typeMap.SyncRoot)
Type? type = null;
lock (typeMap)
{
type = (Type)typeMap[name];
type = typeMap[name];
}
return type.GetProperties()[i];
@ -84,30 +88,27 @@ namespace DynamicProxy
/// </summary>
public class ProxyFactory
{
private static ProxyFactory _instance;
private static ProxyFactory? _instance;
private static readonly object LockObj = new object();
private readonly Hashtable _typeMap = Hashtable.Synchronized(new Hashtable());
private static readonly Hashtable OpCodeTypeMapper = new Hashtable();
private readonly Dictionary<string, Type> _typeMap = new Dictionary<string, Type>();
private const string PROXY_SUFFIX = "Proxy";
private const string ASSEMBLY_NAME = "ProxyAssembly";
private const string MODULE_NAME = "ProxyModule";
private const string HANDLER_NAME = "handler";
// Initialize the value type mapper. This is needed for methods with intrinsic
// return types, used in the Emit process.
static ProxyFactory()
private static readonly Dictionary<Type, OpCode> OpCodeTypeMapper = new Dictionary<Type, OpCode>
{
OpCodeTypeMapper.Add(typeof(bool), OpCodes.Ldind_I1);
OpCodeTypeMapper.Add(typeof(short), OpCodes.Ldind_I2);
OpCodeTypeMapper.Add(typeof(int), OpCodes.Ldind_I4);
OpCodeTypeMapper.Add(typeof(long), OpCodes.Ldind_I8);
OpCodeTypeMapper.Add(typeof(double), OpCodes.Ldind_R8);
OpCodeTypeMapper.Add(typeof(float), OpCodes.Ldind_R4);
OpCodeTypeMapper.Add(typeof(ushort), OpCodes.Ldind_U2);
OpCodeTypeMapper.Add(typeof(uint), OpCodes.Ldind_U4);
}
{ typeof(bool), OpCodes.Ldind_I1 },
{ typeof(short), OpCodes.Ldind_I2 },
{ typeof(int), OpCodes.Ldind_I4 },
{ typeof(long), OpCodes.Ldind_I8 },
{ typeof(double), OpCodes.Ldind_R8 },
{ typeof(float), OpCodes.Ldind_R4 },
{ typeof(ushort), OpCodes.Ldind_U2 },
{ typeof(uint), OpCodes.Ldind_U4 },
};
private const string ProxySuffix = "Proxy";
private const string AssemblyName = "ProxyAssembly";
private const string ModuleName = "ProxyModule";
private const string HandlerName = "handler";
private ProxyFactory()
{
@ -120,24 +121,25 @@ namespace DynamicProxy
CreateInstance();
}
return _instance;
return _instance!;
}
private static void CreateInstance()
{
lock (LockObj)
{
if (_instance == null)
{
_instance = new ProxyFactory();
}
_instance ??= new ProxyFactory();
}
}
public object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface)
{
string typeName = objType.FullName + PROXY_SUFFIX;
Type type = (Type)_typeMap[typeName];
string typeName = objType.FullName + ProxySuffix;
Type? type = null;
lock (_typeMap)
{
_ = _typeMap.TryGetValue(typeName, out type);
}
// check to see if the type was in the cache. If the type was not cached, then
// create a new instance of the dynamic type and add it to the cache.
@ -152,11 +154,14 @@ namespace DynamicProxy
type = CreateType(handler, objType.GetInterfaces(), typeName);
}
_typeMap.Add(typeName, type);
lock (_typeMap)
{
_typeMap.Add(typeName, type);
}
}
// return a new instance of the type.
return Activator.CreateInstance(type, new object[] { handler });
return Activator.CreateInstance(type, new object[] { handler })!;
}
public object Create(IProxyInvocationHandler handler, Type objType)
@ -166,88 +171,78 @@ namespace DynamicProxy
private Type CreateType(IProxyInvocationHandler handler, Type[] interfaces, string dynamicTypeName)
{
Type retVal = null;
Type objType = typeof(object);
Type handlerType = typeof(IProxyInvocationHandler);
if (handler != null && interfaces != null)
{
Type objType = typeof(object);
Type handlerType = typeof(IProxyInvocationHandler);
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = AssemblyName;
assemblyName.Version = new Version(1, 0, 0, 0);
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = ASSEMBLY_NAME;
assemblyName.Version = new Version(1, 0, 0, 0);
// create a new assembly for this proxy, one that isn't presisted on the file system
AssemblyBuilder assemblyBuilder =
// create a new assembly for this proxy, one that isn't presisted on the file system
AssemblyBuilder assemblyBuilder =
#if VNEXT
AssemblyBuilder.DefineDynamicAssembly(
AssemblyBuilder.DefineDynamicAssembly(
#else
AppDomain.CurrentDomain.DefineDynamicAssembly(
AppDomain.CurrentDomain.DefineDynamicAssembly(
#endif
assemblyName, AssemblyBuilderAccess.Run);
assemblyName, AssemblyBuilderAccess.Run);
// create a new module for this proxy
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(MODULE_NAME);
// create a new module for this proxy
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(ModuleName);
// Set the class to be public and sealed
TypeAttributes typeAttributes =
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
// Set the class to be public and sealed
TypeAttributes typeAttributes =
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
// Gather up the proxy information and create a new type builder. One that
// inherits from Object and implements the interface passed in
TypeBuilder typeBuilder = moduleBuilder.DefineType(
dynamicTypeName, typeAttributes, objType, interfaces);
// Gather up the proxy information and create a new type builder. One that
// inherits from Object and implements the interface passed in
TypeBuilder typeBuilder = moduleBuilder.DefineType(
dynamicTypeName, typeAttributes, objType, interfaces);
// Define a member variable to hold the delegate
FieldBuilder handlerField = typeBuilder.DefineField(
HANDLER_NAME, handlerType, FieldAttributes.Private);
// Define a member variable to hold the delegate
FieldBuilder handlerField = typeBuilder.DefineField(
HandlerName, handlerType, FieldAttributes.Private);
// build a constructor that takes the delegate object as the only argument
// ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] );
ConstructorInfo superConstructor = objType.GetConstructor(new Type[0]);
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
// build a constructor that takes the delegate object as the only argument
ConstructorInfo baseConstructor = objType.GetConstructor(Type.EmptyTypes)!;
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
#region( "Constructor IL Code" )
ILGenerator constructorIL = delegateConstructor.GetILGenerator();
#region( "Constructor IL Code" )
ILGenerator constructorIL = delegateConstructor.GetILGenerator();
// Load "this"
constructorIL.Emit(OpCodes.Ldarg_0);
// Load first constructor parameter
constructorIL.Emit(OpCodes.Ldarg_1);
// Set the first parameter into the handler field
constructorIL.Emit(OpCodes.Stfld, handlerField);
// Load "this"
constructorIL.Emit(OpCodes.Ldarg_0);
// Call the super constructor
constructorIL.Emit(OpCodes.Call, superConstructor);
// Constructor return
constructorIL.Emit(OpCodes.Ret);
#endregion
// Load "this"
constructorIL.Emit(OpCodes.Ldarg_0);
// Load first constructor parameter
constructorIL.Emit(OpCodes.Ldarg_1);
// Set the first parameter into the handler field
constructorIL.Emit(OpCodes.Stfld, handlerField);
// Load "this"
constructorIL.Emit(OpCodes.Ldarg_0);
// Call the super constructor
constructorIL.Emit(OpCodes.Call, baseConstructor);
// Constructor return
constructorIL.Emit(OpCodes.Ret);
#endregion
// for every method that the interfaces define, build a corresponding
// method in the dynamic type that calls the handlers invoke method.
foreach (Type interfaceType in interfaces)
{
GenerateMethod(interfaceType, handlerField, typeBuilder);
}
retVal = typeBuilder.CreateType();
// assemblyBuilder.Save(dynamicTypeName + ".dll");
// for every method that the interfaces define, build a corresponding
// method in the dynamic type that calls the handlers invoke method.
foreach (Type interfaceType in interfaces)
{
GenerateMethod(interfaceType, handlerField, typeBuilder);
}
return retVal;
return typeBuilder.CreateType()!;
}
private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod("Invoke");
private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod("GetMethod", new Type[] { typeof(string), typeof(int) });
private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod(nameof(IProxyInvocationHandler.Invoke))!;
private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod(nameof(MetaDataFactory.GetMethod))!;
private void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
{
MetaDataFactory.Add(interfaceType);
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
PropertyInfo[] props = interfaceType.GetProperties();
// PropertyInfo[] props = interfaceType.GetProperties();
for (int i = 0; i < interfaceMethods.Length; i++)
{
@ -272,7 +267,7 @@ namespace DynamicProxy
CallingConventions.Standard,
methodInfo.ReturnType, methodParameters);
#region( "Handler Method IL Code" )
#region( "Handler Method IL Code" )
ILGenerator methodIL = methodBuilder.GetILGenerator();
// load "this"
@ -283,7 +278,7 @@ namespace DynamicProxy
methodIL.Emit(OpCodes.Ldarg_0);
// load the name of the interface, used to get the MethodInfo object
// from MetaDataFactory
methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName);
methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName!);
// load the index, used to get the MethodInfo object
// from MetaDataFactory
methodIL.Emit(OpCodes.Ldc_I4, i);
@ -315,7 +310,7 @@ namespace DynamicProxy
if (methodInfo.ReturnType != typeof(void))
{
// if the return type if a value type, then unbox the return value
// if the return type is a value type, then unbox the return value
// so that we don't get junk.
if (methodInfo.ReturnType.IsValueType)
{
@ -330,7 +325,7 @@ namespace DynamicProxy
}
else
{
methodIL.Emit((OpCode)OpCodeTypeMapper[methodInfo.ReturnType]);
methodIL.Emit(OpCodeTypeMapper[methodInfo.ReturnType]);
}
}
}
@ -343,7 +338,7 @@ namespace DynamicProxy
// Return
methodIL.Emit(OpCodes.Ret);
#endregion
#endregion
}
// for (int i = 0; i < props.Length; i++)

View File

@ -1,5 +1,4 @@
using System;
using System.Xml;
using System.Xml;
namespace winsw.Extensions
{
@ -7,7 +6,9 @@ namespace winsw.Extensions
{
public abstract string DisplayName { get; }
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public WinSWExtensionDescriptor Descriptor { get; set; }
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public virtual void Configure(ServiceDescriptor descriptor, XmlNode node)
{

View File

@ -1,5 +1,4 @@
using System;
using System.Xml;
using System.Xml;
namespace winsw.Extensions
{

View File

@ -1,5 +1,4 @@
using System;
using System.Xml;
using System.Xml;
using winsw.Util;
namespace winsw.Extensions

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using log4net;
@ -128,8 +127,8 @@ namespace winsw.Extensions
throw new ExtensionException(id, "Extension has been already loaded");
}
var extensionsConfig = ServiceDescriptor.ExtensionsConfiguration;
XmlElement configNode = (extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement : null;
XmlNode? extensionsConfig = ServiceDescriptor.ExtensionsConfiguration;
XmlElement? configNode = (extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement : null;
if (configNode == null)
{
throw new ExtensionException(id, "Cannot get the configuration entry");
@ -165,13 +164,13 @@ namespace winsw.Extensions
try
{
Type t = Type.GetType(className);
Type? t = Type.GetType(className);
if (t == null)
{
throw new ExtensionException(id, "Class " + className + " does not exist");
}
created = Activator.CreateInstance(t);
created = Activator.CreateInstance(t)!;
}
catch (Exception ex)
{

View File

@ -30,7 +30,9 @@ namespace winsw
/// <summary>
/// Error and information about logging should be reported here.
/// </summary>
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public EventLogger EventLogger { get; set; }
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
/// <summary>
/// Convenience method to copy stuff from StreamReader to StreamWriter
@ -403,7 +405,7 @@ namespace winsw
var buf = new byte[1024];
var baseDirectory = Path.GetDirectoryName(BaseLogFileName);
var baseDirectory = Path.GetDirectoryName(BaseLogFileName)!;
var baseFileName = Path.GetFileName(BaseLogFileName);
var logFile = BaseLogFileName + extension;
@ -411,10 +413,10 @@ namespace winsw
var sz = 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
if (AutoRollAtTime != null)
if (AutoRollAtTime is TimeSpan autoRollAtTime)
{
// Run at start
var tickTime = SetupRollTimer();
var tickTime = SetupRollTimer(autoRollAtTime);
var timer = new System.Timers.Timer(tickTime);
timer.Elapsed += (s, e) =>
{
@ -444,7 +446,7 @@ namespace winsw
finally
{
// Recalculate the next interval
timer.Interval = SetupRollTimer();
timer.Interval = SetupRollTimer(autoRollAtTime);
timer.Start();
}
};
@ -543,7 +545,7 @@ namespace winsw
#if VNEXT
private void ZipOneFile(string sourceFilePath, string entryName, string zipFilePath)
{
ZipArchive zipArchive = null;
ZipArchive? zipArchive = null;
try
{
zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Update);
@ -565,7 +567,7 @@ namespace winsw
#else
private void ZipOneFile(string sourceFilePath, string entryName, string zipFilePath)
{
ZipFile zipFile = null;
ZipFile? zipFile = null;
try
{
zipFile = new ZipFile(File.Open(zipFilePath, FileMode.OpenOrCreate));
@ -590,11 +592,17 @@ namespace winsw
}
#endif
private double SetupRollTimer()
private double SetupRollTimer(TimeSpan autoRollAtTime)
{
var nowTime = DateTime.Now;
var scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, AutoRollAtTime.Value.Hours,
AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); // Specify your time HH,MM,SS
var scheduledTime = new DateTime(
nowTime.Year,
nowTime.Month,
nowTime.Day,
autoRollAtTime.Hours,
autoRollAtTime.Minutes,
autoRollAtTime.Seconds,
0);
if (nowTime > scheduledTime)
scheduledTime = scheduledTime.AddDays(1);

View File

@ -11,6 +11,6 @@ namespace winsw.Logging
/// Locates Event Log for the service.
/// </summary>
/// <returns>Event Log or null if it is not avilable</returns>
EventLog locate();
EventLog? locate();
}
}

View File

@ -10,16 +10,16 @@ namespace winsw.Logging
/// </summary>
public class ServiceEventLogAppender : AppenderSkeleton
{
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public IServiceEventLogProvider provider { get; set; }
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
override protected void Append(LoggingEvent loggingEvent)
{
EventLog eventLog = provider.locate();
if (eventLog != null)
{
// We write the event iff the provider is ready
eventLog.WriteEntry(loggingEvent.RenderedMessage, toEventLogEntryType(loggingEvent.Level));
}
EventLog? eventLog = provider.locate();
// We write the event iff the provider is ready
eventLog?.WriteEntry(loggingEvent.RenderedMessage, toEventLogEntryType(loggingEvent.Level));
}
private static EventLogEntryType toEventLogEntryType(Level level)

View File

@ -133,7 +133,7 @@ namespace winsw.Native
}
}
private static string GetDomain(string s)
private static string? GetDomain(string s)
{
int stop = s.IndexOf("\\", StringComparison.Ordinal);
if (stop >= 0)
@ -151,7 +151,7 @@ namespace winsw.Native
private static string GetLocalAccountIfLocalAccount(string username)
{
var machinename = Environment.MachineName;
string domain = GetDomain(username);
string? domain = GetDomain(username);
if (domain == null || domain.ToLower() == machinename.ToLower() || domain == ".")
{
return GetLogin(username);
@ -287,7 +287,7 @@ namespace winsw.Native
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_DELAYED_AUTO_START sfa);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
internal static extern IntPtr OpenSCManager(string? machineName, string? databaseName, uint dwAccess);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

View File

@ -13,12 +13,17 @@ namespace winsw.Native
public static extern bool SetStdHandle(int nStdHandle, SafeFileHandle handle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CreateProcess(string lpApplicationName,
string lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandles,
uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
public static extern bool CreateProcess(
string? lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string? lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
public static extern int GetLastError();

View File

@ -0,0 +1,12 @@
#if !NETCOREAPP
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
internal sealed class AllowNullAttribute : Attribute { }
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
internal sealed class MaybeNullAttribute : Attribute { }
}
#endif

View File

@ -1,8 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using winsw.Configuration;
using winsw.Native;
@ -81,7 +81,9 @@ namespace winsw
/// <summary>
/// Loads descriptor from existing DOM
/// </summary>
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public ServiceDescriptor(XmlDocument dom)
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
{
this.dom = dom;
}
@ -96,10 +98,10 @@ namespace winsw
private string SingleElement(string tagName)
{
return SingleElement(tagName, false);
return SingleElement(tagName, false)!;
}
private string SingleElement(string tagName, bool optional)
private string? SingleElement(string tagName, bool optional)
{
var n = dom.SelectSingleNode("//" + tagName);
if (n == null && !optional)
@ -174,7 +176,7 @@ namespace winsw
/// <summary>
/// Optionally specify a different Path to an executable to shutdown the service.
/// </summary>
public string StopExecutable => SingleElement("stopexecutable", true);
public string? StopExecutable => SingleElement("stopexecutable", true);
/// <summary>
/// Arguments or multiple optional argument elements which overrule the arguments element.
@ -183,7 +185,7 @@ namespace winsw
{
get
{
string arguments = AppendTags("argument", null);
string? arguments = AppendTags("argument", null);
if (arguments == null)
{
@ -206,19 +208,19 @@ namespace winsw
/// <summary>
/// Multiple optional startargument elements.
/// </summary>
public string Startarguments => AppendTags("startargument", Defaults.Startarguments);
public string? Startarguments => AppendTags("startargument", Defaults.Startarguments);
/// <summary>
/// Multiple optional stopargument elements.
/// </summary>
public string Stoparguments => AppendTags("stopargument", Defaults.Stoparguments);
public string? Stoparguments => AppendTags("stopargument", Defaults.Stoparguments);
public string WorkingDirectory
{
get
{
var wd = SingleElement("workingdirectory", true);
return string.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd;
return string.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd!;
}
}
@ -226,65 +228,65 @@ namespace winsw
{
get
{
List<string> res = new List<string>();
XmlNode argumentNode = ExtensionsConfiguration;
XmlNodeList extensions = argumentNode?.SelectNodes("extension");
if (extensions != null)
XmlNode? argumentNode = ExtensionsConfiguration;
XmlNodeList? extensions = argumentNode?.SelectNodes("extension");
if (extensions == null)
{
foreach (XmlNode e in extensions)
{
XmlElement extension = (XmlElement)e;
string extensionId = XmlHelper.SingleAttribute<string>(extension, "id");
res.Add(extensionId);
}
return new List<string>(0);
}
return res;
List<string> result = new List<string>(extensions.Count);
for (int i = 0; i < extensions.Count; i++)
{
result.Add(XmlHelper.SingleAttribute<string>((XmlElement)extensions[i], "id"));
}
return result;
}
}
public XmlNode ExtensionsConfiguration => dom.SelectSingleNode("//extensions");
public XmlNode? ExtensionsConfiguration => dom.SelectSingleNode("//extensions");
/// <summary>
/// Combines the contents of all the elements of the given name,
/// or return null if no element exists. Handles whitespace quotation.
/// </summary>
private string AppendTags(string tagName, string defaultValue = null)
private string? AppendTags(string tagName, string? defaultValue = null)
{
XmlNode argumentNode = dom.SelectSingleNode("//" + tagName);
XmlNode? argumentNode = dom.SelectSingleNode("//" + tagName);
if (argumentNode == null)
{
return defaultValue;
}
else
StringBuilder arguments = new StringBuilder();
XmlNodeList argumentNodeList = dom.SelectNodes("//" + tagName);
for (int i = 0; i < argumentNodeList.Count; i++)
{
string arguments = string.Empty;
arguments.Append(' ');
foreach (XmlElement argument in dom.SelectNodes("//" + tagName))
string token = Environment.ExpandEnvironmentVariables(argumentNodeList[i].InnerText);
if (token.StartsWith("\"") && token.EndsWith("\""))
{
string token = Environment.ExpandEnvironmentVariables(argument.InnerText);
if (token.StartsWith("\"") && token.EndsWith("\""))
// for backward compatibility, if the argument is already quoted, leave it as is.
// in earlier versions we didn't handle quotation, so the user might have worked
// around it by themselves
}
else
{
if (token.Contains(" "))
{
// for backward compatibility, if the argument is already quoted, leave it as is.
// in earlier versions we didn't handle quotation, so the user might have worked
// around it by themselves
arguments.Append('"').Append(token).Append('"');
continue;
}
else
{
if (token.Contains(" "))
{
token = '"' + token + '"';
}
}
arguments += " " + token;
}
return arguments;
arguments.Append(token);
}
return arguments.ToString();
}
/// <summary>
@ -311,7 +313,7 @@ namespace winsw
{
get
{
string mode = null;
string? mode = null;
// first, backward compatibility with older configuration
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
@ -469,19 +471,19 @@ namespace winsw
{
get
{
var xmlNodeList = dom.SelectNodes("//depend");
if (xmlNodeList != null)
XmlNodeList? nodeList = dom.SelectNodes("//depend");
if (nodeList == null)
{
ArrayList serviceDependencies = new ArrayList();
foreach (XmlNode depend in xmlNodeList)
{
serviceDependencies.Add(depend.InnerText);
}
return (string[])serviceDependencies.ToArray(typeof(string));
return Defaults.ServiceDependencies;
}
return Defaults.ServiceDependencies;
string[] serviceDependencies = new string[nodeList.Count];
for (int i = 0; i < nodeList.Count; i++)
{
serviceDependencies[i] = nodeList[i].InnerText;
}
return serviceDependencies;
}
}
@ -558,10 +560,12 @@ namespace winsw
get
{
Dictionary<string, string> map = new Dictionary<string, string>();
foreach (XmlNode n in dom.SelectNodes("//env"))
XmlNodeList nodeList = dom.SelectNodes("//env");
for (int i = 0; i < nodeList.Count; i++)
{
string key = n.Attributes["name"].Value;
string value = Environment.ExpandEnvironmentVariables(n.Attributes["value"].Value);
XmlNode node = nodeList[i];
string key = node.Attributes["name"].Value;
string value = Environment.ExpandEnvironmentVariables(node.Attributes["value"].Value);
map[key] = value;
Environment.SetEnvironmentVariable(key, value);
@ -579,22 +583,22 @@ namespace winsw
{
get
{
var xmlNodeList = dom.SelectNodes("//download");
if (xmlNodeList == null)
XmlNodeList? nodeList = dom.SelectNodes("//download");
if (nodeList == null)
{
return Defaults.Downloads;
}
List<Download> r = new List<Download>();
foreach (XmlNode n in xmlNodeList)
List<Download> result = new List<Download>(nodeList.Count);
for (int i = 0; i < nodeList.Count; i++)
{
if (n is XmlElement el)
if (nodeList[i] is XmlElement element)
{
r.Add(new Download(el));
result.Add(new Download(element));
}
}
return r;
return result;
}
}
@ -602,41 +606,35 @@ namespace winsw
{
get
{
List<SC_ACTION> r = new List<SC_ACTION>();
var childNodes = dom.SelectNodes("//onfailure");
if (childNodes != null)
XmlNodeList? childNodes = dom.SelectNodes("//onfailure");
if (childNodes == null)
{
foreach (XmlNode n in childNodes)
{
SC_ACTION_TYPE type;
string action = n.Attributes["action"].Value;
switch (action)
{
case "restart":
type = SC_ACTION_TYPE.SC_ACTION_RESTART;
break;
case "none":
type = SC_ACTION_TYPE.SC_ACTION_NONE;
break;
case "reboot":
type = SC_ACTION_TYPE.SC_ACTION_REBOOT;
break;
default:
throw new Exception("Invalid failure action: " + action);
}
XmlAttribute delay = n.Attributes["delay"];
r.Add(new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero));
}
return new List<SC_ACTION>(0);
}
return r;
List<SC_ACTION> result = new List<SC_ACTION>(childNodes.Count);
for (int i = 0; i < childNodes.Count; i++)
{
XmlNode node = childNodes[i];
string action = node.Attributes["action"].Value;
SC_ACTION_TYPE type = action switch
{
"restart" => SC_ACTION_TYPE.SC_ACTION_RESTART,
"none" => SC_ACTION_TYPE.SC_ACTION_NONE,
"reboot" => SC_ACTION_TYPE.SC_ACTION_REBOOT,
_ => throw new Exception("Invalid failure action: " + action)
};
XmlAttribute? delay = node.Attributes["delay"];
result.Add(new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero));
}
return result;
}
}
public TimeSpan ResetFailureAfter => SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter);
protected string GetServiceAccountPart(string subNodeName)
protected string? GetServiceAccountPart(string subNodeName)
{
var node = dom.SelectSingleNode("//serviceaccount");
@ -652,15 +650,15 @@ namespace winsw
return null;
}
protected string AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
protected string? AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
// ReSharper disable once InconsistentNaming
protected string serviceAccountDomain => GetServiceAccountPart("domain");
protected string? serviceAccountDomain => GetServiceAccountPart("domain");
// ReSharper disable once InconsistentNaming
protected string serviceAccountName => GetServiceAccountPart("user");
protected string? serviceAccountName => GetServiceAccountPart("user");
public string ServiceAccountPassword => GetServiceAccountPart("password");
public string? ServiceAccountPassword => GetServiceAccountPart("password");
public string ServiceAccountUser => (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL");

View File

@ -131,8 +131,17 @@ namespace winsw.Util
/// <param name="callback">Completion callback. If null, the completion won't be monitored</param>
/// <param name="logHandler">Log handler. If enabled, logs will be redirected to the process and then reported</param>
/// <param name="redirectStdin">Redirect standard input</param>
public static void StartProcessAndCallbackForExit(Process processToStart, string executable = null, string arguments = null, Dictionary<string, string> envVars = null,
string workingDirectory = null, ProcessPriorityClass? priority = null, ProcessCompletionCallback callback = null, bool redirectStdin = true, LogHandler logHandler = null, bool hideWindow = false)
public static void StartProcessAndCallbackForExit(
Process processToStart,
string? executable = null,
string? arguments = null,
Dictionary<string, string>? envVars = null,
string? workingDirectory = null,
ProcessPriorityClass? priority = null,
ProcessCompletionCallback? callback = null,
bool redirectStdin = true,
LogHandler? logHandler = null,
bool hideWindow = false)
{
var ps = processToStart.StartInfo;
ps.FileName = executable ?? ps.FileName;

View File

@ -19,7 +19,7 @@ namespace winsw.Util
private static extern bool FreeConsole();
[DllImport(KERNEL32)]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate? HandlerRoutine, bool Add);
// Delegate type to be used as the Handler Routine for SCCH
private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml;
@ -11,10 +12,10 @@ namespace winsw.Util
/// </summary>
/// <param name="node">Parent node</param>
/// <param name="tagName">Element name</param>
/// <param name="optional">If optional, don't throw an exception if the elemen is missing</param>
/// <param name="optional">If optional, don't throw an exception if the element is missing</param>
/// <returns>String value or null</returns>
/// <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)
{
var n = node.SelectSingleNode(tagName);
if (n == null && !optional)
@ -28,10 +29,10 @@ namespace winsw.Util
/// </summary>
/// <param name="node">Parent node</param>
/// <param name="tagName">Element name</param>
/// <param name="optional">If otional, don't throw an exception if the elemen is missing</param>
/// <param name="optional">If otional, don't throw an exception if the element is missing</param>
/// <returns>String value or null</returns>
/// <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)
{
var n = node.SelectSingleNode(tagName);
if (n == null && !optional)
@ -54,7 +55,7 @@ namespace winsw.Util
throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML");
}
return SingleAttribute(node, attributeName, default(TAttributeType));
return SingleAttribute<TAttributeType>(node, attributeName, default);
}
/// <summary>
@ -64,7 +65,8 @@ namespace winsw.Util
/// <param name="attributeName">Attribute name</param>
/// <param name="defaultValue">Default value</param>
/// <returns>Attribute value (or default)</returns>
public static TAttributeType SingleAttribute<TAttributeType>(XmlElement node, string attributeName, TAttributeType defaultValue)
[return: MaybeNull]
public static TAttributeType SingleAttribute<TAttributeType>(XmlElement node, string attributeName, [AllowNull] TAttributeType defaultValue)
{
if (!node.HasAttribute(attributeName))
return defaultValue;

View File

@ -2,6 +2,8 @@
<PropertyGroup>
<TargetFrameworks>net20;net40;net461;netcoreapp3.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Version><!-- Populated by AppVeyor --></Version>
<RootNamespace>winsw</RootNamespace>
<SignAssembly>true</SignAssembly>

View File

@ -89,17 +89,19 @@ namespace WMI
public WmiRoot() : this(null) { }
public WmiRoot(string machineName)
public WmiRoot(string? machineName)
{
ConnectionOptions options = new ConnectionOptions();
options.EnablePrivileges = true;
options.Impersonation = ImpersonationLevel.Impersonate;
options.Authentication = AuthenticationLevel.PacketPrivacy;
ConnectionOptions options = new ConnectionOptions
{
EnablePrivileges = true,
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.PacketPrivacy,
};
string path;
if (machineName != null)
path = string.Format(@"\\{0}\root\cimv2", machineName);
path = $@"\\{machineName}\root\cimv2";
else
path = @"\root\cimv2";
scope = new ManagementScope(path, options);
@ -113,7 +115,7 @@ namespace WMI
abstract class BaseHandler : IProxyInvocationHandler
{
public abstract object Invoke(object proxy, MethodInfo method, object[] args);
public abstract object? Invoke(object proxy, MethodInfo method, object[] args);
protected void CheckError(ManagementBaseObject result)
{
@ -127,9 +129,9 @@ namespace WMI
{
private readonly ManagementObject _mo;
public InstanceHandler(ManagementObject o) { _mo = o; }
public InstanceHandler(ManagementObject o) => _mo = o;
public override object Invoke(object proxy, MethodInfo method, object[] args)
public override object? Invoke(object proxy, MethodInfo method, object[] args)
{
if (method.DeclaringType == typeof(IWmiObject))
{
@ -153,7 +155,7 @@ namespace WMI
ManagementBaseObject wmiArgs = _mo.GetMethodParameters(method.Name);
for (int i = 0; i < args.Length; i++)
wmiArgs[Capitalize(methodArgs[i].Name)] = args[i];
wmiArgs[Capitalize(methodArgs[i].Name!)] = args[i];
CheckError(_mo.InvokeMethod(method.Name, wmiArgs, null));
return null;
@ -172,7 +174,7 @@ namespace WMI
public ClassHandler(ManagementClass mc, string wmiClass) { _mc = mc; _wmiClass = wmiClass; }
public override object Invoke(object proxy, MethodInfo method, object[] args)
public override object? Invoke(object proxy, MethodInfo method, object[] args)
{
ParameterInfo[] methodArgs = method.GetParameters();
@ -185,7 +187,7 @@ namespace WMI
if (i != 0)
query += " AND ";
query += ' ' + Capitalize(methodArgs[i].Name) + " = '" + args[i] + "'";
query += ' ' + Capitalize(methodArgs[i].Name!) + " = '" + args[i] + "'";
}
ManagementObjectSearcher searcher = new ManagementObjectSearcher(_mc.Scope, new ObjectQuery(query));
@ -198,7 +200,7 @@ namespace WMI
ManagementBaseObject wmiArgs = _mc.GetMethodParameters(method.Name);
for (int i = 0; i < args.Length; i++)
wmiArgs[Capitalize(methodArgs[i].Name)] = args[i];
wmiArgs[Capitalize(methodArgs[i].Name!)] = args[i];
CheckError(_mc.InvokeMethod(method.Name, wmiArgs, null));
return null;

View File

@ -48,7 +48,7 @@ namespace WMI
public interface Win32Services : IWmiCollection
{
// ReturnValue Create(bool desktopInteract, string displayName, int errorControl, string loadOrderGroup, string loadOrderGroupDependencies, string name, string pathName, string serviceDependencies, string serviceType, string startMode, string startName, string startPassword);
void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, StartMode startMode, bool desktopInteract, string startName, string startPassword, string[] serviceDependencies);
void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, StartMode startMode, bool desktopInteract, string? startName, string? startPassword, string[] serviceDependencies);
void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, StartMode startMode, bool desktopInteract, string[] serviceDependencies);

View File

@ -2,6 +2,8 @@
<PropertyGroup>
<TargetFrameworks>net20;net40;net461;netcoreapp3.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Version><!-- Populated by AppVeyor --></Version>
<RootNamespace>winsw.Plugins.RunawayProcessKiller</RootNamespace>
<SignAssembly>true</SignAssembly>

View File

@ -40,12 +40,16 @@ namespace winsw.Plugins.RunawayProcessKiller
private static readonly ILog Logger = LogManager.GetLogger(typeof(RunawayProcessKillerExtension));
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public RunawayProcessKillerExtension()
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
{
// Default initializer
}
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public RunawayProcessKillerExtension(string pidfile, int stopTimeoutMs = 5000, bool stopParentFirst = false, bool checkWinSWEnvironmentVariable = true)
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
{
this.Pidfile = pidfile;
this.StopTimeout = TimeSpan.FromMilliseconds(stopTimeoutMs);
@ -57,9 +61,9 @@ namespace winsw.Plugins.RunawayProcessKiller
{
// We expect the upper logic to process any errors
// TODO: a better parser API for types would be useful
Pidfile = XmlHelper.SingleElement(node, "pidfile", false);
StopTimeout = TimeSpan.FromMilliseconds(int.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)));
StopParentProcessFirst = bool.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false));
Pidfile = XmlHelper.SingleElement(node, "pidfile", false)!;
StopTimeout = TimeSpan.FromMilliseconds(int.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)!));
StopParentProcessFirst = bool.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false)!);
ServiceId = descriptor.Id;
// TODO: Consider making it documented
var checkWinSWEnvironmentVariable = XmlHelper.SingleElement(node, "checkWinSWEnvironmentVariable", true);
@ -117,7 +121,7 @@ namespace winsw.Plugins.RunawayProcessKiller
}
// Ensure the process references the service
string affiliatedServiceId;
string? affiliatedServiceId;
// TODO: This method is not ideal since it works only for vars explicitly mentioned in the start info
// No Windows 10- compatible solution for EnvVars retrieval, see https://blog.gapotchenko.com/eazfuscator.net/reading-environment-variables
StringDictionary previousProcessEnvVars = proc.StartInfo.EnvironmentVariables;

View File

@ -28,12 +28,12 @@ namespace winsw.Plugins.SharedDirectoryMapper
public override void Configure(ServiceDescriptor descriptor, XmlNode node)
{
var nodes = XmlHelper.SingleNode(node, "mapping", false).SelectNodes("map");
if (nodes != null)
var mapNodes = XmlHelper.SingleNode(node, "mapping", false)!.SelectNodes("map");
if (mapNodes != null)
{
foreach (XmlNode mapNode in nodes)
for (int i = 0; i < mapNodes.Count; i++)
{
if (mapNode is XmlElement mapElement)
if (mapNodes[i] is XmlElement mapElement)
{
var config = SharedDirectoryMapperConfig.FromXml(mapElement);
_entries.Add(config);

View File

@ -2,6 +2,8 @@
<PropertyGroup>
<TargetFrameworks>net20;net40;net461;netcoreapp3.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Version><!-- Populated by AppVeyor --></Version>
<RootNamespace>winsw.Plugins.SharedDirectoryMapper</RootNamespace>
<SignAssembly>true</SignAssembly>