From 30c5994c42191d0543cb2ba2d45a2559d0d98f3d Mon Sep 17 00:00:00 2001 From: NextTurn <45985406+NextTurn@users.noreply.github.com> Date: Thu, 27 Dec 2018 00:00:00 +0800 Subject: [PATCH 1/2] Migrate to MMI --- Directory.Build.targets | 4 + src/Core/ServiceWrapper/Main.cs | 2 +- src/Core/ServiceWrapper/winsw.csproj | 1 - src/Core/WinSWCore/Util/ProcessHelper.cs | 25 ++- src/Core/WinSWCore/WinSWCore.csproj | 2 +- src/Core/WinSWCore/Wmi.cs | 229 +++++++++++++++++------ src/Core/WinSWCore/WmiSchema.cs | 8 +- 7 files changed, 203 insertions(+), 68 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 3d3afd7..2af5e3f 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -4,4 +4,8 @@ VNEXT + + $(DefineConstants);CIM + + diff --git a/src/Core/ServiceWrapper/Main.cs b/src/Core/ServiceWrapper/Main.cs index 277a282..1c22b9b 100644 --- a/src/Core/ServiceWrapper/Main.cs +++ b/src/Core/ServiceWrapper/Main.cs @@ -596,7 +596,7 @@ namespace winsw "\"" + descriptor.ExecutablePath + "\"", ServiceType.OwnProcess, ErrorControl.UserNotified, - descriptor.StartMode, + descriptor.StartMode.ToString(), descriptor.Interactive, username, password, diff --git a/src/Core/ServiceWrapper/winsw.csproj b/src/Core/ServiceWrapper/winsw.csproj index 46aa178..e76aa60 100644 --- a/src/Core/ServiceWrapper/winsw.csproj +++ b/src/Core/ServiceWrapper/winsw.csproj @@ -28,7 +28,6 @@ - diff --git a/src/Core/WinSWCore/Util/ProcessHelper.cs b/src/Core/WinSWCore/Util/ProcessHelper.cs index e784fb3..edce46a 100644 --- a/src/Core/WinSWCore/Util/ProcessHelper.cs +++ b/src/Core/WinSWCore/Util/ProcessHelper.cs @@ -1,9 +1,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +#if !CIM using System.Management; +#endif using System.Threading; using log4net; +#if CIM +using Microsoft.Management.Infrastructure; +#endif namespace winsw.Util { @@ -26,13 +31,25 @@ namespace winsw.Util try { - var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid); - foreach (var mo in searcher.Get()) + string query = "SELECT * FROM Win32_Process WHERE ParentProcessID = " + pid; +#if CIM + using CimSession session = CimSession.Create(null); + foreach (CimInstance instance in session.QueryInstances("root/cimv2", "WQL", query)) { - var childProcessId = mo["ProcessID"]; - Logger.Info("Found child process: " + childProcessId + " Name: " + mo["Name"]); + object childProcessId = instance.CimInstanceProperties["ProcessID"].Value; + Logger.Info("Found child process: " + childProcessId + " Name: " + instance.CimInstanceProperties["Name"].Value); childPids.Add(Convert.ToInt32(childProcessId)); } +#else + using ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); + using ManagementObjectCollection results = searcher.Get(); + foreach (ManagementBaseObject wmiObject in results) + { + var childProcessId = wmiObject["ProcessID"]; + Logger.Info("Found child process: " + childProcessId + " Name: " + wmiObject["Name"]); + childPids.Add(Convert.ToInt32(childProcessId)); + } +#endif } catch (Exception ex) { diff --git a/src/Core/WinSWCore/WinSWCore.csproj b/src/Core/WinSWCore/WinSWCore.csproj index cc339d4..d6d93e9 100644 --- a/src/Core/WinSWCore/WinSWCore.csproj +++ b/src/Core/WinSWCore/WinSWCore.csproj @@ -14,8 +14,8 @@ + - diff --git a/src/Core/WinSWCore/Wmi.cs b/src/Core/WinSWCore/Wmi.cs index 119123f..c1a34cb 100755 --- a/src/Core/WinSWCore/Wmi.cs +++ b/src/Core/WinSWCore/Wmi.cs @@ -1,13 +1,19 @@ using System; +using System.Diagnostics; +#if !CIM using System.Management; +#endif using System.Reflection; using DynamicProxy; +#if CIM +using Microsoft.Management.Infrastructure; +using Microsoft.Management.Infrastructure.Generic; +#endif namespace WMI { - // Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx - - public enum ReturnValue + // https://docs.microsoft.com/windows/win32/cimwin32prov/create-method-in-class-win32-service + public enum ReturnValue : uint { Success = 0, NotSupported = 1, @@ -45,8 +51,8 @@ namespace WMI { public readonly ReturnValue ErrorCode; - public WmiException(string msg, ReturnValue code) - : base(msg) + public WmiException(string message, ReturnValue code) + : base(message) { ErrorCode = code; } @@ -83,14 +89,21 @@ namespace WMI void Commit(); } - public class WmiRoot + public sealed class WmiRoot { - private readonly ManagementScope scope; +#if CIM + private const string CimNamespace = "root/cimv2"; - public WmiRoot() : this(null) { } + private readonly CimSession cimSession; +#else + private readonly ManagementScope wmiScope; +#endif - public WmiRoot(string? machineName) + public WmiRoot(string? machineName = null) { +#if CIM + this.cimSession = CimSession.Create(machineName); +#else ConnectionOptions options = new ConnectionOptions { EnablePrivileges = true, @@ -104,8 +117,9 @@ namespace WMI path = $@"\\{machineName}\root\cimv2"; else path = @"\root\cimv2"; - scope = new ManagementScope(path, options); - scope.Connect(); + wmiScope = new ManagementScope(path, options); + wmiScope.Connect(); +#endif } private static string Capitalize(string s) @@ -113,96 +127,195 @@ namespace WMI return char.ToUpper(s[0]) + s.Substring(1); } - abstract class BaseHandler : IProxyInvocationHandler + private abstract class BaseHandler : IProxyInvocationHandler { - public abstract object? Invoke(object proxy, MethodInfo method, object[] args); + public abstract object? Invoke(object proxy, MethodInfo method, object[] arguments); - protected void CheckError(ManagementBaseObject result) +#if CIM + protected void CheckError(CimMethodResult result) { - int code = Convert.ToInt32(result["returnValue"]); + uint code = (uint)result.ReturnValue.Value; if (code != 0) throw new WmiException((ReturnValue)code); } +#else + protected void CheckError(ManagementBaseObject result) + { + uint code = (uint)result["returnValue"]; + if (code != 0) + throw new WmiException((ReturnValue)code); + } +#endif + +#if CIM + protected CimMethodParametersCollection GetMethodParameters(CimClass cimClass, string methodName, ParameterInfo[] methodParameters, object[] arguments) + { + CimMethodParametersCollection cimParameters = new CimMethodParametersCollection(); + CimReadOnlyKeyedCollection cimParameterDeclarations = cimClass.CimClassMethods[methodName].Parameters; + for (int i = 0; i < arguments.Length; i++) + { + string capitalizedName = Capitalize(methodParameters[i].Name!); + cimParameters.Add(CimMethodParameter.Create(capitalizedName, arguments[i], cimParameterDeclarations[capitalizedName].CimType, CimFlags.None)); + } + + return cimParameters; + } +#else + 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; + } +#endif } - class InstanceHandler : BaseHandler, IWmiObject + private class InstanceHandler : BaseHandler, IWmiObject { - private readonly ManagementObject _mo; +#if CIM + private readonly CimSession cimSession; + private readonly CimInstance cimInstance; - public InstanceHandler(ManagementObject o) => _mo = o; + public InstanceHandler(CimSession cimSession, CimInstance cimInstance) + { + this.cimSession = cimSession; + this.cimInstance = cimInstance; + } +#else + private readonly ManagementObject wmiObject; - public override object? Invoke(object proxy, MethodInfo method, object[] args) + public InstanceHandler(ManagementObject wmiObject) => this.wmiObject = wmiObject; +#endif + + public override object? Invoke(object proxy, MethodInfo method, object[] arguments) { if (method.DeclaringType == typeof(IWmiObject)) { - return method.Invoke(this, args); + return method.Invoke(this, arguments); } // TODO: proper property support if (method.Name.StartsWith("set_")) { - _mo[method.Name.Substring(4)] = args[0]; +#if CIM + CimProperty cimProperty = this.cimInstance.CimInstanceProperties[method.Name.Substring(4)]; + Debug.Assert((cimProperty.Flags & CimFlags.ReadOnly) == CimFlags.None); + cimProperty.Value = arguments[0]; +#else + this.wmiObject[method.Name.Substring(4)] = arguments[0]; +#endif return null; } if (method.Name.StartsWith("get_")) { - return _mo[method.Name.Substring(4)]; +#if CIM + return this.cimInstance.CimInstanceProperties[method.Name.Substring(4)].Value; +#else + return this.wmiObject[method.Name.Substring(4)]; +#endif } - // method invocations - ParameterInfo[] methodArgs = method.GetParameters(); - - ManagementBaseObject wmiArgs = _mo.GetMethodParameters(method.Name); - for (int i = 0; i < args.Length; i++) - wmiArgs[Capitalize(methodArgs[i].Name!)] = args[i]; - - CheckError(_mo.InvokeMethod(method.Name, wmiArgs, null)); + string methodName = method.Name; +#if CIM + using CimMethodParametersCollection? cimParameters = arguments.Length == 0 ? null : + this.GetMethodParameters(this.cimInstance.CimClass, methodName, method.GetParameters(), arguments); + using CimMethodResult result = this.cimSession.InvokeMethod(CimNamespace, this.cimInstance, methodName, cimParameters); + this.CheckError(result); +#else + 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); +#endif return null; } public void Commit() { - _mo.Put(); +#if !CIM + this.wmiObject.Put(); +#endif } } - class ClassHandler : BaseHandler + private class ClassHandler : BaseHandler { - private readonly ManagementClass _mc; - private readonly string _wmiClass; +#if CIM + private readonly CimSession cimSession; + private readonly CimClass cimClass; +#else + private readonly ManagementClass wmiClass; +#endif + private readonly string className; - public ClassHandler(ManagementClass mc, string wmiClass) { _mc = mc; _wmiClass = wmiClass; } - - public override object? Invoke(object proxy, MethodInfo method, object[] args) +#if CIM + public ClassHandler(CimSession cimSession, string className) { - ParameterInfo[] methodArgs = method.GetParameters(); + this.cimSession = cimSession; + this.cimClass = cimSession.GetClass(CimNamespace, className); + this.className = className; + } +#else + public ClassHandler(ManagementScope wmiScope, string className) + { + this.wmiClass = new ManagementClass(wmiScope, new ManagementPath(className), null); + this.className = className; + } +#endif - if (method.Name.StartsWith("Select")) + public override object? Invoke(object proxy, MethodInfo method, object[] arguments) + { + ParameterInfo[] methodParameters = method.GetParameters(); + + if (method.Name == nameof(Win32Services.Select)) { // select method to find instances - string query = "SELECT * FROM " + _wmiClass + " WHERE "; - for (int i = 0; i < args.Length; i++) + string query = "SELECT * FROM " + this.className + " WHERE "; + for (int i = 0; i < arguments.Length; i++) { if (i != 0) query += " AND "; - query += ' ' + Capitalize(methodArgs[i].Name!) + " = '" + args[i] + "'"; + query += ' ' + Capitalize(methodParameters[i].Name!) + " = '" + arguments[i] + "'"; } - ManagementObjectSearcher searcher = new ManagementObjectSearcher(_mc.Scope, new ObjectQuery(query)); - ManagementObjectCollection results = searcher.Get(); +#if CIM // TODO: support collections - foreach (ManagementObject manObject in results) - return ProxyFactory.GetInstance().Create(new InstanceHandler(manObject), method.ReturnType, true); + foreach (CimInstance cimInstance in this.cimSession.QueryInstances(CimNamespace, "WQL", query)) + { + return ProxyFactory.GetInstance().Create(new InstanceHandler(this.cimSession, cimInstance), method.ReturnType, true); + } +#else + using ManagementObjectSearcher searcher = new ManagementObjectSearcher(this.wmiClass.Scope, new ObjectQuery(query)); + using ManagementObjectCollection results = searcher.Get(); + // TODO: support collections + foreach (ManagementObject wmiObject in results) + { + return ProxyFactory.GetInstance().Create(new InstanceHandler(wmiObject), method.ReturnType, true); + } +#endif + return null; } - ManagementBaseObject wmiArgs = _mc.GetMethodParameters(method.Name); - for (int i = 0; i < args.Length; i++) - wmiArgs[Capitalize(methodArgs[i].Name!)] = args[i]; - - CheckError(_mc.InvokeMethod(method.Name, wmiArgs, null)); + string methodName = method.Name; +#if CIM + using CimMethodParametersCollection? cimParameters = arguments.Length == 0 ? null : + this.GetMethodParameters(this.cimClass, methodName, methodParameters, arguments); + using CimMethodResult result = this.cimSession.InvokeMethod(CimNamespace, this.className, methodName, cimParameters); + this.CheckError(result); +#else + 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); +#endif return null; } } @@ -212,12 +325,16 @@ namespace WMI /// public T GetCollection() where T : IWmiCollection { - WmiClassName cn = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0]; + WmiClassName className = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0]; - ObjectGetOptions getOptions = new ObjectGetOptions(); - ManagementPath path = new ManagementPath(cn.Name); - ManagementClass manClass = new ManagementClass(scope, path, getOptions); - return (T)ProxyFactory.GetInstance().Create(new ClassHandler(manClass, cn.Name), typeof(T), true); + return (T)ProxyFactory.GetInstance().Create( +#if CIM + new ClassHandler(this.cimSession, className.Name), +#else + new ClassHandler(this.wmiScope, className.Name), +#endif + typeof(T), + true); } } } diff --git a/src/Core/WinSWCore/WmiSchema.cs b/src/Core/WinSWCore/WmiSchema.cs index bfa55a1..a3adfbd 100755 --- a/src/Core/WinSWCore/WmiSchema.cs +++ b/src/Core/WinSWCore/WmiSchema.cs @@ -48,18 +48,16 @@ namespace WMI public interface Win32Services : IWmiCollection { // ReturnValue Create(bool desktopInteract, string displayName, int errorControl, string loadOrderGroup, string loadOrderGroupDependencies, string name, string pathName, string serviceDependencies, string serviceType, string startMode, string startName, string startPassword); - void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, StartMode startMode, bool desktopInteract, string? startName, string? startPassword, string[] serviceDependencies); + void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, string startMode, bool desktopInteract, string? startName, string? startPassword, string[] serviceDependencies); - void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, StartMode startMode, bool desktopInteract, string[] serviceDependencies); + void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, string startMode, bool desktopInteract, string[] serviceDependencies); Win32Service Select(string name); } - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa394418(v=vs.85).aspx + // https://docs.microsoft.com/windows/win32/cimwin32prov/win32-service public interface Win32Service : IWmiObject { - string Description { get; set; } - string Name { get; } bool Started { get; } void Delete(); void StartService(); From ec6d9b0a692cbb5c0f166a9e16462c60505ecaf8 Mon Sep 17 00:00:00 2001 From: NextTurn <45985406+NextTurn@users.noreply.github.com> Date: Mon, 19 Aug 2019 00:00:00 +0800 Subject: [PATCH 2/2] Rename to FEATURE_CIM --- Directory.Build.targets | 3 ++- src/Core/WinSWCore/Util/ProcessHelper.cs | 6 ++--- src/Core/WinSWCore/Wmi.cs | 32 ++++++++++++------------ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 2af5e3f..782bcd9 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -5,7 +5,8 @@ - $(DefineConstants);CIM + + $(DefineConstants);FEATURE_CIM diff --git a/src/Core/WinSWCore/Util/ProcessHelper.cs b/src/Core/WinSWCore/Util/ProcessHelper.cs index edce46a..b785f08 100644 --- a/src/Core/WinSWCore/Util/ProcessHelper.cs +++ b/src/Core/WinSWCore/Util/ProcessHelper.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; using System.Diagnostics; -#if !CIM +#if !FEATURE_CIM using System.Management; #endif using System.Threading; using log4net; -#if CIM +#if FEATURE_CIM using Microsoft.Management.Infrastructure; #endif @@ -32,7 +32,7 @@ namespace winsw.Util try { string query = "SELECT * FROM Win32_Process WHERE ParentProcessID = " + pid; -#if CIM +#if FEATURE_CIM using CimSession session = CimSession.Create(null); foreach (CimInstance instance in session.QueryInstances("root/cimv2", "WQL", query)) { diff --git a/src/Core/WinSWCore/Wmi.cs b/src/Core/WinSWCore/Wmi.cs index c1a34cb..22c6b27 100755 --- a/src/Core/WinSWCore/Wmi.cs +++ b/src/Core/WinSWCore/Wmi.cs @@ -1,11 +1,11 @@ using System; using System.Diagnostics; -#if !CIM +#if !FEATURE_CIM using System.Management; #endif using System.Reflection; using DynamicProxy; -#if CIM +#if FEATURE_CIM using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure.Generic; #endif @@ -91,7 +91,7 @@ namespace WMI public sealed class WmiRoot { -#if CIM +#if FEATURE_CIM private const string CimNamespace = "root/cimv2"; private readonly CimSession cimSession; @@ -101,7 +101,7 @@ namespace WMI public WmiRoot(string? machineName = null) { -#if CIM +#if FEATURE_CIM this.cimSession = CimSession.Create(machineName); #else ConnectionOptions options = new ConnectionOptions @@ -131,7 +131,7 @@ namespace WMI { public abstract object? Invoke(object proxy, MethodInfo method, object[] arguments); -#if CIM +#if FEATURE_CIM protected void CheckError(CimMethodResult result) { uint code = (uint)result.ReturnValue.Value; @@ -147,7 +147,7 @@ namespace WMI } #endif -#if CIM +#if FEATURE_CIM protected CimMethodParametersCollection GetMethodParameters(CimClass cimClass, string methodName, ParameterInfo[] methodParameters, object[] arguments) { CimMethodParametersCollection cimParameters = new CimMethodParametersCollection(); @@ -177,7 +177,7 @@ namespace WMI private class InstanceHandler : BaseHandler, IWmiObject { -#if CIM +#if FEATURE_CIM private readonly CimSession cimSession; private readonly CimInstance cimInstance; @@ -202,7 +202,7 @@ namespace WMI // TODO: proper property support if (method.Name.StartsWith("set_")) { -#if CIM +#if FEATURE_CIM CimProperty cimProperty = this.cimInstance.CimInstanceProperties[method.Name.Substring(4)]; Debug.Assert((cimProperty.Flags & CimFlags.ReadOnly) == CimFlags.None); cimProperty.Value = arguments[0]; @@ -214,7 +214,7 @@ namespace WMI if (method.Name.StartsWith("get_")) { -#if CIM +#if FEATURE_CIM return this.cimInstance.CimInstanceProperties[method.Name.Substring(4)].Value; #else return this.wmiObject[method.Name.Substring(4)]; @@ -222,7 +222,7 @@ namespace WMI } string methodName = method.Name; -#if CIM +#if FEATURE_CIM using CimMethodParametersCollection? cimParameters = arguments.Length == 0 ? null : this.GetMethodParameters(this.cimInstance.CimClass, methodName, method.GetParameters(), arguments); using CimMethodResult result = this.cimSession.InvokeMethod(CimNamespace, this.cimInstance, methodName, cimParameters); @@ -238,7 +238,7 @@ namespace WMI public void Commit() { -#if !CIM +#if !FEATURE_CIM this.wmiObject.Put(); #endif } @@ -246,7 +246,7 @@ namespace WMI private class ClassHandler : BaseHandler { -#if CIM +#if FEATURE_CIM private readonly CimSession cimSession; private readonly CimClass cimClass; #else @@ -254,7 +254,7 @@ namespace WMI #endif private readonly string className; -#if CIM +#if FEATURE_CIM public ClassHandler(CimSession cimSession, string className) { this.cimSession = cimSession; @@ -285,7 +285,7 @@ namespace WMI query += ' ' + Capitalize(methodParameters[i].Name!) + " = '" + arguments[i] + "'"; } -#if CIM +#if FEATURE_CIM // TODO: support collections foreach (CimInstance cimInstance in this.cimSession.QueryInstances(CimNamespace, "WQL", query)) { @@ -305,7 +305,7 @@ namespace WMI } string methodName = method.Name; -#if CIM +#if FEATURE_CIM using CimMethodParametersCollection? cimParameters = arguments.Length == 0 ? null : this.GetMethodParameters(this.cimClass, methodName, methodParameters, arguments); using CimMethodResult result = this.cimSession.InvokeMethod(CimNamespace, this.className, methodName, cimParameters); @@ -328,7 +328,7 @@ namespace WMI WmiClassName className = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0]; return (T)ProxyFactory.GetInstance().Create( -#if CIM +#if FEATURE_CIM new ClassHandler(this.cimSession, className.Name), #else new ClassHandler(this.wmiScope, className.Name),