Annotate WinSWCore for nullable reference types

pull/356/head
NextTurn 2018-12-05 00:00:00 +08:00
parent d10f3b8ccf
commit 5be8708701
No known key found for this signature in database
GPG Key ID: 17A0D50ADDE1A0C4
19 changed files with 298 additions and 290 deletions

View File

@ -402,7 +402,7 @@ namespace winsw
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 // Define handler of the completed process
ProcessCompletionCallback processCompletionCallback = proc => void OnProcessCompleted(Process proc)
{ {
string msg = processToStart.Id + " - " + processToStart.StartInfo.FileName + " " + processToStart.StartInfo.Arguments; string msg = processToStart.Id + " - " + processToStart.StartInfo.FileName + " " + processToStart.StartInfo.Arguments;
try try
@ -427,16 +427,11 @@ namespace winsw
{ {
LogEvent("WaitForExit " + ioe.Message); LogEvent("WaitForExit " + ioe.Message);
} }
finally
try
{ {
proc.Dispose(); proc.Dispose();
} }
catch (InvalidOperationException ioe)
{
LogEvent("Dispose " + ioe.Message);
} }
};
// Invoke process and exit // Invoke process and exit
ProcessHelper.StartProcessAndCallbackForExit( ProcessHelper.StartProcessAndCallbackForExit(
@ -446,7 +441,7 @@ namespace winsw
envVars: _envs, envVars: _envs,
workingDirectory: _descriptor.WorkingDirectory, workingDirectory: _descriptor.WorkingDirectory,
priority: _descriptor.Priority, priority: _descriptor.Priority,
callback: processCompletionCallback, callback: OnProcessCompleted,
logHandler: logHandler, logHandler: logHandler,
redirectStdin: redirectStdin, redirectStdin: redirectStdin,
hideWindow: _descriptor.HideWindow); hideWindow: _descriptor.HideWindow);
@ -712,8 +707,7 @@ namespace winsw
// run restart from another process group. see README.md for why this is useful. // run restart from another process group. see README.md for why this is useful.
STARTUPINFO si = default; 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 _);
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);
if (!result) if (!result)
{ {
throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error()); throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
@ -731,6 +725,7 @@ namespace winsw
Console.WriteLine("Started"); Console.WriteLine("Started");
else else
Console.WriteLine("Stopped"); Console.WriteLine("Stopped");
return; return;
} }

View File

@ -19,30 +19,23 @@ namespace winsw.Configuration
public string Executable => null; public string Executable => null;
public bool HideWindow => false; public bool HideWindow => false;
public string ExecutablePath
{
get
{
// this returns the executable name as given by the calling process, so // this returns the executable name as given by the calling process, so
// it needs to be absolutized. // it needs to be absolutized.
string p = Environment.GetCommandLineArgs()[0]; public string ExecutablePath => Path.GetFullPath(Environment.GetCommandLineArgs()[0]);
return Path.GetFullPath(p);
}
}
// Installation // Installation
public bool AllowServiceAcountLogonRight => false; public bool AllowServiceAcountLogonRight => false;
public string ServiceAccountPassword => null; public string? ServiceAccountPassword => null;
public string ServiceAccountUser => "NULL\\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>();
public TimeSpan ResetFailureAfter => TimeSpan.FromDays(1); public TimeSpan ResetFailureAfter => TimeSpan.FromDays(1);
// Executable management // Executable management
public string Arguments => string.Empty; public string Arguments => string.Empty;
public string Startarguments => null; public string? Startarguments => null;
public string StopExecutable => null; public string? StopExecutable => null;
public string Stoparguments => null; public string? Stoparguments => null;
public string WorkingDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); public string WorkingDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
public ProcessPriorityClass Priority => ProcessPriorityClass.Normal; public ProcessPriorityClass Priority => ProcessPriorityClass.Normal;
public TimeSpan StopTimeout => TimeSpan.FromSeconds(15); public TimeSpan StopTimeout => TimeSpan.FromSeconds(15);
public bool StopParentProcessFirst => false; public bool StopParentProcessFirst => false;
@ -56,7 +49,7 @@ namespace winsw.Configuration
public bool Interactive => false; public bool Interactive => false;
// Logging // Logging
public string LogDirectory => Path.GetDirectoryName(ExecutablePath); public string LogDirectory => Path.GetDirectoryName(ExecutablePath)!;
public string LogMode => "append"; public string LogMode => "append";
public bool OutFileDisabled => false; public bool OutFileDisabled => false;
@ -72,6 +65,6 @@ namespace winsw.Configuration
public bool BeepOnShutdown => false; public bool BeepOnShutdown => false;
// Extensions // Extensions
public XmlNode ExtensionsConfiguration => null; public XmlNode? ExtensionsConfiguration => null;
} }
} }

View File

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

View File

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

View File

@ -1,5 +1,5 @@
using System; using System;
using System.Collections; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; 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="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> /// <param name="parameters">Parameters to pass to the method</param>
/// <returns>Object</returns> /// <returns>Object</returns>
object Invoke(object proxy, MethodInfo method, object[] parameters); object? Invoke(object proxy, MethodInfo method, object[] parameters);
} }
/// <summary> /// <summary>
@ -23,7 +23,7 @@ namespace DynamicProxy
/// </summary> /// </summary>
public class MetaDataFactory public class MetaDataFactory
{ {
private static Hashtable typeMap = new Hashtable(); private static readonly Dictionary<string, Type> typeMap = new Dictionary<string, Type>();
/// <summary> /// <summary>
/// Class constructor. Private because this is a static class. /// Class constructor. Private because this is a static class.
@ -41,12 +41,16 @@ namespace DynamicProxy
{ {
if (interfaceType != null) 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> ///<returns>MethodInfo</returns>
public static MethodInfo GetMethod(string name, int i) public static MethodInfo GetMethod(string name, int i)
{ {
Type type = null; Type? type = null;
lock (typeMap.SyncRoot) lock (typeMap)
{ {
type = (Type)typeMap[name]; type = typeMap[name];
} }
return type.GetMethods()[i]; return type.GetMethods()[i];
@ -70,10 +74,10 @@ namespace DynamicProxy
public static PropertyInfo GetProperty(string name, int i) public static PropertyInfo GetProperty(string name, int i)
{ {
Type type = null; Type? type = null;
lock (typeMap.SyncRoot) lock (typeMap)
{ {
type = (Type)typeMap[name]; type = typeMap[name];
} }
return type.GetProperties()[i]; return type.GetProperties()[i];
@ -84,30 +88,27 @@ namespace DynamicProxy
/// </summary> /// </summary>
public class ProxyFactory public class ProxyFactory
{ {
private static ProxyFactory _instance; private static ProxyFactory? _instance;
private static readonly object LockObj = new object(); private static readonly object LockObj = new object();
private readonly Hashtable _typeMap = Hashtable.Synchronized(new Hashtable()); private readonly Dictionary<string, Type> _typeMap = new Dictionary<string, Type>();
private static readonly Hashtable OpCodeTypeMapper = new Hashtable();
private const string PROXY_SUFFIX = "Proxy"; private static readonly Dictionary<Type, OpCode> OpCodeTypeMapper = new Dictionary<Type, OpCode>
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()
{ {
OpCodeTypeMapper.Add(typeof(bool), OpCodes.Ldind_I1); { typeof(bool), OpCodes.Ldind_I1 },
OpCodeTypeMapper.Add(typeof(short), OpCodes.Ldind_I2); { typeof(short), OpCodes.Ldind_I2 },
OpCodeTypeMapper.Add(typeof(int), OpCodes.Ldind_I4); { typeof(int), OpCodes.Ldind_I4 },
OpCodeTypeMapper.Add(typeof(long), OpCodes.Ldind_I8); { typeof(long), OpCodes.Ldind_I8 },
OpCodeTypeMapper.Add(typeof(double), OpCodes.Ldind_R8); { typeof(double), OpCodes.Ldind_R8 },
OpCodeTypeMapper.Add(typeof(float), OpCodes.Ldind_R4); { typeof(float), OpCodes.Ldind_R4 },
OpCodeTypeMapper.Add(typeof(ushort), OpCodes.Ldind_U2); { typeof(ushort), OpCodes.Ldind_U2 },
OpCodeTypeMapper.Add(typeof(uint), OpCodes.Ldind_U4); { 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() private ProxyFactory()
{ {
@ -120,24 +121,25 @@ namespace DynamicProxy
CreateInstance(); CreateInstance();
} }
return _instance; return _instance!;
} }
private static void CreateInstance() private static void CreateInstance()
{ {
lock (LockObj) lock (LockObj)
{ {
if (_instance == null) _instance ??= new ProxyFactory();
{
_instance = new ProxyFactory();
}
} }
} }
public object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface) public object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface)
{ {
string typeName = objType.FullName + PROXY_SUFFIX; string typeName = objType.FullName + ProxySuffix;
Type type = (Type)_typeMap[typeName]; 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 // 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. // 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); type = CreateType(handler, objType.GetInterfaces(), typeName);
} }
lock (_typeMap)
{
_typeMap.Add(typeName, type); _typeMap.Add(typeName, type);
} }
}
// return a new instance of the 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) public object Create(IProxyInvocationHandler handler, Type objType)
@ -165,16 +170,12 @@ namespace DynamicProxy
} }
private Type CreateType(IProxyInvocationHandler handler, Type[] interfaces, string dynamicTypeName) private Type CreateType(IProxyInvocationHandler handler, Type[] interfaces, string dynamicTypeName)
{
Type retVal = null;
if (handler != null && interfaces != null)
{ {
Type objType = typeof(object); Type objType = typeof(object);
Type handlerType = typeof(IProxyInvocationHandler); Type handlerType = typeof(IProxyInvocationHandler);
AssemblyName assemblyName = new AssemblyName(); AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = ASSEMBLY_NAME; assemblyName.Name = AssemblyName;
assemblyName.Version = new Version(1, 0, 0, 0); assemblyName.Version = new Version(1, 0, 0, 0);
// create a new assembly for this proxy, one that isn't presisted on the file system // create a new assembly for this proxy, one that isn't presisted on the file system
@ -187,7 +188,7 @@ namespace DynamicProxy
assemblyName, AssemblyBuilderAccess.Run); assemblyName, AssemblyBuilderAccess.Run);
// create a new module for this proxy // create a new module for this proxy
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(MODULE_NAME); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(ModuleName);
// Set the class to be public and sealed // Set the class to be public and sealed
TypeAttributes typeAttributes = TypeAttributes typeAttributes =
@ -200,15 +201,14 @@ namespace DynamicProxy
// Define a member variable to hold the delegate // Define a member variable to hold the delegate
FieldBuilder handlerField = typeBuilder.DefineField( FieldBuilder handlerField = typeBuilder.DefineField(
HANDLER_NAME, handlerType, FieldAttributes.Private); HandlerName, handlerType, FieldAttributes.Private);
// build a constructor that takes the delegate object as the only argument // build a constructor that takes the delegate object as the only argument
// ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] ); ConstructorInfo baseConstructor = objType.GetConstructor(Type.EmptyTypes)!;
ConstructorInfo superConstructor = objType.GetConstructor(new Type[0]);
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor( ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType }); MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
#region( "Constructor IL Code" ) #region( "Constructor IL Code" )
ILGenerator constructorIL = delegateConstructor.GetILGenerator(); ILGenerator constructorIL = delegateConstructor.GetILGenerator();
// Load "this" // Load "this"
@ -220,10 +220,10 @@ namespace DynamicProxy
// Load "this" // Load "this"
constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldarg_0);
// Call the super constructor // Call the super constructor
constructorIL.Emit(OpCodes.Call, superConstructor); constructorIL.Emit(OpCodes.Call, baseConstructor);
// Constructor return // Constructor return
constructorIL.Emit(OpCodes.Ret); constructorIL.Emit(OpCodes.Ret);
#endregion #endregion
// for every method that the interfaces define, build a corresponding // for every method that the interfaces define, build a corresponding
// method in the dynamic type that calls the handlers invoke method. // method in the dynamic type that calls the handlers invoke method.
@ -232,22 +232,17 @@ namespace DynamicProxy
GenerateMethod(interfaceType, handlerField, typeBuilder); GenerateMethod(interfaceType, handlerField, typeBuilder);
} }
retVal = typeBuilder.CreateType(); return typeBuilder.CreateType()!;
// assemblyBuilder.Save(dynamicTypeName + ".dll");
} }
return retVal; 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 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 void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder) private void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
{ {
MetaDataFactory.Add(interfaceType); MetaDataFactory.Add(interfaceType);
MethodInfo[] interfaceMethods = interfaceType.GetMethods(); MethodInfo[] interfaceMethods = interfaceType.GetMethods();
PropertyInfo[] props = interfaceType.GetProperties(); // PropertyInfo[] props = interfaceType.GetProperties();
for (int i = 0; i < interfaceMethods.Length; i++) for (int i = 0; i < interfaceMethods.Length; i++)
{ {
@ -272,7 +267,7 @@ namespace DynamicProxy
CallingConventions.Standard, CallingConventions.Standard,
methodInfo.ReturnType, methodParameters); methodInfo.ReturnType, methodParameters);
#region( "Handler Method IL Code" ) #region( "Handler Method IL Code" )
ILGenerator methodIL = methodBuilder.GetILGenerator(); ILGenerator methodIL = methodBuilder.GetILGenerator();
// load "this" // load "this"
@ -283,7 +278,7 @@ namespace DynamicProxy
methodIL.Emit(OpCodes.Ldarg_0); methodIL.Emit(OpCodes.Ldarg_0);
// load the name of the interface, used to get the MethodInfo object // load the name of the interface, used to get the MethodInfo object
// from MetaDataFactory // from MetaDataFactory
methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName); methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName!);
// load the index, used to get the MethodInfo object // load the index, used to get the MethodInfo object
// from MetaDataFactory // from MetaDataFactory
methodIL.Emit(OpCodes.Ldc_I4, i); methodIL.Emit(OpCodes.Ldc_I4, i);
@ -315,7 +310,7 @@ namespace DynamicProxy
if (methodInfo.ReturnType != typeof(void)) 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. // so that we don't get junk.
if (methodInfo.ReturnType.IsValueType) if (methodInfo.ReturnType.IsValueType)
{ {
@ -330,7 +325,7 @@ namespace DynamicProxy
} }
else else
{ {
methodIL.Emit((OpCode)OpCodeTypeMapper[methodInfo.ReturnType]); methodIL.Emit(OpCodeTypeMapper[methodInfo.ReturnType]);
} }
} }
} }
@ -343,7 +338,7 @@ namespace DynamicProxy
// Return // Return
methodIL.Emit(OpCodes.Ret); methodIL.Emit(OpCodes.Ret);
#endregion #endregion
} }
// for (int i = 0; i < props.Length; i++) // 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 namespace winsw.Extensions
{ {

View File

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

View File

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

View File

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

View File

@ -403,7 +403,7 @@ namespace winsw
var buf = new byte[1024]; var buf = new byte[1024];
var baseDirectory = Path.GetDirectoryName(BaseLogFileName); var baseDirectory = Path.GetDirectoryName(BaseLogFileName)!;
var baseFileName = Path.GetFileName(BaseLogFileName); var baseFileName = Path.GetFileName(BaseLogFileName);
var logFile = BaseLogFileName + extension; var logFile = BaseLogFileName + extension;
@ -411,10 +411,10 @@ namespace winsw
var sz = new FileInfo(logFile).Length; 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 // 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 // Run at start
var tickTime = SetupRollTimer(); var tickTime = SetupRollTimer(autoRollAtTime);
var timer = new System.Timers.Timer(tickTime); var timer = new System.Timers.Timer(tickTime);
timer.Elapsed += (s, e) => timer.Elapsed += (s, e) =>
{ {
@ -444,7 +444,7 @@ namespace winsw
finally finally
{ {
// Recalculate the next interval // Recalculate the next interval
timer.Interval = SetupRollTimer(); timer.Interval = SetupRollTimer(autoRollAtTime);
timer.Start(); timer.Start();
} }
}; };
@ -543,7 +543,7 @@ namespace winsw
#if VNEXT #if VNEXT
private void ZipOneFile(string sourceFilePath, string entryName, string zipFilePath) private void ZipOneFile(string sourceFilePath, string entryName, string zipFilePath)
{ {
ZipArchive zipArchive = null; ZipArchive? zipArchive = null;
try try
{ {
zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Update); zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Update);
@ -565,7 +565,7 @@ namespace winsw
#else #else
private void ZipOneFile(string sourceFilePath, string entryName, string zipFilePath) private void ZipOneFile(string sourceFilePath, string entryName, string zipFilePath)
{ {
ZipFile zipFile = null; ZipFile? zipFile = null;
try try
{ {
zipFile = new ZipFile(File.Open(zipFilePath, FileMode.OpenOrCreate)); zipFile = new ZipFile(File.Open(zipFilePath, FileMode.OpenOrCreate));
@ -590,11 +590,17 @@ namespace winsw
} }
#endif #endif
private double SetupRollTimer() private double SetupRollTimer(TimeSpan autoRollAtTime)
{ {
var nowTime = DateTime.Now; var nowTime = DateTime.Now;
var scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, AutoRollAtTime.Value.Hours, var scheduledTime = new DateTime(
AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); // Specify your time HH,MM,SS nowTime.Year,
nowTime.Month,
nowTime.Day,
autoRollAtTime.Hours,
autoRollAtTime.Minutes,
autoRollAtTime.Seconds,
0);
if (nowTime > scheduledTime) if (nowTime > scheduledTime)
scheduledTime = scheduledTime.AddDays(1); scheduledTime = scheduledTime.AddDays(1);

View File

@ -14,12 +14,10 @@ namespace winsw.Logging
override protected void Append(LoggingEvent loggingEvent) override protected void Append(LoggingEvent loggingEvent)
{ {
EventLog eventLog = provider.locate(); EventLog? eventLog = provider.locate();
if (eventLog != null)
{
// 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));
}
} }
private static EventLogEntryType toEventLogEntryType(Level 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); int stop = s.IndexOf("\\", StringComparison.Ordinal);
if (stop >= 0) if (stop >= 0)
@ -151,7 +151,7 @@ namespace winsw.Native
private static string GetLocalAccountIfLocalAccount(string username) private static string GetLocalAccountIfLocalAccount(string username)
{ {
var machinename = Environment.MachineName; var machinename = Environment.MachineName;
string domain = GetDomain(username); string? domain = GetDomain(username);
if (domain == null || domain.ToLower() == machinename.ToLower() || domain == ".") if (domain == null || domain.ToLower() == machinename.ToLower() || domain == ".")
{ {
return GetLogin(username); 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); 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)] [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)] [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

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;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text;
using System.Xml; using System.Xml;
using winsw.Configuration; using winsw.Configuration;
using winsw.Native; using winsw.Native;
@ -96,10 +96,10 @@ namespace winsw
private string SingleElement(string tagName) 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); var n = dom.SelectSingleNode("//" + tagName);
if (n == null && !optional) if (n == null && !optional)
@ -174,7 +174,7 @@ namespace winsw
/// <summary> /// <summary>
/// Optionally specify a different Path to an executable to shutdown the service. /// Optionally specify a different Path to an executable to shutdown the service.
/// </summary> /// </summary>
public string StopExecutable => SingleElement("stopexecutable", true); public string? StopExecutable => SingleElement("stopexecutable", true);
/// <summary> /// <summary>
/// Arguments or multiple optional argument elements which overrule the arguments element. /// Arguments or multiple optional argument elements which overrule the arguments element.
@ -183,7 +183,7 @@ namespace winsw
{ {
get get
{ {
string arguments = AppendTags("argument", null); string? arguments = AppendTags("argument", null);
if (arguments == null) if (arguments == null)
{ {
@ -206,19 +206,19 @@ namespace winsw
/// <summary> /// <summary>
/// Multiple optional startargument elements. /// Multiple optional startargument elements.
/// </summary> /// </summary>
public string Startarguments => AppendTags("startargument", Defaults.Startarguments); public string? Startarguments => AppendTags("startargument", Defaults.Startarguments);
/// <summary> /// <summary>
/// Multiple optional stopargument elements. /// Multiple optional stopargument elements.
/// </summary> /// </summary>
public string Stoparguments => AppendTags("stopargument", Defaults.Stoparguments); public string? Stoparguments => AppendTags("stopargument", Defaults.Stoparguments);
public string WorkingDirectory public string WorkingDirectory
{ {
get get
{ {
var wd = SingleElement("workingdirectory", true); var wd = SingleElement("workingdirectory", true);
return string.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd; return string.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd!;
} }
} }
@ -226,45 +226,45 @@ namespace winsw
{ {
get get
{ {
List<string> res = new List<string>(); XmlNode? argumentNode = ExtensionsConfiguration;
XmlNodeList? extensions = argumentNode?.SelectNodes("extension");
XmlNode argumentNode = ExtensionsConfiguration; if (extensions == null)
XmlNodeList extensions = argumentNode?.SelectNodes("extension");
if (extensions != null)
{ {
foreach (XmlNode e in extensions) return new List<string>(0);
}
List<string> result = new List<string>(extensions.Count);
for (int i = 0; i < extensions.Count; i++)
{ {
XmlElement extension = (XmlElement)e; result.Add(XmlHelper.SingleAttribute<string>((XmlElement)extensions[i], "id"));
string extensionId = XmlHelper.SingleAttribute<string>(extension, "id"); }
res.Add(extensionId);
return result;
} }
} }
return res; public XmlNode? ExtensionsConfiguration => dom.SelectSingleNode("//extensions");
}
}
public XmlNode ExtensionsConfiguration => dom.SelectSingleNode("//extensions");
/// <summary> /// <summary>
/// Combines the contents of all the elements of the given name, /// Combines the contents of all the elements of the given name,
/// or return null if no element exists. Handles whitespace quotation. /// or return null if no element exists. Handles whitespace quotation.
/// </summary> /// </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) if (argumentNode == null)
{ {
return defaultValue; return defaultValue;
} }
else
{
string arguments = string.Empty;
foreach (XmlElement argument in dom.SelectNodes("//" + tagName)) StringBuilder arguments = new StringBuilder();
XmlNodeList argumentNodeList = dom.SelectNodes("//" + tagName);
for (int i = 0; i < argumentNodeList.Count; i++)
{ {
string token = Environment.ExpandEnvironmentVariables(argument.InnerText); arguments.Append(' ');
string token = Environment.ExpandEnvironmentVariables(argumentNodeList[i].InnerText);
if (token.StartsWith("\"") && token.EndsWith("\"")) if (token.StartsWith("\"") && token.EndsWith("\""))
{ {
@ -276,15 +276,15 @@ namespace winsw
{ {
if (token.Contains(" ")) if (token.Contains(" "))
{ {
token = '"' + token + '"'; arguments.Append('"').Append(token).Append('"');
continue;
} }
} }
arguments += " " + token; arguments.Append(token);
} }
return arguments; return arguments.ToString();
}
} }
/// <summary> /// <summary>
@ -311,7 +311,7 @@ namespace winsw
{ {
get get
{ {
string mode = null; string? mode = null;
// first, backward compatibility with older configuration // first, backward compatibility with older configuration
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode"); XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
@ -469,20 +469,20 @@ namespace winsw
{ {
get get
{ {
var xmlNodeList = dom.SelectNodes("//depend"); XmlNodeList? nodeList = dom.SelectNodes("//depend");
if (xmlNodeList != null) 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;
}
} }
public string Id => SingleElement("id"); public string Id => SingleElement("id");
@ -558,10 +558,12 @@ namespace winsw
get get
{ {
Dictionary<string, string> map = new Dictionary<string, string>(); 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; XmlNode node = nodeList[i];
string value = Environment.ExpandEnvironmentVariables(n.Attributes["value"].Value); string key = node.Attributes["name"].Value;
string value = Environment.ExpandEnvironmentVariables(node.Attributes["value"].Value);
map[key] = value; map[key] = value;
Environment.SetEnvironmentVariable(key, value); Environment.SetEnvironmentVariable(key, value);
@ -579,22 +581,22 @@ namespace winsw
{ {
get get
{ {
var xmlNodeList = dom.SelectNodes("//download"); XmlNodeList? nodeList = dom.SelectNodes("//download");
if (xmlNodeList == null) if (nodeList == null)
{ {
return Defaults.Downloads; return Defaults.Downloads;
} }
List<Download> r = new List<Download>(); List<Download> result = new List<Download>(nodeList.Count);
foreach (XmlNode n in xmlNodeList) 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 +604,35 @@ namespace winsw
{ {
get get
{ {
List<SC_ACTION> r = new List<SC_ACTION>(); XmlNodeList? childNodes = dom.SelectNodes("//onfailure");
var childNodes = dom.SelectNodes("//onfailure"); if (childNodes == null)
if (childNodes != null)
{ {
foreach (XmlNode n in childNodes) return new List<SC_ACTION>(0);
{
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"]; List<SC_ACTION> result = new List<SC_ACTION>(childNodes.Count);
r.Add(new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero)); 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 r; return result;
} }
} }
public TimeSpan ResetFailureAfter => SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter); public TimeSpan ResetFailureAfter => SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter);
protected string GetServiceAccountPart(string subNodeName) protected string? GetServiceAccountPart(string subNodeName)
{ {
var node = dom.SelectSingleNode("//serviceaccount"); var node = dom.SelectSingleNode("//serviceaccount");
@ -652,15 +648,15 @@ namespace winsw
return null; return null;
} }
protected string AllowServiceLogon => GetServiceAccountPart("allowservicelogon"); protected string? AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
protected string serviceAccountDomain => GetServiceAccountPart("domain"); protected string? serviceAccountDomain => GetServiceAccountPart("domain");
// ReSharper disable once InconsistentNaming // 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"); 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="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="logHandler">Log handler. If enabled, logs will be redirected to the process and then reported</param>
/// <param name="redirectStdin">Redirect standard input</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, public static void StartProcessAndCallbackForExit(
string workingDirectory = null, ProcessPriorityClass? priority = null, ProcessCompletionCallback callback = null, bool redirectStdin = true, LogHandler logHandler = null, bool hideWindow = false) 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; var ps = processToStart.StartInfo;
ps.FileName = executable ?? ps.FileName; ps.FileName = executable ?? ps.FileName;

View File

@ -19,7 +19,7 @@ namespace winsw.Util
private static extern bool FreeConsole(); private static extern bool FreeConsole();
[DllImport(KERNEL32)] [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 // Delegate type to be used as the Handler Routine for SCCH
private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType); private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);

View File

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

View File

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

View File

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