using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using System.Security; using System.Text; using System.Threading.Tasks; namespace RoboSharp { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static class VersionManager { public enum VersionCheckType { UseRtlGetVersion, UseWMI } public static VersionCheckType VersionCheck { get; set; } = VersionManager.VersionCheckType.UseRtlGetVersion; private static double? version; public static double Version { get { if (version == null) { if (VersionCheck == VersionCheckType.UseWMI) { var v = GetOsVersion(); version = GetOsVersionNumber(v); return version.Value; } else { var osVersionInfo = new OSVERSIONINFOEX { OSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)) }; RtlGetVersion(ref osVersionInfo); var versionString = $"{osVersionInfo.MajorVersion}.{osVersionInfo.MinorVersion}{osVersionInfo.BuildNumber}"; version = GetOsVersionNumber(versionString); return version.Value; } } else { return version.Value; } } } static VersionManager() { System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone(); customCulture.NumberFormat.NumberDecimalSeparator = "."; System.Threading.Thread.CurrentThread.CurrentCulture = customCulture; } private static string GetOsVersion() { #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER using (var session = Microsoft.Management.Infrastructure.CimSession.Create(".")) { var win32OperatingSystemCimInstance = session.QueryInstances("root\\cimv2", "WQL", "SELECT Version FROM Win32_OperatingSystem").FirstOrDefault(); if (win32OperatingSystemCimInstance?.CimInstanceProperties["Version"] != null) { return win32OperatingSystemCimInstance.CimInstanceProperties["Version"].Value.ToString(); } } #endif #if NET40_OR_GREATER using (System.Management.ManagementObjectSearcher objMOS = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem")) { foreach (System.Management.ManagementObject objManagement in objMOS.Get()) { var version = objManagement.GetPropertyValue("Version"); if (version != null) { return version.ToString(); } } } #endif return Environment.OSVersion.Version.ToString(); } private static double GetOsVersionNumber(string version) { if (version.IsNullOrWhiteSpace()) return 0; var segments = version.Split(new char[] { '.' }); var major = Convert.ToDouble(segments[0]); var otherSegments = segments.Skip(1).ToArray(); var dec = Convert.ToDouble("." + string.Join("", otherSegments), CultureInfo.InvariantCulture); return major + dec; } /// /// taken from https://stackoverflow.com/a/49641055 /// /// /// [SecurityCritical] [DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern int RtlGetVersion(ref OSVERSIONINFOEX versionInfo); [StructLayout(LayoutKind.Sequential)] private struct OSVERSIONINFOEX { // The OSVersionInfoSize field must be set to Marshal.SizeOf(typeof(OSVERSIONINFOEX)) internal int OSVersionInfoSize; internal int MajorVersion; internal int MinorVersion; internal int BuildNumber; internal int PlatformId; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] internal string CSDVersion; internal ushort ServicePackMajor; internal ushort ServicePackMinor; internal short SuiteMask; internal byte ProductType; internal byte Reserved; } } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member }