using BytecodeApi.Extensions;
using BytecodeApi.Interop;
using BytecodeApi.IO;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Principal;
using System.Text;
namespace BytecodeApi;
///
/// Provides methods to manage an application.
///
public static class ApplicationBase
{
private static bool? _DebugMode;
///
/// Gets the path for the executable file that started the application, not including the executable name.
///
public static string Path => AppDomain.CurrentDomain.BaseDirectory;
///
/// Gets the path for the executable file that started the application, including the executable name.
///
[SupportedOSPlatform("windows")]
public static string FileName
{
get
{
if (field == null)
{
StringBuilder fileName = new(260);
field = Native.GetModuleFileName(0, fileName, fileName.Capacity) != 0 ? fileName.ToString() : throw Throw.Win32();
}
return field;
}
}
///
/// Gets the of the entry assembly.
///
public static Version Version => field ??= Assembly.GetEntryAssembly()?.GetName().Version ?? throw Throw.Win32();
///
/// Gets a value indicating whether was the first time this property is retrieved, or if this executable is located in a directory named like "\bin\Debug", "\bin\x86\Debug", or "\bin\x64\Debug".
///
public static bool DebugMode => _DebugMode ??= Debugger.IsAttached || new[] { @"\bin\Debug", @"\bin\x86\Debug", @"\bin\x64\Debug", @"\$Build" }.Any(path => Path.Replace('/', '\\').Contains($@"{path}\", StringComparison.OrdinalIgnoreCase) || Path.Replace('/', '\\').EndsWith(path, StringComparison.OrdinalIgnoreCase));
///
/// Restarts the current with elevated privileges. Returns , if the process is already elevated; , if elevation failed; if the restart was successful.
///
/// A specifying the commandline for the new .
/// A callback that is invoked after the new was successfully started with elevated privileges. Depending on application type, this is typically or Application.Shutdown() in a GUI app.
///
/// , if the process is already elevated;
/// , if elevation failed;
/// , if the restart was successful.
///
[SupportedOSPlatform("windows")]
public static bool? RestartElevated(string? commandLine, Action? shutdownCallback)
{
if (Process.IsElevated)
{
return null;
}
else
{
try
{
using System.Diagnostics.Process? process = System.Diagnostics.Process.Start(new ProcessStartInfo(FileName, commandLine ?? "")
{
UseShellExecute = true,
Verb = "runas"
});
shutdownCallback?.Invoke();
return true;
}
catch
{
return false;
}
}
}
///
/// Provides information about the current process.
///
public static class Process
{
private static int? _SessionId;
private static ProcessIntegrityLevel? _IntegrityLevel;
private static bool? _IsElevated;
private static ElevationType? _ElevationType;
///
/// Gets the ProcessID of the current .
///
public static int Id
{
get
{
if (field == 0)
{
using System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
field = process.Id;
}
return field;
}
}
///
/// Gets the SessionID of the current .
///
public static int SessionId
{
get
{
if (_SessionId == null)
{
using System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
_SessionId = process.SessionId;
}
return _SessionId.Value;
}
}
///
/// Gets the mandatory integrity level for the current .
///
[SupportedOSPlatform("windows")]
public static ProcessIntegrityLevel IntegrityLevel
{
get
{
if (_IntegrityLevel == null)
{
using System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
_IntegrityLevel = process.IntegrityLevel;
}
return _IntegrityLevel.Value;
}
}
///
/// Gets a value indicating whether the current is elevated or not.
///
[SupportedOSPlatform("windows")]
public static bool IsElevated
{
get
{
if (_IsElevated == null)
{
using WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
_IsElevated = new WindowsPrincipal(windowsIdentity).IsInRole(WindowsBuiltInRole.Administrator);
}
return _IsElevated.Value;
}
}
///
/// Gets the for the current .
///
[SupportedOSPlatform("windows")]
public static ElevationType ElevationType
{
get
{
if (_ElevationType == null)
{
nint token;
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
token = process.OpenToken(8);
}
try
{
using HGlobal elevationTypePtr = new(4);
if (Native.GetTokenInformation(token, 18, elevationTypePtr.Handle, 4, out int returnLength) && returnLength == 4)
{
_ElevationType = (ElevationType)Marshal.ReadInt32(elevationTypePtr.Handle);
}
else
{
throw Throw.Win32();
}
}
finally
{
if (token != 0) Native.CloseHandle(token);
}
}
return _ElevationType.Value;
}
}
///
/// Gets the amount of private memory, in bytes, allocated for the current .
///
public static long Memory
{
get
{
using System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
return process.PrivateMemorySize64;
}
}
///
/// Gets the of the .NET Framework that the current is running with.
///
public static Version FrameworkVersion => field ??= new(typeof(object).Assembly.GetCustomAttribute()?.InformationalVersion.SubstringUntil('+') ?? throw Throw.Win32());
}
///
/// Provides information about the current logon session and related information.
///
[SupportedOSPlatform("windows")]
public static class Session
{
///
/// Gets the name of the current , including the domain or workstation name.
///
public static string CurrentUser => field ??= WindowsIdentity.GetCurrent().Name;
///
/// Gets the name of the current , not including the domain or workstation name.
///
public static string CurrentUserShort => field ??= CurrentUser.SubstringFromLast('\\');
///
/// Gets the domain in which the local computer is registered, or , if the user is not member of a domain.
///
public static string? DomainName => (field ??= IPGlobalProperties.GetIPGlobalProperties().DomainName).ToNullIfEmpty();
///
/// Gets a value indicating whether the current session is an RDP session.
///
public static bool IsRdp => Environment.GetEnvironmentVariable("SESSIONNAME")?.StartsWith("RDP-", StringComparison.OrdinalIgnoreCase) == true;
}
}
[SupportedOSPlatform("windows")]
file static class Native
{
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(nint obj);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetModuleFileName([In] nint module, [Out] StringBuilder fileName, [In][MarshalAs(UnmanagedType.U4)] int size);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(nint tokenHandle, int tokenInformationClass, nint tokenInformation, int tokenInformationLength, out int returnLength);
}