/// <summary> /// Fetches the Windows version from system files /// </summary> /// <param name="version">System version</param> /// <returns>True if successful, false otherwise</returns> internal static bool TryCheckWindowsFileVersion(out Version version) { foreach (string file in new[] { "cmd.exe", "conhost.exe", "dxdiag.exe", "msinfo32.exe", "msconfig.exe", "mspaint.exe", "notepad.exe", "winver.exe" }) { FileVersionInfo fileVersionInfo; try { // use a system file to obtain the true version string path = Path.Combine(Environment.SystemDirectory, file); if (!File.Exists(path)) { continue; } fileVersionInfo = FileVersionInfo.GetVersionInfo(path); } catch (Exception ex) { PlatformSettings.Log($"Failed to get the version of {file}! {ex.Message}", LogType.Warning); continue; } version = new Version(fileVersionInfo.FileMajorPart, fileVersionInfo.FileMinorPart, fileVersionInfo.FileBuildPart); if (!IsValidWindowsVersion(version)) { version = new Version(fileVersionInfo.ProductMajorPart, fileVersionInfo.ProductMinorPart, fileVersionInfo.ProductBuildPart); } if (IsValidWindowsVersion(version)) { return(true); } } version = null; return(false); }
private static bool TryGetPatches(out string info, out string patches) { info = null; patches = null; try { // disabled since Wine 5.9, should still work on older versions though WinePatch *patch = GetWinePatches(); if (patch == null) { PlatformSettings.Log("Wine Staging detected, but no patches found!", LogType.Debug); return(false); } int patchCount = 0; StringBuilder patchBuilder = StringBuilderPool.Shared.Rent(); while (patch->author != IntPtr.Zero) { patchCount++; // ReSharper disable once HeapView.BoxingAllocation patchBuilder.AppendFormat("Author: {0} Subject: {1} Revision: {2}", Marshal.PtrToStringAnsi(patch->author), Marshal.PtrToStringAnsi(patch->subject), patch->revision); patch++; } patches = patchBuilder.ToString(); StringBuilderPool.Shared.Return(patchBuilder); // ReSharper disable once HeapView.BoxingAllocation info = $" (Staging - {patchCount} patches)"; return(true); } catch (Exception ex) { PlatformSettings.Log($"Wine Staging not detected! {ex.Message}", LogType.Debug); } return(false); }
/// <summary> /// Checks /etc/os-release for Linux distribution info /// </summary> /// <param name="version">OS version</param> /// <param name="name">Used Linux distribution</param> /// <returns>True if operation was successful</returns> private static bool TryGetUnixOs(out Version version, out string name) { version = Environment.OSVersion.Version; // linux distributions store info about themselves here const string osrelease = "/etc/os-release"; try { if (File.Exists(osrelease)) { using (FileStream fs = new FileStream(osrelease, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (StreamReader sr = new StreamReader(fs)) { string line; while ((line = sr.ReadLine()) != null) { line = line.Trim(); const string prettyname = "PRETTY_NAME="; if (line.StartsWith(prettyname)) { name = $"{line.Substring(prettyname.Length).Replace("\"", "").Trim()} {Environment.OSVersion.VersionString}".Trim(); return(true); } } } } } } catch (Exception ex) { PlatformSettings.Log($"Error while reading {osrelease}: {ex.Message}", LogType.Warning); } name = null; return(false); }
static WineInfo() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // Wine will always report as Windows UsesWine = false; WineVersion = null; return; } try { // this will fail on Windows or when user disables exporting wine_get_version string wineVersion = GetWineVersion(); if (string.IsNullOrWhiteSpace(wineVersion)) { UsesWine = false; WineVersion = null; return; } UsesWine = true; WineVersion = $"Wine {wineVersion}"; } catch (Exception ex) { // not using Wine, ignore PlatformSettings.Log($"Wine not detected! {ex.Message}", LogType.Debug); UsesWine = false; WineVersion = null; return; } try { string wineBuild = GetWineBuildId(); if (!string.IsNullOrWhiteSpace(wineBuild)) { WineVersion += $" {wineBuild}"; } } catch (Exception ex) { PlatformSettings.Log($"Wine build not detected! {ex.Message}", LogType.Debug); } if (TryGetPatches(out string info, out string patches)) { WineVersion += info; WinePatches = patches; } try { GetWineHostVersion(out string sysname, out string release); WineHost = "Host:"; if (!string.IsNullOrWhiteSpace(sysname)) { WineHost += $" {sysname}"; } if (!string.IsNullOrWhiteSpace(release)) { WineHost += $" {release}"; } WineVersion += $" {WineHost}"; } catch (Exception ex) { PlatformSettings.Log($"Wine host not detected! {ex.Message}", LogType.Debug); } WineVersion = WineVersion.Trim(); PlatformSettings.Log($"{WineVersion} detected!", LogType.Info); }
private static string GetProductInfo(Version osVersion, Version spVersion) { uint pdwReturnedProductType; try { if (!GetProductInfo((uint)osVersion.Major, (uint)osVersion.Minor, (uint)spVersion.Major, (uint)spVersion.Minor, out pdwReturnedProductType)) { return(null); } } catch (Exception ex) { PlatformSettings.Log($"Error while fetching the product info: {ex.Message}", LogType.Error); return(null); } // from https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getproductinfo switch (pdwReturnedProductType) { case 0x00000006: return("Business"); case 0x00000010: return("Business N"); case 0x00000012: return("HPC Edition"); case 0x00000040: return("Server Hyper Core V"); case 0x00000065: return("Home"); case 0x00000063: return("Home China"); case 0x00000062: return("Home N"); case 0x00000064: return("Home Single Language"); case 0x00000050: return("Server Datacenter (evaluation installation)"); case 0x00000091: return("Server Datacenter, Semi-Annual Channel (core installation)"); case 0x00000092: return("Server Standard, Semi-Annual Channel (core installation)"); case 0x00000008: return("Server Datacenter (full installation)"); case 0x0000000C: return("Server Datacenter (core installation)"); case 0x00000027: return("Server Datacenter without Hyper-V (core installation)"); case 0x00000025: return("Server Datacenter without Hyper-V (full installation)"); case 0x00000079: return("Education"); case 0x0000007A: return("Education N"); case 0x00000004: return("Enterprise"); case 0x00000046: return("Enterprise E"); case 0x00000048: return("Enterprise Evaluation"); case 0x0000001B: return("Enterprise N"); case 0x00000054: return("Enterprise N Evaluation"); case 0x0000007D: return("Enterprise 2015 LTSB"); case 0x00000081: return("Enterprise 2015 LTSB Evaluation"); case 0x0000007E: return("Enterprise 2015 LTSB N"); case 0x00000082: return("Enterprise 2015 LTSB N Evaluation"); case 0x0000000A: return("Server Enterprise (full installation)"); case 0x0000000E: return("Server Enterprise (core installation)"); case 0x00000029: return("Server Enterprise without Hyper-V (core installation)"); case 0x0000000F: return("Server Enterprise for Itanium-based Systems"); case 0x00000026: return("Server Enterprise without Hyper-V (full installation)"); case 0x0000003C: return("Essential Server Solution Additional"); case 0x0000003E: return("Essential Server Solution Additional SVC"); case 0x0000003B: return("Essential Server Solution Management"); case 0x0000003D: return("Essential Server Solution Management SVC"); case 0x00000002: return("Home Basic"); case 0x00000043: return("Not supported"); case 0x00000005: return("Home Basic N"); case 0x00000003: return("Home Premium"); case 0x00000044: return("Not supported"); case 0x0000001A: return("Home Premium N"); case 0x00000022: return("Home Server 2011"); case 0x00000013: return("Storage Server 2008 R2 Essentials"); case 0x0000002A: return("Microsoft Hyper-V Server"); case 0x0000007B: return("IoT Core"); case 0x00000083: return("IoT Core Commercial"); case 0x0000001E: return("Essential Business Server Management Server"); case 0x00000020: return("Essential Business Server Messaging Server"); case 0x0000001F: return("Essential Business Server Security Server"); case 0x00000068: return("Mobile"); case 0x00000085: return("Mobile Enterprise"); case 0x0000004D: return("MultiPoint Server Premium (full installation)"); case 0x0000004C: return("MultiPoint Server Standard (full installation)"); case 0x000000A1: return("Pro for Workstations"); case 0x000000A2: return("Pro for Workstations N"); case 0x00000030: return("Pro"); case 0x00000045: return("Not supported"); case 0x00000031: return("Pro N"); case 0x00000067: return("Professional with Media Center"); case 0x00000032: return("Small Business Server 2011 Essentials"); case 0x00000036: return("Server For SB Solutions EM"); case 0x00000033: return("Server For SB Solutions"); case 0x00000037: return("Server For SB Solutions EM"); case 0x00000018: return("Server 2008 for Windows Essential Server Solutions"); case 0x00000023: return("Server 2008 without Hyper-V for Windows Essential Server Solutions"); case 0x00000021: return("Server Foundation"); case 0x00000009: return("Small Business Server"); case 0x00000019: return("Small Business Server Premium"); case 0x0000003F: return("Small Business Server Premium (core installation)"); case 0x00000038: return("MultiPoint Server"); case 0x0000004F: return("Server Standard (evaluation installation)"); case 0x00000007: return("Server Standard (full installation)"); case 0x0000000D: return("Server Standard (core installation)"); case 0x00000028: return("Server Standard without Hyper-V (core installation)"); case 0x00000024: return("Server Standard without Hyper-V"); case 0x00000034: return("Server Solutions Premium"); case 0x00000035: return("Server Solutions Premium (core installation)"); case 0x0000000B: return("Starter"); case 0x00000042: return("Not supported"); case 0x0000002F: return("Starter N"); case 0x00000017: return("Storage Server Enterprise"); case 0x0000002E: return("Storage Server Enterprise (core installation)"); case 0x00000014: return("Storage Server Express"); case 0x0000002B: return("Storage Server Express (core installation)"); case 0x00000060: return("Storage Server Standard (evaluation installation)"); case 0x00000015: return("Storage Server Standard"); case 0x0000002C: return("Storage Server Standard (core installation)"); case 0x0000005F: return("Storage Server Workgroup (evaluation installation)"); case 0x00000016: return("Storage Server Workgroup"); case 0x0000002D: return("Storage Server Workgroup (core installation)"); case 0x00000001: return("Ultimate"); case 0x00000047: return("Not supported"); case 0x0000001C: return("Ultimate N"); case 0x00000000: return("An unknown product"); case 0x00000011: return("Web Server (full installation)"); case 0x0000001D: return("Web Server (core installation)"); // ReSharper disable once HeapView.BoxingAllocation default: return($"0x{pdwReturnedProductType:X8}"); } }
private static string ProcessWindowsVersion(Version version, bool server) { if (server) { switch (version.Major) { case 10: switch (version.Minor) { case 0 when version.Build >= 20348: return("Server 2022"); case 0 when version.Build >= 17677: return("Server 2019"); case 0: return("Server 2016"); } break; case 6: switch (version.Minor) { case 3: return("Server 2012 R2"); case 2: return("Server 2012"); case 1: return("Server 2008 R2"); case 0: return("Server 2008"); } break; case 5: try { switch (version.Minor) { // from https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics case 2 when GetSystemMetrics(89) != 0: return("Server 2003 R2"); case 2: return("Server 2003"); } } catch (Exception ex) { PlatformSettings.Log($"Error while fetching the Windows Server version: {ex.Message}", LogType.Warning); if (version.Minor == 2) { return("Server 2003 - Error"); } } break; } } else { switch (version.Major) { case 10: switch (version.Minor) { case 0 when version.Build == 10240: return("10 1507"); case 0 when version.Build == 10586: return("10 1511"); case 0 when version.Build == 14393: return("10 1607"); case 0 when version.Build == 15063: return("10 1703"); case 0 when version.Build == 16299: return("10 1709"); case 0 when version.Build == 17134: return("10 1803"); case 0 when version.Build == 17763: return("10 1809"); case 0 when version.Build == 18362: return("10 1903"); case 0 when version.Build == 18363: return("10 1909"); case 0 when version.Build == 19041: return("10 2004"); case 0 when version.Build == 19042: return("10 20H2"); case 0 when version.Build == 19043: return("10 21H1"); case 0 when version.Build == 19044: return("10 21H2"); case 0 when version.Build == 22000: return("11"); case 0 when version.Build < 22000: return("10 Preview"); case 0: return("11 Dev Channel"); } break; case 6: switch (version.Minor) { case 4: return("10 Prerelease"); case 3: return("8.1"); case 2: return("8"); case 1: return("7"); case 0: return("Vista"); } break; case 5: switch (version.Minor) { case 2: return("XP Professional x64 Edition"); case 1: return("XP"); case 0: return("2000"); } break; } } return("Unknown"); }
private static bool TryGetWindowsVersion(out Version version, out string name) { name = WineInfo.UsesWine ? $"{WineInfo.WineVersion} " : ""; version = null; bool server = false; string servicePack = null; Version servicePackVersion = null; try { OSVERSIONINFO osVersionInfo = new OSVERSIONINFO { dwOSVersionInfoSize = (uint)Marshal.SizeOf <OSVERSIONINFO>() }; uint status = GetVersion(ref osVersionInfo); if (status != 0) { throw new Win32Exception(NtStatusToDosCode(status)); } version = new Version((int)osVersionInfo.dwMajorVersion, (int)osVersionInfo.dwMinorVersion, (int)osVersionInfo.dwBuildNumber); // from https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw server = osVersionInfo.wProductType != 1; servicePack = osVersionInfo.szCSDVersion; servicePackVersion = new Version(osVersionInfo.wServicePackMajor, osVersionInfo.wServicePackMinor); } catch (Exception ex) { PlatformSettings.Log($"Failed to get Windows version! {ex.Message}", LogType.Warning); } if (!IsValidWindowsVersion(version)) { try { OSVERSIONINFO osVersionInfo = new OSVERSIONINFO { dwOSVersionInfoSize = (uint)Marshal.SizeOf <OSVERSIONINFO>() }; if (!GetVersionFallback(ref osVersionInfo)) { throw new Win32Exception(); } version = new Version((int)osVersionInfo.dwMajorVersion, (int)osVersionInfo.dwMinorVersion, (int)osVersionInfo.dwBuildNumber); // from https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw server = osVersionInfo.wProductType != 1; servicePack = osVersionInfo.szCSDVersion; servicePackVersion = new Version(osVersionInfo.wServicePackMajor, osVersionInfo.wServicePackMinor); } catch (Exception ex) { PlatformSettings.Log($"Failed to correct Windows version with GetVersionExW! {ex.Message}", LogType.Warning); } } try { if (!IsValidWindowsVersion(version) && TryCheckWindowsFileVersion(out Version fileVersion)) { // ReSharper disable HeapView.BoxingAllocation PlatformSettings.Log($"Correcting system version using files from {version?.Major ?? 0}.{version?.Minor ?? 0}.{version?.Build ?? 0} to {fileVersion.Major}.{fileVersion.Minor}.{fileVersion.Build}", LogType.Warning); // ReSharper restore HeapView.BoxingAllocation version = fileVersion; } } catch (Exception ex) { PlatformSettings.Log($"Failed to correct Windows version using files! {ex.Message}", LogType.Warning); } if (!IsValidWindowsVersion(version)) { version = Environment.OSVersion.Version; } if (servicePack == null) { servicePack = Environment.OSVersion.ServicePack; } if (servicePackVersion == null) { switch (Environment.OSVersion.ServicePack) { case "Service Pack 1": servicePackVersion = new Version(1, 0); break; case "Service Pack 2": servicePackVersion = new Version(2, 0); break; case "Service Pack 3": servicePackVersion = new Version(3, 0); break; } } // ReSharper disable HeapView.BoxingAllocation name += $"Windows {ProcessWindowsVersion(version, server)}"; string product = GetProductInfo(version, servicePackVersion); if (!string.IsNullOrWhiteSpace(product)) { name += $" {product}"; } name += $" {version?.Major ?? 0}.{version?.Minor ?? 0}.{version?.Build ?? 0}"; if (servicePackVersion != null && (servicePackVersion.Major != 0 || servicePackVersion.Minor != 0)) { name += $"-{servicePackVersion.Major}.{servicePackVersion.Minor}"; } if (!string.IsNullOrWhiteSpace(servicePack)) { name += $" {servicePack}"; } int systemBits = Environment.Is64BitOperatingSystem ? 64 : 32; int processBits = IntPtr.Size * 8; if (systemBits == processBits) { name += $" {systemBits}bit"; } else { name += $" {systemBits}bit Process: {processBits}bit"; } name = name.Trim(); // ReSharper restore HeapView.BoxingAllocation return(true); }