using System;
using System.Text;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Reflection;
using System.Runtime.InteropServices;
namespace NdisMonitor
{
/// <summary>
/// Summary description for HexViewer.
/// </summary>
public class dlgPacketViewer : System.Windows.Forms.Form, IMessageFilter
{
private System.Windows.Forms.RichTextBox ctrlHexView;
private System.Windows.Forms.ListBox ctrlDetails;
private System.Windows.Forms.ToolBar ctrlToolbar;
private System.Windows.Forms.Splitter ctrlSplitter;
private System.Windows.Forms.ImageList toolbarImgs;
private System.Windows.Forms.ToolBarButton ctrlUpBtn;
private System.Windows.Forms.ToolBarButton ctrlDownBtn;
private System.ComponentModel.IContainer components;
public delegate RawPacket GetPrevOrNextPacketDelegate( int dir );
public dlgPacketViewer( RawPacket rp, GetPrevOrNextPacketDelegate pnp )
{
this._rp = rp;
this._pnp = pnp;
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
//
// Data.
//
RawPacket _rp = null;
GetPrevOrNextPacketDelegate _pnp = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(dlgPacketViewer));
this.ctrlHexView = new System.Windows.Forms.RichTextBox();
this.ctrlDetails = new System.Windows.Forms.ListBox();
this.ctrlToolbar = new System.Windows.Forms.ToolBar();
this.ctrlUpBtn = new System.Windows.Forms.ToolBarButton();
this.ctrlDownBtn = new System.Windows.Forms.ToolBarButton();
this.toolbarImgs = new System.Windows.Forms.ImageList(this.components);
this.ctrlSplitter = new System.Windows.Forms.Splitter();
this.SuspendLayout();
//
// ctrlHexView
//
this.ctrlHexView.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(240)), ((System.Byte)(240)), ((System.Byte)(210)));
this.ctrlHexView.Dock = System.Windows.Forms.DockStyle.Top;
this.ctrlHexView.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.ctrlHexView.Location = new System.Drawing.Point(0, 28);
this.ctrlHexView.Name = "ctrlHexView";
this.ctrlHexView.ReadOnly = true;
this.ctrlHexView.ShowSelectionMargin = true;
this.ctrlHexView.Size = new System.Drawing.Size(568, 150);
this.ctrlHexView.TabIndex = 6;
this.ctrlHexView.Text = "";
this.ctrlHexView.WordWrap = false;
//
// ctrlDetails
//
this.ctrlDetails.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlDetails.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.ctrlDetails.IntegralHeight = false;
this.ctrlDetails.ItemHeight = 14;
this.ctrlDetails.Location = new System.Drawing.Point(0, 181);
this.ctrlDetails.Name = "ctrlDetails";
this.ctrlDetails.Size = new System.Drawing.Size(568, 208);
this.ctrlDetails.TabIndex = 0;
this.ctrlDetails.SelectedIndexChanged += new System.EventHandler(this.ctrlDetails_SelectedIndexChanged);
//
// ctrlToolbar
//
this.ctrlToolbar.Appearance = System.Windows.Forms.ToolBarAppearance.Flat;
this.ctrlToolbar.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] {
this.ctrlUpBtn,
this.ctrlDownBtn});
this.ctrlToolbar.ButtonSize = new System.Drawing.Size(16, 16);
this.ctrlToolbar.DropDownArrows = true;
this.ctrlToolbar.ImageList = this.toolbarImgs;
this.ctrlToolbar.Location = new System.Drawing.Point(0, 0);
this.ctrlToolbar.Name = "ctrlToolbar";
this.ctrlToolbar.ShowToolTips = true;
this.ctrlToolbar.Size = new System.Drawing.Size(568, 28);
this.ctrlToolbar.TabIndex = 2;
this.ctrlToolbar.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this.ctrlToolbar_ButtonClick);
//
// ctrlUpBtn
//
this.ctrlUpBtn.ImageIndex = 0;
this.ctrlUpBtn.ToolTipText = "Go to the previous packet (F3).";
//
// ctrlDownBtn
//
this.ctrlDownBtn.ImageIndex = 1;
this.ctrlDownBtn.ToolTipText = "Go to the next packet (F4).";
//
// toolbarImgs
//
this.toolbarImgs.ImageSize = new System.Drawing.Size(16, 16);
this.toolbarImgs.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("toolbarImgs.ImageStream")));
this.toolbarImgs.TransparentColor = System.Drawing.Color.Transparent;
//
// ctrlSplitter
//
this.ctrlSplitter.Dock = System.Windows.Forms.DockStyle.Top;
this.ctrlSplitter.Location = new System.Drawing.Point(0, 178);
this.ctrlSplitter.Name = "ctrlSplitter";
this.ctrlSplitter.Size = new System.Drawing.Size(568, 3);
this.ctrlSplitter.TabIndex = 3;
this.ctrlSplitter.TabStop = false;
//
// dlgPacketViewer
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(568, 389);
this.Controls.Add(this.ctrlDetails);
this.Controls.Add(this.ctrlSplitter);
this.Controls.Add(this.ctrlHexView);
this.Controls.Add(this.ctrlToolbar);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "dlgPacketViewer";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Packet Viewer";
this.Load += new System.EventHandler(this.dlgPacketViewer_Load);
this.Closed += new System.EventHandler(this.dlgPacketViewer_Closed);
this.ResumeLayout(false);
}
#endregion
internal class DetailsElement
{
// construction.
public DetailsElement( Packet_Part part, PartInfoAttribute partInfo, FieldInfoAttribute fieldInfo, int baseOffset, FieldInfo field )
{
// remember the params.
this._part = part;
this._partInfo = partInfo;
this._fieldInfo = fieldInfo;
this._baseOffset = baseOffset;
this._field = field;
// get the data to display.
if ( _field != null && _fieldInfo != null )
{
// get value.
object val = _field.GetValue( _part );
// get the size of the field.
if ( _fieldInfo.Size != -1 )
{
this._fieldSize = _fieldInfo.Size;
}
else if ( _fieldInfo.FieldSizeFn != null )
{
try
{
this._fieldSize = (int) _part.GetType().GetMethod( _fieldInfo.FieldSizeFn ).Invoke( _part, null );
}
catch
{
this._fieldSize = 0;
}
}
else
{
try
{
if ( val.GetType() == typeof( bool ) )
this._fieldSize = 1;
else
this._fieldSize = Marshal.SizeOf( val );
}
catch
{
if ( val.GetType() == typeof( byte[] ) )
this._fieldSize = ( (byte[]) val ).Length;
else
this._fieldSize = 0;
}
}
// get the value as a string.
if ( _fieldInfo.PrintFn != null )
{
try
{
this._valueAsString = (string) _part.GetType().GetMethod( _fieldInfo.PrintFn ).Invoke( _part, null );
}
catch
{
this._valueAsString = null;
}
}
else if ( val.GetType() == typeof( byte ) )
this._valueAsString = "0x" + ((byte) val).ToString ( "X2" );
else if ( val.GetType() == typeof( ushort ) )
this._valueAsString = "0x" + ((ushort) val).ToString ( "X4" );
else if ( val.GetType() == typeof( uint ) )
this._valueAsString = "0x" + ((uint) val).ToString ( "X8" );
else if ( val.GetType() == typeof( byte[] ) )
{
byte[] arr = (byte[]) val;
string s = "";
for( int i=0; i<arr.Length; i ++ )
s += arr[ i ].ToString( "X2" ) + ( i==arr.Length-1 ? "" : "," );
this._valueAsString = s;
}
else
this._valueAsString = val.ToString ();
}
}
// data.
public Packet_Part _part = null;
public PartInfoAttribute _partInfo = null;
public FieldInfoAttribute _fieldInfo = null;
public int _baseOffset = 0;
public FieldInfo _field = null;
public int _fieldSize = 0;
public string _valueAsString = null;
// methods.
public override string ToString()
{
string retval = "";
if ( _partInfo != null && _fieldInfo == null )
{
// return the name of the packet part.
retval = _partInfo.Name;
}
else if ( _fieldInfo != null )
{
// return name + value.
retval = "\t" + _fieldInfo.Name + " = ";
if ( _fieldSize == 0 || _valueAsString == null || _valueAsString.Length == 0 )
retval += "???";
else
retval += _valueAsString;
}
return retval;
}
}
private void dlgPacketViewer_Load(object sender, System.EventArgs e)
{
Application.AddMessageFilter( this );
// load rp data.
LoadRp ();
}
protected void LoadRp ()
{
ctrlDetails.Items.Clear ();
// set the text in the rich edit box.
StringBuilder text = new StringBuilder();
int index = 0;
string ascii = "";
foreach( byte b in _rp._data )
{
// print offset.
if ( ( index % 16 ) == 0 )
{
if ( index != 0 )
{
// print ascii chrs.
text.Append( " " + ascii + " " );
// CR.
text.Append( "\r\n" );
}
text.Append( index.ToString( "X8" ) + " " );
ascii = "";
}
// print byte.
text.Append( b.ToString( "X2" ) );
if ( ( (index+1) % 16 ) != 0 && index != _rp._data.Length - 1 )
{
if ( ( (index+1) % 8 ) == 0 )
text.Append( " " );
text.Append( " " );
}
if ( b <= 0x20 )
ascii += ".";
else
ascii += (char) b;
// increment index.
index ++;
}
if ( ascii.Length != 0 )
{
int rem = 16 - ( index % 16 );
int spaces = rem * 3;
if ( rem >= 8 )
spaces ++;
for( int i=0; i<spaces; i ++ )
text.Append( ' ' );
text.Append( " " + ascii + " " );
for( int j=0; j<rem; j ++ )
text.Append( ' ' );
}
ctrlHexView.Text = text.ToString ();
// populate the Details View.
Packet_Part[] parts = _rp.GetParts ();
if ( parts == null )
{
ctrlDetails.Items.Add( ">> RawPacket provides no meaningful information <<" );
}
else
{
foreach( Packet_Part part in parts )
{
Type t = part.GetType ();
ArrayList list = new ArrayList ();
int baseOffset = RawPacket.GetTotalLength( parts, part, false );
// make the list of types.
Type baseType = t;
while( baseType != null )
{
list.Add( baseType );
baseType = baseType.BaseType;
}
// iterate starting from the base type going on.
for( int i=list.Count - 1; i >= 0; i -- )
{
Type thisType = (Type) list[ i ];
Attribute[] vAttrs = Attribute.GetCustomAttributes( thisType, typeof( PartInfoAttribute ) );
if ( vAttrs != null && vAttrs.Length == 1 )
{
PartInfoAttribute partInfo = (PartInfoAttribute) vAttrs[ 0 ];
// add header string in list box.
ctrlDetails.Items.Add( new DetailsElement( part, partInfo, null, baseOffset, null ) );
// iterate through the fields.
FieldInfo[] fields = thisType.GetFields ();
foreach( FieldInfo field in fields )
{
if ( field.DeclaringType == thisType )
{
Attribute[] fieldInfo = Attribute.GetCustomAttributes( field, typeof( FieldInfoAttribute ) );
if ( fieldInfo != null && fieldInfo.Length == 1 )
{
FieldInfoAttribute info = (FieldInfoAttribute) fieldInfo[ 0 ];
// add field string in list box.
ctrlDetails.Items.Add( new DetailsElement( part, partInfo, info, baseOffset, field ) );
}
}
}
}
}
}
}
// return.
return;
}
protected void SetSelectionStart( int selStartX, int selStartY )
{
ctrlHexView.SelectionStart =
( selStartY * 78 ) + selStartX;
}
protected void SetSelectionLength( int len )
{
ctrlHexView.SelectionLength = len;
}
protected void HighlightSelText( Color clrFore, Color clrBack )
{
RichTextBox_Interop.CHARFORMAT2 format = new RichTextBox_Interop.CHARFORMAT2 ();
format.cbSize = Marshal.SizeOf( format );
format.dwMask = RichTextBox_Interop.CFM_BACKCOLOR | RichTextBox_Interop.CFM_COLOR;
format.crTextColor = ColorTranslator.ToOle( clrFore );
format.crBackColor = ColorTranslator.ToOle( clrBack );
RichTextBox_Interop.CHARFORMAT2_Funcs.SendMessageA(
ctrlHexView.Handle,
RichTextBox_Interop.EM_SETCHARFORMAT,
RichTextBox_Interop.SCF_SELECTION,
ref format );
}
protected void HighlightText( int selStartX, int selStartY, int len, Color clrFore, Color clrBack )
{
SetSelectionStart( selStartX, selStartY );
SetSelectionLength( len );
HighlightSelText( clrFore, clrBack );
}
protected void HighlightBytes( int offset, int size, Color clrFore, Color clrBack )
{
if ( size == 0 )
return;
// highlight in the rich text box...
int byteStartX = offset % 16;
int selStartY = offset / 16;
int selStartX = 10 + byteStartX * 3;
if ( byteStartX >= 8 )
selStartX ++;
int offsetEnd = offset + size - 1;
int byteEndX = offsetEnd % 16;
int selEndY = offsetEnd / 16;
int selEndX = 10 + byteEndX * 3;
if ( byteEndX >= 8 )
selEndX ++;
int len;
if ( selStartY == selEndY )
len = selEndX - selStartX + 2;
else
len = 58 - selStartX;
HighlightText( selStartX, selStartY, len, clrFore, clrBack );
if ( selStartY != selEndY )
{
for( int i=selStartY+1; i<=selEndY-1; i ++ )
HighlightText( 10, i, 48, clrFore, clrBack );
HighlightText( 10, selEndY, selEndX - 8, clrFore, clrBack );
}
}
private void ctrlDetails_SelectedIndexChanged(object sender, System.EventArgs e)
{
int selIndex = ctrlDetails.SelectedIndex;
if ( selIndex != -1 )
{
DetailsElement sel = (DetailsElement) ctrlDetails.Items[ selIndex ];
// start editing the rich text box...
RichTextBox_Interop.LockWindowUpdate( ctrlHexView.Handle );
try
{
// unhighlight the text.
ctrlHexView.SelectAll ();
HighlightSelText( ctrlHexView.ForeColor, ctrlHexView.BackColor );
// calculate the offset and size vars.
int offset = sel._baseOffset;
int size = sel._part._length;
HighlightBytes( offset, size, Color.White, Color.Red );
if ( sel._fieldInfo != null )
HighlightBytes( offset + sel._fieldInfo.Offset, sel._fieldSize, Color.White, Color.Black );
// unselect text.
SetSelectionLength( 0 );
}
finally
{
RichTextBox_Interop.LockWindowUpdate( IntPtr.Zero );
}
}
// return.
return;
}
protected void PrevPacket ()
{
if ( _pnp != null )
{
// get the previous packet.
RawPacket rp = _pnp( 0 );
if ( rp != null )
{
_rp = rp;
LoadRp ();
}
}
}
protected void NextPacket ()
{
if ( _pnp != null )
{
// get the next packet.
RawPacket rp = _pnp( 1 );
if ( rp != null )
{
_rp = rp;
LoadRp ();
}
}
}
private void ctrlToolbar_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
if ( e.Button == ctrlUpBtn )
PrevPacket ();
else if ( e.Button == ctrlDownBtn )
NextPacket ();
}
#region IMessageFilter Members
public bool PreFilterMessage(ref Message m)
{
// which msg ?
switch( m.Msg )
{
case /*WM_KEYDOWN*/ 0x0100:
if ( m.WParam == new IntPtr( /*VK_F3*/ 0x72 ) )
{
PrevPacket ();
return true;
}
else if ( m.WParam == new IntPtr( /*VK_F4*/ 0x73 ) )
{
NextPacket ();
return true;
}
break;
}
// return.
return false;
}
#endregion
private void dlgPacketViewer_Closed(object sender, System.EventArgs e)
{
Application.RemoveMessageFilter( this );
}
}
internal class RichTextBox_Interop
{
//
// Structures.
//
[ StructLayout( LayoutKind.Sequential ) ]
internal struct CHARFORMAT2
{
public Int32 cbSize;
public Int32 dwMask;
public Int32 dwEffects;
public Int32 yHeight;
public Int32 yOffset;
public Int32 crTextColor;
public Byte bCharSet;
public Byte bPitchAndFamily;
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst = 32 ) ]
public String szFaceName;
public Int16 wWeight;
public Int16 sSpacing;
public Int32 crBackColor;
public Int32 lcid;
public Int32 dwReserved;
public Int16 sStyle;
public Int16 wKerning;
public Byte bUnderlineType;
public Byte bAnimation;
public Byte bRevAuthor;
public Byte bReserved1;
}
//
// Constants.
//
internal const Int32 CFM_COLOR = 0x40000000;
internal const Int32 CFM_BACKCOLOR = 0x4000000;
internal const Int32 EM_SETCHARFORMAT = 0x444;
internal const Int32 SCF_SELECTION = 0x1;
//
// Functions.
//
[DllImport("user32.dll")]
internal static extern bool LockWindowUpdate( IntPtr hWndLock );
internal class CHARFORMAT2_Funcs // this will simplify the whole marshal thing...
{
[ DllImport( "user32.dll" ) ]
internal static extern IntPtr SendMessageA( IntPtr hWnd, uint Msg, /*UIntPtr*/ UInt32 wParam, /*IntPtr*/ ref CHARFORMAT2 lParam );
}
}
}