HexDump Application for .NET Framework

This .NET application opens a file to display its contents in a hexadecimal format. It is a simple application to learn opening, displaying and printing files. Compare it to the MFC HexDump. Source code can be found here: DOTNETHEXDUMP.zip

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.IO;
using System.Text;

namespace HexDump
{
	class HexDump : Form
	{
		private PrintDocument pdoc = new PrintDocument();
		private PrintDialog pdlg = new PrintDialog();
		private PageSetupDialog psdlg = new PageSetupDialog();
		private PrintPreviewDialog prdlg = new PrintPreviewDialog();
		private OpenFileDialog ofd = new OpenFileDialog();
		private long lFilePosition;
		private string strFileName;

		[STAThread]
		public static void Main()
		{
			Application.Run(new HexDump());
		}

		public HexDump()
		{
			Text = "HexDump";
			ForeColor = Color.Black;
			BackColor = Color.White;
			Font = new Font(FontFamily.GenericMonospace, 9.0F);
			AutoScroll = true;
			strFileName = "";
			Width = 600;

			pdoc.PrintPage += new PrintPageEventHandler(pdoc_PrintPage);
			pdlg.Document = pdoc;
			psdlg.Document = pdoc;
			prdlg.Document = pdoc;

			Menu = new MainMenu();
			Menu.MenuItems.Add("&File");
			Menu.MenuItems[0].Popup += new EventHandler(FileMenu_Popup);
			Menu.MenuItems.Add("&Help");
			Menu.MenuItems[0].MenuItems.Add("&Open...", MenuOnOpenFile);
			Menu.MenuItems[0].MenuItems.Add("-");
			Menu.MenuItems[0].MenuItems.Add("&Print...", MenuOnPrint);
			Menu.MenuItems[0].MenuItems.Add("Print Pre&view...", MenuOnPrintPreview);
			Menu.MenuItems[0].MenuItems.Add("Page &Setup...", MenuOnPageSetup);
			Menu.MenuItems[1].MenuItems.Add("God, &Help Me!...", MenuOnHelp);
		}

		void FileMenu_Popup(object sender, EventArgs e)
		{
			Menu.MenuItems[0].MenuItems[2].Enabled =
				Menu.MenuItems[0].MenuItems[3].Enabled = (strFileName != "");
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			if (strFileName.Length > 0)
			{
				try
				{
					using (FileStream fs = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
					{
						using (Graphics g = CreateGraphics())
						{
							DumpStream(g, fs);
						}
					}
				}
				catch (Exception ex)
				{
					MessageBox.Show(ex.Message.ToString());
				}
			}
		}
		void MenuOnOpenFile(object sender, EventArgs e)
		{
			ofd.ShowReadOnly = true;
			ofd.ReadOnlyChecked = true;
			ofd.Multiselect = false;
			if (ofd.ShowDialog() == DialogResult.OK)
			{
				try
				{
					using (FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
					{
						strFileName = ofd.FileName;
						Text = Path.GetFileName(strFileName);
						using (Graphics g = CreateGraphics())
						{
							DumpStream(g, fs);
						}
					}
				}
				catch (Exception ex)
				{
					MessageBox.Show(ex.Message.ToString());
				}
			}
		}

		void MenuOnPrint(object sender, EventArgs e)
		{
			lFilePosition = 0;
			if (pdlg.ShowDialog() == DialogResult.OK)
			{
				pdoc.DocumentName = Text;
				pdoc.Print();
			}
		}

		void MenuOnPrintPreview(object sender, EventArgs e)
		{
			prdlg.ShowDialog();
		}

		void MenuOnPageSetup(object sender, EventArgs e)
		{
			psdlg.ShowDialog();
		}

		void MenuOnHelp(object sender, EventArgs e)
		{
			MessageBox.Show("Keep praying... maybe help will come.", "Help System");
		}

		void pdoc_PrintPage(object sender, PrintPageEventArgs e)
		{
			SolidBrush br = new SolidBrush(this.ForeColor);
			RectangleF rectf = new RectangleF(
				e.MarginBounds.Left - (e.PageBounds.Width - e.Graphics.VisibleClipBounds.Width) / 2,
				e.MarginBounds.Top - (e.PageBounds.Height - e.Graphics.VisibleClipBounds.Height) / 2,
				e.MarginBounds.Width,
				e.MarginBounds.Height);
			int iLinesPerPage = (int)(rectf.Bottom - rectf.Top) / this.Font.Height;
			try
			{
				using (FileStream fs = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
				{
					fs.Position = lFilePosition;
					byte[] buffer = new byte[16];
					long lAddress = 0;
					int iCount;
					float y = rectf.Top;
					while ((iCount = fs.Read(buffer, 0, 16)) > 0 && iLinesPerPage-- > 0)
					{
						e.Graphics.DrawString(ComposeLine(lAddress, buffer, iCount), Font, br, rectf.Left, y);
						y += Font.Height;
						lAddress += 16;
					}
					if (fs.Position < fs.Length - 1)
					{
						e.HasMorePages = true;
						lFilePosition = fs.Position;
					}
					else
						lFilePosition = 0;
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message.ToString());
			}
		}

		private void DumpStream(Graphics g, Stream s)
		{
			byte[] buffer = new byte[16];
			long lAddress = 0;
			int iCount;
			Brush br = new SolidBrush(ForeColor);
			float y = AutoScrollPosition.Y;
			int h = 0;
			while ((iCount = s.Read(buffer, 0, 16)) > 0)
			{
				g.DrawString(ComposeLine(lAddress, buffer, iCount), Font, br, 0, y);
				y += Font.Height;
				h += Font.Height;
				lAddress += 16;
			}
			AutoScrollMinSize = new Size(0, h + Font.Height);
		}

		private string ComposeLine(long lAddress, byte[] buffer, int iCount)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append(string.Format("{0:X8} ", (uint)lAddress));
			for (int i = 0; i < 16; i++)
			{
				sb.Append((i < iCount) ? string.Format("{0:X2}", buffer[i]) : "	");
				sb.Append((i == 7 && iCount > 7) ? "-" : " ");
			}
			sb.Append(" ");
			for (int i = 0; i < 16; i++)
			{
				char ch = (i < iCount) ? Convert.ToChar(buffer[i]) : ' ';
				sb.Append(Char.IsControl(ch) ? "." : ch.ToString());
			}
			return sb.ToString();
		}

	}
}