mirror of https://github.com/winsw/winsw
Fix file permission and line ending issues
parent
139c98403b
commit
7554d0ecbd
|
@ -1,280 +1,280 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
#if !VNEXT
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using System.Text;
|
||||
#if VNEXT
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using WinSW.Util;
|
||||
|
||||
namespace WinSW
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify the download activities prior to the launch.
|
||||
/// This enables self-updating services.
|
||||
/// </summary>
|
||||
public class Download
|
||||
{
|
||||
public enum AuthType
|
||||
{
|
||||
None = 0,
|
||||
Sspi,
|
||||
Basic
|
||||
}
|
||||
|
||||
private static readonly ILog Logger = LogManager.GetLogger(typeof(Download));
|
||||
|
||||
public readonly string From;
|
||||
public readonly string To;
|
||||
public readonly AuthType Auth;
|
||||
public readonly string? Username;
|
||||
public readonly string? Password;
|
||||
public readonly bool UnsecureAuth;
|
||||
public readonly bool FailOnError;
|
||||
public readonly string? Proxy;
|
||||
|
||||
public string ShortId => $"(download from {this.From})";
|
||||
|
||||
static Download()
|
||||
{
|
||||
#if NET461
|
||||
// If your app runs on .NET Framework 4.7 or later versions, but targets an earlier version
|
||||
AppContext.SetSwitch("Switch.System.Net.DontEnableSystemDefaultTlsVersions", false);
|
||||
#elif !VNEXT
|
||||
// If your app runs on .NET Framework 4.6, but targets an earlier version
|
||||
Type.GetType("System.AppContext")?.InvokeMember("SetSwitch", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { "Switch.System.Net.DontEnableSchUseStrongCrypto", false });
|
||||
|
||||
const SecurityProtocolType Tls12 = (SecurityProtocolType)0x00000C00;
|
||||
const SecurityProtocolType Tls11 = (SecurityProtocolType)0x00000300;
|
||||
|
||||
// Windows 7 and Windows Server 2008 R2
|
||||
if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
ServicePointManager.SecurityProtocol |= Tls11 | Tls12;
|
||||
Logger.Info("TLS 1.1/1.2 enabled");
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
Logger.Info("TLS 1.1/1.2 disabled");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// internal
|
||||
public Download(
|
||||
string from,
|
||||
string to,
|
||||
bool failOnError = false,
|
||||
AuthType auth = AuthType.None,
|
||||
string? username = null,
|
||||
string? password = null,
|
||||
bool unsecureAuth = false,
|
||||
string? proxy = null)
|
||||
{
|
||||
this.From = from;
|
||||
this.To = to;
|
||||
this.FailOnError = failOnError;
|
||||
this.Proxy = proxy;
|
||||
this.Auth = auth;
|
||||
this.Username = username;
|
||||
this.Password = password;
|
||||
this.UnsecureAuth = unsecureAuth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the download setting sfrom the XML entry
|
||||
/// </summary>
|
||||
/// <param name="n">XML element</param>
|
||||
/// <exception cref="InvalidDataException">The required attribute is missing or the configuration is invalid.</exception>
|
||||
internal Download(XmlElement n)
|
||||
{
|
||||
this.From = XmlHelper.SingleAttribute<string>(n, "from");
|
||||
this.To = XmlHelper.SingleAttribute<string>(n, "to");
|
||||
|
||||
// All arguments below are optional
|
||||
this.FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false);
|
||||
this.Proxy = XmlHelper.SingleAttribute<string>(n, "proxy", null);
|
||||
|
||||
this.Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.None);
|
||||
this.Username = XmlHelper.SingleAttribute<string>(n, "user", null);
|
||||
this.Password = XmlHelper.SingleAttribute<string>(n, "password", null);
|
||||
this.UnsecureAuth = XmlHelper.SingleAttribute(n, "unsecureAuth", false);
|
||||
|
||||
if (this.Auth == AuthType.Basic)
|
||||
{
|
||||
// Allow it only for HTTPS or for UnsecureAuth
|
||||
if (!this.From.StartsWith("https:") && !this.UnsecureAuth)
|
||||
{
|
||||
throw new InvalidDataException("Warning: you're sending your credentials in clear text to the server " + this.ShortId +
|
||||
"If you really want this you must enable 'unsecureAuth' in the configuration");
|
||||
}
|
||||
|
||||
// Also fail if there is no user/password
|
||||
if (this.Username is null)
|
||||
{
|
||||
throw new InvalidDataException("Basic Auth is enabled, but username is not specified " + this.ShortId);
|
||||
}
|
||||
|
||||
if (this.Password is null)
|
||||
{
|
||||
throw new InvalidDataException("Basic Auth is enabled, but password is not specified " + this.ShortId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Source: http://stackoverflow.com/questions/2764577/forcing-basic-authentication-in-webrequest
|
||||
private void SetBasicAuthHeader(WebRequest request, string username, string password)
|
||||
{
|
||||
string authInfo = username + ":" + password;
|
||||
authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo));
|
||||
request.Headers["Authorization"] = "Basic " + authInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the requested file and puts it to the specified target.
|
||||
/// </summary>
|
||||
/// <exception cref="WebException">
|
||||
/// Download failure. FailOnError flag should be processed outside.
|
||||
/// </exception>
|
||||
#if VNEXT
|
||||
public async Task PerformAsync()
|
||||
#else
|
||||
public void Perform()
|
||||
#endif
|
||||
{
|
||||
WebRequest request = WebRequest.Create(this.From);
|
||||
if (!string.IsNullOrEmpty(this.Proxy))
|
||||
{
|
||||
CustomProxyInformation proxyInformation = new CustomProxyInformation(this.Proxy!);
|
||||
if (proxyInformation.Credentials != null)
|
||||
{
|
||||
request.Proxy = new WebProxy(proxyInformation.ServerAddress, false, null, proxyInformation.Credentials);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Proxy = new WebProxy(proxyInformation.ServerAddress);
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.Auth)
|
||||
{
|
||||
case AuthType.None:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case AuthType.Sspi:
|
||||
request.UseDefaultCredentials = true;
|
||||
request.PreAuthenticate = true;
|
||||
request.Credentials = CredentialCache.DefaultCredentials;
|
||||
break;
|
||||
|
||||
case AuthType.Basic:
|
||||
this.SetBasicAuthHeader(request, this.Username!, this.Password!);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new WebException("Code defect. Unsupported authentication type: " + this.Auth);
|
||||
}
|
||||
|
||||
bool supportsIfModifiedSince = false;
|
||||
if (request is HttpWebRequest httpRequest && File.Exists(this.To))
|
||||
{
|
||||
supportsIfModifiedSince = true;
|
||||
httpRequest.IfModifiedSince = File.GetLastWriteTime(this.To);
|
||||
}
|
||||
|
||||
DateTime lastModified = default;
|
||||
string tmpFilePath = this.To + ".tmp";
|
||||
try
|
||||
{
|
||||
#if VNEXT
|
||||
using (WebResponse response = await request.GetResponseAsync())
|
||||
#else
|
||||
using (WebResponse response = request.GetResponse())
|
||||
#endif
|
||||
using (Stream responseStream = response.GetResponseStream())
|
||||
using (FileStream tmpStream = new FileStream(tmpFilePath, FileMode.Create))
|
||||
{
|
||||
if (supportsIfModifiedSince)
|
||||
{
|
||||
lastModified = ((HttpWebResponse)response).LastModified;
|
||||
}
|
||||
|
||||
#if VNEXT
|
||||
await responseStream.CopyToAsync(tmpStream);
|
||||
#elif NET20
|
||||
CopyStream(responseStream, tmpStream);
|
||||
#else
|
||||
responseStream.CopyTo(tmpStream);
|
||||
#endif
|
||||
}
|
||||
|
||||
FileHelper.MoveOrReplaceFile(this.To + ".tmp", this.To);
|
||||
|
||||
if (supportsIfModifiedSince)
|
||||
{
|
||||
File.SetLastWriteTime(this.To, lastModified);
|
||||
}
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
if (supportsIfModifiedSince && ((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.NotModified)
|
||||
{
|
||||
Logger.Info($"Skipped downloading unmodified resource '{this.From}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NET20
|
||||
private static void CopyStream(Stream source, Stream destination)
|
||||
{
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
|
||||
{
|
||||
destination.Write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public class CustomProxyInformation
|
||||
{
|
||||
public string ServerAddress { get; set; }
|
||||
|
||||
public NetworkCredential? Credentials { get; set; }
|
||||
|
||||
public CustomProxyInformation(string proxy)
|
||||
{
|
||||
if (proxy.Contains("@"))
|
||||
{
|
||||
// Extract proxy credentials
|
||||
int credsFrom = proxy.IndexOf("://") + 3;
|
||||
int credsTo = proxy.LastIndexOf("@");
|
||||
string completeCredsStr = proxy.Substring(credsFrom, credsTo - credsFrom);
|
||||
int credsSeparator = completeCredsStr.IndexOf(":");
|
||||
|
||||
string username = completeCredsStr.Substring(0, credsSeparator);
|
||||
string password = completeCredsStr.Substring(credsSeparator + 1);
|
||||
this.Credentials = new NetworkCredential(username, password);
|
||||
this.ServerAddress = proxy.Replace(completeCredsStr + "@", string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ServerAddress = proxy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
#if !VNEXT
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using System.Text;
|
||||
#if VNEXT
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using WinSW.Util;
|
||||
|
||||
namespace WinSW
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify the download activities prior to the launch.
|
||||
/// This enables self-updating services.
|
||||
/// </summary>
|
||||
public class Download
|
||||
{
|
||||
public enum AuthType
|
||||
{
|
||||
None = 0,
|
||||
Sspi,
|
||||
Basic
|
||||
}
|
||||
|
||||
private static readonly ILog Logger = LogManager.GetLogger(typeof(Download));
|
||||
|
||||
public readonly string From;
|
||||
public readonly string To;
|
||||
public readonly AuthType Auth;
|
||||
public readonly string? Username;
|
||||
public readonly string? Password;
|
||||
public readonly bool UnsecureAuth;
|
||||
public readonly bool FailOnError;
|
||||
public readonly string? Proxy;
|
||||
|
||||
public string ShortId => $"(download from {this.From})";
|
||||
|
||||
static Download()
|
||||
{
|
||||
#if NET461
|
||||
// If your app runs on .NET Framework 4.7 or later versions, but targets an earlier version
|
||||
AppContext.SetSwitch("Switch.System.Net.DontEnableSystemDefaultTlsVersions", false);
|
||||
#elif !VNEXT
|
||||
// If your app runs on .NET Framework 4.6, but targets an earlier version
|
||||
Type.GetType("System.AppContext")?.InvokeMember("SetSwitch", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { "Switch.System.Net.DontEnableSchUseStrongCrypto", false });
|
||||
|
||||
const SecurityProtocolType Tls12 = (SecurityProtocolType)0x00000C00;
|
||||
const SecurityProtocolType Tls11 = (SecurityProtocolType)0x00000300;
|
||||
|
||||
// Windows 7 and Windows Server 2008 R2
|
||||
if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
ServicePointManager.SecurityProtocol |= Tls11 | Tls12;
|
||||
Logger.Info("TLS 1.1/1.2 enabled");
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
Logger.Info("TLS 1.1/1.2 disabled");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// internal
|
||||
public Download(
|
||||
string from,
|
||||
string to,
|
||||
bool failOnError = false,
|
||||
AuthType auth = AuthType.None,
|
||||
string? username = null,
|
||||
string? password = null,
|
||||
bool unsecureAuth = false,
|
||||
string? proxy = null)
|
||||
{
|
||||
this.From = from;
|
||||
this.To = to;
|
||||
this.FailOnError = failOnError;
|
||||
this.Proxy = proxy;
|
||||
this.Auth = auth;
|
||||
this.Username = username;
|
||||
this.Password = password;
|
||||
this.UnsecureAuth = unsecureAuth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the download setting sfrom the XML entry
|
||||
/// </summary>
|
||||
/// <param name="n">XML element</param>
|
||||
/// <exception cref="InvalidDataException">The required attribute is missing or the configuration is invalid.</exception>
|
||||
internal Download(XmlElement n)
|
||||
{
|
||||
this.From = XmlHelper.SingleAttribute<string>(n, "from");
|
||||
this.To = XmlHelper.SingleAttribute<string>(n, "to");
|
||||
|
||||
// All arguments below are optional
|
||||
this.FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false);
|
||||
this.Proxy = XmlHelper.SingleAttribute<string>(n, "proxy", null);
|
||||
|
||||
this.Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.None);
|
||||
this.Username = XmlHelper.SingleAttribute<string>(n, "user", null);
|
||||
this.Password = XmlHelper.SingleAttribute<string>(n, "password", null);
|
||||
this.UnsecureAuth = XmlHelper.SingleAttribute(n, "unsecureAuth", false);
|
||||
|
||||
if (this.Auth == AuthType.Basic)
|
||||
{
|
||||
// Allow it only for HTTPS or for UnsecureAuth
|
||||
if (!this.From.StartsWith("https:") && !this.UnsecureAuth)
|
||||
{
|
||||
throw new InvalidDataException("Warning: you're sending your credentials in clear text to the server " + this.ShortId +
|
||||
"If you really want this you must enable 'unsecureAuth' in the configuration");
|
||||
}
|
||||
|
||||
// Also fail if there is no user/password
|
||||
if (this.Username is null)
|
||||
{
|
||||
throw new InvalidDataException("Basic Auth is enabled, but username is not specified " + this.ShortId);
|
||||
}
|
||||
|
||||
if (this.Password is null)
|
||||
{
|
||||
throw new InvalidDataException("Basic Auth is enabled, but password is not specified " + this.ShortId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Source: http://stackoverflow.com/questions/2764577/forcing-basic-authentication-in-webrequest
|
||||
private void SetBasicAuthHeader(WebRequest request, string username, string password)
|
||||
{
|
||||
string authInfo = username + ":" + password;
|
||||
authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo));
|
||||
request.Headers["Authorization"] = "Basic " + authInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the requested file and puts it to the specified target.
|
||||
/// </summary>
|
||||
/// <exception cref="WebException">
|
||||
/// Download failure. FailOnError flag should be processed outside.
|
||||
/// </exception>
|
||||
#if VNEXT
|
||||
public async Task PerformAsync()
|
||||
#else
|
||||
public void Perform()
|
||||
#endif
|
||||
{
|
||||
WebRequest request = WebRequest.Create(this.From);
|
||||
if (!string.IsNullOrEmpty(this.Proxy))
|
||||
{
|
||||
CustomProxyInformation proxyInformation = new CustomProxyInformation(this.Proxy!);
|
||||
if (proxyInformation.Credentials != null)
|
||||
{
|
||||
request.Proxy = new WebProxy(proxyInformation.ServerAddress, false, null, proxyInformation.Credentials);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Proxy = new WebProxy(proxyInformation.ServerAddress);
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.Auth)
|
||||
{
|
||||
case AuthType.None:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case AuthType.Sspi:
|
||||
request.UseDefaultCredentials = true;
|
||||
request.PreAuthenticate = true;
|
||||
request.Credentials = CredentialCache.DefaultCredentials;
|
||||
break;
|
||||
|
||||
case AuthType.Basic:
|
||||
this.SetBasicAuthHeader(request, this.Username!, this.Password!);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new WebException("Code defect. Unsupported authentication type: " + this.Auth);
|
||||
}
|
||||
|
||||
bool supportsIfModifiedSince = false;
|
||||
if (request is HttpWebRequest httpRequest && File.Exists(this.To))
|
||||
{
|
||||
supportsIfModifiedSince = true;
|
||||
httpRequest.IfModifiedSince = File.GetLastWriteTime(this.To);
|
||||
}
|
||||
|
||||
DateTime lastModified = default;
|
||||
string tmpFilePath = this.To + ".tmp";
|
||||
try
|
||||
{
|
||||
#if VNEXT
|
||||
using (WebResponse response = await request.GetResponseAsync())
|
||||
#else
|
||||
using (WebResponse response = request.GetResponse())
|
||||
#endif
|
||||
using (Stream responseStream = response.GetResponseStream())
|
||||
using (FileStream tmpStream = new FileStream(tmpFilePath, FileMode.Create))
|
||||
{
|
||||
if (supportsIfModifiedSince)
|
||||
{
|
||||
lastModified = ((HttpWebResponse)response).LastModified;
|
||||
}
|
||||
|
||||
#if VNEXT
|
||||
await responseStream.CopyToAsync(tmpStream);
|
||||
#elif NET20
|
||||
CopyStream(responseStream, tmpStream);
|
||||
#else
|
||||
responseStream.CopyTo(tmpStream);
|
||||
#endif
|
||||
}
|
||||
|
||||
FileHelper.MoveOrReplaceFile(this.To + ".tmp", this.To);
|
||||
|
||||
if (supportsIfModifiedSince)
|
||||
{
|
||||
File.SetLastWriteTime(this.To, lastModified);
|
||||
}
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
if (supportsIfModifiedSince && ((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.NotModified)
|
||||
{
|
||||
Logger.Info($"Skipped downloading unmodified resource '{this.From}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NET20
|
||||
private static void CopyStream(Stream source, Stream destination)
|
||||
{
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
|
||||
{
|
||||
destination.Write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public class CustomProxyInformation
|
||||
{
|
||||
public string ServerAddress { get; set; }
|
||||
|
||||
public NetworkCredential? Credentials { get; set; }
|
||||
|
||||
public CustomProxyInformation(string proxy)
|
||||
{
|
||||
if (proxy.Contains("@"))
|
||||
{
|
||||
// Extract proxy credentials
|
||||
int credsFrom = proxy.IndexOf("://") + 3;
|
||||
int credsTo = proxy.LastIndexOf("@");
|
||||
string completeCredsStr = proxy.Substring(credsFrom, credsTo - credsFrom);
|
||||
int credsSeparator = completeCredsStr.IndexOf(":");
|
||||
|
||||
string username = completeCredsStr.Substring(0, credsSeparator);
|
||||
string password = completeCredsStr.Substring(credsSeparator + 1);
|
||||
this.Credentials = new NetworkCredential(username, password);
|
||||
this.ServerAddress = proxy.Replace(completeCredsStr + "@", string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ServerAddress = proxy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,205 +1,205 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace DynamicProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface that a user defined proxy handler needs to implement. This interface
|
||||
/// defines one method that gets invoked by the generated proxy.
|
||||
/// </summary>
|
||||
public interface IProxyInvocationHandler
|
||||
{
|
||||
/// <param name="proxy">The instance of the proxy</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>
|
||||
/// <returns>Object</returns>
|
||||
object? Invoke(object proxy, MethodInfo method, object[] parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public static class ProxyFactory
|
||||
{
|
||||
private const string ProxySuffix = "Proxy";
|
||||
private const string AssemblyName = "ProxyAssembly";
|
||||
private const string ModuleName = "ProxyModule";
|
||||
private const string HandlerName = "handler";
|
||||
|
||||
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
||||
|
||||
private static readonly AssemblyBuilder AssemblyBuilder =
|
||||
#if VNEXT
|
||||
AssemblyBuilder.DefineDynamicAssembly(
|
||||
#else
|
||||
AppDomain.CurrentDomain.DefineDynamicAssembly(
|
||||
#endif
|
||||
new AssemblyName(AssemblyName), AssemblyBuilderAccess.Run);
|
||||
|
||||
private static readonly ModuleBuilder ModuleBuilder = AssemblyBuilder.DefineDynamicModule(ModuleName);
|
||||
|
||||
public static object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface = false)
|
||||
{
|
||||
string typeName = objType.FullName + ProxySuffix;
|
||||
Type? type = null;
|
||||
lock (TypeCache)
|
||||
{
|
||||
if (!TypeCache.TryGetValue(typeName, out type))
|
||||
{
|
||||
type = CreateType(typeName, isObjInterface ? new Type[] { objType } : objType.GetInterfaces());
|
||||
TypeCache.Add(typeName, type);
|
||||
}
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(type, new object[] { handler })!;
|
||||
}
|
||||
|
||||
private static Type CreateType(string dynamicTypeName, Type[] interfaces)
|
||||
{
|
||||
Type objType = typeof(object);
|
||||
Type handlerType = typeof(IProxyInvocationHandler);
|
||||
|
||||
TypeAttributes typeAttributes = 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);
|
||||
|
||||
// Define a member variable to hold the delegate
|
||||
FieldBuilder handlerField = typeBuilder.DefineField(
|
||||
HandlerName, handlerType, FieldAttributes.Private | FieldAttributes.InitOnly);
|
||||
|
||||
// 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 });
|
||||
|
||||
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, baseConstructor);
|
||||
|
||||
// Constructor return
|
||||
constructorIL.Emit(OpCodes.Ret);
|
||||
|
||||
// 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 typeBuilder.CreateType()!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IProxyInvocationHandler.Invoke(object, MethodInfo, object[])"/>.
|
||||
/// </summary>
|
||||
private static readonly MethodInfo InvokeMethod = typeof(IProxyInvocationHandler).GetMethod(nameof(IProxyInvocationHandler.Invoke))!;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="MethodBase.GetMethodFromHandle(RuntimeMethodHandle)"/>.
|
||||
/// </summary>
|
||||
private static readonly MethodInfo GetMethodFromHandleMethod = typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle), new[] { typeof(RuntimeMethodHandle) })!;
|
||||
|
||||
private static void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
|
||||
{
|
||||
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
|
||||
|
||||
for (int i = 0; i < interfaceMethods.Length; i++)
|
||||
{
|
||||
MethodInfo methodInfo = interfaceMethods[i];
|
||||
|
||||
// Get the method parameters since we need to create an array
|
||||
// of parameter types
|
||||
ParameterInfo[] methodParams = methodInfo.GetParameters();
|
||||
int numOfParams = methodParams.Length;
|
||||
Type[] methodParameters = new Type[numOfParams];
|
||||
|
||||
// convert the ParameterInfo objects into Type
|
||||
for (int j = 0; j < numOfParams; j++)
|
||||
{
|
||||
methodParameters[j] = methodParams[j].ParameterType;
|
||||
}
|
||||
|
||||
// create a new builder for the method in the interface
|
||||
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
|
||||
methodInfo.Name,
|
||||
/*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes & ~MethodAttributes.Abstract,
|
||||
CallingConventions.Standard,
|
||||
methodInfo.ReturnType,
|
||||
methodParameters);
|
||||
|
||||
ILGenerator methodIL = methodBuilder.GetILGenerator();
|
||||
|
||||
// invoke target: IProxyInvocationHandler
|
||||
methodIL.Emit(OpCodes.Ldarg_0);
|
||||
methodIL.Emit(OpCodes.Ldfld, handlerField);
|
||||
|
||||
// 1st parameter: object proxy
|
||||
methodIL.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
// 2nd parameter: MethodInfo method
|
||||
methodIL.Emit(OpCodes.Ldtoken, methodInfo);
|
||||
methodIL.Emit(OpCodes.Call, GetMethodFromHandleMethod);
|
||||
methodIL.Emit(OpCodes.Castclass, typeof(MethodInfo));
|
||||
|
||||
// 3rd parameter: object[] parameters
|
||||
methodIL.Emit(OpCodes.Ldc_I4, numOfParams);
|
||||
methodIL.Emit(OpCodes.Newarr, typeof(object));
|
||||
|
||||
// if we have any parameters, then iterate through and set the values
|
||||
// of each element to the corresponding arguments
|
||||
for (int j = 0; j < numOfParams; j++)
|
||||
{
|
||||
methodIL.Emit(OpCodes.Dup); // copy the array
|
||||
methodIL.Emit(OpCodes.Ldc_I4, j);
|
||||
methodIL.Emit(OpCodes.Ldarg, j + 1); // +1 for "this"
|
||||
if (methodParameters[j].IsValueType)
|
||||
{
|
||||
methodIL.Emit(OpCodes.Box, methodParameters[j]);
|
||||
}
|
||||
|
||||
methodIL.Emit(OpCodes.Stelem_Ref);
|
||||
}
|
||||
|
||||
// call the Invoke method
|
||||
methodIL.Emit(OpCodes.Callvirt, InvokeMethod);
|
||||
|
||||
if (methodInfo.ReturnType != typeof(void))
|
||||
{
|
||||
methodIL.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// pop the return value that Invoke returned from the stack since
|
||||
// the method's return type is void.
|
||||
methodIL.Emit(OpCodes.Pop);
|
||||
}
|
||||
|
||||
// Return
|
||||
methodIL.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
// Iterate through the parent interfaces and recursively call this method
|
||||
foreach (Type parentType in interfaceType.GetInterfaces())
|
||||
{
|
||||
GenerateMethod(parentType, handlerField, typeBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace DynamicProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface that a user defined proxy handler needs to implement. This interface
|
||||
/// defines one method that gets invoked by the generated proxy.
|
||||
/// </summary>
|
||||
public interface IProxyInvocationHandler
|
||||
{
|
||||
/// <param name="proxy">The instance of the proxy</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>
|
||||
/// <returns>Object</returns>
|
||||
object? Invoke(object proxy, MethodInfo method, object[] parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public static class ProxyFactory
|
||||
{
|
||||
private const string ProxySuffix = "Proxy";
|
||||
private const string AssemblyName = "ProxyAssembly";
|
||||
private const string ModuleName = "ProxyModule";
|
||||
private const string HandlerName = "handler";
|
||||
|
||||
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
||||
|
||||
private static readonly AssemblyBuilder AssemblyBuilder =
|
||||
#if VNEXT
|
||||
AssemblyBuilder.DefineDynamicAssembly(
|
||||
#else
|
||||
AppDomain.CurrentDomain.DefineDynamicAssembly(
|
||||
#endif
|
||||
new AssemblyName(AssemblyName), AssemblyBuilderAccess.Run);
|
||||
|
||||
private static readonly ModuleBuilder ModuleBuilder = AssemblyBuilder.DefineDynamicModule(ModuleName);
|
||||
|
||||
public static object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface = false)
|
||||
{
|
||||
string typeName = objType.FullName + ProxySuffix;
|
||||
Type? type = null;
|
||||
lock (TypeCache)
|
||||
{
|
||||
if (!TypeCache.TryGetValue(typeName, out type))
|
||||
{
|
||||
type = CreateType(typeName, isObjInterface ? new Type[] { objType } : objType.GetInterfaces());
|
||||
TypeCache.Add(typeName, type);
|
||||
}
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(type, new object[] { handler })!;
|
||||
}
|
||||
|
||||
private static Type CreateType(string dynamicTypeName, Type[] interfaces)
|
||||
{
|
||||
Type objType = typeof(object);
|
||||
Type handlerType = typeof(IProxyInvocationHandler);
|
||||
|
||||
TypeAttributes typeAttributes = 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);
|
||||
|
||||
// Define a member variable to hold the delegate
|
||||
FieldBuilder handlerField = typeBuilder.DefineField(
|
||||
HandlerName, handlerType, FieldAttributes.Private | FieldAttributes.InitOnly);
|
||||
|
||||
// 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 });
|
||||
|
||||
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, baseConstructor);
|
||||
|
||||
// Constructor return
|
||||
constructorIL.Emit(OpCodes.Ret);
|
||||
|
||||
// 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 typeBuilder.CreateType()!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IProxyInvocationHandler.Invoke(object, MethodInfo, object[])"/>.
|
||||
/// </summary>
|
||||
private static readonly MethodInfo InvokeMethod = typeof(IProxyInvocationHandler).GetMethod(nameof(IProxyInvocationHandler.Invoke))!;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="MethodBase.GetMethodFromHandle(RuntimeMethodHandle)"/>.
|
||||
/// </summary>
|
||||
private static readonly MethodInfo GetMethodFromHandleMethod = typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle), new[] { typeof(RuntimeMethodHandle) })!;
|
||||
|
||||
private static void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
|
||||
{
|
||||
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
|
||||
|
||||
for (int i = 0; i < interfaceMethods.Length; i++)
|
||||
{
|
||||
MethodInfo methodInfo = interfaceMethods[i];
|
||||
|
||||
// Get the method parameters since we need to create an array
|
||||
// of parameter types
|
||||
ParameterInfo[] methodParams = methodInfo.GetParameters();
|
||||
int numOfParams = methodParams.Length;
|
||||
Type[] methodParameters = new Type[numOfParams];
|
||||
|
||||
// convert the ParameterInfo objects into Type
|
||||
for (int j = 0; j < numOfParams; j++)
|
||||
{
|
||||
methodParameters[j] = methodParams[j].ParameterType;
|
||||
}
|
||||
|
||||
// create a new builder for the method in the interface
|
||||
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
|
||||
methodInfo.Name,
|
||||
/*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes & ~MethodAttributes.Abstract,
|
||||
CallingConventions.Standard,
|
||||
methodInfo.ReturnType,
|
||||
methodParameters);
|
||||
|
||||
ILGenerator methodIL = methodBuilder.GetILGenerator();
|
||||
|
||||
// invoke target: IProxyInvocationHandler
|
||||
methodIL.Emit(OpCodes.Ldarg_0);
|
||||
methodIL.Emit(OpCodes.Ldfld, handlerField);
|
||||
|
||||
// 1st parameter: object proxy
|
||||
methodIL.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
// 2nd parameter: MethodInfo method
|
||||
methodIL.Emit(OpCodes.Ldtoken, methodInfo);
|
||||
methodIL.Emit(OpCodes.Call, GetMethodFromHandleMethod);
|
||||
methodIL.Emit(OpCodes.Castclass, typeof(MethodInfo));
|
||||
|
||||
// 3rd parameter: object[] parameters
|
||||
methodIL.Emit(OpCodes.Ldc_I4, numOfParams);
|
||||
methodIL.Emit(OpCodes.Newarr, typeof(object));
|
||||
|
||||
// if we have any parameters, then iterate through and set the values
|
||||
// of each element to the corresponding arguments
|
||||
for (int j = 0; j < numOfParams; j++)
|
||||
{
|
||||
methodIL.Emit(OpCodes.Dup); // copy the array
|
||||
methodIL.Emit(OpCodes.Ldc_I4, j);
|
||||
methodIL.Emit(OpCodes.Ldarg, j + 1); // +1 for "this"
|
||||
if (methodParameters[j].IsValueType)
|
||||
{
|
||||
methodIL.Emit(OpCodes.Box, methodParameters[j]);
|
||||
}
|
||||
|
||||
methodIL.Emit(OpCodes.Stelem_Ref);
|
||||
}
|
||||
|
||||
// call the Invoke method
|
||||
methodIL.Emit(OpCodes.Callvirt, InvokeMethod);
|
||||
|
||||
if (methodInfo.ReturnType != typeof(void))
|
||||
{
|
||||
methodIL.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// pop the return value that Invoke returned from the stack since
|
||||
// the method's return type is void.
|
||||
methodIL.Emit(OpCodes.Pop);
|
||||
}
|
||||
|
||||
// Return
|
||||
methodIL.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
// Iterate through the parent interfaces and recursively call this method
|
||||
foreach (Type parentType in interfaceType.GetInterfaces())
|
||||
{
|
||||
GenerateMethod(parentType, handlerField, typeBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,11 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace WinSW.Native
|
||||
{
|
||||
internal static class Kernel32
|
||||
{
|
||||
[DllImport(Libraries.Kernel32)]
|
||||
internal static extern bool SetStdHandle(int stdHandle, SafeFileHandle handle);
|
||||
}
|
||||
}
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace WinSW.Native
|
||||
{
|
||||
internal static class Kernel32
|
||||
{
|
||||
[DllImport(Libraries.Kernel32)]
|
||||
internal static extern bool SetStdHandle(int stdHandle, SafeFileHandle handle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,108 +1,108 @@
|
|||
using System;
|
||||
|
||||
namespace WinSW
|
||||
{
|
||||
// This is largely borrowed from the logback Rolling Calendar.
|
||||
public class PeriodicRollingCalendar
|
||||
{
|
||||
private readonly string format;
|
||||
private readonly long period;
|
||||
private DateTime currentRoll;
|
||||
private DateTime nextRoll;
|
||||
|
||||
public PeriodicRollingCalendar(string format, long period)
|
||||
{
|
||||
this.format = format;
|
||||
this.period = period;
|
||||
this.currentRoll = DateTime.Now;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
this.PeriodicityType = this.DeterminePeriodicityType();
|
||||
this.nextRoll = this.NextTriggeringTime(this.currentRoll, this.period);
|
||||
}
|
||||
|
||||
public enum Periodicity
|
||||
{
|
||||
ERRONEOUS,
|
||||
TOP_OF_MILLISECOND,
|
||||
TOP_OF_SECOND,
|
||||
TOP_OF_MINUTE,
|
||||
TOP_OF_HOUR,
|
||||
TOP_OF_DAY
|
||||
}
|
||||
|
||||
private static readonly Periodicity[] ValidOrderedList =
|
||||
{
|
||||
Periodicity.TOP_OF_MILLISECOND, Periodicity.TOP_OF_SECOND, Periodicity.TOP_OF_MINUTE, Periodicity.TOP_OF_HOUR, Periodicity.TOP_OF_DAY
|
||||
};
|
||||
|
||||
private Periodicity DeterminePeriodicityType()
|
||||
{
|
||||
PeriodicRollingCalendar periodicRollingCalendar = new PeriodicRollingCalendar(this.format, this.period);
|
||||
DateTime epoch = new DateTime(1970, 1, 1);
|
||||
|
||||
foreach (Periodicity i in ValidOrderedList)
|
||||
{
|
||||
string r0 = epoch.ToString(this.format);
|
||||
periodicRollingCalendar.PeriodicityType = i;
|
||||
|
||||
DateTime next = periodicRollingCalendar.NextTriggeringTime(epoch, 1);
|
||||
string r1 = next.ToString(this.format);
|
||||
|
||||
if (r0 != r1)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return Periodicity.ERRONEOUS;
|
||||
}
|
||||
|
||||
private DateTime NextTriggeringTime(DateTime input, long increment) => this.PeriodicityType switch
|
||||
{
|
||||
Periodicity.TOP_OF_MILLISECOND =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second, input.Millisecond)
|
||||
.AddMilliseconds(increment),
|
||||
|
||||
Periodicity.TOP_OF_SECOND =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second)
|
||||
.AddSeconds(increment),
|
||||
|
||||
Periodicity.TOP_OF_MINUTE =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, 0)
|
||||
.AddMinutes(increment),
|
||||
|
||||
Periodicity.TOP_OF_HOUR =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0)
|
||||
.AddHours(increment),
|
||||
|
||||
Periodicity.TOP_OF_DAY =>
|
||||
new DateTime(input.Year, input.Month, input.Day)
|
||||
.AddDays(increment),
|
||||
|
||||
_ => throw new Exception("invalid periodicity type: " + this.PeriodicityType),
|
||||
};
|
||||
|
||||
public Periodicity PeriodicityType { get; set; }
|
||||
|
||||
public bool ShouldRoll
|
||||
{
|
||||
get
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
if (now > this.nextRoll)
|
||||
{
|
||||
this.currentRoll = now;
|
||||
this.nextRoll = this.NextTriggeringTime(now, this.period);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string Format => this.currentRoll.ToString(this.format);
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace WinSW
|
||||
{
|
||||
// This is largely borrowed from the logback Rolling Calendar.
|
||||
public class PeriodicRollingCalendar
|
||||
{
|
||||
private readonly string format;
|
||||
private readonly long period;
|
||||
private DateTime currentRoll;
|
||||
private DateTime nextRoll;
|
||||
|
||||
public PeriodicRollingCalendar(string format, long period)
|
||||
{
|
||||
this.format = format;
|
||||
this.period = period;
|
||||
this.currentRoll = DateTime.Now;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
this.PeriodicityType = this.DeterminePeriodicityType();
|
||||
this.nextRoll = this.NextTriggeringTime(this.currentRoll, this.period);
|
||||
}
|
||||
|
||||
public enum Periodicity
|
||||
{
|
||||
ERRONEOUS,
|
||||
TOP_OF_MILLISECOND,
|
||||
TOP_OF_SECOND,
|
||||
TOP_OF_MINUTE,
|
||||
TOP_OF_HOUR,
|
||||
TOP_OF_DAY
|
||||
}
|
||||
|
||||
private static readonly Periodicity[] ValidOrderedList =
|
||||
{
|
||||
Periodicity.TOP_OF_MILLISECOND, Periodicity.TOP_OF_SECOND, Periodicity.TOP_OF_MINUTE, Periodicity.TOP_OF_HOUR, Periodicity.TOP_OF_DAY
|
||||
};
|
||||
|
||||
private Periodicity DeterminePeriodicityType()
|
||||
{
|
||||
PeriodicRollingCalendar periodicRollingCalendar = new PeriodicRollingCalendar(this.format, this.period);
|
||||
DateTime epoch = new DateTime(1970, 1, 1);
|
||||
|
||||
foreach (Periodicity i in ValidOrderedList)
|
||||
{
|
||||
string r0 = epoch.ToString(this.format);
|
||||
periodicRollingCalendar.PeriodicityType = i;
|
||||
|
||||
DateTime next = periodicRollingCalendar.NextTriggeringTime(epoch, 1);
|
||||
string r1 = next.ToString(this.format);
|
||||
|
||||
if (r0 != r1)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return Periodicity.ERRONEOUS;
|
||||
}
|
||||
|
||||
private DateTime NextTriggeringTime(DateTime input, long increment) => this.PeriodicityType switch
|
||||
{
|
||||
Periodicity.TOP_OF_MILLISECOND =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second, input.Millisecond)
|
||||
.AddMilliseconds(increment),
|
||||
|
||||
Periodicity.TOP_OF_SECOND =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, input.Second)
|
||||
.AddSeconds(increment),
|
||||
|
||||
Periodicity.TOP_OF_MINUTE =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, input.Minute, 0)
|
||||
.AddMinutes(increment),
|
||||
|
||||
Periodicity.TOP_OF_HOUR =>
|
||||
new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0)
|
||||
.AddHours(increment),
|
||||
|
||||
Periodicity.TOP_OF_DAY =>
|
||||
new DateTime(input.Year, input.Month, input.Day)
|
||||
.AddDays(increment),
|
||||
|
||||
_ => throw new Exception("invalid periodicity type: " + this.PeriodicityType),
|
||||
};
|
||||
|
||||
public Periodicity PeriodicityType { get; set; }
|
||||
|
||||
public bool ShouldRoll
|
||||
{
|
||||
get
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
if (now > this.nextRoll)
|
||||
{
|
||||
this.currentRoll = now;
|
||||
this.nextRoll = this.NextTriggeringTime(now, this.period);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string Format => this.currentRoll.ToString(this.format);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,227 +1,227 @@
|
|||
using System;
|
||||
using System.Management;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using DynamicProxy;
|
||||
|
||||
namespace WMI
|
||||
{
|
||||
// https://docs.microsoft.com/windows/win32/cimwin32prov/create-method-in-class-win32-service
|
||||
public enum ReturnValue : uint
|
||||
{
|
||||
Success = 0,
|
||||
NotSupported = 1,
|
||||
AccessDenied = 2,
|
||||
DependentServicesRunning = 3,
|
||||
InvalidServiceControl = 4,
|
||||
ServiceCannotAcceptControl = 5,
|
||||
ServiceNotActive = 6,
|
||||
ServiceRequestTimeout = 7,
|
||||
UnknownFailure = 8,
|
||||
PathNotFound = 9,
|
||||
ServiceAlreadyRunning = 10,
|
||||
ServiceDatabaseLocked = 11,
|
||||
ServiceDependencyDeleted = 12,
|
||||
ServiceDependencyFailure = 13,
|
||||
ServiceDisabled = 14,
|
||||
ServiceLogonFailure = 15,
|
||||
ServiceMarkedForDeletion = 16,
|
||||
ServiceNoThread = 17,
|
||||
StatusCircularDependency = 18,
|
||||
StatusDuplicateName = 19,
|
||||
StatusInvalidName = 20,
|
||||
StatusInvalidParameter = 21,
|
||||
StatusInvalidServiceAccount = 22,
|
||||
StatusServiceExists = 23,
|
||||
ServiceAlreadyPaused = 24,
|
||||
|
||||
NoSuchService = 200
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals a problem in WMI related operations
|
||||
/// </summary>
|
||||
public class WmiException : Exception
|
||||
{
|
||||
public readonly ReturnValue ErrorCode;
|
||||
|
||||
public WmiException(string message, ReturnValue code)
|
||||
: base(message)
|
||||
{
|
||||
this.ErrorCode = code;
|
||||
}
|
||||
|
||||
public WmiException(ReturnValue code)
|
||||
: this(code.ToString(), code)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Associated a WMI class name to the proxy interface (which should extend from IWmiCollection)
|
||||
/// </summary>
|
||||
public class WmiClassName : Attribute
|
||||
{
|
||||
public readonly string Name;
|
||||
|
||||
public WmiClassName(string name) => this.Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface to denote a collection in WMI.
|
||||
/// </summary>
|
||||
public interface IWmiCollection
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface to denote an individual managed object
|
||||
/// </summary>
|
||||
public interface IWmiObject
|
||||
{
|
||||
}
|
||||
|
||||
public sealed class WmiRoot
|
||||
{
|
||||
private readonly ManagementScope wmiScope;
|
||||
|
||||
public WmiRoot()
|
||||
{
|
||||
ConnectionOptions options = new ConnectionOptions
|
||||
{
|
||||
EnablePrivileges = true,
|
||||
Impersonation = ImpersonationLevel.Impersonate,
|
||||
Authentication = AuthenticationLevel.PacketPrivacy,
|
||||
};
|
||||
|
||||
this.wmiScope = new ManagementScope(@"\\.\root\cimv2", options);
|
||||
this.wmiScope.Connect();
|
||||
}
|
||||
|
||||
private static string Capitalize(string s)
|
||||
{
|
||||
return char.ToUpper(s[0]) + s.Substring(1);
|
||||
}
|
||||
|
||||
private abstract class BaseHandler : IProxyInvocationHandler
|
||||
{
|
||||
public abstract object? Invoke(object proxy, MethodInfo method, object[] arguments);
|
||||
|
||||
protected void CheckError(ManagementBaseObject result)
|
||||
{
|
||||
uint code = (uint)result["returnValue"];
|
||||
if (code != 0)
|
||||
{
|
||||
throw new WmiException((ReturnValue)code);
|
||||
}
|
||||
}
|
||||
|
||||
protected ManagementBaseObject GetMethodParameters(ManagementObject wmiObject, string methodName, ParameterInfo[] methodParameters, object[] arguments)
|
||||
{
|
||||
ManagementBaseObject wmiParameters = wmiObject.GetMethodParameters(methodName);
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
string capitalizedName = Capitalize(methodParameters[i].Name!);
|
||||
wmiParameters[capitalizedName] = arguments[i];
|
||||
}
|
||||
|
||||
return wmiParameters;
|
||||
}
|
||||
}
|
||||
|
||||
private class InstanceHandler : BaseHandler, IWmiObject
|
||||
{
|
||||
private readonly ManagementObject wmiObject;
|
||||
|
||||
public InstanceHandler(ManagementObject wmiObject) => this.wmiObject = wmiObject;
|
||||
|
||||
public override object? Invoke(object proxy, MethodInfo method, object[] arguments)
|
||||
{
|
||||
if (method.DeclaringType == typeof(IWmiObject))
|
||||
{
|
||||
return method.Invoke(this, arguments);
|
||||
}
|
||||
|
||||
// TODO: proper property support
|
||||
if (method.Name.StartsWith("set_"))
|
||||
{
|
||||
this.wmiObject[method.Name.Substring(4)] = arguments[0];
|
||||
return null;
|
||||
}
|
||||
|
||||
if (method.Name.StartsWith("get_"))
|
||||
{
|
||||
return this.wmiObject[method.Name.Substring(4)];
|
||||
}
|
||||
|
||||
string methodName = method.Name;
|
||||
using ManagementBaseObject? wmiParameters = arguments.Length == 0 ? null :
|
||||
this.GetMethodParameters(this.wmiObject, methodName, method.GetParameters(), arguments);
|
||||
using ManagementBaseObject result = this.wmiObject.InvokeMethod(methodName, wmiParameters, null);
|
||||
this.CheckError(result);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassHandler : BaseHandler
|
||||
{
|
||||
private readonly ManagementClass wmiClass;
|
||||
private readonly string className;
|
||||
|
||||
public ClassHandler(ManagementScope wmiScope, string className)
|
||||
{
|
||||
this.wmiClass = new ManagementClass(wmiScope, new ManagementPath(className), null);
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public override object? Invoke(object proxy, MethodInfo method, object[] arguments)
|
||||
{
|
||||
ParameterInfo[] methodParameters = method.GetParameters();
|
||||
|
||||
if (method.Name == nameof(IWin32Services.Select))
|
||||
{
|
||||
// select method to find instances
|
||||
StringBuilder query = new StringBuilder("SELECT * FROM ").Append(this.className).Append(" WHERE ");
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
query.Append(" AND ");
|
||||
}
|
||||
|
||||
query.Append(' ').Append(Capitalize(methodParameters[i].Name!)).Append(" = '").Append(arguments[i]).Append('\'');
|
||||
}
|
||||
|
||||
using ManagementObjectSearcher searcher = new ManagementObjectSearcher(this.wmiClass.Scope, new ObjectQuery(query.ToString()));
|
||||
using ManagementObjectCollection results = searcher.Get();
|
||||
|
||||
// TODO: support collections
|
||||
foreach (ManagementObject wmiObject in results)
|
||||
{
|
||||
return ProxyFactory.Create(new InstanceHandler(wmiObject), method.ReturnType, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
string methodName = method.Name;
|
||||
using ManagementBaseObject? wmiParameters = arguments.Length == 0 ? null :
|
||||
this.GetMethodParameters(this.wmiClass, methodName, methodParameters, arguments);
|
||||
using ManagementBaseObject result = this.wmiClass.InvokeMethod(methodName, wmiParameters, null);
|
||||
this.CheckError(result);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains an object that corresponds to a table in WMI, which is a collection of a managed object.
|
||||
/// </summary>
|
||||
public T GetCollection<T>()
|
||||
where T : IWmiCollection
|
||||
{
|
||||
WmiClassName className = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0];
|
||||
|
||||
return (T)ProxyFactory.Create(new ClassHandler(this.wmiScope, className.Name), typeof(T), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Management;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using DynamicProxy;
|
||||
|
||||
namespace WMI
|
||||
{
|
||||
// https://docs.microsoft.com/windows/win32/cimwin32prov/create-method-in-class-win32-service
|
||||
public enum ReturnValue : uint
|
||||
{
|
||||
Success = 0,
|
||||
NotSupported = 1,
|
||||
AccessDenied = 2,
|
||||
DependentServicesRunning = 3,
|
||||
InvalidServiceControl = 4,
|
||||
ServiceCannotAcceptControl = 5,
|
||||
ServiceNotActive = 6,
|
||||
ServiceRequestTimeout = 7,
|
||||
UnknownFailure = 8,
|
||||
PathNotFound = 9,
|
||||
ServiceAlreadyRunning = 10,
|
||||
ServiceDatabaseLocked = 11,
|
||||
ServiceDependencyDeleted = 12,
|
||||
ServiceDependencyFailure = 13,
|
||||
ServiceDisabled = 14,
|
||||
ServiceLogonFailure = 15,
|
||||
ServiceMarkedForDeletion = 16,
|
||||
ServiceNoThread = 17,
|
||||
StatusCircularDependency = 18,
|
||||
StatusDuplicateName = 19,
|
||||
StatusInvalidName = 20,
|
||||
StatusInvalidParameter = 21,
|
||||
StatusInvalidServiceAccount = 22,
|
||||
StatusServiceExists = 23,
|
||||
ServiceAlreadyPaused = 24,
|
||||
|
||||
NoSuchService = 200
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals a problem in WMI related operations
|
||||
/// </summary>
|
||||
public class WmiException : Exception
|
||||
{
|
||||
public readonly ReturnValue ErrorCode;
|
||||
|
||||
public WmiException(string message, ReturnValue code)
|
||||
: base(message)
|
||||
{
|
||||
this.ErrorCode = code;
|
||||
}
|
||||
|
||||
public WmiException(ReturnValue code)
|
||||
: this(code.ToString(), code)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Associated a WMI class name to the proxy interface (which should extend from IWmiCollection)
|
||||
/// </summary>
|
||||
public class WmiClassName : Attribute
|
||||
{
|
||||
public readonly string Name;
|
||||
|
||||
public WmiClassName(string name) => this.Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface to denote a collection in WMI.
|
||||
/// </summary>
|
||||
public interface IWmiCollection
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface to denote an individual managed object
|
||||
/// </summary>
|
||||
public interface IWmiObject
|
||||
{
|
||||
}
|
||||
|
||||
public sealed class WmiRoot
|
||||
{
|
||||
private readonly ManagementScope wmiScope;
|
||||
|
||||
public WmiRoot()
|
||||
{
|
||||
ConnectionOptions options = new ConnectionOptions
|
||||
{
|
||||
EnablePrivileges = true,
|
||||
Impersonation = ImpersonationLevel.Impersonate,
|
||||
Authentication = AuthenticationLevel.PacketPrivacy,
|
||||
};
|
||||
|
||||
this.wmiScope = new ManagementScope(@"\\.\root\cimv2", options);
|
||||
this.wmiScope.Connect();
|
||||
}
|
||||
|
||||
private static string Capitalize(string s)
|
||||
{
|
||||
return char.ToUpper(s[0]) + s.Substring(1);
|
||||
}
|
||||
|
||||
private abstract class BaseHandler : IProxyInvocationHandler
|
||||
{
|
||||
public abstract object? Invoke(object proxy, MethodInfo method, object[] arguments);
|
||||
|
||||
protected void CheckError(ManagementBaseObject result)
|
||||
{
|
||||
uint code = (uint)result["returnValue"];
|
||||
if (code != 0)
|
||||
{
|
||||
throw new WmiException((ReturnValue)code);
|
||||
}
|
||||
}
|
||||
|
||||
protected ManagementBaseObject GetMethodParameters(ManagementObject wmiObject, string methodName, ParameterInfo[] methodParameters, object[] arguments)
|
||||
{
|
||||
ManagementBaseObject wmiParameters = wmiObject.GetMethodParameters(methodName);
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
string capitalizedName = Capitalize(methodParameters[i].Name!);
|
||||
wmiParameters[capitalizedName] = arguments[i];
|
||||
}
|
||||
|
||||
return wmiParameters;
|
||||
}
|
||||
}
|
||||
|
||||
private class InstanceHandler : BaseHandler, IWmiObject
|
||||
{
|
||||
private readonly ManagementObject wmiObject;
|
||||
|
||||
public InstanceHandler(ManagementObject wmiObject) => this.wmiObject = wmiObject;
|
||||
|
||||
public override object? Invoke(object proxy, MethodInfo method, object[] arguments)
|
||||
{
|
||||
if (method.DeclaringType == typeof(IWmiObject))
|
||||
{
|
||||
return method.Invoke(this, arguments);
|
||||
}
|
||||
|
||||
// TODO: proper property support
|
||||
if (method.Name.StartsWith("set_"))
|
||||
{
|
||||
this.wmiObject[method.Name.Substring(4)] = arguments[0];
|
||||
return null;
|
||||
}
|
||||
|
||||
if (method.Name.StartsWith("get_"))
|
||||
{
|
||||
return this.wmiObject[method.Name.Substring(4)];
|
||||
}
|
||||
|
||||
string methodName = method.Name;
|
||||
using ManagementBaseObject? wmiParameters = arguments.Length == 0 ? null :
|
||||
this.GetMethodParameters(this.wmiObject, methodName, method.GetParameters(), arguments);
|
||||
using ManagementBaseObject result = this.wmiObject.InvokeMethod(methodName, wmiParameters, null);
|
||||
this.CheckError(result);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassHandler : BaseHandler
|
||||
{
|
||||
private readonly ManagementClass wmiClass;
|
||||
private readonly string className;
|
||||
|
||||
public ClassHandler(ManagementScope wmiScope, string className)
|
||||
{
|
||||
this.wmiClass = new ManagementClass(wmiScope, new ManagementPath(className), null);
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public override object? Invoke(object proxy, MethodInfo method, object[] arguments)
|
||||
{
|
||||
ParameterInfo[] methodParameters = method.GetParameters();
|
||||
|
||||
if (method.Name == nameof(IWin32Services.Select))
|
||||
{
|
||||
// select method to find instances
|
||||
StringBuilder query = new StringBuilder("SELECT * FROM ").Append(this.className).Append(" WHERE ");
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
query.Append(" AND ");
|
||||
}
|
||||
|
||||
query.Append(' ').Append(Capitalize(methodParameters[i].Name!)).Append(" = '").Append(arguments[i]).Append('\'');
|
||||
}
|
||||
|
||||
using ManagementObjectSearcher searcher = new ManagementObjectSearcher(this.wmiClass.Scope, new ObjectQuery(query.ToString()));
|
||||
using ManagementObjectCollection results = searcher.Get();
|
||||
|
||||
// TODO: support collections
|
||||
foreach (ManagementObject wmiObject in results)
|
||||
{
|
||||
return ProxyFactory.Create(new InstanceHandler(wmiObject), method.ReturnType, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
string methodName = method.Name;
|
||||
using ManagementBaseObject? wmiParameters = arguments.Length == 0 ? null :
|
||||
this.GetMethodParameters(this.wmiClass, methodName, methodParameters, arguments);
|
||||
using ManagementBaseObject result = this.wmiClass.InvokeMethod(methodName, wmiParameters, null);
|
||||
this.CheckError(result);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains an object that corresponds to a table in WMI, which is a collection of a managed object.
|
||||
/// </summary>
|
||||
public T GetCollection<T>()
|
||||
where T : IWmiCollection
|
||||
{
|
||||
WmiClassName className = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0];
|
||||
|
||||
return (T)ProxyFactory.Create(new ClassHandler(this.wmiScope, className.Name), typeof(T), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,72 +1,72 @@
|
|||
namespace WMI
|
||||
{
|
||||
public enum ServiceType
|
||||
{
|
||||
KernalDriver = 1,
|
||||
FileSystemDriver = 2,
|
||||
Adapter = 4,
|
||||
RecognizerDriver = 8,
|
||||
OwnProcess = 16,
|
||||
ShareProcess = 32,
|
||||
InteractiveProcess = 256,
|
||||
}
|
||||
|
||||
public enum ErrorControl
|
||||
{
|
||||
UserNotNotified = 0,
|
||||
UserNotified = 1,
|
||||
SystemRestartedWithLastKnownGoodConfiguration = 2,
|
||||
SystemAttemptsToStartWithAGoodConfiguration = 3
|
||||
}
|
||||
|
||||
public enum StartMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Device driver started by the operating system loader. This value is valid only for driver services.
|
||||
/// </summary>
|
||||
Boot,
|
||||
|
||||
/// <summary>
|
||||
/// Device driver started by the operating system initialization process. This value is valid only for driver services.
|
||||
/// </summary>
|
||||
System,
|
||||
|
||||
/// <summary>
|
||||
/// Service to be started automatically by the Service Control Manager during system startup.
|
||||
/// </summary>
|
||||
Automatic,
|
||||
|
||||
/// <summary>
|
||||
/// Service to be started by the Service Control Manager when a process calls the StartService method.
|
||||
/// </summary>
|
||||
Manual,
|
||||
|
||||
/// <summary>
|
||||
/// Service that can no longer be started.
|
||||
/// </summary>
|
||||
Disabled,
|
||||
}
|
||||
|
||||
[WmiClassName("Win32_Service")]
|
||||
public interface IWin32Services : 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, string startMode, bool desktopInteract, string? startName, string? startPassword, string[] serviceDependencies);
|
||||
|
||||
void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, string startMode, bool desktopInteract, string[] serviceDependencies);
|
||||
|
||||
IWin32Service? Select(string name);
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/windows/win32/cimwin32prov/win32-service
|
||||
public interface IWin32Service : IWmiObject
|
||||
{
|
||||
bool Started { get; }
|
||||
|
||||
void Delete();
|
||||
|
||||
void StartService();
|
||||
|
||||
void StopService();
|
||||
}
|
||||
}
|
||||
namespace WMI
|
||||
{
|
||||
public enum ServiceType
|
||||
{
|
||||
KernalDriver = 1,
|
||||
FileSystemDriver = 2,
|
||||
Adapter = 4,
|
||||
RecognizerDriver = 8,
|
||||
OwnProcess = 16,
|
||||
ShareProcess = 32,
|
||||
InteractiveProcess = 256,
|
||||
}
|
||||
|
||||
public enum ErrorControl
|
||||
{
|
||||
UserNotNotified = 0,
|
||||
UserNotified = 1,
|
||||
SystemRestartedWithLastKnownGoodConfiguration = 2,
|
||||
SystemAttemptsToStartWithAGoodConfiguration = 3
|
||||
}
|
||||
|
||||
public enum StartMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Device driver started by the operating system loader. This value is valid only for driver services.
|
||||
/// </summary>
|
||||
Boot,
|
||||
|
||||
/// <summary>
|
||||
/// Device driver started by the operating system initialization process. This value is valid only for driver services.
|
||||
/// </summary>
|
||||
System,
|
||||
|
||||
/// <summary>
|
||||
/// Service to be started automatically by the Service Control Manager during system startup.
|
||||
/// </summary>
|
||||
Automatic,
|
||||
|
||||
/// <summary>
|
||||
/// Service to be started by the Service Control Manager when a process calls the StartService method.
|
||||
/// </summary>
|
||||
Manual,
|
||||
|
||||
/// <summary>
|
||||
/// Service that can no longer be started.
|
||||
/// </summary>
|
||||
Disabled,
|
||||
}
|
||||
|
||||
[WmiClassName("Win32_Service")]
|
||||
public interface IWin32Services : 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, string startMode, bool desktopInteract, string? startName, string? startPassword, string[] serviceDependencies);
|
||||
|
||||
void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, string startMode, bool desktopInteract, string[] serviceDependencies);
|
||||
|
||||
IWin32Service? Select(string name);
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/windows/win32/cimwin32prov/win32-service
|
||||
public interface IWin32Service : IWmiObject
|
||||
{
|
||||
bool Started { get; }
|
||||
|
||||
void Delete();
|
||||
|
||||
void StartService();
|
||||
|
||||
void StopService();
|
||||
}
|
||||
}
|
||||
|
|
174
src/winsw.sln
174
src/winsw.sln
|
@ -1,87 +1,87 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winsw", "Core\ServiceWrapper\winsw.csproj", "{0DE77F55-ADE5-43C1-999A-0BC81153B039}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winswTests", "Test\winswTests\winswTests.csproj", "{93843402-842B-44B4-B303-AEE829BE0B43}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedDirectoryMapper", "Plugins\SharedDirectoryMapper\SharedDirectoryMapper.csproj", "{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{077C2CEC-B687-4B53-86E9-C1A1BF5554E5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{BC4AD891-E87E-4F30-867C-FD8084A29E5D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{5297623A-1A95-4F89-9AAE-DA634081EC86}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinSWCore", "Core\WinSWCore\WinSWCore.csproj", "{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RunawayProcessKiller", "Plugins\RunawayProcessKiller\RunawayProcessKiller.csproj", "{57284B7A-82A4-407A-B706-EBEA6BF8EA13}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AA414F46-B863-473A-A0E0-C2971B3396AE}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
..\examples\sample-allOptions.xml = ..\examples\sample-allOptions.xml
|
||||
..\examples\sample-minimal.xml = ..\examples\sample-minimal.xml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Win32.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039} = {5297623A-1A95-4F89-9AAE-DA634081EC86}
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43} = {077C2CEC-B687-4B53-86E9-C1A1BF5554E5}
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} = {BC4AD891-E87E-4F30-867C-FD8084A29E5D}
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06} = {5297623A-1A95-4F89-9AAE-DA634081EC86}
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13} = {BC4AD891-E87E-4F30-867C-FD8084A29E5D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winsw", "Core\ServiceWrapper\winsw.csproj", "{0DE77F55-ADE5-43C1-999A-0BC81153B039}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winswTests", "Test\winswTests\winswTests.csproj", "{93843402-842B-44B4-B303-AEE829BE0B43}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedDirectoryMapper", "Plugins\SharedDirectoryMapper\SharedDirectoryMapper.csproj", "{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{077C2CEC-B687-4B53-86E9-C1A1BF5554E5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{BC4AD891-E87E-4F30-867C-FD8084A29E5D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{5297623A-1A95-4F89-9AAE-DA634081EC86}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinSWCore", "Core\WinSWCore\WinSWCore.csproj", "{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RunawayProcessKiller", "Plugins\RunawayProcessKiller\RunawayProcessKiller.csproj", "{57284B7A-82A4-407A-B706-EBEA6BF8EA13}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AA414F46-B863-473A-A0E0-C2971B3396AE}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
..\examples\sample-allOptions.xml = ..\examples\sample-allOptions.xml
|
||||
..\examples\sample-minimal.xml = ..\examples\sample-minimal.xml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13}.Release|Win32.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{0DE77F55-ADE5-43C1-999A-0BC81153B039} = {5297623A-1A95-4F89-9AAE-DA634081EC86}
|
||||
{93843402-842B-44B4-B303-AEE829BE0B43} = {077C2CEC-B687-4B53-86E9-C1A1BF5554E5}
|
||||
{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} = {BC4AD891-E87E-4F30-867C-FD8084A29E5D}
|
||||
{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06} = {5297623A-1A95-4F89-9AAE-DA634081EC86}
|
||||
{57284B7A-82A4-407A-B706-EBEA6BF8EA13} = {BC4AD891-E87E-4F30-867C-FD8084A29E5D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
Loading…
Reference in New Issue