Initial commit
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using IPClab3.Models;
|
||||
using IPClab3.Services;
|
||||
|
||||
namespace IPClab3.ViewModels;
|
||||
|
||||
public partial class MainWindowViewModel(ProcessHackerService processHackerService, FilePickerService filePickerService) : ObservableObject
|
||||
{
|
||||
private ProcessHackerService _processHackerService = processHackerService;
|
||||
private FilePickerService _filePickerService = filePickerService;
|
||||
|
||||
private CancellationTokenSource _cts;
|
||||
private List<ProcessItem> _allProcesses;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<ProcessItem> _suggestions = [];
|
||||
|
||||
private string _searchText = string.Empty;
|
||||
public string SearchText
|
||||
{
|
||||
get => _searchText;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchText, value))
|
||||
{
|
||||
_ = UpdateSuggestionsAsync(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(AttachProcessCommand))]
|
||||
public partial ProcessItem SelectedProcess
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(ReadMemoryCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(WriteMemoryCommand))]
|
||||
public partial int StartedPid
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(ReadMemoryCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(WriteMemoryCommand))]
|
||||
public partial IntPtr MemoryAddress
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private async Task UpdateSuggestionsAsync(string query)
|
||||
{
|
||||
// 1. Cancel the previous running search task immediately
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
_cts = new CancellationTokenSource();
|
||||
var token = _cts.Token;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
Suggestions.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Optional: Debounce briefly (e.g., wait 150ms) to ensure the user
|
||||
// stopped typing before blasting the OS with process queries.
|
||||
await Task.Delay(150, token);
|
||||
|
||||
// 2. Offload the heavy blocking OS operation to a pool thread
|
||||
List<ProcessItem> filteredResults = await Task.Run(() =>
|
||||
{
|
||||
// Check token before starting the heavy lifting
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
// Hit the live OS snapshot
|
||||
var liveSnapshot = Process.GetProcesses();
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
// Filter on the background thread
|
||||
return liveSnapshot
|
||||
.Where(p => p.ProcessName.Contains(query, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(p => new ProcessItem { Pid = p.Id, ProcessName = p.ProcessName })
|
||||
.OrderBy(p => p.ProcessName)
|
||||
.ToList();
|
||||
}, token);
|
||||
|
||||
// 3. Check token one final time before updating the UI thread
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
// Safely swap out items on the Main/UI thread
|
||||
Suggestions.Clear();
|
||||
foreach (var process in filteredResults)
|
||||
{
|
||||
Suggestions.Add(process);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Ignored: Expected when the user types quickly and cancels old operations
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error fetching processes: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(StartProcessCommand))]
|
||||
public partial string FilePath
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public async Task PickFile(IntPtr hwnd)
|
||||
{
|
||||
FilePath = await _filePickerService.RequestFileOpener(hwnd);
|
||||
}
|
||||
|
||||
private bool CanStartProcess()
|
||||
{
|
||||
return File.Exists(FilePath);
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanStartProcess))]
|
||||
public void StartProcess()
|
||||
{
|
||||
StartedPid = _processHackerService.StartProcess(FilePath);
|
||||
}
|
||||
|
||||
private bool CanAttachProcess()
|
||||
{
|
||||
if (SelectedProcess == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.GetProcessById(SelectedProcess.Pid);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentException) { return false; }
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanAttachProcess))]
|
||||
public void AttachProcess()
|
||||
{
|
||||
StartedPid = _processHackerService.AttachProcess(SelectedProcess.Pid);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string ReadData
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = "Прочитать из памяти";
|
||||
|
||||
[ObservableProperty]
|
||||
public partial int ReadLength
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string WriteData
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = "Записать в память";
|
||||
|
||||
private bool CanWorkWithMemory()
|
||||
{
|
||||
return StartedPid != 0 && MemoryAddress != IntPtr.Zero;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanWorkWithMemory))]
|
||||
public void ReadMemory()
|
||||
{
|
||||
if (_processHackerService.ReadMemory(MemoryAddress, ReadLength, out var bytes))
|
||||
ReadData = Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanWorkWithMemory))]
|
||||
public void WriteMemory()
|
||||
{
|
||||
if (_processHackerService.WriteMemory(MemoryAddress, WriteData))
|
||||
{
|
||||
IsSuccessOpen = true;
|
||||
Task.Run(() => { Task.Delay(10000); IsSuccessOpen = false; });
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsSuccessOpen
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user