using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using RyzStudio.IO; using RyzStudio.Runtime.InteropServices; using RyzStudio.Windows.Forms; namespace RandomFileRunner { public partial class MainForm : Form { private readonly FileSearcher _fileSearcher; private CancellationTokenSource _cancellationToken = new CancellationTokenSource(); private List _foundFiles = new List(); private Process _currentProcess = null; public MainForm() { InitializeComponent(); _fileSearcher = new FileSearcher(); _fileSearcher.OnDirectoryFound += fileSearcher_OnDirectoryFound; _fileSearcher.OnFileFound += fileSearcher_OnFileFound; _fileSearcher.OnSearchCompleted += fileSearcher_OnSearchCompleted; memoBox1.WordWrap = false; memoBox1.ScrollBars = ScrollBars.Vertical; } protected async override void OnLoad(EventArgs e) { base.OnLoad(e); this.ClearSession(); var args = this.GetCommandLine(); string jsonfigFilename = null; if (!args.TryGetValue("o", out jsonfigFilename)) { if (!args.TryGetValue("open", out jsonfigFilename)) { jsonfigFilename = null; } } if (string.IsNullOrWhiteSpace(jsonfigFilename)) { jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig"); } if (System.IO.File.Exists(jsonfigFilename)) { await LoadSessionFile(jsonfigFilename); UIControl.Invoke(button1, (x) => button1.Enabled = (this.CurrentSession.SearchItems.Count > 0)); } } protected async override void OnShown(EventArgs e) { base.OnShown(e); memoBox1.Focus(); } protected override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); if (this.IsBusy) { e.Cancel = true; return; } if (this.CurrentSession.ClosePrevOnNext) { CloseCurrentProcess(_currentProcess); } if (this.CurrentSession.NextHotKey != null) { if (this.CurrentSession.NextHotKey.KeyCode != Keys.None) { //#if !DEBUG User32.UnregisterHotKey((IntPtr)Handle, 1); //#endif } } } protected override void WndProc(ref Message m) { switch (m.Msg) { case User32.WM_HOTKEY: if (m.WParam.ToInt32() == 1) { dialogFooter1_OnButton1Click(null, null); } break; //case WM_QUERYENDSESSION: // requestExit = true; // //this.Close(); // Application.Exit(); // break; default: break; } base.WndProc(ref m); } public bool IsBusy { get => field; private set { field = value; UIControl.Invoke(pictureBox1, (x) => pictureBox1.Image = (value ? RyzStudio.Resources.T3Resource.loading_block : null)); UIControl.Invoke(textBox1, (x) => textBox1.Enabled = !value); UIControl.Invoke(button1, (x) => button1.LabelText = (value ? "&Cancel" : "&Search")); UIControl.Invoke(dialogFooter1, (x) => dialogFooter1.Button1Visible = !value); } } public AppSession CurrentSession { get { if (field == null) field = new AppSession(); return field; } private set => field = value; } = new AppSession(); private List SearchPathList { get { return (memoBox1.Lines?.ToList() ?? new List()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); } } private void menuStrip1_MenuActivate(object sender, EventArgs e) { saveAsToolStripMenuItem.Enabled = (!this.IsBusy && (this.SearchPathList.Count > 0)); toolStripMenuItem2.Enabled = (!this.IsBusy && (_foundFiles.Count > 0)); } #region Main Menu /// /// New /// /// /// private async void newToolStripMenuItem_Click(object sender, EventArgs e) { await Task.Run(() => { if (this.IsBusy) { return; } if (this.CurrentSession.ClosePrevOnNext) { CloseCurrentProcess(_currentProcess); } ClearSession(); }); } /// /// Open /// /// /// private async void openToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } if (openFileDialog2.ShowDialog() == DialogResult.OK) { await LoadSessionFile(openFileDialog2.FileName); } } /// /// Save as /// /// /// private async void saveAsToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } saveFileDialog1.Title = "Save session"; saveFileDialog1.Filter = "Session files (*.jsonfig)|*.jsonfig"; saveFileDialog1.DefaultExt = "jsonfig"; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { await SaveSessionFile(saveFileDialog1.FileName); } } /// /// Export file list /// /// /// private async void toolStripMenuItem2_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } if (_foundFiles.Count <= 0) { return; } saveFileDialog1.Title = "Save File List"; saveFileDialog1.Filter = "Text files (*.txt)|*.txt"; saveFileDialog1.DefaultExt = "txt"; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { try { await System.IO.File.WriteAllTextAsync(saveFileDialog1.FileName, string.Join(Environment.NewLine, _foundFiles.ToArray())); } catch (Exception exc) { RyzStudio.Forms.T3MessageBox.Show(this, exc.Message, "Save File List", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } /// /// Close /// /// /// private void exitToolStripMenuItem2_Click(object sender, EventArgs e) { this.Close(); } /// /// Export File List /// /// /// private async void toolStripMenuItem1_Click(object sender, EventArgs e) { } /// /// Options /// /// /// private void optionsToolStripMenuItem_Click(object sender, EventArgs e) { if (this.IsBusy) { return; } var optionsForm = new OptionsForm(this.CurrentSession); if (optionsForm.ShowDialog() == DialogResult.OK) { this.CurrentSession = optionsForm.Result; InvalidateHotKey(); } } /// /// Help /// /// /// private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e) { RyzStudio.Diagnostics.Process.Execute(AppResource.AppHelpURL); } /// /// About /// /// /// private void aboutToolStripMenuItem1_Click(object sender, EventArgs e) { var form = new RyzStudio.Forms.T3AboutForm(); form.ProductURL = AppResource.AppProductURL; form.AuthorURL = AppResource.AppAuthorURL; form.CompanyURL = AppResource.AppCompanyURL; form.ProductCopyrightStartYear = 2021; form.ProductLogo = AppResource.icon_64; form.ShowDialog(); } #endregion #region Search Engine private async Task fileSearcher_OnFileFound(FileSearcher sender, string searchPath, string fileName) { await Task.Run(() => { _foundFiles.Add(fileName); UIControl.Invoke(label3, (x) => label3.Text = Path.GetFileName(fileName)); progressBar2.Maximum = (sender.FileCount + sender.NoAccessFileCount); progressBar2.Value = sender.FileCount; }); } private async Task fileSearcher_OnDirectoryFound(FileSearcher sender, string searchPath, string directoryName) { await Task.Run(() => { UIControl.Invoke(label4, (x) => label4.Text = Path.GetFileName(directoryName)); progressBar1.Maximum = sender.DirectoryCount; progressBar1.Value = sender.BufferLevel; }); } private async Task fileSearcher_OnSearchCompleted(FileSearcher sender, TimeSpan elapsedTime) { await Task.Run(() => { if (!_cancellationToken.IsCancellationRequested) { UIControl.Invoke(label4, (x) => label4.Text = $"Done ({Math.Floor(elapsedTime.TotalMinutes)}m {elapsedTime.Seconds}s)"); } else { UIControl.Invoke(label4, (x) => label4.Text = $"Cancelled ({Math.Floor(elapsedTime.TotalMinutes)}m {elapsedTime.Seconds}s)"); _cancellationToken = new CancellationTokenSource(); } UIControl.Invoke(label3, (x) => label3.Text = ((_foundFiles.Count <= 0) ? "0" : _foundFiles.Count.ToString("#,#", System.Globalization.CultureInfo.CurrentCulture)) + " File" + ((_foundFiles.Count == 1) ? "" : "s") + " Found"); progressBar1.Value = sender.BufferLevel; progressBar2.Value = sender.FileCount; UIControl.Invoke(dialogFooter1, (x) => dialogFooter1.Button1Visible = (_foundFiles.Count > 0)); this.IsBusy = false; }); } #endregion /// /// Search /// /// /// private async void button2_MouseClick(object sender, MouseEventArgs e) { if (this.IsBusy) { button1.LabelText = "&Cancelling..."; _cancellationToken.Cancel(); return; } this.IsBusy = true; progressBar1.ShowText = true; progressBar2.ShowText = true; _foundFiles = new List(); _cancellationToken = new CancellationTokenSource(); _currentProcess = null; var paths = this.SearchPathList; _fileSearcher.FileSearchPattern = textBox1.Text; _fileSearcher.SearchPath = new List(); UIControl.Invoke(label4, (x) => label4.Text = $"Peeking..."); UIControl.Invoke(label3, (x) => label3.Text = ""); await Task.Run(() => { foreach (var item in paths) { if (_cancellationToken.IsCancellationRequested) { break; } if (System.IO.File.Exists(item)) { _foundFiles.Add(item); UIControl.Invoke(label3, (x) => label3.Text = item); continue; } if (System.IO.Directory.Exists(item)) { _fileSearcher.SearchPath.Add(item); UIControl.Invoke(label3, (x) => label3.Text = item); continue; } } UIControl.Invoke(label4, (x) => label4.Text = $"Peeking... {paths.Count}"); UIControl.Invoke(label3, (x) => label3.Text = ((_foundFiles.Count <= 0) ? "0" : _foundFiles.Count.ToString("#,#", System.Globalization.CultureInfo.CurrentCulture)) + " File" + ((_foundFiles.Count == 1) ? "" : "s") + " Found"); }); if (_fileSearcher.SearchPath.Count <= 0) { UIControl.Invoke(label4, (x) => label4.Text = $"Done"); UIControl.Invoke(label3, (x) => label3.Text = ((_foundFiles.Count <= 0) ? "0" : _foundFiles.Count.ToString("#,#", System.Globalization.CultureInfo.CurrentCulture)) + " File" + ((_foundFiles.Count == 1) ? "" : "s") + " Found"); } else { UIControl.Invoke(label4, (x) => label4.Text = $"Searching..."); await _fileSearcher.Search(_cancellationToken.Token); } //this.IsBusy = false; } /// /// Close /// /// /// private void button1_MouseClick(object sender, MouseEventArgs e) { this.Close(); } private void CloseCurrentProcess(Process p) { if (p == null) { return; } try { p.CloseMainWindow(); } catch (Exception) { // do nothing } } private void InvalidateHotKey() { //#if !DEBUG UIControl.Invoke(this, (x) => { User32.UnregisterHotKey((IntPtr)Handle, 1); }); //#endif if (this.CurrentSession.NextHotKey != null) { if (this.CurrentSession.NextHotKey.KeyCode != Keys.None) { //#if !DEBUG UIControl.Invoke(this, (x) => { User32.RegisterHotKey((IntPtr)Handle, 1, this.CurrentSession.NextHotKey.ModifierCode, this.CurrentSession.NextHotKey.Key); }); //#endif } } } private void ClearSession() { _foundFiles = new List(); _currentProcess = null; UIControl.Invoke(textBox1, (_) => textBox1.Text = "*.*"); UIControl.Invoke(memoBox1, (_) => memoBox1.Clear()); progressBar1.Clear(0); progressBar2.Clear(0); UIControl.Invoke(label4, (x) => label4.Text = ""); UIControl.Invoke(label3, (x) => label3.Text = ""); UIControl.Invoke(button1, (x) => button1.Enabled = false); UIControl.Invoke(dialogFooter1, (x) => dialogFooter1.Button1Visible = false); } protected async Task LoadSessionFile(string filename) { await Task.Run(async () => { this.CurrentSession = await RyzStudio.Text.Json.JsonSerialiser.DeserialiseFile(filename); ClearSession(); textBox1.Text = (string.IsNullOrWhiteSpace(this.CurrentSession.SearchFilePattern) ? "*" : this.CurrentSession.SearchFilePattern?.Trim()); foreach (var item in this.CurrentSession?.SearchItems) { if (string.IsNullOrWhiteSpace(item)) { continue; } UIControl.Invoke(memoBox1, (_) => memoBox1.AddLine(item)); } UIControl.Invoke(label4, (x) => label4.Text = "Ready"); UIControl.Invoke(button1, (x) => button1.Enabled = (this.CurrentSession?.SearchItems.Count > 0)); // hotkey InvalidateHotKey(); }); } protected async Task SaveSessionFile(string filename) { if (string.IsNullOrWhiteSpace(filename)) { return; } if (this.CurrentSession == null) { this.CurrentSession = new AppSession(); } await Task.Run(() => { this.CurrentSession.SearchFilePattern = textBox1.Text; this.CurrentSession.SearchItems = this.SearchPathList; var result = RyzStudio.Text.Json.JsonSerialiser.SerialiseFile(filename, this.CurrentSession); if (result.Success) { RyzStudio.Forms.T3MessageBox.Show(this, "Session saved!", "Save session"); } else { RyzStudio.Forms.T3MessageBox.Show(this, result.Message, "Save session", MessageBoxButtons.OK, MessageBoxIcon.Error); } }); } /// /// Run Next /// /// /// private async void dialogFooter1_OnButton1Click(object sender, MouseEventArgs e) { if (this.IsBusy) { return; } if (_foundFiles.Count <= 0) { return; } await Task.Run(() => { this.IsBusy = true; if (this.CurrentSession.ClosePrevOnNext) { CloseCurrentProcess(_currentProcess); } string filename = null; // retry 8 times for (int i = 0; i < this.CurrentSession.RetryOnError; i++) { filename = _foundFiles[Random.Shared.Next(0, (_foundFiles.Count - 1))]; if (System.IO.File.Exists(filename)) { continue; } filename = null; } if (!string.IsNullOrWhiteSpace(filename)) { _currentProcess = RyzStudio.Diagnostics.Process.Execute(filename); } this.IsBusy = false; }); } /// /// Close /// /// /// private void dialogFooter1_OnButton2Click(object sender, MouseEventArgs e) { this.Close(); } private void memoBox1_TextChanged(object sender, EventArgs e) { UIControl.Invoke(button1, (x) => button1.Enabled = !string.IsNullOrWhiteSpace(memoBox1.Text)); } } }