/// <summary>Called when the "Attach/Detach" button gets clicked.</summary> /// <param name="sender">The object which sent the event.</param> /// <param name="e">Holds data about the event.</param> private void ButtonAttachDetachClick(object sender, RoutedEventArgs e) { if (TargetProcessIO.IsAttached() == false) { Process selectedProcess = (Process)m_lstProcesses.SelectedItem; if (TargetProcessIO.AttachToProcess(selectedProcess) == false) { MessageBox.Show(this, Properties.Resources.strErrorDuringAttachmentMsg, Properties.Resources.strErrorDuringAttachmentTitle, MessageBoxButton.OK, MessageBoxImage.Error); return; } else { // Output for the user this.PrintLineToConsole(Properties.Resources.strConsoleMsgAttachedToProcess, selectedProcess.ProcessName, selectedProcess.Id); // Enable the program to know when the target process exits TargetProcessIO.TargetProcess.EnableRaisingEvents = true; TargetProcessIO.TargetProcess.Exited += (evtSender, evtArgs) => { // Execute this in the Main (GUI) thread this.Dispatcher.Invoke(() => { this.DetachFromTargetProcess(); }); }; } } else { this.DetachFromTargetProcess(); } }
/// <summary> /// Makes the program detach from the target process, by calling <see cref="Target.DetachFromProcess()"/> on /// the object <see cref="TargetProcessIO"/>. /// </summary> private void DetachFromTargetProcess() { Process targetProcess = TargetProcessIO.TargetProcess; if (TargetProcessIO.IsAttached() && TargetProcessIO.DetachFromProcess() == false) { MessageBox.Show(this, Properties.Resources.strErrorDuringDetachmentMsg, Properties.Resources.strErrorDuringDetachmentTitle, MessageBoxButton.OK, MessageBoxImage.Error); } else { // Output for the user this.PrintLineToConsole(Properties.Resources.strConsoleMsgDetachedFromProcess, targetProcess.ProcessName, targetProcess.Id); // Automatically refresh the list of running processes this.RefreshProcessesList(); } }
/// <summary> /// Called to read the contents on all registered addresses on the target process' memory space, and update /// their values to be displayed to the user in the <see cref="DataGrid"/> containing /// the registered addresses. /// Notice that frozen values are NEVER updated, as they must remain unchanged (with the contents typed by /// the user). /// </summary> private void RefreshRegisteredAddresses() { if (TargetProcessIO.IsAttached() == false) { return; } foreach (AddressData curData in RegisteredAddresses) { // Perform read operations object newValue = null; if (curData.Freeze == false && curData.IsValueBeingEdited == false && TargetProcessIO.ReadFromTarget(new AbsoluteMemoryAddress(curData.Address), curData.Type, ref newValue)) { // For unfrozen values, we should just read the contents of the address in the target process and update // our local process' variables curData.Value = newValue; } else if (curData.Freeze) { // For frozen values, we should just overwrite the contents of the address in the target process with the "frozen value" TargetProcessIO.WriteToTarget(new AbsoluteMemoryAddress(curData.Address), curData.Value); } } }
/// <summary> /// Called when the user is finalizing the edition of a cell in the <see cref="DataGrid"/> of registered /// addresses. /// </summary> /// <param name="sender">The object which sent the event.</param> /// <param name="e">Holds data about the event.</param> private void DataGridCellEditEnding(object sender, DataGridCellEditEndingEventArgs e) { // Mark the data as "not being edited" anymore AddressData editedData = ((AddressData)e.Row.Item); editedData.IsValueBeingEdited = false; // When editing the "Value" datagrid column... if (e.Column == m_registeredAddressesDataGridValueColumn && e.EditAction == DataGridEditAction.Commit) { // Retrieve the new value from the textbox used to update the data grid cell TextBox editElement = (TextBox)e.EditingElement; string newValueRaw = editElement.Text.ToLowerInvariant().Trim(); // Try to convert the typed value to the type expected for the registered address Type expectedDataType = editedData.Type; object newValue = null; try { // Conversion to IntPtr is done in an special way if (expectedDataType == typeof(IntPtr)) { // Parse the number as an hex string, converting it to an Int64 string stringToParse = newValueRaw; if (stringToParse.StartsWith("0x")) { stringToParse = stringToParse.Substring(2); } Int64 valueAsLong = Convert.ToInt64(stringToParse, 16); // Perform value conversion on the Int64 value directly to IntPtr newValue = new IntPtr(valueAsLong); } else { newValue = Convert.ChangeType(newValueRaw, expectedDataType); } } catch (OverflowException) { e.Cancel = true; } catch (FormatException) { e.Cancel = true; } // If an error ocurred because invalid input was entered, the event is cancelled. // In that case, we will display an error message to the user. // NOTE: when the event is cancelled, the textbox used to edit the value is not hidden and the user can // type a new (correct) value on it. if (e.Cancel) { MessageBox.Show(this, Properties.Resources.strErrorInvalidInputValueMsg, Properties.Resources.strErrorInvalidInputValueTitle, MessageBoxButton.OK, MessageBoxImage.Error); return; } // Write the value to the target process' memory space if (TargetProcessIO.IsAttached() && TargetProcessIO.WriteToTarget(new AbsoluteMemoryAddress(editedData.Address), newValue) == false) { MessageBox.Show(this, Properties.Resources.strErrorCannotUpdateValueMsg, Properties.Resources.strErrorCannotUpdateValueTitle, MessageBoxButton.OK, MessageBoxImage.Error); } } }