using System; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Windows.Forms; using Serilog; namespace DeheadEmAll_GUI { /// /// The DeheadEmAll Class which interacts with the Main Program Class. /// public partial class FrmDeheadEmAll : Form { #region Constructors DeheadEmAll.DeheadEmAll DHEA = new DeheadEmAll.DeheadEmAll(); /// /// Constructor /// public FrmDeheadEmAll() { InitializeComponent(); // Print the version. DHEA.PrintVersion(); // Load the options passed from the command line arguments. DHEA.LoadOptionsFromCLI(Environment.GetCommandLineArgs()); // Load the options passed from the default options file. DHEA.LoadOptionsFromFile(); // Add data bindings. chkA7800.DataBindings.Add("Checked", DHEA, "A7800"); chkNES.DataBindings.Add("Checked", DHEA, "NES"); chkLynx.DataBindings.Add("Checked", DHEA, "Lynx"); chkFDS.DataBindings.Add("Checked", DHEA, "FDS"); txtPathROMsDir.DataBindings.Add("Text", DHEA, "PathROMsDir"); txtPathROMsDeheaderedDir.DataBindings.Add("Text", DHEA, "PathROMsDeheadedDir"); cbLanguage.DataBindings.Add("SelectedItem", DHEA, "Language"); cbLogLevel.DataBindings.Add("SelectedItem", DHEA, "LogLevel"); // Update the title. UpdateTitle(); // Hide the Help and License tabs. tcMain.TabPages.Remove(tabHelp); tcMain.TabPages.Remove(tabLicense); tcMain.TabPages.Remove(tabDonations); // Load the GUI RichTextBoxes from resources. rtbHelp.Text = DeheadEmAll.Properties.Resources.DeheadEmAll_HELP; rtbLicense.Text = DeheadEmAll.Properties.Resources.DeheadEmAll_LICENSE; rtbDonations.Text = DeheadEmAll.Properties.Resources.DeheadEmAll_DONATIONS; } #endregion #region Getters/Setters Public Accessors /// LogLines public string[] LogLines { get { return rtblLog.Lines; } set { rtblLog.Lines = value; } } #endregion #region Log /// /// Saves the log to a text file. /// /// /// private bool SaveLogToFile(string strPath = null) { try { if (strPath != null) { DHEA.PathLogFile = strPath; } // Determine if the user selected a log filename. if (DHEA.PathLogFile.Length == 0) { // Return a bool value. return false; } else { // Print to screen Log.Information("Saving log file ..."); // Create log file directory if it doesn't exist. if (Directory.Exists(Path.GetDirectoryName(DHEA.PathLogFile)) == false) Directory.CreateDirectory(Path.GetDirectoryName(DHEA.PathLogFile)); // Save the contents of the log to a text file. File.WriteAllLines(DHEA.PathLogFile, LogLines); // Print to screen Log.Information("Log file saved (" + DHEA.PathLogFile + ")"); // Return a bool value. return true; } } catch (Exception ex) { // Print to screen Log.Error("Saving log file failed"); Log.Error(ex.Message); // Return a bool value. return false; } } #endregion #region Startup Tasks /// /// Performs the startup tasks BGW DoWork. /// /// /// private void StartupTasks_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { // Run startup tasks. DHEA.StartupTasks(); } /// /// Startup tasks BGW RunWorkerCompleted. /// /// /// private void StartupTasks_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { if (e.Cancelled) { Log.Warning("Startup tasks canceled"); Log.Information("Ready"); } else if (e.Error != null) { Log.Error("Startup tasks failed"); Log.Error(e.Error.Message); Log.Information("Ready"); } else { Log.Information("Ready"); } // Update the status message label. UpdateStatusMessage("Ready"); // Enable buttons. EnableAllButtons(); } #endregion #region GUI Methods /// /// Changes the path to the ROMs directory. /// /// /// private void ChangeROMsDir_Click(object sender, EventArgs e) { // Disable all buttons. DisableAllButtons(); // Create and initialize a FolderBrowserDialog for the ROMs directory. FolderBrowserDialog fbdPathRomsDir = new FolderBrowserDialog { ShowNewFolderButton = true, Description = "Please enter a path to the ROMs directory: ", SelectedPath = Path.GetFullPath(DHEA.PathROMsDir) }; // Determine if the user selected a folder name from the FolderBrowserDialog. if (fbdPathRomsDir.ShowDialog() == DialogResult.OK) { // Set both variables for compatibility for Windows .Net and Mono. this.DHEA.PathROMsDir = fbdPathRomsDir.SelectedPath; txtPathROMsDir.Text = fbdPathRomsDir.SelectedPath; } // Dispose of the FolderBrowserDialog. fbdPathRomsDir.Dispose(); // Enable all buttons. EnableAllButtons(); } /// /// Changes the path to the ROMs deheadered directory. /// /// /// private void ChangeROMsDeheaderedDir_Click(object sender, EventArgs e) { // Disable all buttons. DisableAllButtons(); // Create and initialize a FolderBrowserDialog for the ROMs deheadered directory. FolderBrowserDialog fbdPathRomsDeheadedDir = new FolderBrowserDialog { ShowNewFolderButton = true, Description = "Please enter a path to the ROMs deheadered directory: ", SelectedPath = Path.GetFullPath(DHEA.PathROMsDeheadedDir) }; // Determine if the user selected a folder name from the FolderBrowserDialog. if (fbdPathRomsDeheadedDir.ShowDialog() == DialogResult.OK) { // Set both variables for compatibility for Windows .Net and Mono. this.DHEA.PathROMsDeheadedDir = fbdPathRomsDeheadedDir.SelectedPath; txtPathROMsDeheaderedDir.Text = fbdPathRomsDeheadedDir.SelectedPath; } // Dispose of the FolderBrowserDialog. fbdPathRomsDeheadedDir.Dispose(); // Enable all buttons. EnableAllButtons(); } /// /// Cancels the current backgroundworker. /// /// /// private void Cancel_Click(object sender, EventArgs e) { if (bgwDeheaderROMs.WorkerSupportsCancellation == true) { // Print to screen Log.Information("Cancellation pending after current operation ..."); // Update the status message label. UpdateStatusMessage("Cancellation Pending ..."); // Disable the cancel button. tsddbCancel.Enabled = false; // Cancel the asynchronous operation. bgwDeheaderROMs.CancelAsync(); } } /// /// Loads an options file. /// /// /// private void LoadOptions_Click(object sender, EventArgs e) { try { // Disable all buttons. DisableAllButtons(); // Create and initialize an OpenFileDialog for the options file. OpenFileDialog ofdOptions = new OpenFileDialog { DefaultExt = "*.xml", Filter = "XML Files|*.xml", Title = "Please enter a path to the options file: ", InitialDirectory = Path.GetDirectoryName(DHEA.PathOptionsFile) }; // Determine if the user selected a file name from the OpenFileDialog. if (ofdOptions.ShowDialog() == DialogResult.OK && ofdOptions.FileName.Length > 0) { // Set the options file path. DHEA.PathOptionsFile = ofdOptions.FileName; // Select the Log tab. if (tcMain.TabPages.Contains(tabLog)) { tcMain.SelectTab(tabLog); } // Load the options. DHEA.LoadOptionsFromFile(); // Print to screen Log.Information("Ready"); } // Dispose of the OpenFileDialog. ofdOptions.Dispose(); // Enable all buttons. EnableAllButtons(); } catch (Exception ex) { // Print to screen Log.Error("Loading options failed"); Log.Error(ex.Message); Log.Information("Ready"); } } /// /// Saves an options file. /// /// /// private void SaveOptions_Click(object sender, EventArgs e) { try { // Disable all buttons. DisableAllButtons(); // Create and initialize a SaveFileDialog for the options file. SaveFileDialog sfdOptions = new SaveFileDialog { DefaultExt = "*.xml", Filter = "XML Files|*.xml", FileName = "Options - DeheadEmAll.xml", Title = "Please enter a path to the options file: ", InitialDirectory = Path.GetDirectoryName(DHEA.PathOptionsFile) }; // Determine if the user selected a file name from the SaveFileDialog. if (sfdOptions.ShowDialog() == DialogResult.OK && sfdOptions.FileName.Length > 0) { // Set the options file path. DHEA.PathOptionsFile = sfdOptions.FileName; // Select the Log tab. if (tcMain.TabPages.Contains(tabLog)) { tcMain.SelectTab(tabLog); } // Save the options. DHEA.SaveOptionsToFile(); // Print to screen Log.Information("Ready"); } // Dispose of the SaveFileDialog. sfdOptions.Dispose(); // Enable all buttons. EnableAllButtons(); } catch (Exception ex) { // Print to screen Log.Error("Saving options failed"); Log.Error(ex.Message); Log.Information("Ready"); } } /// /// Saves a log file. /// /// /// private void SaveLog_Click(object sender, EventArgs e) { try { // Disable all buttons. DisableAllButtons(); // Create and initialize a SaveFileDialog for the log file. SaveFileDialog sfdLog = new SaveFileDialog { DefaultExt = "*.txt", Filter = "TXT Files|*.txt", FileName = "DeheadEmAll-Log-" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt", Title = "Please enter a path to the log file: ", InitialDirectory = Path.Combine(Application.StartupPath, "Logs") }; // Determine if the user selected a log filename. if (sfdLog.ShowDialog() == DialogResult.OK && sfdLog.FileName.Length > 0) { // Set the log file path. DHEA.PathLogFile = sfdLog.FileName; // Select the Log tab. if (tcMain.TabPages.Contains(tabLog)) { tcMain.SelectTab(tabLog); } // Save the log. SaveLogToFile(DHEA.PathLogFile); // Print to screen Log.Information("Ready"); } // Dispose of the SaveFileDialog. sfdLog.Dispose(); // Enable all buttons. EnableAllButtons(); } catch (Exception ex) { // Print to screen Log.Error("Saving log file failed"); Log.Error(ex.Message); Log.Information("Ready"); } } /// /// Toggles the visibility of the log. /// /// /// private void ViewLog_Click(object sender, EventArgs e) { if (tsmiLog.Checked) { tsmiLog.Checked = false; tcMain.TabPages.Remove(tabLog); } else { tsmiLog.Checked = true; tcMain.TabPages.Add(tabLog); tcMain.SelectTab(tabLog); } } /// /// Toggles the visibility of the options. /// /// /// private void ViewOptions_Click(object sender, EventArgs e) { if (tsmiOptions.Checked) { tsmiOptions.Checked = false; tcMain.TabPages.Remove(tabOptions); } else { tsmiOptions.Checked = true; tcMain.TabPages.Add(tabOptions); tcMain.SelectTab(tabOptions); } } /// /// Toggles the visibility of the help. /// /// /// private void ViewHelp_Click(object sender, EventArgs e) { if (tsmiHelp.Checked) { tsmiHelp.Checked = false; tcMain.TabPages.Remove(tabHelp); } else { tsmiHelp.Checked = true; tcMain.TabPages.Add(tabHelp); tcMain.SelectTab(tabHelp); } } /// /// Toggles the visibility of the license. /// /// /// private void ViewLicense_Click(object sender, EventArgs e) { if (tsmiLicense.Checked) { tsmiLicense.Checked = false; tcMain.TabPages.Remove(tabLicense); } else { tsmiLicense.Checked = true; tcMain.TabPages.Add(tabLicense); tcMain.SelectTab(tabLicense); } } /// /// Toggles the visibility of the Donations. /// private void ViewDonations_Click(object sender, EventArgs e) { if (tsmiDonations.Checked) { tsmiDonations.Checked = false; tsmiDonations.CheckState = CheckState.Unchecked; tcMain.TabPages.Remove(tabDonations); } else { tsmiDonations.Checked = true; tsmiDonations.CheckState = CheckState.Checked; tcMain.TabPages.Add(tabDonations); tcMain.SelectTab(tabDonations); } } /// /// Toggles the visibility of the toolbar. /// /// /// private void ViewToolbar_Click(object sender, EventArgs e) { if (tsMain.Visible) { tsMain.Visible = false; tsmiToolba.Checked = false; } else { tsMain.Visible = true; tsmiToolba.Checked = true; } } /// /// After the form is shown, performs the startup tasks. /// /// /// private void Fprm_Shown(object sender, EventArgs e) { // Perform the application startup tasks. bgwStartupTasks.RunWorkerAsync(); } /// /// Exits the WinForms app. /// /// /// private void Exit_Click(object sender, EventArgs e) { Application.Exit(); } /// /// Check some things to make sure it is safe to exit the WinForms application. /// /// /// private void Form_FormClosing(object sender, FormClosingEventArgs e) { if (bgwDeheaderROMs.IsBusy == true) { if (MessageBox.Show("The ROMs deheaderer is currently running. Exiting now may cause corrupt or incomplete files! Are you sure you want to exit now?", "Confirm Exit", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK) { e.Cancel = true; } } } /// /// Enables all of the buttons. /// private void EnableAllButtons() { // Enable all Menu Item buttons. tsmiCommand.Enabled = true; tsmiExit.Enabled = true; tsmiDeheaderROMs.Enabled = true; tsmiLoadOptions.Enabled = true; tsmiSaveOptions.Enabled = true; tsmiSaveLog.Enabled = true; // Enable all Toolbar buttons. tsbDeheaderROMs.Enabled = true; tsbLoadOptions.Enabled = true; tsbSaveOptions.Enabled = true; tsbSaveLog.Enabled = true; // Enable all Options buttons. txtPathROMsDir.Enabled = true; txtPathROMsDeheaderedDir.Enabled = true; // Enable all Options checkboxes. chkA7800.Enabled = true; chkFDS.Enabled = true; chkLynx.Enabled = true; chkNES.Enabled = true; // Disable all Options comboboxes. cbLanguage.Enabled = true; cbLogLevel.Enabled = true; } /// /// Disables all of the buttons. /// private void DisableAllButtons() { // Disable all Menu Item buttons. tsmiCommand.Enabled = false; tsmiExit.Enabled = false; tsmiDeheaderROMs.Enabled = false; tsmiLoadOptions.Enabled = false; tsmiSaveOptions.Enabled = false; tsmiSaveLog.Enabled = false; // Disable all Toolbar buttons. tsbDeheaderROMs.Enabled = false; tsbLoadOptions.Enabled = false; tsbSaveOptions.Enabled = false; tsbSaveLog.Enabled = false; // Disable all Options buttons. txtPathROMsDir.Enabled = false; txtPathROMsDeheaderedDir.Enabled = false; // Disable all Options checkboxes. chkA7800.Enabled = false; chkFDS.Enabled = false; chkLynx.Enabled = false; chkNES.Enabled = false; // Disable all Options comboboxes. cbLanguage.Enabled = false; cbLogLevel.Enabled = false; } /// /// Updates the application title. /// /// /// public bool UpdateTitle(string strTitle = "") { try { if (this.InvokeRequired && !this.IsDisposed) { Invoke(new MethodInvoker(delegate () { // Update the application title. this.Text = DHEA.AppName + " v" + DHEA.AppVersion + strTitle; })); } else if (!this.IsDisposed) { // Update the application title. this.Text = DHEA.AppName + " v" + DHEA.AppVersion + strTitle; } return true; } catch (Exception) { return false; } } /// /// Updates the progress status message label. /// /// private void UpdateStatusMessage(string strMsg) { // Update the status message label. tsslStatusMessage.Text = strMsg; } /// /// Updates the deheader progress bar. /// /// private void UpdateDeheaderProgress(int intPercentage) { // Update the build progress status progress bar. tspbDeheaderProgress.Value = intPercentage; } #endregion #region Deheader ROMs /// /// Deheaders all of the selected ROMs. /// /// /// private void DeheadROMs_Click(object sender, EventArgs e) { // Select the Log tab. if (tcMain.TabPages.Contains(tabLog)) { tcMain.SelectTab(tabLog); } // Disable all buttons. DisableAllButtons(); // Enable the cancel button. tsddbCancel.Enabled = true; // Change the log background color. // rtblLog.BackColor = Color.LightGreen; // Update the status message label. UpdateStatusMessage("Deheadering ROMs ..."); // Print to screen Log.Information("Deheadering all selected ROMs ..."); // Deheader ROMs. bgwDeheaderROMs.RunWorkerAsync(); } /// /// Deheaders all of the selected ROMs. /// /// /// private void DeheaderROMs_DoWork(object sender, DoWorkEventArgs e) { try { // Declarations BackgroundWorker worker = sender as BackgroundWorker; // Background worker int intProgress = 0; // Background worker progress int intCountTotalFilesProcessed = 0; // Total files processed int intCounterTotalDeheaded = 0; // Total deheadered counter int intCountArrDirFiles = 0; // Total loop count string strPathROMsDir = DHEA.PathROMsDir; // Path to the ROMs directory string strPathROMsDeheadedDir = DHEA.PathROMsDeheadedDir; // Path to the deheadered ROMs directory // Checkers bool boolPathROMsDirCheck = DHEA.PathROMsDirCheck(); bool boolPathROMsDeheadedDirCheck = DHEA.PathROMsDeheadedDirCheck(); // Check the paths and directories. if (boolPathROMsDirCheck != false && boolPathROMsDeheadedDirCheck != false) { // Print to screen Log.Information("Options: ROMs Directory (" + strPathROMsDir + ")"); Log.Information("Options: ROMsDeheaded Directory (" + strPathROMsDeheadedDir + ")"); // Get the directory files array and count. string[] arrDirFiles = Directory.GetFiles(strPathROMsDir, "*.*", SearchOption.AllDirectories); intCountArrDirFiles = arrDirFiles.Count(); // Create and start a stopwatch. var stopWatch = new Stopwatch(); stopWatch.Start(); // Main loop - Deheader all of the ROMs. foreach (string strPathFile in arrDirFiles) { FileInfo fiInputFile = new FileInfo(strPathFile); if ((fiInputFile.Extension == ".fds" || fiInputFile.Extension == ".nes") && (DHEA.FDS == true || DHEA.NES == true) && fiInputFile.Length > 16) { Log.Information("Deheadering: " + fiInputFile.FullName); // UpdateStatusMessage("Deheadering " + (intCountTotalFilesProcessed + 1) + " of " + intCountArrDirFiles + " ROMs ..."); int intOutputFileLength = (int)(fiInputFile.Length - 16); byte[] arrOutputFileBytes = new byte[intOutputFileLength]; using (BinaryReader reader = new BinaryReader(new FileStream(fiInputFile.FullName, FileMode.Open))) { reader.BaseStream.Seek(16, SeekOrigin.Begin); reader.Read(arrOutputFileBytes, 0, intOutputFileLength); } File.WriteAllBytes(Path.Combine(strPathROMsDeheadedDir, fiInputFile.Name), arrOutputFileBytes); intCounterTotalDeheaded++; } else if (fiInputFile.Extension == ".lnx" && DHEA.Lynx == true && fiInputFile.Length > 64) { Log.Information("Deheadering: " + fiInputFile.FullName); // UpdateStatusMessage("Deheadering " + (intCountTotalFilesProcessed + 1) + " of " + intCountArrDirFiles + " ROMs ..."); int intOutputFileLength = (int)(fiInputFile.Length - 64); byte[] arrOutputFileBytes = new byte[intOutputFileLength]; using (BinaryReader reader = new BinaryReader(new FileStream(fiInputFile.FullName, FileMode.Open))) { reader.BaseStream.Seek(64, SeekOrigin.Begin); reader.Read(arrOutputFileBytes, 0, intOutputFileLength); } File.WriteAllBytes(Path.Combine(strPathROMsDeheadedDir, fiInputFile.Name), arrOutputFileBytes); intCounterTotalDeheaded++; } else if (fiInputFile.Extension == ".a78" && DHEA.A7800 == true && fiInputFile.Length > 128) { Log.Information("Deheadering: " + fiInputFile.FullName); // UpdateStatusMessage("Deheadering " + (intCountTotalFilesProcessed + 1) + " of " + intCountArrDirFiles + " ROMs ..."); int intOutputFileLength = (int)(fiInputFile.Length - 128); byte[] arrOutputFileBytes = new byte[intOutputFileLength]; using (BinaryReader reader = new BinaryReader(new FileStream(fiInputFile.FullName, FileMode.Open))) { reader.BaseStream.Seek(128, SeekOrigin.Begin); reader.Read(arrOutputFileBytes, 0, intOutputFileLength); } File.WriteAllBytes(Path.Combine(strPathROMsDeheadedDir, fiInputFile.Name), arrOutputFileBytes); intCounterTotalDeheaded++; } else { Log.Information("Skipping: " + fiInputFile.FullName); // UpdateStatusMessage("Skipping " + (intCountTotalFilesProcessed + 1) + " of " + intCountArrDirFiles + " ROMs ..."); } // Increment the progress bar. intCountTotalFilesProcessed++; intProgress = (int)((double)intCountTotalFilesProcessed / (double)intCountArrDirFiles * 100); worker.ReportProgress(intProgress); // Check if the background worker is pending cancellation. if (worker.CancellationPending == true) { e.Cancel = true; break; } } // Stop the stopwatch. stopWatch.Stop(); // Print to screen Log.Information("Deheadered " + intCounterTotalDeheaded + " ROMs in " + stopWatch.Elapsed); } } catch (Exception ex) { // Print to screen Log.Error("Error: " + ex.Message); } } /// /// DeheaderROMs ProgressChanged. /// /// /// private void DeheaderROMs_ProgressChanged(object sender, ProgressChangedEventArgs e) { // Display the changed progress status. UpdateDeheaderProgress(e.ProgressPercentage); } /// /// DeheaderROMs RunWorkerCompleted /// /// /// private void DeheaderROMs_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { Log.Warning("Deheadering all selected ROMs canceled"); Log.Information("Ready"); } else if (e.Error != null) { Log.Error("Deheadering all selected ROMs failed"); Log.Error(e.Error.Message); Log.Information("Ready"); } else { Log.Information("Deheadering all selected ROMs completed"); Log.Information("Ready"); } // Reset the log background color. // rtblLog.BackColor = SystemColors.Control; // Reset the progress bar. UpdateDeheaderProgress(0); // Update the status message label. UpdateStatusMessage("Ready"); // Disable the cancel button. tsddbCancel.Enabled = false; // Enable all buttons. EnableAllButtons(); } #endregion } }