private async void BtnSubmitInput_Click(object Sender, EventArgs E) // To send input to the user program { var ToSubmit = Regex.Replace(TxtInputToProgram.Text, @"\p{C}+", string.Empty); // Remove unreadable characters (Thanks Regex) if (ToSubmit == string.Empty) { TxtInputToProgram.Text = ""; // Empty the text box TxtInputToProgram_TextChanged(null, null); // No need for parameters return; } // Don't send an empty string //Console.WriteLine(@"Sent: " + ToSubmit); TxtInputToProgram.AutoCompleteCustomSource.Add(ToSubmit); TxtStandardOutput.Text += $@"> {ToSubmit}{Environment.NewLine}"; // Reflect user input await _DebugProcess.StandardInput.WriteLineAsync(ToSubmit); // Send input to the program TxtInputToProgram.Text = ""; // Empty the text box TxtInputToProgram.Focus(); // Give focus to TxtInputToProgram }
/// <inheritdoc /> /// <summary> /// Initialization with parameters. Allows debugging to begin /// </summary> /// <param name="FileToDebug">The path of the "*.exe" file to be debugged</param> /// <param name="MyParent">The FrmWelcome that instantiated the FrmDebugger</param> public FrmDebugger(string FileToDebug, FrmDesigner MyParent) { InitializeComponent(); // Reqd. for forms BtnStartExecution.Enabled = true; // Text colour changes do not occur on disabled controls BtnStartExecution.EnabledChanged += Buttons_EnabledChanged; // Handle the events BtnExitDebugging.EnabledChanged += Buttons_EnabledChanged; // By using the same handler, code can be BtnPauseExecution.EnabledChanged += Buttons_EnabledChanged; // reduced to prevent unnecessary BtnSubmitInput.EnabledChanged += Buttons_EnabledChanged; // methods BtnStopExecution.EnabledChanged += Buttons_EnabledChanged; StopDebuggingInterfaceChanges(); // Not sure if we're ready yet, so disable everything Just In Case (JIC) // Bind the enter key to sending an input TxtInputToProgram.KeyUp += (Sender, Args) => { if (Args.KeyCode == Keys.Enter) { BtnSubmitInput_Click(null, null); // null parameters because the delegate requires them, but we don't use them } }; // If parameters are missing, don't function because otherwise things are going to break violently if (FileToDebug == null || MyParent == null) { TxtStandardOutput.Text = @"No program was loaded, debugging will not occur"; TxtVariableOutput.Text = @"No variables can be observed"; TxtErrorOutput.Text = @"No errors will be recorded"; return; } // If the App is closed, kill the process Application.ApplicationExit += (S, E) => { try { _DebugProcess?.Close(); _DebugProcess?.Kill(); // This is needed because otherwise the child process is not killed. It then keeps running, // causing RAM-leaking behaviours. We don't like those. They're bad for the RAM } catch (InvalidOperationException) {} // Don't break if the program has already been murdered }; // Instantiate the process _DebugProcess = new Process { StartInfo = new ProcessStartInfo { FileName = FileToDebug, CreateNoWindow = true, // No new window UseShellExecute = false, // Don't run it in the system shell Arguments = "DEBUG", // We are debugging after all, and it's crucial // to the behaviour of the programs RedirectStandardError = true, // Allows me to read the error output RedirectStandardOutput = true, // Allows me to read normal output RedirectStandardInput = true // Allows me to send my own inputs to the program }, EnableRaisingEvents = true // Allows me to hook on to the "Exited" event }; _ParentFrmDesigner = MyParent; // Set parent form _ParentFrmDesigner.Hide(); // Hide the parent form _ParentFrmDesigner._ParentFrmWelcome.Hide(); _IsDebugging = _DebugProcess.Start(); // Start the process if (!_IsDebugging) // Did something break? { MessageBox.Show(@"Something went wrong and the process couldn't start, sorry.", @"Unable to start process", MessageBoxButtons.OK); KillDebugProcess(); // Kill everything just in case _ParentFrmDesigner.Show(); // Show the main form _ParentFrmDesigner._ParentFrmWelcome.Hide(); // Prevent some quirky behaviour Hide(); // Disappear Dispose(); // Clean up } TxtStandardOutput.Text = $@": Process started at {_DebugProcess.StartTime:f} {Environment.NewLine}"; // Feedback to user //Console.WriteLine($@"Process is called: {_DebugProcess.ProcessName} {Environment.NewLine}" + // $@"Process was started at {_DebugProcess.StartTime:f} {Environment.NewLine}" + // $@"Process has {(_DebugProcess.HasExited ? "" : "not ")}exited"); // // Feedback to me (plus string interpolation, yay) // Add output listeners _DebugProcess.ErrorDataReceived += ReadError; // Bind the ASYNC code _DebugProcess.OutputDataReceived += ReadOutput; // MORE ASYNC CODE BINDING _DebugProcess.Exited += (Sender, E) => { WriteExitText(); StopDebuggingInterfaceChanges(); }; // Sleep if the program exits StartDebuggingInterfaceChanges(); // Enable buttons because nothing broke TxtInputToProgram.Text = ""; // Empty the input TxtInputToProgram_TextChanged(null, null); // Disable the SUBMIT button // START THE ASYNC OPERATIONS _DebugProcess.BeginOutputReadLine(); _DebugProcess.BeginErrorReadLine(); TxtInputToProgram.Focus(); // Give focus to TxtInputToProgram }