2015-07-01 23:17:14 -04:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Forms;
|
2015-08-05 20:40:10 -04:00
|
|
|
|
using Mesen.GUI.Debugger.Controls;
|
2016-06-04 14:43:13 -04:00
|
|
|
|
using Mesen.GUI.Config;
|
2015-07-01 23:17:14 -04:00
|
|
|
|
|
|
|
|
|
namespace Mesen.GUI.Debugger
|
|
|
|
|
{
|
2015-08-05 20:40:10 -04:00
|
|
|
|
public partial class ctrlDebuggerCode : BaseScrollableTextboxUserControl
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
2015-08-17 21:59:22 -04:00
|
|
|
|
public delegate void AddressEventHandler(AddressEventArgs args);
|
|
|
|
|
public event AddressEventHandler OnWatchAdded;
|
|
|
|
|
public event AddressEventHandler OnSetNextStatement;
|
2016-06-04 14:43:13 -04:00
|
|
|
|
private DebugViewInfo _config;
|
2015-07-01 23:17:14 -04:00
|
|
|
|
|
|
|
|
|
public ctrlDebuggerCode()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-04 14:43:13 -04:00
|
|
|
|
public void SetConfig(DebugViewInfo config)
|
|
|
|
|
{
|
|
|
|
|
_config = config;
|
|
|
|
|
this.mnuShowLineNotes.Checked = config.ShowPrgAddresses;
|
|
|
|
|
this.mnuShowCodeNotes.Checked = config.ShowByteCode;
|
|
|
|
|
this.FontSize = config.FontSize;
|
|
|
|
|
|
|
|
|
|
this.ctrlCodeViewer.ShowLineNumberNotes = this.mnuShowLineNotes.Checked;
|
|
|
|
|
this.ctrlCodeViewer.ShowContentNotes = this.mnuShowCodeNotes.Checked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateConfig()
|
|
|
|
|
{
|
|
|
|
|
_config.ShowPrgAddresses = this.mnuShowLineNotes.Checked;
|
|
|
|
|
_config.ShowByteCode = this.mnuShowCodeNotes.Checked;
|
|
|
|
|
_config.FontSize = this.FontSize;
|
|
|
|
|
ConfigManager.ApplyChanges();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override float FontSize
|
|
|
|
|
{
|
|
|
|
|
get { return base.FontSize; }
|
|
|
|
|
set { base.FontSize=value; UpdateConfig(); }
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-05 20:40:10 -04:00
|
|
|
|
protected override ctrlScrollableTextbox ScrollableTextbox
|
|
|
|
|
{
|
|
|
|
|
get { return this.ctrlCodeViewer; }
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
|
private string _code;
|
|
|
|
|
private bool _codeChanged;
|
|
|
|
|
public string Code
|
|
|
|
|
{
|
|
|
|
|
get { return _code; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if(value != _code) {
|
|
|
|
|
_codeChanged = true;
|
|
|
|
|
_code = value;
|
2015-08-02 19:27:02 -04:00
|
|
|
|
UpdateCode();
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private UInt32? _currentActiveAddress = null;
|
|
|
|
|
public void SelectActiveAddress(UInt32 address)
|
|
|
|
|
{
|
2015-08-02 19:27:02 -04:00
|
|
|
|
this.SetActiveAddress(address);
|
2015-08-03 21:53:46 -04:00
|
|
|
|
this.ctrlCodeViewer.ScrollToLineNumber((int)address);
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-02 19:27:02 -04:00
|
|
|
|
public void SetActiveAddress(UInt32 address)
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
2015-08-02 19:27:02 -04:00
|
|
|
|
//Set line background to yellow
|
|
|
|
|
this.ctrlCodeViewer.ClearLineStyles();
|
2015-08-04 19:50:57 -04:00
|
|
|
|
this.ctrlCodeViewer.SetLineColor((int)address, Color.Black, Color.Yellow, null, LineSymbol.Arrow);
|
2015-08-02 19:27:02 -04:00
|
|
|
|
_currentActiveAddress = address;
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
2015-08-02 19:27:02 -04:00
|
|
|
|
|
|
|
|
|
public void ClearActiveAddress()
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
2015-08-02 19:27:02 -04:00
|
|
|
|
_currentActiveAddress = null;
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
2015-08-03 21:53:46 -04:00
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
|
public bool UpdateCode(bool forceUpdate = false)
|
|
|
|
|
{
|
|
|
|
|
if(_codeChanged || forceUpdate) {
|
2015-08-03 21:53:46 -04:00
|
|
|
|
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
|
|
|
|
sw.Start();
|
2015-08-02 19:27:02 -04:00
|
|
|
|
this.ctrlCodeViewer.ClearLineStyles();
|
|
|
|
|
|
|
|
|
|
List<int> lineNumbers = new List<int>();
|
2015-08-21 22:42:44 -04:00
|
|
|
|
List<string> lineNumberNotes = new List<string>();
|
|
|
|
|
List<string> codeNotes = new List<string>();
|
2015-08-02 19:27:02 -04:00
|
|
|
|
List<string> codeLines = new List<string>();
|
2016-11-21 22:34:47 -05:00
|
|
|
|
|
2015-08-21 22:42:44 -04:00
|
|
|
|
string[] lines = _code.Split('\n');
|
|
|
|
|
for(int i = 0, len = lines.Length - 1; i < len; i++) {
|
|
|
|
|
string line = lines[i];
|
2016-11-21 22:34:47 -05:00
|
|
|
|
string[] lineParts = line.Split('\x1');
|
|
|
|
|
|
2015-08-21 22:42:44 -04:00
|
|
|
|
if(lineParts.Length >= 4) {
|
2016-11-21 22:34:47 -05:00
|
|
|
|
lineNumbers.Add(ParseHexAddress(lineParts[0]));
|
|
|
|
|
lineNumberNotes.Add(lineParts[1]);
|
|
|
|
|
codeNotes.Add(lineParts[2]);
|
|
|
|
|
codeLines.Add(lineParts[3]);
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-02 19:27:02 -04:00
|
|
|
|
|
|
|
|
|
ctrlCodeViewer.TextLines = codeLines.ToArray();
|
|
|
|
|
ctrlCodeViewer.LineNumbers = lineNumbers.ToArray();
|
2015-08-21 22:42:44 -04:00
|
|
|
|
ctrlCodeViewer.TextLineNotes = codeNotes.ToArray();
|
|
|
|
|
ctrlCodeViewer.LineNumberNotes = lineNumberNotes.ToArray();
|
2015-08-03 21:53:46 -04:00
|
|
|
|
sw.Stop();
|
2015-07-01 23:17:14 -04:00
|
|
|
|
_codeChanged = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-21 22:34:47 -05:00
|
|
|
|
private int ParseHexAddress(string hexAddress)
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
2016-11-21 22:34:47 -05:00
|
|
|
|
if(string.IsNullOrWhiteSpace(hexAddress)) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
return (int)UInt32.Parse(hexAddress, System.Globalization.NumberStyles.AllowHexSpecifier);
|
|
|
|
|
}
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-10 00:33:33 -05:00
|
|
|
|
public void HighlightBreakpoints()
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
2015-08-02 19:27:02 -04:00
|
|
|
|
ctrlCodeViewer.ClearLineStyles();
|
|
|
|
|
if(_currentActiveAddress.HasValue) {
|
2015-08-04 19:50:57 -04:00
|
|
|
|
SetActiveAddress(_currentActiveAddress.Value);
|
2015-08-02 19:27:02 -04:00
|
|
|
|
}
|
2016-01-10 00:33:33 -05:00
|
|
|
|
foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) {
|
2015-08-02 19:27:02 -04:00
|
|
|
|
Color? fgColor = Color.White;
|
|
|
|
|
Color? bgColor = null;
|
|
|
|
|
Color? outlineColor = Color.FromArgb(140, 40, 40);
|
2015-08-04 19:50:57 -04:00
|
|
|
|
LineSymbol symbol;
|
2015-08-02 19:27:02 -04:00
|
|
|
|
if(breakpoint.Enabled) {
|
|
|
|
|
bgColor = Color.FromArgb(140, 40, 40);
|
2015-08-04 19:50:57 -04:00
|
|
|
|
symbol = LineSymbol.Circle;
|
2015-08-02 19:27:02 -04:00
|
|
|
|
} else {
|
|
|
|
|
fgColor = Color.Black;
|
2015-08-04 19:50:57 -04:00
|
|
|
|
symbol = LineSymbol.CircleOutline;
|
2015-08-02 19:27:02 -04:00
|
|
|
|
}
|
|
|
|
|
if(breakpoint.Address == (UInt32)(_currentActiveAddress.HasValue ? (int)_currentActiveAddress.Value : -1)) {
|
|
|
|
|
fgColor = Color.Black;
|
|
|
|
|
bgColor = Color.Yellow;
|
2015-08-04 19:50:57 -04:00
|
|
|
|
symbol |= LineSymbol.Arrow;
|
2015-08-02 19:27:02 -04:00
|
|
|
|
}
|
2015-07-01 23:17:14 -04:00
|
|
|
|
|
2015-08-04 19:50:57 -04:00
|
|
|
|
ctrlCodeViewer.SetLineColor((int)breakpoint.Address, fgColor, bgColor, outlineColor, symbol);
|
2015-08-02 19:27:02 -04:00
|
|
|
|
}
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Events
|
|
|
|
|
private Point _previousLocation;
|
2015-08-02 19:27:02 -04:00
|
|
|
|
private void ctrlCodeViewer_MouseMove(object sender, MouseEventArgs e)
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
2016-01-10 00:33:33 -05:00
|
|
|
|
if(e.Location.X < this.ctrlCodeViewer.CodeMargin / 5) {
|
|
|
|
|
this.ContextMenuStrip = contextMenuMargin;
|
|
|
|
|
} else {
|
|
|
|
|
this.ContextMenuStrip = contextMenuCode;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
|
if(_previousLocation != e.Location) {
|
|
|
|
|
string word = GetWordUnderLocation(e.Location);
|
|
|
|
|
if(word.StartsWith("$")) {
|
|
|
|
|
UInt32 address = UInt32.Parse(word.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier);
|
|
|
|
|
Byte memoryValue = InteropEmu.DebugGetMemoryValue(address);
|
2015-07-03 00:12:02 -04:00
|
|
|
|
string valueText = "$" + memoryValue.ToString("X");
|
2015-08-09 18:24:24 -04:00
|
|
|
|
toolTip.Show(valueText, ctrlCodeViewer, e.Location.X + 5, e.Location.Y - 20, 3000);
|
|
|
|
|
} else {
|
2016-11-21 22:34:47 -05:00
|
|
|
|
CodeLabel label = LabelManager.GetLabel(word);
|
|
|
|
|
|
|
|
|
|
if(label == null) {
|
|
|
|
|
toolTip.Hide(ctrlCodeViewer);
|
|
|
|
|
} else {
|
2016-11-22 22:38:14 -05:00
|
|
|
|
Int32 relativeAddress = InteropEmu.DebugGetRelativeAddress(label.Address, label.AddressType);
|
|
|
|
|
Int32 memoryValue = relativeAddress >= 0 ? InteropEmu.DebugGetMemoryValue((UInt32)relativeAddress) : -1;
|
2016-11-21 22:34:47 -05:00
|
|
|
|
toolTip.Show(
|
|
|
|
|
"Label: " + label.Label + Environment.NewLine +
|
2016-11-22 22:38:14 -05:00
|
|
|
|
"Address: $" + InteropEmu.DebugGetRelativeAddress(label.Address, label.AddressType).ToString("X4") + Environment.NewLine +
|
|
|
|
|
"Value: " + (memoryValue >= 0 ? ("$" + memoryValue.ToString("X2")) : "n/a") + Environment.NewLine +
|
2016-11-21 22:34:47 -05:00
|
|
|
|
"Comment: " + (label.Comment.Contains(Environment.NewLine) ? (Environment.NewLine + label.Comment) : label.Comment)
|
|
|
|
|
, ctrlCodeViewer, e.Location.X + 5, e.Location.Y - 60 - label.Comment.Split('\n').Length * 14, 3000);
|
|
|
|
|
}
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
_previousLocation = e.Location;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UInt32 _lastClickedAddress = UInt32.MaxValue;
|
2015-08-02 19:27:02 -04:00
|
|
|
|
private void ctrlCodeViewer_MouseUp(object sender, MouseEventArgs e)
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
|
|
|
|
string word = GetWordUnderLocation(e.Location);
|
|
|
|
|
if(word.StartsWith("$")) {
|
|
|
|
|
_lastClickedAddress = UInt32.Parse(word.Substring(1), System.Globalization.NumberStyles.AllowHexSpecifier);
|
|
|
|
|
mnuGoToLocation.Enabled = true;
|
|
|
|
|
mnuGoToLocation.Text = "Go to Location (" + word + ")";
|
|
|
|
|
|
|
|
|
|
mnuAddToWatch.Enabled = true;
|
|
|
|
|
mnuAddToWatch.Text = "Add to Watch (" + word + ")";
|
|
|
|
|
} else {
|
|
|
|
|
mnuGoToLocation.Enabled = false;
|
|
|
|
|
mnuGoToLocation.Text = "Go to Location";
|
|
|
|
|
mnuAddToWatch.Enabled = false;
|
|
|
|
|
mnuAddToWatch.Text = "Add to Watch";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-10 00:33:33 -05:00
|
|
|
|
Breakpoint _lineBreakpoint = null;
|
|
|
|
|
private void ctrlCodeViewer_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
int address = ctrlCodeViewer.GetLineNumberAtPosition(e.Y);
|
|
|
|
|
_lineBreakpoint = BreakpointManager.GetMatchingBreakpoint(address);
|
|
|
|
|
|
|
|
|
|
if(e.Location.X < this.ctrlCodeViewer.CodeMargin / 5) {
|
|
|
|
|
if(e.Button == System.Windows.Forms.MouseButtons.Left) {
|
|
|
|
|
if(_lineBreakpoint == null) {
|
|
|
|
|
Breakpoint bp = new Breakpoint();
|
|
|
|
|
bp.Address = (UInt32)address;
|
|
|
|
|
bp.BreakOnExec = true;
|
|
|
|
|
BreakpointManager.AddBreakpoint(bp);
|
|
|
|
|
} else {
|
|
|
|
|
BreakpointManager.RemoveBreakpoint(_lineBreakpoint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-21 22:34:47 -05:00
|
|
|
|
|
|
|
|
|
private void ctrlCodeViewer_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
2016-11-22 22:38:14 -05:00
|
|
|
|
int relativeAddress = ctrlCodeViewer.GetLineNumberAtPosition(e.Y);
|
2016-11-21 22:34:47 -05:00
|
|
|
|
|
2016-11-22 22:38:14 -05:00
|
|
|
|
if(relativeAddress >= 0 && e.Location.X > this.ctrlCodeViewer.CodeMargin / 2 && e.Location.X < this.ctrlCodeViewer.CodeMargin) {
|
|
|
|
|
AddressTypeInfo info = new AddressTypeInfo();
|
|
|
|
|
InteropEmu.DebugGetAbsoluteAddressAndType((UInt32)relativeAddress, ref info);
|
2016-11-21 22:34:47 -05:00
|
|
|
|
|
2016-11-22 22:38:14 -05:00
|
|
|
|
if(info.Address >= 0) {
|
2016-11-22 23:07:28 -05:00
|
|
|
|
ctrlLabelList.EditLabel((UInt32)info.Address, info.Type);
|
2016-11-21 22:34:47 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-10 00:33:33 -05:00
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
|
#region Context Menu
|
2016-01-10 00:33:33 -05:00
|
|
|
|
|
|
|
|
|
private void contextMenuMargin_Opening(object sender, CancelEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if(_lineBreakpoint == null) {
|
|
|
|
|
e.Cancel = true;
|
|
|
|
|
} else {
|
|
|
|
|
mnuDisableBreakpoint.Text = _lineBreakpoint.Enabled ? "Disable breakpoint" : "Enable breakpoint";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuRemoveBreakpoint_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
BreakpointManager.RemoveBreakpoint(_lineBreakpoint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuEditBreakpoint_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
BreakpointManager.EditBreakpoint(_lineBreakpoint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuDisableBreakpoint_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_lineBreakpoint.SetEnabled(!_lineBreakpoint.Enabled);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
|
private void contextMenuCode_Opening(object sender, CancelEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
mnuShowNextStatement.Enabled = _currentActiveAddress.HasValue;
|
2015-08-17 21:59:22 -04:00
|
|
|
|
mnuSetNextStatement.Enabled = _currentActiveAddress.HasValue;
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuShowNextStatement_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2015-08-03 21:53:46 -04:00
|
|
|
|
this.ctrlCodeViewer.ScrollToLineNumber((int)_currentActiveAddress.Value);
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuShowOnlyDisassembledCode_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
UpdateCode(true);
|
2015-08-02 19:27:02 -04:00
|
|
|
|
if(_currentActiveAddress.HasValue) {
|
|
|
|
|
SelectActiveAddress(_currentActiveAddress.Value);
|
|
|
|
|
}
|
2016-06-04 14:43:13 -04:00
|
|
|
|
this.UpdateConfig();
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
2015-08-21 22:42:44 -04:00
|
|
|
|
|
|
|
|
|
private void mnuShowLineNotes_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
this.ctrlCodeViewer.ShowLineNumberNotes = this.mnuShowLineNotes.Checked;
|
2016-06-04 14:43:13 -04:00
|
|
|
|
this.UpdateConfig();
|
2015-08-21 22:42:44 -04:00
|
|
|
|
}
|
2015-07-01 23:17:14 -04:00
|
|
|
|
|
2015-08-21 22:42:44 -04:00
|
|
|
|
private void mnuShowCodeNotes_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
this.ctrlCodeViewer.ShowContentNotes = this.mnuShowCodeNotes.Checked;
|
2016-06-04 14:43:13 -04:00
|
|
|
|
this.UpdateConfig();
|
2015-08-21 22:42:44 -04:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
|
private void mnuGoToLocation_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2015-08-03 21:53:46 -04:00
|
|
|
|
this.ctrlCodeViewer.ScrollToLineNumber((int)_lastClickedAddress);
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void mnuAddToWatch_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if(this.OnWatchAdded != null) {
|
2015-08-17 21:59:22 -04:00
|
|
|
|
this.OnWatchAdded(new AddressEventArgs() { Address = _lastClickedAddress});
|
2015-07-01 23:17:14 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-17 21:59:22 -04:00
|
|
|
|
|
|
|
|
|
private void mnuSetNextStatement_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if(this.OnSetNextStatement != null) {
|
|
|
|
|
this.OnSetNextStatement(new AddressEventArgs() { Address = (UInt32)this.ctrlCodeViewer.CurrentLine });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-04 14:43:13 -04:00
|
|
|
|
private void ctrlCodeViewer_FontSizeChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
UpdateConfig();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-17 21:59:22 -04:00
|
|
|
|
public class AddressEventArgs : EventArgs
|
2015-07-01 23:17:14 -04:00
|
|
|
|
{
|
|
|
|
|
public UInt32 Address { get; set; }
|
|
|
|
|
}
|
|
|
|
|
}
|