using MahApps.Metro.Controls; using MahApps.Metro.Controls.Dialogs; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; namespace GTAOnlineCasinoHelper.Views { public partial class AutoLobby : UserControl { [Flags] public enum ThreadAccess : int { TERMINATE = (0x0001), SUSPEND_RESUME = (0x0002), GET_CONTEXT = (0x0008), SET_CONTEXT = (0x0010), SET_INFORMATION = (0x0020), QUERY_INFORMATION = (0x0040), SET_THREAD_TOKEN = (0x0080), IMPERSONATE = (0x0100), DIRECT_IMPERSONATION = (0x0200) } [DllImport("kernel32.dll")] static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); [DllImport("kernel32.dll")] static extern uint SuspendThread(IntPtr hThread); [DllImport("kernel32.dll")] static extern int ResumeThread(IntPtr hThread); [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)] static extern bool CloseHandle(IntPtr handle); private const int SECONDS = 8; private const int TIMER_INTERVAL = 50; private const string PROCESS_NAME = "GTA5"; private int Seconds { get { if (CheckBox_OverrideTimeout.IsChecked.HasValue && CheckBox_OverrideTimeout.IsChecked.Value && int.TryParse(TextBox_TimeoutSeconds.Text, out int seconds)) { return seconds; } else { return SECONDS; } } } private string ProcessName { get { return (CheckBox_OverrideProcessName.IsChecked.HasValue && CheckBox_OverrideProcessName.IsChecked.Value) ? TextBox_ProcessName.Text : PROCESS_NAME; } } private bool IsSuspended { get { return suspendedProcesses != null && suspendedProcesses.Length > 0; } } private Process[] suspendedProcesses = new Process[0]; private Timer timer; private DateTimeOffset timestamp = DateTimeOffset.MinValue; public AutoLobby() { this.InitializeComponent(); this.TextBox_ProcessName.Text = PROCESS_NAME; this.TextBox_TimeoutSeconds.Text = SECONDS.ToString(); this.timer = new Timer(Timer_Tick, this, Timeout.Infinite, TIMER_INTERVAL); } private double GetMilliseconds() { return DateTime.Now.ToUniversalTime().Subtract( new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) ).TotalMilliseconds; } private void Timer_Tick(object state) { Dispatcher.Invoke(() => { if (!IsSuspended) { TextBlock_Status.Text = ""; this.timer.Change(Timeout.Infinite, 50); } TimeSpan timeSpan = timestamp - DateTimeOffset.Now; if (timeSpan.TotalMilliseconds < 0) { ResumeGTA(); TextBlock_Status.Text = ""; return; } TextBlock_Status.Text = $"{timeSpan.TotalSeconds.ToString("F3")}s"; }); } private void CheckBox_OverrideProcessName_Checked(object sender, RoutedEventArgs e) { TextBox_ProcessName.Visibility = Visibility.Visible; } private void CheckBox_OverrideProcessName_Unchecked(object sender, RoutedEventArgs e) { TextBox_ProcessName.Visibility = Visibility.Collapsed; } private void CheckBox_OverrideTimeout_Checked(object sender, RoutedEventArgs e) { TextBox_TimeoutSeconds.Visibility = Visibility.Visible; } private void CheckBox_OverrideTimeout_Unchecked(object sender, RoutedEventArgs e) { TextBox_TimeoutSeconds.Visibility = Visibility.Collapsed; } private async void Button_AutoLobby_Click(object sender, RoutedEventArgs e) { if (IsSuspended) { await MainWindow.Instance.ShowMessageAsync("GTA V is already suspended", $"GTA V ({ProcessName}.exe) is already suspended"); return; } if (!SuspendGTA()) { await MainWindow.Instance.ShowMessageAsync("GTA V is not running", $"GTA V ({ProcessName}.exe) is not running"); return; } timestamp = DateTimeOffset.Now + new TimeSpan(0, 0, Seconds); TextBlock_Status.Text = $"{Seconds}.000s"; timer.Change(TIMER_INTERVAL, TIMER_INTERVAL); } private async void Button_Suspend_Click(object sender, RoutedEventArgs e) { if (IsSuspended) { await MainWindow.Instance.ShowMessageAsync("GTA V is already suspended", $"GTA V ({ProcessName}.exe) is already suspended"); return; } if (!SuspendGTA()) { await MainWindow.Instance.ShowMessageAsync("GTA V is not running", $"GTA V ({ProcessName}.exe) is not running"); return; } TextBlock_Status.Text = "Suspended"; } private async void Button_Resume_Click(object sender, RoutedEventArgs e) { if (!IsSuspended) { await MainWindow.Instance.ShowMessageAsync("GTA V is not suspended", $"GTA V ({ProcessName}.exe) is not suspended"); return; } ResumeGTA(); TextBlock_Status.Text = ""; } private static void SuspendProcess(int pid) { var process = Process.GetProcessById(pid); if (process.ProcessName == string.Empty) return; foreach (ProcessThread pT in process.Threads) { IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); if (pOpenThread == IntPtr.Zero) { continue; } SuspendThread(pOpenThread); CloseHandle(pOpenThread); } } public static void ResumeProcess(int pid) { var process = Process.GetProcessById(pid); if (process.ProcessName == string.Empty) return; foreach (ProcessThread pT in process.Threads) { IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); if (pOpenThread == IntPtr.Zero) { continue; } var suspendCount = 0; do { suspendCount = ResumeThread(pOpenThread); } while (suspendCount > 0); CloseHandle(pOpenThread); } } private bool SuspendGTA() { suspendedProcesses = Process.GetProcessesByName(ProcessName); if (suspendedProcesses.Length < 1) { return false; } foreach (Process process in suspendedProcesses) { SuspendProcess(process.Id); } //labelState.Text = "Suspended"; return true; } private void ResumeGTA() { timer.Change(Timeout.Infinite, TIMER_INTERVAL); foreach (var process in suspendedProcesses) { ResumeProcess(process.Id); } suspendedProcesses = new Process[0]; TextBlock_Status.Text = ""; } } }