diff --git a/src/.vs/ChecksumValidator/project-colors.json b/src/.vs/ChecksumValidator/project-colors.json new file mode 100644 index 0000000..509e419 --- /dev/null +++ b/src/.vs/ChecksumValidator/project-colors.json @@ -0,0 +1,11 @@ +{ + "Version": 1, + "ProjectMap": { + "67aa0267-46db-4857-bfc1-87c9ab535542": { + "ProjectGuid": "67aa0267-46db-4857-bfc1-87c9ab535542", + "DisplayName": "Gardian.Utilities.ChecksumValidator", + "ColorIndex": 0 + } + }, + "NextColorIndex": 1 +} \ No newline at end of file diff --git a/src/Backup/ChecksumValidator.sln b/src/Backup/ChecksumValidator.sln new file mode 100644 index 0000000..f613ea8 --- /dev/null +++ b/src/Backup/ChecksumValidator.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gardian.Utilities.ChecksumValidator", "Gardian.Utilities.ChecksumValidator\Gardian.Utilities.ChecksumValidator.csproj", "{67AA0267-46DB-4857-BFC1-87C9AB535542}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Release|Any CPU.ActiveCfg = Release|Any CPU + {67AA0267-46DB-4857-BFC1-87C9AB535542}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/CRC32.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/CRC32.cs new file mode 100644 index 0000000..004a7d6 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/CRC32.cs @@ -0,0 +1,145 @@ +// Author: Damien Guard, (c) 2006 +// (http://damieng.com/blog/2006/08/08/Calculating_CRC32_in_C_and_NET) + +using System; +using System.Security.Cryptography; + +/// +/// +public sealed class CRC32 : HashAlgorithm +{ + + /// + /// Default polynomial used for CRC32 computation. + /// + [CLSCompliant(false)] + public const UInt32 DefaultPolynomial = 0xedb88320; + + /// + /// Default CRC32 computation seed. + /// + [CLSCompliant(false)] + public const UInt32 DefaultSeed = 0xffffffff; + + private UInt32 _hash; + private readonly UInt32 _seed; + private readonly UInt32[] _table; + private static UInt32[] DefaultTable; + + /// + /// + public CRC32() + { + this._table = InitializeTable(DefaultPolynomial); + this._seed = DefaultSeed; + Initialize(); + } + + /// + /// + [CLSCompliant(false)] + public CRC32(UInt32 polynomial, UInt32 seed) + { + this._table = InitializeTable(polynomial); + this._seed = seed; + Initialize(); + } + + /// + /// + public override void Initialize() + { + this._hash = this._seed; + } + + /// + /// + protected override void HashCore(byte[] buffer, int start, int length) + { + this._hash = CalculateHash(this._table, this._hash, buffer, start, length); + } + + /// + /// + protected override byte[] HashFinal() + { + byte[] hashBuffer = UInt32ToBigEndianBytes(~this._hash); + this.HashValue = hashBuffer; + return hashBuffer; + } + + /// + /// + public override int HashSize + { + get { return 32; } + } + + /// + /// + [CLSCompliant(false)] + public static UInt32 Compute(byte[] buffer) + { + return ~CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length); + } + + /// + /// + [CLSCompliant(false)] + public static UInt32 Compute(UInt32 seed, byte[] buffer) + { + return ~CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length); + } + + /// + /// + [CLSCompliant(false)] + public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer) + { + return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); + } + + private static UInt32[] InitializeTable(UInt32 polynomial) + { + if (polynomial == DefaultPolynomial && DefaultTable != null) + return DefaultTable; + + var createTable = new UInt32[256]; + for (int i = 0; i < 256; i++) + { + var entry = (UInt32)i; + for (int j = 0; j < 8; j++) + if ((entry & 1) == 1) + entry = (entry >> 1) ^ polynomial; + else + entry = entry >> 1; + createTable[i] = entry; + } + + if (polynomial == DefaultPolynomial) + DefaultTable = createTable; + + return createTable; + } + + private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, byte[] buffer, int start, int size) + { + UInt32 crc = seed; + for (int i = start; i < size; i++) + unchecked + { + crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff]; + } + return crc; + } + + private static byte[] UInt32ToBigEndianBytes(UInt32 x) + { + return new[] { + (byte)((x >> 24) & 0xff), + (byte)((x >> 16) & 0xff), + (byte)((x >> 8) & 0xff), + (byte)(x & 0xff) + }; + } +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Checksum.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Checksum.cs new file mode 100644 index 0000000..991ea77 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Checksum.cs @@ -0,0 +1,184 @@ +using System; +using System.Globalization; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Threading; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// Checksum computation implementation. + /// + internal static class Checksum + { + + //************************************************** + //* Public interface + //************************************************** + + //------------------------------------------------- + /// + /// Compute checksum for the specified source file, + /// return it as hex string ("F3BA87..."). + /// + /// + /// This method will be run on a worker thread + /// (from thread pool) via async invocation. + /// + public static string ComputeChecksum(string sourceFile, ChecksumMethod method, Action progressNotifier) + { + System.Threading.Thread.Sleep(100); + using (var hashAlgorithm = CreateHashAlgorithm(method)) + using (var source = new TrackingStream(File.OpenRead(sourceFile), progressNotifier)) + { + var hash = hashAlgorithm.ComputeHash(source); + + var msg = new StringBuilder(128); + foreach (var byteValue in hash) + { + msg.AppendFormat(byteValue.ToString("X2", CultureInfo.InvariantCulture)); + } + return msg.ToString(); + } + } + + + //------------------------------------------------- + /// + /// Flag that requests cancellation of the current computation + /// (if set to true and a computation is ongoing). + /// + /// + /// Field marked as volatile because it will be accessed + /// by multiple threads (UI thread to set it, worker + /// thread to check it). + /// + public static volatile bool Cancel; + + + + + //************************************************** + //* Private + //************************************************** + + //------------------------------------------------- + /// + /// Find hash algorithm that corresponds to the + /// requested method + /// + /// Thrown + /// when requested method is not recognized. + private static HashAlgorithm CreateHashAlgorithm(ChecksumMethod method) + { + switch (method) + { + case ChecksumMethod.SHA1: return new SHA1CryptoServiceProvider(); + case ChecksumMethod.MD5: return new MD5CryptoServiceProvider(); + case ChecksumMethod.CRC32: return new CRC32(); + default: throw new NotSupportedException(string.Concat("Requested checksum method ", method, " is not supported")); + } + } + + + //------------------------------------------------- + /// + /// Custom stream for hash algorithm that only implements + /// Read & Dispose methods (every other method will + /// throw NotSupportedException). This class implements + /// a bridge pattern (both Read and Dispose are forwarded + /// to the underlying "tracked" stream). The only extra + /// functionality is that if Read operation read another + /// megabyte of data since last progress notifier invocation, + /// progress percentage is recomputed and progress notifier + /// is called with this value. This allows us to track + /// progress of hash computation even though HashAlgorithm + /// does not support this. + /// + private sealed class TrackingStream : Stream + { + public TrackingStream(Stream trackedStream, Action progressNotifier) + { + if (trackedStream == null) { throw new ArgumentNullException("trackedStream"); } + this._trackedStream = trackedStream; + this._progressNotifier = progressNotifier; + } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + this._trackedStream.Dispose(); + } + } + public override void Flush() + { + throw new NotImplementedException(); + } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + public override int Read(byte[] buffer, int offset, int count) + { + var ret = this._trackedStream.Read(buffer, offset, count); + + if (Checksum.Cancel) + { + throw new ThreadInterruptedException(); + } + if (this._progressNotifier != null) + { + var position = this._trackedStream.Position; + const long mb = 2L << 19; + var megabyte = position / mb; + if (megabyte > this._lastMegabyte) + { + this._lastMegabyte = megabyte; + var percentage = ((decimal)position / this._trackedStream.Length); + this._progressNotifier(percentage); + } + } + return ret; + } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + public override bool CanRead + { + get { throw new NotImplementedException(); } + } + public override bool CanSeek + { + get { throw new NotImplementedException(); } + } + public override bool CanWrite + { + get { throw new NotImplementedException(); } + } + public override long Length + { + get { throw new NotImplementedException(); } + } + public override long Position + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + private long _lastMegabyte; + private readonly Action _progressNotifier; + private readonly Stream _trackedStream; + + } + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/ChecksumMethod.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/ChecksumMethod.cs new file mode 100644 index 0000000..53f5e8f --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/ChecksumMethod.cs @@ -0,0 +1,17 @@ +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// Define supported checksum (hash) methods. + /// + internal enum ChecksumMethod + { + // ReSharper disable InconsistentNaming + None = 0, + SHA1, + MD5, + CRC32, + // ReSharper restore InconsistentNaming + } + +} diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/ColorPulser.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/ColorPulser.cs new file mode 100644 index 0000000..c8b72d7 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/ColorPulser.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// + internal sealed class ColorPulser + { + + //************************************************** + //* Construction & destruction + //************************************************** + + //------------------------------------------------- + /// + /// Create new instance of color pulser, initializing + /// the color-transitions table. + /// + public ColorPulser(Timer timer, List ongoingPulses, Color startColor, Color endColor, TimeSpan pulseDuration) + { + if (timer == null) { throw new ArgumentNullException("timer"); } + this._timer = timer; + if (ongoingPulses == null) { throw new ArgumentNullException("ongoingPulses"); } + this._pulses = ongoingPulses; + + var change = timer.Interval; + if (change < 10) { throw new ArgumentException("Timer interval should be longer than 10 milliseconds", "timer");} + + var pulse = (int)pulseDuration.TotalMilliseconds; + if (pulse <= change) { throw new ArgumentException("Pulse duration should be longer than change period", "pulseDuration");} + + var count = pulse / change; + this._colors = new List(count * 2); + var redStep = (decimal)(endColor.R - startColor.R) / count; + var greenStep = (decimal)(endColor.G - startColor.G) / count; + var blueStep = (decimal)(endColor.B - startColor.B) / count; + /* + var currentRed = (decimal)startColor.R; + var currentGreen = (decimal)startColor.G; + var currentBlue = (decimal)startColor.B; + for (var i = 0; i < count - 1; ++i) + { + currentRed += redStep; + currentGreen += greenStep; + currentBlue += blueStep; + this._colors.Add(Color.FromArgb((int)currentRed, (int)currentGreen, (int)currentBlue)); + } + */ + this._colors.Add(endColor); + decimal currentRed = endColor.R; + decimal currentGreen = endColor.G; + decimal currentBlue = endColor.B; + for (var i = 0; i < count - 1; ++i) + { + currentRed -= redStep; + currentGreen -= greenStep; + currentBlue -= blueStep; + this._colors.Add(Color.FromArgb((int)currentRed, (int)currentGreen, (int)currentBlue)); + } + this._colors.Add(startColor); + + this._timer.Tick += this.OnTimer; + } + + + + + //************************************************** + //* Public interface + //************************************************** + + //------------------------------------------------- + /// + /// + public void Pulse(Control control) + { + if (control != null) + { + this._pulses.RemoveAll(p => object.ReferenceEquals(((PulseProgress)p).Control, control)); + this._pulses.Add(new PulseProgress { Pulser = this, Control = control, NextColorIndex = 0 }); + this.OnTimer(null, null); // immediately set color[0] + } + } + + + + + //************************************************** + //* Private + //************************************************** + + //------------------------------------------------- + /// + /// + /// + /// + private void OnTimer(object sender, EventArgs e) + { + if (this._pulses.Count > 0) + { + if (!this._timer.Enabled) + { + this._timer.Enabled = true; + } + + var i = 0; + while (i < this._pulses.Count) + { + var pulseProgress = (PulseProgress)this._pulses[i]; + if (object.ReferenceEquals(this, pulseProgress.Pulser)) + { + pulseProgress.Control.BackColor = this._colors[pulseProgress.NextColorIndex++]; + if (pulseProgress.NextColorIndex >= this._colors.Count) + { + this._pulses.RemoveAt(i--); + } + } + ++i; + } + } + else + { + this._timer.Enabled = false; + } + } + + + private sealed class PulseProgress + { + public ColorPulser Pulser; + public Control Control; + public int NextColorIndex; + } + + + private readonly List _colors; + private readonly List _pulses; + private readonly Timer _timer; + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj b/src/Backup/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj new file mode 100644 index 0000000..8dbb484 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj @@ -0,0 +1,73 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {67AA0267-46DB-4857-BFC1-87C9AB535542} + WinExe + Properties + Gardian.Utilities.ChecksumValidator + ChecksumValidator + v2.0 + 512 + ..\..\build\$(Configuration)\ + ..\..\build\$(Configuration)\$(AssemblyName).xml + prompt + 4 + Resources\App.ico + + + true + full + false + DEBUG;TRACE + + + pdbonly + true + TRACE + + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + + + + + + + \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.Designer.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.Designer.cs new file mode 100644 index 0000000..7b78a2d --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.Designer.cs @@ -0,0 +1,351 @@ +namespace Gardian.Utilities.ChecksumValidator +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.TableLayoutPanel layout; + System.Windows.Forms.Button cancel; + System.Windows.Forms.ToolTip tooltop; + this._methodsContainer = new System.Windows.Forms.FlowLayoutPanel(); + this._methodLabel = new System.Windows.Forms.Label(); + this._methodSha1 = new System.Windows.Forms.RadioButton(); + this._methodMd5 = new System.Windows.Forms.RadioButton(); + this._methodCrc32 = new System.Windows.Forms.RadioButton(); + this._fileLabel = new System.Windows.Forms.Label(); + this._file = new System.Windows.Forms.TextBox(); + this._filePaste = new System.Windows.Forms.Button(); + this._fileBrowse = new System.Windows.Forms.Button(); + this._checksumLabel = new System.Windows.Forms.Label(); + this._checksum = new System.Windows.Forms.TextBox(); + this._checksumPaste = new System.Windows.Forms.Button(); + this._resultLabel = new System.Windows.Forms.Label(); + this._result = new System.Windows.Forms.TextBox(); + this._resultCompute = new System.Windows.Forms.Button(); + this._timer = new System.Windows.Forms.Timer(this.components); + layout = new System.Windows.Forms.TableLayoutPanel(); + cancel = new System.Windows.Forms.Button(); + tooltop = new System.Windows.Forms.ToolTip(this.components); + layout.SuspendLayout(); + this._methodsContainer.SuspendLayout(); + this.SuspendLayout(); + // + // layout + // + layout.AutoSize = true; + layout.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + layout.ColumnCount = 3; + layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + layout.Controls.Add(this._methodsContainer, 0, 0); + layout.Controls.Add(this._fileLabel, 0, 1); + layout.Controls.Add(this._file, 0, 2); + layout.Controls.Add(this._filePaste, 1, 2); + layout.Controls.Add(this._fileBrowse, 2, 2); + layout.Controls.Add(this._checksumLabel, 0, 3); + layout.Controls.Add(this._checksum, 0, 4); + layout.Controls.Add(this._checksumPaste, 1, 4); + layout.Controls.Add(this._resultLabel, 0, 5); + layout.Controls.Add(this._result, 0, 6); + layout.Controls.Add(this._resultCompute, 1, 6); + layout.Location = new System.Drawing.Point(0, 0); + layout.Margin = new System.Windows.Forms.Padding(0); + layout.Name = "layout"; + layout.Padding = new System.Windows.Forms.Padding(6, 9, 6, 9); + layout.RowCount = 7; + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + layout.Size = new System.Drawing.Size(478, 200); + layout.TabIndex = 0; + // + // _methodsContainer + // + this._methodsContainer.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._methodsContainer.AutoSize = true; + this._methodsContainer.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + layout.SetColumnSpan(this._methodsContainer, 2); + this._methodsContainer.Controls.Add(this._methodLabel); + this._methodsContainer.Controls.Add(this._methodSha1); + this._methodsContainer.Controls.Add(this._methodMd5); + this._methodsContainer.Controls.Add(this._methodCrc32); + this._methodsContainer.Location = new System.Drawing.Point(6, 9); + this._methodsContainer.Margin = new System.Windows.Forms.Padding(0); + this._methodsContainer.Name = "_methodsContainer"; + this._methodsContainer.Size = new System.Drawing.Size(279, 23); + this._methodsContainer.TabIndex = 0; + // + // _methodLabel + // + this._methodLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._methodLabel.AutoSize = true; + this._methodLabel.Location = new System.Drawing.Point(0, 5); + this._methodLabel.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); + this._methodLabel.Name = "_methodLabel"; + this._methodLabel.Size = new System.Drawing.Size(98, 13); + this._methodLabel.TabIndex = 0; + this._methodLabel.Text = "Checksum method:"; + // + // _methodSha1 + // + this._methodSha1.AutoSize = true; + this._methodSha1.Checked = true; + this._methodSha1.Location = new System.Drawing.Point(104, 3); + this._methodSha1.Name = "_methodSha1"; + this._methodSha1.Size = new System.Drawing.Size(53, 17); + this._methodSha1.TabIndex = 0; + this._methodSha1.TabStop = true; + this._methodSha1.Text = "SHA1"; + this._methodSha1.UseVisualStyleBackColor = true; + // + // _methodMd5 + // + this._methodMd5.AutoSize = true; + this._methodMd5.Location = new System.Drawing.Point(163, 3); + this._methodMd5.Name = "_methodMd5"; + this._methodMd5.Size = new System.Drawing.Size(48, 17); + this._methodMd5.TabIndex = 0; + this._methodMd5.Text = "MD5"; + this._methodMd5.UseVisualStyleBackColor = true; + // + // _methodCrc32 + // + this._methodCrc32.AutoSize = true; + this._methodCrc32.Location = new System.Drawing.Point(217, 3); + this._methodCrc32.Name = "_methodCrc32"; + this._methodCrc32.Size = new System.Drawing.Size(59, 17); + this._methodCrc32.TabIndex = 0; + this._methodCrc32.Text = "CRC32"; + this._methodCrc32.UseVisualStyleBackColor = true; + // + // _fileLabel + // + this._fileLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._fileLabel.AutoSize = true; + this._fileLabel.Location = new System.Drawing.Point(6, 41); + this._fileLabel.Margin = new System.Windows.Forms.Padding(0, 9, 3, 0); + this._fileLabel.Name = "_fileLabel"; + this._fileLabel.Size = new System.Drawing.Size(66, 13); + this._fileLabel.TabIndex = 0; + this._fileLabel.Text = "File to verify:"; + // + // _file + // + this._file.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._file.Location = new System.Drawing.Point(9, 59); + this._file.Name = "_file"; + this._file.Size = new System.Drawing.Size(340, 20); + this._file.TabIndex = 0; + this._file.TextChanged += new System.EventHandler(this.CheckComputationAvailability); + // + // _filePaste + // + this._filePaste.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._filePaste.AutoSize = true; + this._filePaste.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this._filePaste.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Paste; + this._filePaste.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._filePaste.Location = new System.Drawing.Point(355, 57); + this._filePaste.Name = "_filePaste"; + this._filePaste.Padding = new System.Windows.Forms.Padding(3, 1, 3, 1); + this._filePaste.Size = new System.Drawing.Size(28, 25); + this._filePaste.TabIndex = 0; + tooltop.SetToolTip(this._filePaste, "Paste clipboard as \"File to verify\""); + this._filePaste.UseVisualStyleBackColor = true; + this._filePaste.Click += new System.EventHandler(this.OnFilePaste); + // + // _fileBrowse + // + this._fileBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._fileBrowse.AutoSize = true; + this._fileBrowse.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this._fileBrowse.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Open; + this._fileBrowse.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._fileBrowse.Location = new System.Drawing.Point(386, 57); + this._fileBrowse.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3); + this._fileBrowse.Name = "_fileBrowse"; + this._fileBrowse.Padding = new System.Windows.Forms.Padding(3, 1, 3, 1); + this._fileBrowse.Size = new System.Drawing.Size(83, 25); + this._fileBrowse.TabIndex = 0; + this._fileBrowse.Text = " Browse"; + this._fileBrowse.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + tooltop.SetToolTip(this._fileBrowse, "Browse for \"File to verify\""); + this._fileBrowse.UseVisualStyleBackColor = true; + this._fileBrowse.Click += new System.EventHandler(this.OnBrowse); + // + // _checksumLabel + // + this._checksumLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._checksumLabel.AutoSize = true; + this._checksumLabel.Location = new System.Drawing.Point(6, 94); + this._checksumLabel.Margin = new System.Windows.Forms.Padding(0, 9, 3, 0); + this._checksumLabel.Name = "_checksumLabel"; + this._checksumLabel.Size = new System.Drawing.Size(107, 13); + this._checksumLabel.TabIndex = 0; + this._checksumLabel.Text = "Expected checksum:"; + // + // _checksum + // + this._checksum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._checksum.Location = new System.Drawing.Point(9, 112); + this._checksum.Name = "_checksum"; + this._checksum.Size = new System.Drawing.Size(340, 20); + this._checksum.TabIndex = 0; + // + // _checksumPaste + // + this._checksumPaste.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._checksumPaste.AutoSize = true; + this._checksumPaste.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + layout.SetColumnSpan(this._checksumPaste, 2); + this._checksumPaste.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Paste; + this._checksumPaste.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._checksumPaste.Location = new System.Drawing.Point(355, 110); + this._checksumPaste.Name = "_checksumPaste"; + this._checksumPaste.Padding = new System.Windows.Forms.Padding(3, 1, 3, 1); + this._checksumPaste.Size = new System.Drawing.Size(114, 25); + this._checksumPaste.TabIndex = 0; + this._checksumPaste.Text = "Paste"; + this._checksumPaste.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + tooltop.SetToolTip(this._checksumPaste, "Paste clipboard as \"Expected checksum\""); + this._checksumPaste.UseVisualStyleBackColor = true; + this._checksumPaste.Click += new System.EventHandler(this.OnChecksumPaste); + // + // _resultLabel + // + this._resultLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this._resultLabel.AutoSize = true; + this._resultLabel.Enabled = false; + this._resultLabel.Location = new System.Drawing.Point(6, 147); + this._resultLabel.Margin = new System.Windows.Forms.Padding(0, 9, 3, 0); + this._resultLabel.Name = "_resultLabel"; + this._resultLabel.Size = new System.Drawing.Size(110, 13); + this._resultLabel.TabIndex = 0; + this._resultLabel.Text = "Computed checksum:"; + // + // _result + // + this._result.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._result.BackColor = System.Drawing.SystemColors.Window; + this._result.Enabled = false; + this._result.Location = new System.Drawing.Point(9, 165); + this._result.Name = "_result"; + this._result.ReadOnly = true; + this._result.Size = new System.Drawing.Size(340, 20); + this._result.TabIndex = 0; + // + // _resultCompute + // + this._resultCompute.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this._resultCompute.AutoSize = true; + layout.SetColumnSpan(this._resultCompute, 2); + this._resultCompute.Enabled = false; + this._resultCompute.Image = global::Gardian.Utilities.ChecksumValidator.Properties.Resources.Run; + this._resultCompute.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this._resultCompute.Location = new System.Drawing.Point(355, 163); + this._resultCompute.Name = "_resultCompute"; + this._resultCompute.Padding = new System.Windows.Forms.Padding(6, 1, 3, 1); + this._resultCompute.Size = new System.Drawing.Size(114, 25); + this._resultCompute.TabIndex = 0; + this._resultCompute.Text = "Compute"; + this._resultCompute.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + tooltop.SetToolTip(this._resultCompute, "Compute checksum and verify it against the specified expected value"); + this._resultCompute.UseVisualStyleBackColor = true; + this._resultCompute.Click += new System.EventHandler(this.OnCompute); + // + // cancel + // + cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + cancel.Location = new System.Drawing.Point(0, 0); + cancel.Name = "cancel"; + cancel.Size = new System.Drawing.Size(75, 23); + cancel.TabIndex = 0; + cancel.TabStop = false; + cancel.Text = "Cancel"; + cancel.UseVisualStyleBackColor = true; + cancel.Click += new System.EventHandler(this.OnCancel); + // + // _timer + // + this._timer.Interval = 20; + // + // MainForm + // + this.AcceptButton = this._resultCompute; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.CancelButton = cancel; + this.ClientSize = new System.Drawing.Size(594, 274); + this.Controls.Add(layout); + this.Controls.Add(cancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "MainForm"; + this.Text = "Main dialog"; + layout.ResumeLayout(false); + layout.PerformLayout(); + this._methodsContainer.ResumeLayout(false); + this._methodsContainer.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox _file; + private System.Windows.Forms.Label _checksumLabel; + private System.Windows.Forms.TextBox _checksum; + private System.Windows.Forms.Button _fileBrowse; + private System.Windows.Forms.Button _checksumPaste; + private System.Windows.Forms.Label _resultLabel; + private System.Windows.Forms.Button _resultCompute; + private System.Windows.Forms.TextBox _result; + private System.Windows.Forms.Timer _timer; + private System.Windows.Forms.Label _fileLabel; + private System.Windows.Forms.RadioButton _methodSha1; + private System.Windows.Forms.RadioButton _methodMd5; + private System.Windows.Forms.FlowLayoutPanel _methodsContainer; + private System.Windows.Forms.Label _methodLabel; + private System.Windows.Forms.RadioButton _methodCrc32; + private System.Windows.Forms.Button _filePaste; + } +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.cs new file mode 100644 index 0000000..45999d7 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.cs @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Threading; +using System.Windows.Forms; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// + public sealed partial class MainForm : Form + { + + //************************************************** + //* Construction & destruction + //************************************************** + + //------------------------------------------------- + /// + /// Create new instance of main form, initializing + /// controls (designer), fonts, icon and color pulsers + /// (pulsers are used to temporarily highlight input + /// controls when something interesting happens). + /// + public MainForm() + { + this.InitializeComponent(); + this.Font = SystemFonts.MessageBoxFont; + this.Icon = Properties.Resources.App; + this.Text = Properties.Resources.Title; + var boldFont = new Font(this.Font, FontStyle.Bold); + this._methodLabel.Font = this._fileLabel.Font = this._checksumLabel.Font = this._resultLabel.Font = boldFont; + + var ongoingPulses = new List(); + this._greenPulser = new ColorPulser( + this._timer, + ongoingPulses, + SystemColors.Window, + Color.PaleGreen, //SystemColors.Info, + TimeSpan.FromMilliseconds(250)); + this._redPulser = new ColorPulser( + this._timer, + ongoingPulses, + SystemColors.Window, + Color.MistyRose, + TimeSpan.FromMilliseconds(250)); + this._result.MouseClick += this.OnErrorDetails; + this.HelpRequested += this.OnErrorDetails; + } + + + //------------------------------------------------- + /// + /// Set initial form focus. + /// + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + this._file.Focus(); + } + + + + + //************************************************** + //* Private + //************************************************** + + //------------------------------------------------- + /// + /// + private void CheckComputationAvailability(object sender, EventArgs e) + { + this._resultCompute.Enabled = !string.IsNullOrEmpty(this._file.Text); + } + + + //------------------------------------------------- + /// + /// + private void OnBrowse(object sender, EventArgs e) + { + using (var dlg = new OpenFileDialog + { + CheckFileExists = false, + CheckPathExists = false, + DereferenceLinks = true, + Multiselect = false, + Title = "Select file to compute checksum for", + Filter = "Executable files (*.exe;*.msi;*.msu;*.iso)|*.exe;*.msi;*.msu;*.iso|All files (*.*)|*.*", + }) + { + if (!string.IsNullOrEmpty(this._file.Text)) + { + try + { + dlg.InitialDirectory = Path.GetDirectoryName(this._file.Text); + } + catch (ArgumentException) {} + } + if (dlg.ShowDialog(this) == DialogResult.OK) + { + this._file.Text = dlg.FileName; + this._greenPulser.Pulse(this._file); + this.CheckComputationAvailability(null, null); + this._checksum.Focus(); + } + } + } + + + //------------------------------------------------- + /// + /// + private void OnCancel(object sender, EventArgs e) + { + this.Close(); + } + + + //------------------------------------------------- + /// + /// + private void OnChecksumPaste(object sender, EventArgs e) + { + if (Clipboard.ContainsText()) + { + this._checksum.Text = Clipboard.GetText(); + this._checksum.Select(this._checksum.Text.Length, 0); + this._greenPulser.Pulse(this._checksum); + if (this._resultCompute.Enabled) + { + this._resultCompute.Focus(); + } + } + } + + + //------------------------------------------------- + /// + /// + private void OnCompute(object sender, EventArgs e) + { + if (this._resultCompute.Tag != null) + { + Checksum.Cancel = true; + this._resultCompute.Text = "Cancelling"; + } + else + { + this._result.Enabled = true; + + FileInfo fileInfo = null; + try { fileInfo = new FileInfo(this._file.Text); } catch (ArgumentException) {} + if (fileInfo == null || !fileInfo.Exists) + { + this._file.Focus(); + this._result.ForeColor = Color.Red; + this._result.Text = "Specified file does not exist or is not readable"; + this._result.Select(this._result.Text.Length, 0); + + this._redPulser.Pulse(this._file); + this._redPulser.Pulse(this._result); + return; + } + + this._methodsContainer.Enabled = false; + this._checksumLabel.Enabled = false; + this._checksum.Enabled = false; + this._checksumPaste.Enabled = false; + this._fileLabel.Enabled = false; + this._file.Enabled = false; + this._filePaste.Enabled = false; + this._fileBrowse.Enabled = false; + this._resultLabel.Enabled = true; + this._result.ForeColor = SystemColors.ControlText; + this.OnComputeProgress(0m); + //this._greenPulser.Pulse(this._result); + this._resultCompute.Text = "Cancel"; + this._resultCompute.Image = Properties.Resources.Stop; + this._resultCompute.Tag = string.Empty; // make Tag non-null + this._resultCompute.Focus(); + + Checksum.Cancel = false; + this._error = null; + Func, string> computeFunction = Checksum.ComputeChecksum; + computeFunction.BeginInvoke( + fileInfo.FullName, + this._methodMd5.Checked + ? ChecksumMethod.MD5 + : this._methodCrc32.Checked + ? ChecksumMethod.CRC32 + : ChecksumMethod.SHA1, + this.OnComputeProgress, + this.OnComputeDone, + computeFunction); + } + } + + + //------------------------------------------------- + /// + /// + private void OnComputeDone(IAsyncResult result) + { + string checksum = null; + string error = null; + try + { + var test = (Func, string>)result.AsyncState; + checksum = test.EndInvoke(result); + } + catch (Exception ex) + { + error = (ex is ThreadInterruptedException + ? string.Empty + : TraceUtilities.BuildExceptionReport( + "Checksum computation failed", + string.Empty, null, ex, null).ToString()); + if (error.Length > 0) + { + TraceUtilities.TraceMultilineText(error, "Checksum Error"); + } + } + + this.BeginInvoke(new Action(this.OnComputeReportResults), checksum, error); // marshall to the UI thread + } + + + //------------------------------------------------- + /// + /// Computation is still going on, + /// + private void OnComputeProgress(decimal percentage) + { + if (this.InvokeRequired) + { + this.Invoke(new Action(this.OnComputeProgress), percentage); // marshall to the UI thread + } + else + { + var percentageStr = percentage.ToString("0.0%"); + var currentTicks = DateTime.Now.Ticks; + if (currentTicks > this._nextTitleUpdateTicks) + { + const long delay = 150 * TimeSpan.TicksPerMillisecond; + this._nextTitleUpdateTicks = currentTicks + delay; + this.Text = string.Concat(percentageStr, " - ", Properties.Resources.Title); + } + this._result.Text = string.Concat("Please wait... (", percentageStr, " complete)"); + } + } + + + //------------------------------------------------- + /// + /// + private void OnComputeReportResults(string checksum, string error) + { + this.Text = Properties.Resources.Title; + this._methodsContainer.Enabled = true; + this._checksumLabel.Enabled = true; + this._checksum.Enabled = true; + this._checksumPaste.Enabled = true; + this._fileLabel.Enabled = true; + this._file.Enabled = true; + this._filePaste.Enabled = true; + this._fileBrowse.Enabled = true; + this._resultCompute.Text = "Compute"; + this._resultCompute.Image = Properties.Resources.Run; + this._resultCompute.Tag = null; + + if (error != null) + { + if (error.Length == 0) + { + this._result.Text = "Cancelled"; + } + else + { + this._error = error; + this._result.Text = "Failed (click here or press F1 for error details)"; + } + this._redPulser.Pulse(this._result); + this._result.ForeColor = Color.Red; + } + else + { + var identical = StringComparer.OrdinalIgnoreCase.Equals(checksum, this._checksum.Text.Trim()); + this._result.Text = string.Concat( + checksum ?? "(no results)", + " - ", + identical ? "OK" : "INVALID"); + this._result.ForeColor = identical ? Color.Green : Color.Red; + if (identical) + { + this._greenPulser.Pulse(this._checksum); + this._greenPulser.Pulse(this._result); + } + else + { + this._checksum.Focus(); + this._redPulser.Pulse(this._checksum); + this._redPulser.Pulse(this._result); + } + } + + this._result.Select(this._result.Text.Length, 0); + } + + + //------------------------------------------------- + /// + /// + private void OnErrorDetails(object sender, EventArgs e) + { + if (this._error != null) + { + MessageBox.Show( + this, + this._error, + "SHA1 Computation Error", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + } + + + //------------------------------------------------- + /// + /// + private void OnFilePaste(object sender, EventArgs e) + { + if (Clipboard.ContainsText()) + { + this._file.Text = Clipboard.GetText(); + this._file.Select(this._file.Text.Length, 0); + this._greenPulser.Pulse(this._file); + this.CheckComputationAvailability(null, null); + this._checksum.Focus(); + } + } + + + private string _error; + private readonly ColorPulser _greenPulser; + private long _nextTitleUpdateTicks; // earliest time when titlebar can be updated again (DateTime ticks); for discussion on reason behind this see http://stackoverflow.com/questions/380380/how-to-force-a-redraw-of-my-applications-entry-in-the-taskbar + private readonly ColorPulser _redPulser; + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.resx b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.resx new file mode 100644 index 0000000..b78cb16 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/MainForm.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + 102, 17 + + + False + + + 17, 17 + + \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Program.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Program.cs new file mode 100644 index 0000000..660ddf5 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Program.cs @@ -0,0 +1,32 @@ +using System; +using System.Windows.Forms; + +namespace Gardian.Utilities.ChecksumValidator +{ + + // .NET 3.5 - style delegates + internal delegate void Action(T value); + internal delegate void Action(T1 value1, T2 value2); + internal delegate T4 Func(T1 value1, T2 value2, T3 value3); + + + /// + /// + public static class Program + { + + /// + /// The main entry point for the application. + /// + [STAThread] + public static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Control.CheckForIllegalCrossThreadCalls = true; + Application.Run(new MainForm()); + } + + } + +} \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/AssemblyInfo.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7d7a364 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/AssemblyInfo.cs @@ -0,0 +1,28 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("ChecksumValidator")] +[assembly: AssemblyDescription("ChecksumValidator: GUI application to compute checksum of a specified file and validate it against expected checksum")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyCopyright("Copyright (C) 2009 Milan Gardian. All rights reserved.")] +[assembly: ComVisible(false)] +[assembly: Guid("10ABE120-00E5-43FB-8101-16ACA2A31A04")] +[assembly: CLSCompliant(true)] + +[assembly: AssemblyVersion("1.2")] +[assembly: AssemblyFileVersion("1.2.2009.05130")] +[assembly: AssemblyProduct("ChecksumValidator v1.2 " +#if DEBUG + + "(debug)" +#else + + "(release)" +#endif +)] +[assembly: AssemblyConfiguration( +#if DEBUG + "DEBUG" +#else + "RELEASE" +#endif +)] \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs new file mode 100644 index 0000000..1690113 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3074 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Gardian.Utilities.ChecksumValidator.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Gardian.Utilities.ChecksumValidator.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Icon App { + get { + object obj = ResourceManager.GetObject("App", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + internal static System.Drawing.Bitmap Open { + get { + object obj = ResourceManager.GetObject("Open", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Paste { + get { + object obj = ResourceManager.GetObject("Paste", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Run { + get { + object obj = ResourceManager.GetObject("Run", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Stop { + get { + object obj = ResourceManager.GetObject("Stop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Checksum validator. + /// + internal static string Title { + get { + return ResourceManager.GetString("Title", resourceCulture); + } + } + } +} diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.resx b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.resx new file mode 100644 index 0000000..7460970 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/Properties/Resources.resx @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\App.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\openHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\PasteHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\RunHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\StopHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Checksum validator + + \ No newline at end of file diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/App.ico b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/App.ico new file mode 100644 index 0000000..b2ec917 Binary files /dev/null and b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/App.ico differ diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/OpenHS.png b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/OpenHS.png new file mode 100644 index 0000000..0bc670e Binary files /dev/null and b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/OpenHS.png differ diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/PasteHS.png b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/PasteHS.png new file mode 100644 index 0000000..95d9df6 Binary files /dev/null and b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/PasteHS.png differ diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/RunHS.png b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/RunHS.png new file mode 100644 index 0000000..105ac78 Binary files /dev/null and b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/RunHS.png differ diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/StopHS.png b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/StopHS.png new file mode 100644 index 0000000..a75db77 Binary files /dev/null and b/src/Backup/Gardian.Utilities.ChecksumValidator/Resources/StopHS.png differ diff --git a/src/Backup/Gardian.Utilities.ChecksumValidator/TraceUtilities.cs b/src/Backup/Gardian.Utilities.ChecksumValidator/TraceUtilities.cs new file mode 100644 index 0000000..efb7e45 --- /dev/null +++ b/src/Backup/Gardian.Utilities.ChecksumValidator/TraceUtilities.cs @@ -0,0 +1,489 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace Gardian.Utilities.ChecksumValidator +{ + + /// + /// Collection of tracing methods. + /// + public static class TraceUtilities + { + + ///------------------------------------------------ + /// + /// Build string that contains all available information + /// about the specified exception (all nested exceptions, + /// type of exception, mesage, stack). + /// + public static StringBuilder BuildExceptionReport(Exception ex) + { + return BuildExceptionReport(null, null, null, ex, null); + } + + + ///------------------------------------------------ + /// + /// Build string that contains all available information + /// about the specified exception (all nested exceptions, + /// type of exception, mesage, stack). + /// + public static StringBuilder BuildExceptionReport(Exception ex, StringBuilder builder) + { + return BuildExceptionReport(null, null, null, ex, builder); + } + + + ///------------------------------------------------ + /// + /// Build string that contains all available information + /// about the specified exception (all nested exceptions, + /// type of exception, mesage, stack). + /// + public static StringBuilder BuildExceptionReport(string header, string footer, string separator, Exception ex, StringBuilder builder) + { + //validate arguments + if (null == builder) + { + builder = new StringBuilder(512); + } + if (null == header) + { + header = "~~~~~~~~~" + Environment.NewLine + "Exception report"; + } + if (null == footer) + { + footer = "~~~~~~~~~"; + } + if (null == separator) + { + separator = "---------"; + } + + //header + LinePrinter linePrinter = new LinePrinter(' ', 0, builder); + if (header.Length > 0) + { + TraverseStringLines(header, linePrinter.Print); + linePrinter.Print(separator); + } + + //body + TraverseExceptionTree( + ex, + 0, //starting level + true, //first exception in list + delegate(KeyValuePair, string> info) //section header printer + { + //print section header + linePrinter.UpdateIndent(info.Key.Key); + if (info.Key.Value) //first section + { + linePrinter.Print(string.Empty); + linePrinter.Print("List of embedded exceptions:"); + linePrinter.Print(string.Empty); + } + else + { + linePrinter.Print(separator); + } + + //user-friendly message (if present) + if (string.IsNullOrEmpty(info.Value)) + { + linePrinter.Print(""); + } + else + { + linePrinter.PrintPrefix(); + builder.Append("User-friendly message: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(info.Value, linePrinter.Print); + } + }, + delegate(KeyValuePair, Exception> info) //exception detail printer + { + //make sure indent is up-to-date + linePrinter.UpdateIndent(info.Key.Key); + + //separator between exceptions (if needed) + if (info.Key.Value) + { + if (info.Key.Key > 0) + { + linePrinter.UpdateIndent(info.Key.Key - 1); + linePrinter.Print("Exception details:"); + linePrinter.UpdateIndent(info.Key.Key); + } + } + else + { + linePrinter.Print(separator); + } + + //exception details + if (null == info.Value) + { + linePrinter.Print(""); + } + else + { + linePrinter.PrintPrefix(); + builder.Append(info.Value.GetType().FullName); + builder.Append(" - "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(string.IsNullOrEmpty(info.Value.Message) ? "" : info.Value.Message, linePrinter.Print); + + FileNotFoundException tex = info.Value as FileNotFoundException; + if (null != tex) + { + if (!string.IsNullOrEmpty(tex.FileName)) + { + linePrinter.PrintPrefix(); + builder.Append("FileNotFoundException.FileName: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(tex.FileName, linePrinter.Print); + } + if (!string.IsNullOrEmpty(tex.FusionLog)) + { + linePrinter.PrintPrefix(); + builder.Append("FileNotFoundException.FusionLog: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(tex.FusionLog, linePrinter.Print); + } + } + else + { + SqlException sex = info.Value as SqlException; + if (null != sex) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.ErrorCode: "); + builder.Append(sex.ErrorCode); + builder.Append(" (0x"); + builder.Append(sex.ErrorCode.ToString("X8", CultureInfo.InvariantCulture)); + builder.AppendLine(")"); + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors.Count: "); + builder.AppendLine(sex.Errors.Count.ToString(CultureInfo.InvariantCulture)); + builder.AppendLine(); + + int index = 0; + foreach (SqlError sqlError in sex.Errors) + { + string indexStr = (index++).ToString(CultureInfo.InvariantCulture); + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Class: "); + builder.AppendLine(sqlError.Class.ToString(CultureInfo.InvariantCulture)); + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].LineNumber: "); + builder.AppendLine(sqlError.LineNumber.ToString(CultureInfo.InvariantCulture)); + + if (!string.IsNullOrEmpty(sqlError.Message)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Message: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Message, linePrinter.Print); + } + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Number: "); + builder.Append(sqlError.Number.ToString(CultureInfo.InvariantCulture)); + builder.Append(" (0x"); + builder.Append(sqlError.Number.ToString("X8", CultureInfo.InvariantCulture)); + builder.AppendLine(")"); + + if (!string.IsNullOrEmpty(sqlError.Procedure)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Procedure: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Procedure, linePrinter.Print); + } + + if (!string.IsNullOrEmpty(sqlError.Server)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Server: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Server, linePrinter.Print); + } + + if (!string.IsNullOrEmpty(sqlError.Source)) + { + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].Source: "); + linePrinter.StartWithoutPrefix(); + TraverseStringLines(sqlError.Source, linePrinter.Print); + } + + linePrinter.PrintPrefix(); + builder.Append("SqlException.Errors["); + builder.Append(indexStr); + builder.Append("].State: "); + builder.AppendLine(sqlError.State.ToString(CultureInfo.InvariantCulture)); + + builder.AppendLine(); + } + } + else + { + ExternalException eex = info.Value as ExternalException; + if (null != eex) + { + linePrinter.PrintPrefix(); + builder.Append("ExternalException.ErrorCode: "); + builder.Append(eex.ErrorCode); + builder.Append(" (0x"); + builder.Append(eex.ErrorCode.ToString("X8", CultureInfo.InvariantCulture)); + builder.AppendLine(")"); + } + } + } + + TraverseStringLines(string.IsNullOrEmpty(info.Value.StackTrace) ? "" : info.Value.StackTrace, linePrinter.Print); + } + }); + + //footer + if (footer.Length > 0) + { + linePrinter.UpdateIndent(0); + TraverseStringLines(footer, linePrinter.Print); + } + + return builder; + } + + + //------------------------------------------------- + /// + /// Output exception report (from BuildExceptionReport) + /// to .NET's diagnostic trace using the specified category + /// to mark each output line. + /// + public static void TraceExceptionReport(string category, Exception ex) + { + TraceExceptionReport(null, null, null, category, ex); + } + + + //------------------------------------------------- + /// + /// Output exception report (from BuildExceptionReport) + /// to .NET's diagnostic trace using the specified category + /// to mark each output line. + /// + public static void TraceExceptionReport(string header, string footer, string separator, string category, Exception ex) + { + StringBuilder b = BuildExceptionReport(header, footer, separator, ex, null); + TraceMultilineText(b.ToString(), category); + } + + + //------------------------------------------------- + /// + /// + public static void TraceMultilineText(string text, string category) + { + TraverseStringLines(text, delegate(string s) + { + Trace.WriteLine(s, category); + }); + } + + + //------------------------------------------------- + /// + /// Traverse all exceptions that are hanging off the + /// specified root exception, calling the action handler + /// for each exception encountered (including the root + /// exception). Callback receives level + /// + /// + /// + /// + /// + /// + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Method signature was designed so that only standard .NET types are used (helpful when this class is included in PRun project directly for compile)")] + [SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", Justification = "We don't expect levels to rise beyond int boundaries :)")] + public static void TraverseExceptionTree(Exception ex, int level, bool first, System.Action, string>> sectionStartHandler, System.Action, Exception>> exceptionHandler) + { + while (null != ex) + { + if (null != exceptionHandler) { exceptionHandler(new KeyValuePair, Exception>(new KeyValuePair(level, first), ex)); } + if (null != ex.Data) + { + int sectionLevel = level + 1; + int exceptionLevel = level + 2; + bool firstInSection = true; + ReflectionTypeLoadException loadException = ex as ReflectionTypeLoadException; + if (null != loadException) + { + foreach (Exception subex in loadException.LoaderExceptions) + { + if (null != sectionStartHandler) { sectionStartHandler(new KeyValuePair, string>(new KeyValuePair(sectionLevel, firstInSection), null)); } + TraverseExceptionTree(subex, exceptionLevel, true, sectionStartHandler, exceptionHandler); + firstInSection = false; + } + } + foreach (DictionaryEntry dictionaryEntry in ex.Data) + { + IEnumerable subexCollection = dictionaryEntry.Value as IEnumerable; + if (null != subexCollection) + { + foreach (Exception subex in subexCollection) + { + if (null != sectionStartHandler) { sectionStartHandler(new KeyValuePair, string>(new KeyValuePair(sectionLevel, firstInSection), null)); } + TraverseExceptionTree(subex, exceptionLevel, true, sectionStartHandler, exceptionHandler); + firstInSection = false; + } + } + else + { + IEnumerable> subexCollection2 = dictionaryEntry.Value as IEnumerable>; + if (null != subexCollection2) + { + foreach (KeyValuePair pair in subexCollection2) + { + if (null != sectionStartHandler) { sectionStartHandler(new KeyValuePair, string>(new KeyValuePair(sectionLevel, firstInSection), pair.Key)); } + TraverseExceptionTree(pair.Value, exceptionLevel, true, sectionStartHandler, exceptionHandler); + firstInSection = false; + } + } + } + } + } + ex = ex.InnerException; + first = false; + } + } + + + //------------------------------------------------- + /// + /// Invoke the specified delegate for each line that's + /// contained in the provided value. E.g. value + /// "hello(newline)world(newline)" would cause action + /// to be called twice, once with "hello" and once + /// with "world". + /// + public static void TraverseStringLines(string value, System.Action action) + { + if (null != action && null != value) + { + int start = 0; + while (true) + { + int end = value.IndexOf(Environment.NewLine, start, StringComparison.Ordinal); + if (end >= 0) + { + action(value.Substring(start, end - start)); + start = end + Environment.NewLine.Length; + } + else + { + if (0 == start) + { + action(value); + } + else + { + int finalSegmentLength = value.Length - start; + if (finalSegmentLength > 0) + { + action(value.Substring(start, finalSegmentLength)); + } + } + break; + } + } + } + } + + + + + /************************************************** + /* Private + /**************************************************/ + + //------------------------------------------------- + /// + /// + private sealed class LinePrinter + { + public LinePrinter(char prefix, int indent, StringBuilder stringBuilder) + { + this._prefix = prefix; + this._repeatCount = indent; + this._stringBuilder = stringBuilder; + } + + public void Print(string s) + { + if (this._noPrefix) + { + this._noPrefix = false; + } + else + { + this._stringBuilder.Append(this._prefix, this._repeatCount); + } + this._stringBuilder.AppendLine(s); + } + + public void PrintPrefix() + { + if (this._repeatCount > 0) + { + this._stringBuilder.Append(this._prefix, this._repeatCount); + } + } + + public void StartWithoutPrefix() + { + this._noPrefix = true; + } + + public void UpdateIndent(int indent) + { + this._repeatCount = 4 * indent; + } + + private readonly char _prefix; + private int _repeatCount; + private bool _noPrefix; //initialized to false by CLR + private readonly StringBuilder _stringBuilder; + } + + } + +} \ No newline at end of file diff --git a/src/ChecksumValidator.sln b/src/ChecksumValidator.sln index f613ea8..0e19e80 100644 --- a/src/ChecksumValidator.sln +++ b/src/ChecksumValidator.sln @@ -1,6 +1,8 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gardian.Utilities.ChecksumValidator", "Gardian.Utilities.ChecksumValidator\Gardian.Utilities.ChecksumValidator.csproj", "{67AA0267-46DB-4857-BFC1-87C9AB535542}" EndProject Global @@ -17,4 +19,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E2831EED-D6CE-4816-A557-D19454FC5CB4} + EndGlobalSection EndGlobal diff --git a/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj b/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj index 8dbb484..d570d3f 100644 --- a/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj +++ b/src/Gardian.Utilities.ChecksumValidator/Gardian.Utilities.ChecksumValidator.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,24 +10,32 @@ Properties Gardian.Utilities.ChecksumValidator ChecksumValidator - v2.0 + v4.8 512 ..\..\build\$(Configuration)\ ..\..\build\$(Configuration)\$(AssemblyName).xml prompt 4 Resources\App.ico + + + + + 3.5 + true full false DEBUG;TRACE + false pdbonly true TRACE + false @@ -63,6 +71,7 @@ True + diff --git a/src/Gardian.Utilities.ChecksumValidator/MainForm.cs b/src/Gardian.Utilities.ChecksumValidator/MainForm.cs index 45999d7..9fa0663 100644 --- a/src/Gardian.Utilities.ChecksumValidator/MainForm.cs +++ b/src/Gardian.Utilities.ChecksumValidator/MainForm.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Security; using System.Threading; using System.Windows.Forms; @@ -98,7 +99,7 @@ private void OnBrowse(object sender, EventArgs e) { dlg.InitialDirectory = Path.GetDirectoryName(this._file.Text); } - catch (ArgumentException) {} + catch (ArgumentException) { } } if (dlg.ShowDialog(this) == DialogResult.OK) { @@ -152,8 +153,32 @@ private void OnCompute(object sender, EventArgs e) { this._result.Enabled = true; + //Included all possible exceptions catching for FileInfo FileInfo fileInfo = null; - try { fileInfo = new FileInfo(this._file.Text); } catch (ArgumentException) {} + try + { + fileInfo = new FileInfo(this._file.Text); + } + catch (ArgumentNullException) + { + MessageBox.Show("ArgumentNullException Occured: The file name might be null"); + } + catch (SecurityException) + { + MessageBox.Show("SecurityException Occured: The caller does not have the required permission"); + } + catch (ArgumentException) + { + MessageBox.Show("ArgumentException Occured: The file name might be empty, might contains only white spaces, or might contain invalid characters"); + } + catch (UnauthorizedAccessException) + { + MessageBox.Show("UnauthorizedAccessException Occured: The access for the file might be restricted"); + } + catch (NotSupportedException) + { + MessageBox.Show("NotSupportedException Occured: The file name might contain : in the middle of its string"); + } if (fileInfo == null || !fileInfo.Exists) { this._file.Focus(); diff --git a/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs b/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs index 1690113..6a5add4 100644 --- a/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs +++ b/src/Gardian.Utilities.ChecksumValidator/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3074 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -19,7 +19,7 @@ namespace Gardian.Utilities.ChecksumValidator.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -60,6 +60,9 @@ internal Resources() { } } + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// internal static System.Drawing.Icon App { get { object obj = ResourceManager.GetObject("App", resourceCulture); @@ -67,6 +70,9 @@ internal static System.Drawing.Icon App { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Open { get { object obj = ResourceManager.GetObject("Open", resourceCulture); @@ -74,6 +80,9 @@ internal static System.Drawing.Bitmap Open { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Paste { get { object obj = ResourceManager.GetObject("Paste", resourceCulture); @@ -81,6 +90,9 @@ internal static System.Drawing.Bitmap Paste { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Run { get { object obj = ResourceManager.GetObject("Run", resourceCulture); @@ -88,6 +100,9 @@ internal static System.Drawing.Bitmap Run { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap Stop { get { object obj = ResourceManager.GetObject("Stop", resourceCulture); diff --git a/src/Gardian.Utilities.ChecksumValidator/app.config b/src/Gardian.Utilities.ChecksumValidator/app.config new file mode 100644 index 0000000..3e0e37c --- /dev/null +++ b/src/Gardian.Utilities.ChecksumValidator/app.config @@ -0,0 +1,3 @@ + + + diff --git a/src/UpgradeLog.htm b/src/UpgradeLog.htm new file mode 100644 index 0000000..6e9e5e3 Binary files /dev/null and b/src/UpgradeLog.htm differ