mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
57dbbce784
- **UI:** - (Improvement) Auto show a horizontal scroll bar on wider than screen contents on the tool windows - (Improvement) Move normal windows to zero position if negative and auto constrain height if necessary - (Improvement) Set a minimum width and minimum height for tool windows - (Fix) Setting - "Allow resize the tool windows" had been lost and no effect when checked - (Add) Windows MSI - Option: Add installation directory to system PATH environment variable - (Improvement) Better fetch of UVtools.Core.dll on PowerShell scripts under Windows - (Improvement) Better handling in get the process output, this fixes processor name not being shown on macOS
409 lines
23 KiB
C#
409 lines
23 KiB
C#
/*
|
|
* GNU AFFERO GENERAL PUBLIC LICENSE
|
|
* Version 3, 19 November 2007
|
|
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
* Everyone is permitted to copy and distribute verbatim copies
|
|
* of this license document, but changing it is not allowed.
|
|
*/
|
|
|
|
using Microsoft.Win32;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
|
|
namespace UVtools.Core.SystemOS;
|
|
|
|
public static class SystemAware
|
|
{
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
public class MEMORYSTATUSEX
|
|
{
|
|
public uint dwLength;
|
|
public uint dwMemoryLoad;
|
|
public ulong ullTotalPhys;
|
|
public ulong ullAvailPhys;
|
|
public ulong ullTotalPageFile;
|
|
public ulong ullAvailPageFile;
|
|
public ulong ullTotalVirtual;
|
|
public ulong ullAvailVirtual;
|
|
public ulong ullAvailExtendedVirtual;
|
|
public MEMORYSTATUSEX()
|
|
{
|
|
dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
|
}
|
|
}
|
|
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer); //Used to use ref with comment below
|
|
// but ref doesn't work.(Use of [In, Out] instead of ref
|
|
//causes access violation exception on windows xp
|
|
//comment: most probably caused by MEMORYSTATUSEX being declared as a class
|
|
//(at least at pinvoke.net). On Win7, ref and struct work.
|
|
|
|
// Alternate Version Using "ref," And Works With Alternate Code Below.
|
|
// Also See Alternate Version Of [MEMORYSTATUSEX] Structure With
|
|
// Fields Documented.
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, EntryPoint = "GlobalMemoryStatusEx", SetLastError = true)]
|
|
static extern bool _GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
|
|
|
public static MEMORYSTATUSEX GetMemoryStatus()
|
|
{
|
|
var statEX = new MEMORYSTATUSEX();
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
GlobalMemoryStatusEx(statEX);
|
|
}
|
|
else if (OperatingSystem.IsLinux())
|
|
{
|
|
if (!File.Exists("/proc/meminfo")) return statEX;
|
|
try
|
|
{
|
|
const ushort factor = 1024;
|
|
var result = File.ReadAllText("/proc/meminfo");
|
|
//var result = "MemTotal: 8288440 kB\nMemFree: 5616380 kB\nMemAvailable: 6885408 kB\nBuffers: 63240 kB\nCached: 1390996 kB\nSwapCached: 0 kB\nActive: 272516 kB\nInactive: 1773312 kB\nActive(anon): 1888 kB\nInactive(anon): 596168 kB\nActive(file): 270628 kB\nInactive(file): 1177144 kB\nUnevictable: 0 kB\nMlocked: 0 kB\nSwapTotal: 2097148 kB\nSwapFree: 2097148 kB\nDirty: 172 kB\nWriteback: 0 kB\nAnonPages: 591608 kB\nMapped: 292288 kB\nShmem: 6464 kB\nKReclaimable: 86228 kB\nSlab: 170544 kB\nSReclaimable: 86228 kB\nSUnreclaim: 84316 kB\nKernelStack: 12160 kB\nPageTables: 13992 kB\nNFS_Unstable: 0 kB\nBounce: 0 kB\nWritebackTmp: 0 kB\nCommitLimit: 6241368 kB\nCommitted_AS: 3588500 kB\nVmallocTotal: 34359738367 kB\nVmallocUsed: 61060 kB\nVmallocChunk: 0 kB\nPercpu: 91136 kB\nHardwareCorrupted: 0 kB\nAnonHugePages: 0 kB\nShmemHugePages: 0 kB\nShmemPmdMapped: 0 kB\nFileHugePages: 0 kB\nFilePmdMapped: 0 kB\nHugePages_Total: 0\nHugePages_Free: 0\nHugePages_Rsvd: 0\nHugePages_Surp: 0\nHugepagesize: 2048 kB\nHugetlb: 0 kB\nDirectMap4k: 216464 kB\nDirectMap2M: 4169728 kB\nDirectMap1G: 5242880 kB";
|
|
var matches = Regex.Matches(result, @"(\S+):\s*(\d+).(\S+)");
|
|
foreach (Match match in matches)
|
|
{
|
|
if (!match.Success || match.Groups.Count < 2) continue;
|
|
ulong value = ulong.Parse(match.Groups[2].Value) * factor;
|
|
switch (match.Groups[1].Value)
|
|
{
|
|
case "MemTotal":
|
|
statEX.ullTotalPhys = value;
|
|
statEX.ullTotalVirtual = value;
|
|
continue;
|
|
case "MemFree":
|
|
statEX.ullAvailPhys = value;
|
|
continue;
|
|
case "MemAvailable":
|
|
statEX.ullAvailVirtual = value;
|
|
continue;
|
|
case "SwapTotal":
|
|
statEX.ullTotalPageFile = value;
|
|
continue;
|
|
case "SwapFree":
|
|
statEX.ullAvailPageFile = value;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.WriteLine(e);
|
|
}
|
|
}
|
|
else if(OperatingSystem.IsMacOS())
|
|
{
|
|
try
|
|
{
|
|
var result = GetProcessOutput("vm_stat");
|
|
|
|
if (string.IsNullOrWhiteSpace(result)) return statEX;
|
|
|
|
//var result = "Mach Virtual Memory Statistics: (page size of 4096 bytes)\nPages free: 3044485.\nPages active: 400375.\nPages inactive: 235679.\nPages speculative: 189311.\nPages throttled: 0.\nPages wired down: 324269.\nPages purgeable: 27417.\n\"Translation faults\": 5500903.\nPages copy-on-write: 388354.\nPages zero filled: 2724856.\nPages reactivated: 410.\nPages purged: 972.\nFile-backed pages: 400847.\nAnonymous pages: 424518.\nPages stored in compressor: 0.\nPages occupied by compressor: 0.\nDecompressions: 0.\nCompressions: 0.\nPageins: 354428.\nPageouts: 0.\nSwapins: 0.\nSwapouts: 0.";
|
|
var matchPageSize = Regex.Match(result, @"page size of (\d+) bytes");
|
|
|
|
if (!matchPageSize.Success || matchPageSize.Groups.Count < 2) return statEX;
|
|
ushort pageSize = ushort.Parse(matchPageSize.Groups[1].Value);
|
|
|
|
var matches = Regex.Matches(result, @"(.*):\s*(\d+)");
|
|
foreach (Match match in matches)
|
|
{
|
|
if (!match.Success || match.Groups.Count < 2) continue;
|
|
|
|
ulong value = ulong.Parse(match.Groups[2].Value) * pageSize;
|
|
|
|
if (match.Groups[1].Value.StartsWith("\"Translation faults\"")) break;
|
|
if (match.Groups[1].Value.StartsWith("Pages "))
|
|
{
|
|
statEX.ullTotalPhys += value;
|
|
}
|
|
|
|
switch (match.Groups[1].Value)
|
|
{
|
|
case "Pages free":
|
|
case "Pages inactive":
|
|
case "Pages purgeable":
|
|
case "Pages throttled":
|
|
case "Pages speculative":
|
|
statEX.ullAvailPhys += value;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
statEX.ullTotalVirtual = statEX.ullTotalPhys;
|
|
statEX.ullAvailVirtual = statEX.ullAvailPhys;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.WriteLine(e);
|
|
}
|
|
}
|
|
|
|
return statEX;
|
|
}
|
|
|
|
public static string? GetProcessorName()
|
|
{
|
|
try
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
/*ManagementObjectSearcher mos =
|
|
new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Processor");
|
|
foreach (ManagementObject mo in mos.Get())
|
|
{
|
|
Console.WriteLine(mo["Name"]);
|
|
}*/
|
|
using var key = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DESCRIPTION\System\CentralProcessor\0");
|
|
return key?.GetValue("ProcessorNameString")?.ToString();
|
|
}
|
|
|
|
if (OperatingSystem.IsLinux())
|
|
{
|
|
if (!File.Exists("/proc/cpuinfo")) return null;
|
|
//var result = "processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 158\nmodel name\t: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz\nstepping\t: 12\nmicrocode\t: 0xffffffff\ncpu MHz\t\t: 3600.011\ncache size\t: 16384 KB\nphysical id\t: 0\nsiblings\t: 6\ncore id\t\t: 0\ncpu cores\t: 6\napicid\t\t: 0\ninitial apicid\t: 0\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 22\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat flush_l1d arch_capabilities\nbugs\t\t: spectre_v1 spectre_v2 spec_store_bypass mds swapgs itlb_multihit srbds\nbogomips\t: 7200.02\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 45 bits physical, 48 bits virtual\npower management:\n\nprocessor\t: 1\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 158\nmodel name\t: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz\nstepping\t: 12\nmicrocode\t: 0xffffffff\ncpu MHz\t\t: 3600.011\ncache size\t: 16384 KB\nphysical id\t: 0\nsiblings\t: 6\ncore id\t\t: 1\ncpu cores\t: 6\napicid\t\t: 1\ninitial apicid\t: 1\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 22\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat flush_l1d arch_capabilities\nbugs\t\t: spectre_v1 spectre_v2 spec_store_bypass mds swapgs itlb_multihit srbds\nbogomips\t: 7200.02\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 45 bits physical, 48 bits virtual\npower management:\n\nprocessor\t: 2\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 158\nmodel name\t: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz\nstepping\t: 12\nmicrocode\t: 0xffffffff\ncpu MHz\t\t: 3600.011\ncache size\t: 16384 KB\nphysical id\t: 0\nsiblings\t: 6\ncore id\t\t: 2\ncpu cores\t: 6\napicid\t\t: 2\ninitial apicid\t: 2\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 22\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat flush_l1d arch_capabilities\nbugs\t\t: spectre_v1 spectre_v2 spec_store_bypass mds swapgs itlb_multihit srbds\nbogomips\t: 7200.02\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 45 bits physical, 48 bits virtual\npower management:\n\nprocessor\t: 3\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 158\nmodel name\t: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz\nstepping\t: 12\nmicrocode\t: 0xffffffff\ncpu MHz\t\t: 3600.011\ncache size\t: 16384 KB\nphysical id\t: 0\nsiblings\t: 6\ncore id\t\t: 3\ncpu cores\t: 6\napicid\t\t: 3\ninitial apicid\t: 3\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 22\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat flush_l1d arch_capabilities\nbugs\t\t: spectre_v1 spectre_v2 spec_store_bypass mds swapgs itlb_multihit srbds\nbogomips\t: 7200.02\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 45 bits physical, 48 bits virtual\npower management:\n\nprocessor\t: 4\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 158\nmodel name\t: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz\nstepping\t: 12\nmicrocode\t: 0xffffffff\ncpu MHz\t\t: 3600.011\ncache size\t: 16384 KB\nphysical id\t: 0\nsiblings\t: 6\ncore id\t\t: 4\ncpu cores\t: 6\napicid\t\t: 4\ninitial apicid\t: 4\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 22\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat flush_l1d arch_capabilities\nbugs\t\t: spectre_v1 spectre_v2 spec_store_bypass mds swapgs itlb_multihit srbds\nbogomips\t: 7200.02\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 45 bits physical, 48 bits virtual\npower management:\n\nprocessor\t: 5\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 158\nmodel name\t: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz\nstepping\t: 12\nmicrocode\t: 0xffffffff\ncpu MHz\t\t: 3600.011\ncache size\t: 16384 KB\nphysical id\t: 0\nsiblings\t: 6\ncore id\t\t: 5\ncpu cores\t: 6\napicid\t\t: 5\ninitial apicid\t: 5\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 22\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat flush_l1d arch_capabilities\nbugs\t\t: spectre_v1 spectre_v2 spec_store_bypass mds swapgs itlb_multihit srbds\nbogomips\t: 7200.02\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 45 bits physical, 48 bits virtual\npower management:";
|
|
var result = File.ReadAllText("/proc/cpuinfo");
|
|
var match = Regex.Match(result, @"model name.*:.(.*)");
|
|
if (!match.Success || match.Groups.Count < 2)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return match.Groups[1].ToString();
|
|
}
|
|
|
|
if (OperatingSystem.IsMacOS())
|
|
{
|
|
return GetProcessOutput("sysctl", "-n machdep.cpu.brand_string")?.TrimEnd('\r', '\n');
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.WriteLine(e);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static bool SelectFileOnExplorer(string filePath)
|
|
{
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
StartProcess("explorer.exe", $"/select,\"{filePath}\"");
|
|
}
|
|
else
|
|
{
|
|
var path = Path.GetDirectoryName(filePath);
|
|
if (path is null) return false;
|
|
StartProcess(path);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void OpenBrowser(string url)
|
|
{
|
|
try
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
using (Process.Start(new ProcessStartInfo(url) { UseShellExecute = true })) {}
|
|
}
|
|
else if (OperatingSystem.IsLinux())
|
|
{
|
|
using (Process.Start("xdg-open", url)) {}
|
|
}
|
|
else if (OperatingSystem.IsMacOS())
|
|
{
|
|
using (Process.Start("open", url)) {}
|
|
}
|
|
else
|
|
{
|
|
// throw
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.WriteLine(e);
|
|
}
|
|
|
|
}
|
|
|
|
public static void StartProcess(string name, string? arguments = null, bool waitForCompletion = false, int waitTimeout = Timeout.Infinite)
|
|
{
|
|
try
|
|
{
|
|
using var process = Process.Start(new ProcessStartInfo(name, arguments!) {UseShellExecute = true});
|
|
if (process is null) return;
|
|
if (waitForCompletion) process.WaitForExit(waitTimeout);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.WriteLine(e);
|
|
}
|
|
}
|
|
|
|
public static void StartThisApplication(string? arguments = null)
|
|
{
|
|
var executable = Environment.ProcessPath;
|
|
|
|
if (File.Exists(executable)) // Direct execute
|
|
{
|
|
StartProcess(executable, arguments);
|
|
}
|
|
}
|
|
|
|
public static string GetExecutableName(string executable)
|
|
{
|
|
return OperatingSystem.IsWindows() ? $"{executable}.exe" : executable;
|
|
}
|
|
|
|
public static (string standardOutput, string errorOutput) GetProcessOutputWithErrors(string filename, string? arguments = null, string? workingDirectory = null, int timeout = Timeout.Infinite)
|
|
{
|
|
using var process = new Process();
|
|
process.StartInfo.WorkingDirectory = workingDirectory;
|
|
process.StartInfo.FileName = filename;
|
|
process.StartInfo.Arguments = arguments;
|
|
process.StartInfo.CreateNoWindow = true;
|
|
process.StartInfo.RedirectStandardOutput = true;
|
|
process.StartInfo.RedirectStandardError = true;
|
|
process.StartInfo.UseShellExecute = false;
|
|
|
|
var standardOutput = new StringBuilder();
|
|
var errorOutput = new StringBuilder();
|
|
|
|
|
|
using var outputWaitHandle = new AutoResetEvent(false);
|
|
using var errorWaitHandle = new AutoResetEvent(false);
|
|
|
|
process.OutputDataReceived += (sender, e) =>
|
|
{
|
|
if (e.Data is null)
|
|
{
|
|
outputWaitHandle.Set();
|
|
}
|
|
else
|
|
{
|
|
standardOutput.AppendLine(e.Data);
|
|
}
|
|
};
|
|
|
|
process.ErrorDataReceived += (sender, e) =>
|
|
{
|
|
if (e.Data is null)
|
|
{
|
|
errorWaitHandle.Set();
|
|
}
|
|
else
|
|
{
|
|
errorOutput.AppendLine(e.Data);
|
|
}
|
|
};
|
|
|
|
process.Start();
|
|
|
|
process.BeginErrorReadLine();
|
|
process.BeginOutputReadLine();
|
|
|
|
process.WaitForExit(timeout);
|
|
outputWaitHandle.WaitOne(timeout);
|
|
errorWaitHandle.WaitOne(timeout);
|
|
|
|
return (standardOutput.ToString(), errorOutput.ToString());
|
|
}
|
|
|
|
public static string GetProcessOutput(string filename, string? arguments = null, string? workingDirectory = null, int timeout = Timeout.Infinite)
|
|
{
|
|
using var process = new Process();
|
|
process.StartInfo.WorkingDirectory = workingDirectory;
|
|
process.StartInfo.FileName = filename;
|
|
process.StartInfo.Arguments = arguments;
|
|
process.StartInfo.CreateNoWindow = true;
|
|
process.StartInfo.RedirectStandardOutput = true;
|
|
process.StartInfo.UseShellExecute = false;
|
|
|
|
var stringBuilder = new StringBuilder();
|
|
|
|
using var outputWaitHandle = new AutoResetEvent(false);
|
|
|
|
process.OutputDataReceived += (sender, e) =>
|
|
{
|
|
if (e.Data is null)
|
|
{
|
|
outputWaitHandle.Set();
|
|
}
|
|
else
|
|
{
|
|
stringBuilder.AppendLine(e.Data);
|
|
}
|
|
};
|
|
|
|
process.Start();
|
|
|
|
process.BeginOutputReadLine();
|
|
|
|
process.WaitForExit(timeout);
|
|
outputWaitHandle.WaitOne(timeout);
|
|
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets if is running under Linux and under AppImage format
|
|
/// </summary>
|
|
public static bool IsRunningLinuxAppImage(out string? path)
|
|
{
|
|
path = null;
|
|
if (!OperatingSystem.IsLinux()) return false;
|
|
path = Environment.GetEnvironmentVariable("APPIMAGE");
|
|
return !string.IsNullOrWhiteSpace(path);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets if is running under Linux and under AppImage format
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static bool IsRunningLinuxAppImage() => IsRunningLinuxAppImage(out _);
|
|
|
|
/// <summary>
|
|
/// Gets if is running under MacOS and under app format
|
|
/// </summary>
|
|
public static bool IsRunningMacOSApp => OperatingSystem.IsMacOS() && AppContext.BaseDirectory.EndsWith(Path.Combine(".app", "Contents", $"MacOS{Path.DirectorySeparatorChar}"));
|
|
|
|
/// <summary>
|
|
/// Gets the main name of the operative system
|
|
/// </summary>
|
|
public static string OperatingSystemName
|
|
{
|
|
get
|
|
{
|
|
if (OperatingSystem.IsWindows()) return "Windows";
|
|
if (OperatingSystem.IsMacOS()) return "macOS";
|
|
if (OperatingSystem.IsLinux()) return "Linux";
|
|
if (OperatingSystem.IsFreeBSD()) return "FreeBSD";
|
|
if (OperatingSystem.IsAndroid()) return "Android";
|
|
if (OperatingSystem.IsIOS()) return "iOS";
|
|
if (OperatingSystem.IsTvOS()) return "Tv OS";
|
|
if (OperatingSystem.IsWatchOS()) return "WatchOS";
|
|
if (OperatingSystem.IsBrowser()) return "Browser";
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the main name of the operative system with architecture
|
|
/// </summary>
|
|
public static string OperatingSystemNameWithArch => $"{OperatingSystemName} {RuntimeInformation.OSArchitecture}";
|
|
} |