using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Resources;
using System.Reflection;
using System.IO;
using System.Net.NetworkInformation;
using System.Net;
using System.Diagnostics;
namespace LookAlive
{
public partial class FrmLookAlive : Form
{
private bool argumentsParsedOk = true;
private bool firstUpdate = true;
private bool notifyOnStateChange = true;
private bool targetAlive = false;
private bool pingCompleted = false;
private string targetAddress = "";
private string targetLabel = "";
private int pingPeriodMs = 1000;
private System.Drawing.SolidBrush colourBrush = null;
private BackgroundWorker worker = null;
private FrmPingResults frmPingResults = null;
private string commandAppFileName = "";
private string commandAppArgs = "";
private bool commandHidden = false;
private string aliveIconPath = "";
private string deadIconPath = "";
private Icon aliveIcon;
private Icon deadIcon;
///
/// Constructor for a new FrmLookAlive.
///
/// An array of arguments passed to the program at startup.
public FrmLookAlive(string[] args)
{
InitializeComponent();
argumentsParsedOk = ParseArgs(args);
if (argumentsParsedOk)
{
if (!LoadIcon(ref aliveIcon, aliveIconPath, "LookAlive.Resources.Alive.ico") ||
!LoadIcon(ref deadIcon, deadIconPath, "LookAlive.Resources.Dead.ico"))
{
argumentsParsedOk = false;
}
}
if (!argumentsParsedOk)
{
ShowAboutBox();
}
monitorIcon.Icon = deadIcon;
targetLabel = lblEnterName.Text;
frmPingResults = new FrmPingResults();
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += MonitorTargetAddress;
worker.ProgressChanged += Monitor_ProgressChanged;
worker.RunWorkerCompleted += Monitor_Completed;
}
private bool LoadIcon(ref Icon icon, string iconFilePath, string iconResourcePath)
{
if (String.IsNullOrEmpty(iconFilePath))
{
using (Stream imageStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(iconResourcePath))
{
icon = new Icon(imageStream);
}
}
else
{
try
{
icon = new Icon(iconFilePath, new Size(16, 16));
}
catch (System.Exception ex)
{
MessageBox.Show(String.Format("Error parsing arguments:\n\nError loading icon from '{0}':\n\n{1}", iconFilePath, ex.Message), "Look Alive", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
if (colourBrush != null)
{
try
{
icon = AddColourId(icon, colourBrush);
}
catch (System.Exception)
{
MessageBox.Show(String.Format("Unable to add colour to icon '{0}'.\n\nPlease ensure this is a 16x16 icon (or contains a 16x16 icon).", iconFilePath), "Look Alive", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
return true;
}
private Icon AddColourId(Icon icon, Brush colour)
{
System.Drawing.Bitmap b = icon.ToBitmap();
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(b);
g.FillRectangle(colour, new System.Drawing.Rectangle(12, 0, 4, 4));
return FlimFlan.IconEncoder.Converter.BitmapToIcon(b);
}
///
/// See help.rtf for argument syntax.
///
///
///
private bool ParseOptionalArg(string arg)
{
if (arg.ToLowerInvariant().StartsWith("/upicon="))
{
aliveIconPath = arg.Substring(8);
return true;
}
if (arg.ToLowerInvariant().StartsWith("/dnicon="))
{
deadIconPath = arg.Substring(8);
return true;
}
if (arg == "/d")
{
SetNofityOnStateChange(false);
return true;
}
if (arg.StartsWith("{"))
{
if (arg.EndsWith("}"))
{
string commandArg = arg.Substring(1, arg.Length - 2);
if (commandArg.StartsWith("!"))
{
commandHidden = true;
commandArg = commandArg.Substring(1);
}
int commandAppFileNameIndex = commandArg.IndexOf(",");
if (commandAppFileNameIndex > 0)
{
commandAppFileName = commandArg.Substring(0, commandAppFileNameIndex);
commandAppArgs = commandArg.Substring(commandAppFileNameIndex + 1);
}
else
{
commandAppFileName = commandArg;
}
return true;
}
else
{
MessageBox.Show("Error parsing arguments:\n\nMissing closing brace for command argument.", "Look Alive", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
int period = 0;
try
{
period = Convert.ToInt32(arg);
}
catch (Exception) { }
if (period >= 1)
{
SetPeriod(period);
return true;
}
Color colour = System.Drawing.Color.FromName(arg);
if (colour.IsKnownColor)
{
SetColourId(colour);
return true;
}
else
{
MessageBox.Show("Error parsing arguments:\n\nUnrecognised colour name '" + arg + "'.", "Look Alive", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
private bool ParseArgs(string[] args)
{
if (args.Length > 0)
{
SetTarget(args[0]);
for (int argNum = 1; argNum < args.Length; argNum++)
{
if (!ParseOptionalArg(args[argNum]))
{
return false;
}
}
}
return true;
}
private void EnableMonitoring(bool enable)
{
monitorIcon.Visible = enable;
btnLookAlive.Enabled = txtTargetName.Enabled = txtPingPeriod.Enabled = enable;
lblEnterName.Text = "Please wait...";
txtTargetName.Text = targetAddress;
txtPingPeriod.Text = Convert.ToString(pingPeriodMs / 1000);
checkNotify.Checked = notifyOnStateChange;
this.Visible = !monitorIcon.Visible;
this.ShowInTaskbar = this.Visible;
this.WindowState = monitorIcon.Visible ? FormWindowState.Minimized : FormWindowState.Normal;
WaitForWorkerToStop();
if (enable)
{
firstUpdate = true;
monitorIcon.Text = String.Format("Look Alive - Monitoring '{0}'", targetAddress);
// First argument is the background worker object itself.
// This allows the calling function to notify the calling
// thread of progress changes etc.
//
// Use the following code in the worker method:
//
// object[] o = (object[])e.Argument;
// BackgroundWorkerEx worker = (BackgroundWorkerEx)o[0];
object[] parms = { worker };
worker.RunWorkerAsync(parms);
}
else
{
lblEnterName.Text = targetLabel;
btnLookAlive.Enabled = txtTargetName.Enabled = txtPingPeriod.Enabled = true;
txtTargetName.Focus();
}
}
private void WaitForWorkerToStop()
{
while (worker.IsBusy)
{
if (!worker.CancellationPending)
{
worker.CancelAsync();
}
Application.DoEvents();
Thread.Sleep(100);
}
}
private void btnLookAlive_Click(object sender, EventArgs e)
{
int period = 0;
try
{
period = Convert.ToInt32(txtPingPeriod.Text);
}
catch (Exception) {}
if (period >= 1)
{
if (txtTargetName.Text.Length > 0)
{
SetPeriod(period);
SetTarget(txtTargetName.Text);
SetNofityOnStateChange(checkNotify.Checked);
EnableMonitoring(true);
}
}
else
{
MessageBox.Show("Ping period must be a number greater than 0.", "Look Alive", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void SetNofityOnStateChange(bool notify)
{
notifyOnStateChange = notify;
}
private void SetTarget(string target)
{
targetAddress = target;
}
private void SetPeriod(int periodSec)
{
pingPeriodMs = periodSec * 1000;
}
private void SetColourId(Color colour)
{
colourBrush = new System.Drawing.SolidBrush(colour);
}
private void MonitorTargetAddress(object sender, DoWorkEventArgs e)
{
// first argument is the background worker object itself
object[] o = (object[])e.Argument;
BackgroundWorker worker = (BackgroundWorker)o[0];
Ping ping = new Ping();
ping.PingCompleted += new PingCompletedEventHandler(ping_PingCompleted);
while (!worker.CancellationPending)
{
pingCompleted = false;
try
{
ping.SendAsync(targetAddress, worker);
}
catch (Exception ex)
{
if (ex.InnerException != null)
{
worker.ReportProgress(0, new PingResult(ex.InnerException.Message));
}
else
{
worker.ReportProgress(0, new PingResult(ex.Message));
}
}
bool pingCancelled = false;
while (!pingCompleted)
{
if (worker.CancellationPending && !pingCancelled)
{
ping.SendAsyncCancel();
pingCancelled = true;
}
Thread.Sleep(100);
}
for (int slice = 0; slice < pingPeriodMs / 100; slice++)
{
if (worker.CancellationPending)
{
break;
}
Thread.Sleep(100);
}
}
}
void ping_PingCompleted(object sender, PingCompletedEventArgs e)
{
if (!e.Cancelled)
{
BackgroundWorker worker = (BackgroundWorker)e.UserState;
if (e.Error != null)
{
if (e.Error.InnerException != null)
{
worker.ReportProgress(0, new PingResult(e.Error.InnerException.Message));
}
else
{
worker.ReportProgress(0, new PingResult(e.Error.Message));
}
}
else
{
worker.ReportProgress(0, new PingResult((e.Reply.Status == IPStatus.Success), (int)e.Reply.RoundtripTime));
}
}
pingCompleted = true;
}
private void Monitor_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
PingResult result = (PingResult)e.UserState;
if (String.IsNullOrEmpty(result.PingError))
{
if (result.IsAlive)
{
frmPingResults.AddText(String.Format("[{0}] Replied in {1} ms.", targetAddress, result.ResponseTimeMs));
}
else
{
frmPingResults.AddText(String.Format("[{0}] Request timed out.", targetAddress));
}
}
else
{
frmPingResults.AddText(String.Format("[{0}] Error: {1}", targetAddress, result.PingError));
}
RunStateChangeCommand(result.IsAlive);
UpdateMonitorIcon(result.IsAlive);
}
private void RunStateChangeCommand(bool targetNowAlive)
{
if (commandAppFileName.Length > 0)
{
if (this.targetAlive != targetNowAlive || firstUpdate)
{
ProcessStartInfo psi;
string fileName = SubstituteFields(commandAppFileName, targetNowAlive);
if (commandAppArgs.Length > 0)
{
string arguments = SubstituteFields(commandAppArgs, targetNowAlive);
psi = new ProcessStartInfo(fileName, arguments);
}
else
{
psi = new ProcessStartInfo(fileName);
}
if (commandHidden)
{
psi.CreateNoWindow = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
}
Process.Start(psi);
}
}
}
private string SubstituteFields(string sourceString, bool targetNowAlive)
{
return sourceString.Replace("{hostname_ip}", targetAddress)
.Replace("{state}", targetNowAlive ? "online" : "offline")
.Replace("{time}", DateTime.Now.ToString());
}
private void Monitor_Completed(object sender, RunWorkerCompletedEventArgs e)
{
// nothing to do here
}
private void UpdateMonitorIcon(bool targetNowAlive)
{
if (this.targetAlive != targetNowAlive || firstUpdate)
{
monitorIcon.Icon = targetNowAlive ? aliveIcon : deadIcon;
if (!firstUpdate && notifyOnStateChange)
{
monitorIcon.ShowBalloonTip(10000, "Look Alive", String.Format("Host '{0}' is {1}.", this.targetAddress, targetNowAlive ? "online" : "offline"), ToolTipIcon.Info);
}
this.targetAlive = targetNowAlive;
firstUpdate = false;
}
}
private void FrmLookAlive_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
btnLookAlive.PerformClick();
}
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
monitorIcon.Visible = false;
frmPingResults.Exit();
WaitForWorkerToStop();
this.Close();
}
private void txtTargetName_TextChanged(object sender, EventArgs e)
{
btnLookAlive.Enabled = (txtTargetName.Text.Length > 0);
}
private void FrmLookAlive_Load(object sender, EventArgs e)
{
if (argumentsParsedOk && targetAddress.Length > 0)
{
EnableMonitoring(true);
}
Program.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
private void changeTargetToolStripMenuItem_Click(object sender, EventArgs e)
{
EnableMonitoring(false);
}
private void responseTimeToolStripMenuItem_Click(object sender, EventArgs e)
{
frmPingResults.Show();
frmPingResults.Activate();
}
private void monitorIcon_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
responseTimeToolStripMenuItem.PerformClick();
}
}
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
ShowAboutBox();
}
private void ShowAboutBox()
{
using (FrmAbout frmAbout = new FrmAbout())
{
frmAbout.ShowDialog();
}
}
private void FrmLookAlive_FormClosing(object sender, FormClosingEventArgs e)
{
if (worker.IsBusy)
{
monitorIcon.Visible = false;
worker.CancelAsync();
}
}
private void btnHelp_Click(object sender, EventArgs e)
{
ShowAboutBox();
}
}
}