jMonitor : a program to monitor remote computers

Download jmonitor.zip

Synopsis:

jMonitor/AddDialog.cs
jMonitor/ComputerInfo.cs
jMonitor/EditDialog.cs
jMonitor/Form1.cs
jMonitor/IRefreshable.cs
jMonitor/IStateChecker.cs
jMonitor/ITraceable.cs
jMonitor/Program.cs
jMonitor/WorkerThread.cs
jMonitorService/Program.cs
jMonitorService/Service1.cs
ProcessCheck/ProcessCheck.cs


jMonitor/AddDialog.cs

Synopsis
using System;
using System.Windows.Forms;

namespace jMonitor
  {
  public partial class AddDialog : Form
    {
    /// <summary>
    /// Add a new Computer to monitor
    /// </summary>
    public AddDialog()
      {
      InitializeComponent();
      }
    /// <summary>
    /// get the newly added info and return it as a ComputerInfo
    /// </summary>
    /// <returns>ComputerInfo object</returns>
    public ComputerInfo GetInfo()
      {
      ComputerInfo ci = new ComputerInfo(null, null, null, this.textBoxName.Text);
      //set the computer name. must be before other lines so the xml entity is created
      ci.ComputerName = this.textBoxName.Text;
      ci.Port = Int32.Parse(this.textBoxPort.Text);
      return ci;
      }

    /// <summary>
    /// default the Port to 5000
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void AddDialog_Load(object sender, EventArgs e)
      {
      this.textBoxPort.Text = ComputerInfo.DefaultPort.ToString();
      }
    private void btnOk_Click(object sender, EventArgs e)
      {
      this.DialogResult = DialogResult.OK;
      }
    private void btnCancel_Click(object sender, EventArgs e)
      {
      this.DialogResult = DialogResult.Cancel;
      }
    }
  }

jMonitor/ComputerInfo.cs

Synopsis
using System;
using System.Collections;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Xml;
using System.IO;
using System.Data;
using System.Reflection;

namespace jMonitor
  {
  /// keeps all the Computer information together
  /// runs the query and sets the result Control
  public class ComputerInfo : CheckBox, IStateChecker, IEnumerable
    {
    public const int DefaultPort = 5000;
    public const int DefaultRetryTimeout = 200;
    public const int DefaultNumRetries = 3;

    private static string mXmlPath;
    private static System.Xml.XmlDataDocument mXml = null;
    private string mComputerName;

    private WorkerThread mWorkerThread;
    private ITraceable mTracer;
    private IRefreshable mRefresher;

    private string mReason;
    private Control mControl;
    private int mRow;

    public static string GetXmlPath()
      {
      if (mXmlPath == null)
        {
        mXmlPath = Directory.GetCurrentDirectory() + @"\jMonitor.xml";
        }
      return mXmlPath;
      }
    
    public static ArrayList GetComputers()
      {
      ArrayList computers = new ArrayList();
      System.Xml.XmlDataDocument doc = new System.Xml.XmlDataDocument();
      doc.Load(GetXmlPath());
      XmlNodeList nodes = doc.SelectNodes("/ComputerList/Computer");
      foreach (XmlNode node in nodes)
        {
        XmlNode n = node.Attributes.GetNamedItem("name");
        string name = n.Value;
        //Console.WriteLine("x=name='" + name + "'");
        computers.Add(new ComputerInfo(null, null, null, name));
        }
      return computers;
      }

    public ComputerInfo(ITraceable t, IRefreshable i, Control c, string n)
      {
      if (mXml == null)
        {
        mXml = new System.Xml.XmlDataDocument();
        mXml.Load(GetXmlPath());
        }

      mComputerName = n;

      mTracer = t;
      mRefresher = i;
      mControl = c;
      mReason = "";
      mRow = -1;
      }

    public void SetUI(ITraceable t, IRefreshable i, Control c)
      {
      mTracer = t;
      mRefresher = i;
      mControl = c;
      mControl.Text = "unknown";
      mWorkerThread = new WorkerThread(t, this, this);
      }

    private int mFailureCount = 0;
    private int mSuccessCount = 0;
    public void Reset()
      {
      mFailureCount = 0;
      mSuccessCount = 0;
      mControl.BackColor = Color.Transparent;
      mReason = "";
      }
    public void ConnectionFailed(string reason)
      {
      mControl.BackColor = Color.Red;
      mReason = mReason + ((mReason == "") ? "" : "\n") + reason;
      }
    public void ConnectionSucceeded()
      {
      mControl.BackColor = Color.Blue;
      mReason = mReason + ((mReason == "") ? "" : "\n") + "Connection OK";
      }
    public void RequestFailed(string reason)
      {
      mFailureCount++;
      if (mSuccessCount == 0)
        {
        mControl.BackColor = Color.Orange;
        }
      else
        {
        mControl.BackColor = Color.Yellow;
        }
      mReason = mReason + ((mReason == "") ? "" : "\n") + reason + "\n";
      mReason += "Succeeded: " + mSuccessCount.ToString() + " Failed: " + mFailureCount.ToString();
      }

    public void RequestSucceeded()
      {
      mSuccessCount++;
      if (mFailureCount == 0)
        {
        mControl.BackColor = Color.Green;
        }
      else
        {
        mControl.BackColor = Color.Yellow;
        }
      mReason = "Succeeded: " + mSuccessCount.ToString() + " Failed: " + mFailureCount.ToString();
      }

    public void CheckResponse(string computer, string component, string parameter, string response)
      {
      bool gotit = RunAssembly(component, computer, parameter, response);
      if (gotit)
        {
        RequestSucceeded();
        }
      else
        {
        RequestFailed("CheckResponse failed");
        }
      }

    //---------------------------
    bool RunAssembly(string name, string computer, string parameter, string response)
      {
      string cwd = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
      string path = cwd + "\\" + name + ".dll";
      string title_class = name + "." + name;
      string title_method = "CheckResponse";

      Assembly u = Assembly.LoadFrom(path);
      if (u == null)
        {
        throw new Exception("LoadAssemblyIntoDomain: LoadAssembly failed, returned null");
        }

      Type t = u.GetType(title_class);
      if (t == null)
        {
        throw new Exception("LoadAssemblyIntoDomain: GetType failed, returned null");
        }

      MethodInfo m = t.GetMethod(title_method);
      if (m == null)
        {
        throw new Exception("LoadAssemblyIntoDomain: GetMethod failed, returned null");
        }

      object[] myparam = new object[3];
      myparam[0] = computer;
      myparam[1] = parameter;
      myparam[2] = response;
      return (bool)m.Invoke(null, myparam);
      }

    public void RefreshControls()
      {
      mRefresher.RefreshControls(this);
      }

    public void Run()
      {
      mWorkerThread.Run();
      }
    public void WaitFor()
      {
      mWorkerThread.WaitFor();
      }
    public int Row
      {
      get { return mRow; }
      set { mRow = value; }
      }
    //public override string ToString()
    //  {
    //  return mData.ToString();
    //  }
    public string Reason
      {
      get { return mReason; }
      }

    public static void Save()
      {
      mXml.Save(GetXmlPath());
      }

    public void DeleteComputer()
      {
      XmlNode pnode = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
      if (pnode == null)
          return;
      XmlNode computers = mXml.SelectSingleNode("/ComputerList");
      computers.RemoveChild(pnode);
      }

    public string ComputerName
      {
      get { return mComputerName; }
      set
        {
        //convert to lowercase and find the current element...
        XmlElement computer = (XmlElement)mXml.SelectSingleNode("/ComputerList/Computer[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" + mComputerName.ToLower() + "']");
        //before setting to the new name
        mComputerName = value;
        if (computer == null)
          {
          //not there, so add it
          computer = mXml.CreateElement("Computer");
          computer.SetAttribute("name", mComputerName);
          XmlNode computers = mXml.SelectSingleNode("/ComputerList");
          //todo: check if null
          computers.AppendChild(computer);
          }
        }
      }
    public string IPAddress
      {
      get
        {
        XmlNode ipnode = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/IPAddress");
        if (ipnode == null)
          return "";
        return ipnode.InnerText;
        }
      set
        {
        XmlNode ipnode = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/IPAddress");
        if (ipnode == null)
          {
          XmlElement ipelem = mXml.CreateElement("IPAddress");
          ipelem.InnerText = value;
          XmlElement computer = (XmlElement)mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
          computer.AppendChild(ipelem);
          }
        else
          {
          ipnode.InnerText = value;
          }
        }
      }
    public Boolean UseIPAddress
      {
      get
        {
        XmlNode useipnode = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/UseIPAddress");
        if (useipnode == null)
          return false;
        return (useipnode.InnerText == "True");
        }
      set
        {
        XmlNode useipnode = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/UseIPAddress");
        if (useipnode == null)
          {
          XmlElement useipelem = mXml.CreateElement("UseIPAddress");
          useipelem.InnerText = value.ToString();
          XmlElement computer = (XmlElement)mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
          computer.AppendChild(useipelem);
          }
        else
          {
          useipnode.InnerText = value.ToString();
          }

        }
      }
    public int Port
      {
      get
        {
        XmlNode pnode = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/Port");
        if (pnode == null)
          return ComputerInfo.DefaultPort;
        return Int32.Parse(pnode.InnerText);
        }
      set
        {
        XmlNode pnode = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/Port");
        if (pnode == null)
          {
          XmlElement portelem = mXml.CreateElement("Port");
          portelem.InnerText = value.ToString();
          XmlElement computer = (XmlElement)mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
          computer.AppendChild(portelem);
          }
        else
          {
          pnode.InnerText = value.ToString();
          }
        }
      }

    public class ActionEnum : IEnumerator
      {
      DataTable table;
      IEnumerator rows;

      public ActionEnum(ComputerInfo ci)
        {
        DataSet ds = ci.ActionList;
        table = ds.Tables["Action"];
        rows = table.Rows.GetEnumerator();
        }

      public bool MoveNext()
        {
        return rows.MoveNext();
        }

      public void Reset()
        {
        rows.Reset();
        }

      public object Current
        {
        get
          {
          DataRow row = (DataRow)rows.Current;
          string c = (string)row[table.Columns["Component"]];
          string p = (string)row[table.Columns["Parameter"]];
          return c + ":" + p;
          }
        }
      }

    IEnumerator IEnumerable.GetEnumerator()
      {
      return new ActionEnum(this);
      }

    public DataSet ActionList
      {
      get
        {
        XmlNode node = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/ActionList");
        DataSet ds = new DataSet();
        if (node == null)
          {
          ds.ReadXml(new StringReader("<ActionList><Action><Component/><Parameter/></Action></ActionList>"));
          }
        else
          {
          ds.ReadXml(new StringReader(node.OuterXml));
          }
        return ds;
        }

      set
        {
        XmlNode node = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
        if (node == null)
          {
          node = mXml.CreateElement("ActionList");
          XmlElement computer = (XmlElement)mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
          computer.AppendChild(node);
          }
        node.InnerXml = value.GetXml();
        }
      }
    public int RetryTimeout
      {
      get
        {
        XmlNode node = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/RetryTimeout");
        if (node == null)
          return ComputerInfo.DefaultRetryTimeout;
        return Int32.Parse(node.InnerText);
        }
      set
        {
        XmlNode node = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/RetryTimeout");
        if (node == null)
          {
          XmlElement elem = mXml.CreateElement("RetryTimeout");
          elem.InnerText = value.ToString();
          XmlElement computer = (XmlElement)mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
          computer.AppendChild(elem);
          }
        else
          {
          node.InnerText = value.ToString();
          }
        }
      }
    public int NumRetries
      {
      get
        {
        XmlNode node = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/NumRetries");
        if (node == null)
          return ComputerInfo.DefaultNumRetries;
        return Int32.Parse(node.InnerText);
        }
      set
        {
        XmlNode node = mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']/NumRetries");
        if (node == null)
          {
          XmlElement elem = mXml.CreateElement("NumRetries");
          elem.InnerText = value.ToString();
          XmlElement computer = (XmlElement)mXml.SelectSingleNode("/ComputerList/Computer[@name='" + mComputerName + "']");
          computer.AppendChild(elem);
          }
        else
          {
          node.InnerText = value.ToString();
          }
        }
      }
    }
  }

jMonitor/EditDialog.cs

Synopsis
using System;
using System.Data;
using System.Windows.Forms;

namespace jMonitor
  {
  public partial class EditDialog : Form
    {
    private ComputerInfo mComputerInfo;

    /// <summary>
    /// Edit an existing computer to monitor
    /// </summary>
    /// <param name="ci">the computer to monitor</param>
    public EditDialog(ref ComputerInfo ci)
      {
      InitializeComponent();

      mComputerInfo = ci;
      textBoxName.Text = mComputerInfo.ComputerName;
      checkBoxUseIPAddress.Checked = mComputerInfo.UseIPAddress;
      textBoxAddress.Text = mComputerInfo.IPAddress;
      textBoxPort.Text = mComputerInfo.Port.ToString();
      dataGridView1.DataSource = mComputerInfo.ActionList;
      dataGridView1.DataMember = "Action";
      textBoxRetryTimeout.Text = mComputerInfo.RetryTimeout.ToString();
      textBoxNumRetries.Text = mComputerInfo.NumRetries.ToString();
      }
    private void btnCancel_Click(object sender, EventArgs e)
      {
      this.DialogResult = DialogResult.Cancel;
      }
    /// <summary>
    /// add the dialog's values to computer
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnAccept_Click(object sender, EventArgs e)
      {
      this.DialogResult = DialogResult.OK;

      mComputerInfo.ComputerName = this.textBoxName.Text;

      //actionlist/watch parameters
      mComputerInfo.ActionList = (DataSet)dataGridView1.DataSource;
      mComputerInfo.Port = Int32.Parse(this.textBoxPort.Text);
      mComputerInfo.UseIPAddress = this.checkBoxUseIPAddress.Checked;
      mComputerInfo.IPAddress = this.textBoxAddress.Text;
      mComputerInfo.RetryTimeout = Int32.Parse(textBoxRetryTimeout.Text);
      mComputerInfo.NumRetries = Int32.Parse(textBoxNumRetries.Text);

      //finally... save to the config file.
      ComputerInfo.Save();
      }
    }
  }

jMonitor/Form1.cs

Synopsis
using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;

namespace jMonitor
  {
  public partial class Form1 : Form, ITraceable, IRefreshable
    {
    /// <summary>
    /// indicate whether or not we are currently checking the computers
    /// </summary>
    private bool mBusy;

    private ToolTip toolTip1 = new ToolTip();

    /// <summary>
    /// The main panel for monitoring computers
    /// </summary>
    public Form1()
      {
      InitializeComponent();
      mBusy = false;
      LoadComputers();

      // Set up the delays for the ToolTip.
      toolTip1.AutoPopDelay = 3000;
      toolTip1.InitialDelay = 500;
      toolTip1.ReshowDelay = 500;
      // Force the ToolTip text to be displayed whether or not the form is active.
      toolTip1.ShowAlways = true;
      }

    void c_CheckedChanged(object sender, EventArgs e)
      {
      CheckBox c = (CheckBox)sender;
      if (c.Checked)
        {
        c.BackColor = Color.Turquoise;
        }
      else
        {
        c.BackColor = Color.Transparent;
        }
      }

    /// <summary>
    /// get the list of computers from the registry
    /// </summary>
    private void LoadComputers()
      {
      tblComputerInfo.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
      tblComputerInfo.AutoSize = true;
      tblComputerInfo.GrowStyle = TableLayoutPanelGrowStyle.AddRows;

      tblComputerInfo.RowCount = 0;
      tblComputerInfo.ColumnCount = 0;

      foreach (ComputerInfo ci in ComputerInfo.GetComputers())
        {
        tblComputerInfo.RowCount = tblComputerInfo.RowCount + 1;
        CreateComputer(tblComputerInfo.RowCount, ci);
        }
      }


    private void CreateComputer(int row, ComputerInfo ci)
      {
      Label statelabel = new Label();
      statelabel.TextAlign = ContentAlignment.MiddleCenter;

      ci.SetUI(this, this, statelabel);
      ci.Row = row;

      int col = 0;
      CheckBox c = new CheckBox();
      c.CheckAlign = ContentAlignment.MiddleCenter;
      c.CheckedChanged += new EventHandler(c_CheckedChanged);
      tblComputerInfo.Controls.Add(ci, col, row);
      col++;

      statelabel.Text = ci.ComputerName;
      statelabel.TextAlign = ContentAlignment.MiddleCenter;
      tblComputerInfo.Controls.Add(statelabel, col, row);
      col++;

      Label x;

      x = new Label();
      x.Text = ci.IPAddress;
      x.TextAlign = ContentAlignment.MiddleCenter;
      x.AutoSize = true;
      tblComputerInfo.Controls.Add(x, col, row);
      col++;

      if (tblComputerInfo.ColumnCount == 0)
        tblComputerInfo.ColumnCount = col;
      }

    delegate void SetTextCallback(string format, params object[] arg);

    /// <summary>
    /// add a line to the console output
    /// </summary>
    /// <param name="format"></param>
    /// <param name="arg"></param>
    public void AddLine(string format, params object[] arg)
      {
      // InvokeRequired required compares the thread ID of the
      // calling thread to the thread ID of the creating thread.
      // If these threads are different, it returns true.
      if (this.listboxConsole.InvokeRequired)
        {
        SetTextCallback d = new SetTextCallback(AddLine);
        this.Invoke(d, new object[] { format, arg });
        }
      else
        {
        string msg = String.Format(format, arg);

        for (; ; )
          {
          if (msg == "\n" || msg == "")
            break;
          int i = msg.IndexOf('\n');
          if (i == -1)
            {
            listboxConsole.Items.Add(msg);
            break;
            }
          else
            {
            string msg1 = msg.Substring(0, i);
            listboxConsole.Items.Add(msg1);
            msg = msg.Substring(i + 1);
            }
          }

        while (listboxConsole.Items.Count > 1000)
          {
          listboxConsole.Items.RemoveAt(0);
          }

        ScrollTextBoxEnd(listboxConsole);
        }
      }

    /// <summary>
    /// check all computers in the list
    /// </summary>
    /// <param name="parm"></param>
    private void Check(object parm)
      {
      mBusy = true;
      this.UseWaitCursor = true;

      foreach (ComputerInfo ci in (ArrayList)parm)
        {
        AddLine("Checking - running: " + ci.ComputerName);
        ci.Run();
        }

      foreach (ComputerInfo ci in (ArrayList)parm)
        {
        ci.WaitFor();
        }
      mBusy = false;
      this.UseWaitCursor = false;
      }

    delegate void UpdateLabels(ComputerInfo ci);


    public void RefreshControls(ComputerInfo ci)
      {
      // InvokeRequired required compares the thread ID of the
      // calling thread to the thread ID of the creating thread.
      // If these threads are different, it returns true.
      if (this.tblComputerInfo.InvokeRequired)
        {
        UpdateLabels d = new UpdateLabels(RefreshControls);
        this.Invoke(d, ci);
        }
      else
        {
        int row = ci.Row - 1;
        ((Label)tblComputerInfo.Controls[(row * tblComputerInfo.ColumnCount) + 1]).Text = ci.ComputerName;
        ((Label)tblComputerInfo.Controls[(row * tblComputerInfo.ColumnCount) + 2]).Text = ci.IPAddress;

        // Set up the ToolTip text for the Button and Checkbox.
        toolTip1.SetToolTip(tblComputerInfo.Controls[(row * tblComputerInfo.ColumnCount) + 1], ci.Reason);
        }
      }

    /// <summary>
    /// spin off a thread to monitor all checked computers
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnCheck_Click(object sender, EventArgs e)
      {
      Thread t = new Thread(new ParameterizedThreadStart(Check));

      ArrayList cilist = new ArrayList();

      int itemcount = tblComputerInfo.Controls.Count / tblComputerInfo.ColumnCount;
      bool doall = true;
      for (int i = 0; i < itemcount; ++i)
        {
        if (((CheckBox)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount]).Checked)
          {
          doall = false;
          }
        }

      for (int i = 0; i < itemcount; ++i)
        {
        if (doall || ((CheckBox)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount]).Checked)
          {
          cilist.Add((ComputerInfo)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount]);
          }
        }

      t.Start(cilist);
      }

    /// <summary>
    /// if we are in the middle of monitoring, disallow the close
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Form1_FormClosing(object sender, System.ComponentModel.CancelEventArgs e)
      {
      if (mBusy)
        {
        e.Cancel = true;
        }
      else
        {
        ComputerInfo.Save();
        }
      }


    #region Native

    /// <summary>
    /// Scrolls the textbox to the end
    /// </summary>
    /// <param name="tb"></param>
    private void ScrollTextBoxEnd(ListBox tb)
      {
      const int WM_VSCROLL = 277;
      const int SB_BOTTOM = 7;

      IntPtr ptrWparam = new IntPtr(SB_BOTTOM);
      IntPtr ptrLparam = new IntPtr(0);
      SendMessage(tb.Handle, WM_VSCROLL, ptrWparam, ptrLparam);
      }


    [DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    #endregion //Private

    /// <summary>
    /// add a new computer
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnAdd_Click(object sender, EventArgs e)
      {
      AddDialog dlg = new AddDialog();
      if (dlg.ShowDialog() == DialogResult.OK)
        {
        tblComputerInfo.RowCount = tblComputerInfo.RowCount + 1;
        CreateComputer(tblComputerInfo.RowCount, dlg.GetInfo());
        }
      }

    /// <summary>
    /// edit one or more computers
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnEdit_Click(object sender, EventArgs e)
      {
      int itemcount = tblComputerInfo.Controls.Count / tblComputerInfo.ColumnCount;
      for (int i = 0; i < itemcount; ++i)
        {
        if (((CheckBox)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount]).Checked)
          {
          ComputerInfo ci = (ComputerInfo)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount];
          EditDialog dlg = new EditDialog(ref ci);
          if (dlg.ShowDialog() == DialogResult.OK)
            {
            //todo: use ComputerInfo copy assignment or something better than this!!
            ((ComputerInfo)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount]).ComputerName = ci.ComputerName;
            ((ComputerInfo)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount]).Port = ci.Port;

            //todo: remove dependency on column order (i.e. + 1, + 2)
            ((Label)tblComputerInfo.Controls[(i * tblComputerInfo.ColumnCount) + 1]).Text = ci.ComputerName;
            }
          }
        }
      }

    /// <summary>
    /// delete a computer from the list
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnDelete_Click(object sender, EventArgs e)
      {
      if (MessageBox.Show("Are you sure you want to delete?", "Confirm Deletion", MessageBoxButtons.YesNo) == DialogResult.No)
        return;

      int itemcount = tblComputerInfo.Controls.Count / tblComputerInfo.ColumnCount;
      //iterate backwards to preserve the indexes into the column widgets
      for (int i = itemcount - 1; i >= 0; --i)
        {
        if (((CheckBox)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount]).Checked)
          {
          //remove the computer in the xml config file
          ComputerInfo ci = (ComputerInfo)tblComputerInfo.Controls[i * tblComputerInfo.ColumnCount];
          ci.DeleteComputer();

          //remove the row on the screen, by removing the controls in the columns
          for (int j = 0; j < tblComputerInfo.ColumnCount; ++j)
            {
            tblComputerInfo.Controls.RemoveAt(i * tblComputerInfo.ColumnCount);
            }
          }
        }
      }
    }
  }

jMonitor/IRefreshable.cs

Synopsis
namespace jMonitor
{
   public interface IRefreshable
   {
      void RefreshControls(ComputerInfo ci);
   }
}

jMonitor/IStateChecker.cs

Synopsis
namespace jMonitor
  {
  public interface IStateChecker
    {
    void Reset();
    void ConnectionFailed(string reason);
    void ConnectionSucceeded();
    void RequestFailed(string reason);
    void RequestSucceeded();
    void CheckResponse(string computer, string component, string parameter, string response);
    }
  }

jMonitor/ITraceable.cs

Synopsis
namespace jMonitor
{
   public interface ITraceable
   {
      void AddLine(string format, params object[] arg);
   }
}

jMonitor/Program.cs

Synopsis
using System;
using System.Windows.Forms;

namespace jMonitor
{
   static class Program
   {
      /// <summary>
      /// The main entry point for the application.
      /// </summary>

      [STAThread]
      static void Main()
      {
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);
         Form1 form = new Form1();
         Application.Run(form);
      }
   }
}

jMonitor/WorkerThread.cs

Synopsis
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace jMonitor
  {
  class WorkerThread
    {
    private Thread mThread;
    private ITraceable mTracer;
    private IStateChecker mStateChecker;
    private ComputerInfo mInfo;

    public WorkerThread(ITraceable t, IStateChecker sc, ComputerInfo ci)
      {
      mTracer = t;
      mInfo = ci;
      mStateChecker = sc;
      }

    public void Run()
      {
      mThread = new Thread(new ThreadStart(ThreadProc));

      mThread.Start();
      Thread.Sleep(0);
      }

    public void WaitFor()
      {
      mTracer.AddLine("[{0}] Run: Waiting until ThreadProc ends.", mInfo.ComputerName);
      mThread.Join();
      mTracer.AddLine("[{0}] Run: ThreadProc has ended.", mInfo.ComputerName);
      }

    private System.Net.IPAddress[] GetAddressList()
      {
      System.Net.IPAddress[] addresslist;

      if (mInfo.UseIPAddress)
        {
        addresslist = new System.Net.IPAddress[1];
        addresslist[0] = System.Net.IPAddress.Parse(mInfo.IPAddress);
        }
      else if (mInfo.ComputerName.ToUpperInvariant().Equals(SystemInformation.ComputerName.ToUpperInvariant()))
        {
        mTracer.AddLine("[{0}] INFO: Current computer {1}", mInfo.ComputerName, mInfo.ComputerName);
        mInfo.ComputerName = SystemInformation.ComputerName;
        addresslist = new System.Net.IPAddress[1];
        addresslist[0] = System.Net.IPAddress.Loopback;
        }
      else
        {
        //try and get the IP address of the remote computer
        try
          {
          System.Net.IPHostEntry host;
          host = System.Net.Dns.GetHostEntry(mInfo.ComputerName);
          addresslist = host.AddressList;
          }
        catch (System.Net.Sockets.SocketException /*ignore*/)
          {
          mTracer.AddLine("[{0}] ERROR: Could not find IP address for {1}", mInfo.ComputerName, mInfo.ComputerName);
          mTracer.AddLine("[{0}]      : check the name", mInfo.ComputerName);
          mTracer.AddLine("[{0}]      : or use the IP address", mInfo.ComputerName);
          mStateChecker.ConnectionFailed("Could find IP address of remote computer");
          mInfo.RefreshControls();
          addresslist = null;
          }
        }
      return addresslist;
      }

    private void AdjustComputerInfo(System.Net.IPAddress addr)
      {
      System.Net.IPHostEntry ipHostEntry = System.Net.Dns.GetHostEntry(addr.ToString());
      mTracer.AddLine("[{0}] INFO: remote {1} is IP address: {2}",
         mInfo.ComputerName, mInfo.ComputerName, addr.ToString());
      mTracer.AddLine("[{0}] INFO: remote {1} is Host      : {2}",
         mInfo.ComputerName, mInfo.ComputerName, ipHostEntry.HostName);

      //if the computername was entered as an ip address, then convert to a name
      if (mInfo.ComputerName.Equals(addr.ToString()))
        {
        mInfo.ComputerName = ipHostEntry.HostName;
        }

      //if it's just a difference in case, use the correct case
      if (mInfo.ComputerName.ToUpperInvariant().Equals(ipHostEntry.HostName.ToUpperInvariant()))
        {
        mInfo.ComputerName = ipHostEntry.HostName;
        }

      foreach (string alias in ipHostEntry.Aliases)
        {
        mTracer.AddLine("[{0}] INFO: remote {1} is Alias    : {2}",
           mInfo.ComputerName, mInfo.ComputerName, alias);
        }

      mInfo.IPAddress = addr.ToString();
      }

    private class ClientSocket
      {
      Socket mClient;
      System.Net.EndPoint mEndPoint;

      public ClientSocket(System.Net.IPAddress addr, int port)
        {
        mEndPoint = new System.Net.IPEndPoint(new System.Net.IPAddress(addr.GetAddressBytes()), port);
        mClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        mClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100);
        }
      public int Send(byte[] buf)
        {
        return mClient.SendTo(buf, buf.Length, SocketFlags.None, mEndPoint);
        }

      public int WaitForReply(int timeout, int maxtries)
        {
        int bytesready = 0;
        for (int j = 0; j < maxtries; ++j)
          {
          //if there is, go get em
          bytesready = mClient.Available;
          if (bytesready > 0)
            break;

          //sleep a while and try again
          Thread.Sleep(timeout);

          //use exponential backoff
          timeout = 2 * timeout;
          }
        return bytesready;
        }

      public int Receive(byte[] buf)
        {
        return mClient.ReceiveFrom(buf, buf.Length, SocketFlags.None, ref mEndPoint);
        }
      }

    private int SendWithRetry(ClientSocket client, byte[] buf)
      {
      int bytesready = 0;
      for (int retries = 0; retries < 3; ++retries)
        {
        mTracer.AddLine("[{0}] INFO: Trying to send (try {1})...", mInfo.ComputerName, retries + 1);
        int bytessent = client.Send(buf);
        if (bytessent != buf.Length)
          {
          mTracer.AddLine("[{0}] WARN: Send failed, trying again...", mInfo.ComputerName);
          mStateChecker.ConnectionFailed("Send failed"); //todo: why did it fail?
          continue;
          }

        //check if there is a reply. If not, try again.
        bytesready = client.WaitForReply(mInfo.RetryTimeout, mInfo.NumRetries);
        if (bytesready == 0)
          {
          mTracer.AddLine("[{0}] WARN: Message sent, but didn't get a reply...", mInfo.ComputerName);
          mStateChecker.ConnectionFailed("Send succeeded, but no reply"); //todo: why did it fail?
          continue;
          }

        break;
        }

      return bytesready;
      }


    public void ThreadProc()
      {
      mStateChecker.Reset();

      System.Net.IPAddress[] addresslist = GetAddressList();
      if (addresslist == null)
        return;

      foreach (System.Net.IPAddress addr in addresslist)
        {
        AdjustComputerInfo(addr);
        mInfo.RefreshControls();

        //set up the socket and endpoint needed to send
        ClientSocket client = new ClientSocket(addr, mInfo.Port);
        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();

        foreach (string action in mInfo)
          {
          mTracer.AddLine("[{0}] Action: {1}", mInfo.ComputerName, action);

          //set up the buffer to send
          byte[] buf = new byte[4096];
          buf = encoding.GetBytes(action);

          bool transactioncompleted = false;
          bool communicatedwithremote = false;
          int bytesready = 0;

          //try to sending a few times in case once didn't work
          bytesready = SendWithRetry(client, buf);
          if (bytesready > 0)
            {
            communicatedwithremote = true;
            try
              {
              //we got a reply, handle it
              byte[] recvbuf = new byte[bytesready];
              int bytesreceived = client.Receive(recvbuf);
              mTracer.AddLine("[{0}] INFO: Reply received from: {1}", mInfo.ComputerName, addr.ToString());

              string s = Encoding.ASCII.GetString(recvbuf, 0, bytesreceived);
              foreach (string l in s.Split('\n'))
                {
                if (l != "")
                  mTracer.AddLine("[{0}] {1}", mInfo.ComputerName, l);
                }
              //todo: create a small class to hold component and parameter
              string component = action.Substring(0, action.IndexOf(':'));
              string parameter = action.Substring(action.IndexOf(':') + 1);
              mStateChecker.CheckResponse(mInfo.ComputerName, component, parameter, s);
              transactioncompleted = true; //we're done
              }
            catch (SocketException ex)
              {
              mTracer.AddLine("[{0}] WARN: Got a reply but couldn't read it: ", mInfo.ComputerName);
              mTracer.AddLine("[{0}] WARN:  {1}", mInfo.ComputerName, ex.Message);
              mStateChecker.RequestFailed("Request sent, but could not read reply");
              }
            }

          if (transactioncompleted)
            {
            mInfo.RefreshControls();
            //go on to the next Action
            }
          else if (communicatedwithremote)
            {
            mTracer.AddLine("[{0}] ERROR: Could not communicate with {1}", mInfo.ComputerName, mInfo.ComputerName);
            mTracer.AddLine("[{0}]      : check that the Monitor service is running", mInfo.ComputerName);
            mStateChecker.RequestFailed("Send succeeded, did not receive a reply from remote computer");
            mInfo.RefreshControls();
            break; //don't try anymore Actions
            }
          else
            {
            mTracer.AddLine("[{0}] ERROR: Could not communicate with {1}", mInfo.ComputerName, mInfo.ComputerName);
            mTracer.AddLine("[{0}]      : check the name or IP address", mInfo.ComputerName);
            mTracer.AddLine("[{0}]      : or check firewall settings", mInfo.ComputerName);
            mStateChecker.ConnectionFailed("Could not communicate with remote computer");
            mInfo.RefreshControls();
            break; //don't try anymore Actions
            }
          }
        }
      }
    }
  }

jMonitorService/Program.cs

Synopsis
using System.ServiceProcess;

namespace jMonitorService
{
   static class Program
   {
      /// <summary>
      /// The main entry point for the application.
      /// </summary>
      static void Main()
      {
         ServiceBase[] ServicesToRun;

         // More than one user Service may run within the same process. To add
         // another service to this process, change the following line to
         // create a second service object. For example,
         //
         //   ServicesToRun = new ServiceBase[] {new Service1(), new MySecondUserService()};
         //
         ServicesToRun = new ServiceBase[] { new Service1() };

         ServiceBase.Run(ServicesToRun);
      }
   }
}

jMonitorService/Service1.cs

Synopsis
//#define LOGEVENTS
using System;
using System.ServiceProcess;
using System.Threading;
using System.Diagnostics;
using System.Text;
using System.Net.Sockets;
using System.Reflection;
using System.IO;

namespace jMonitorService
  {
  public partial class Service1 : ServiceBase
    {
    private Thread mServerThread;
    static private AppDomain mDomain;

    //------------------------------------
    public Service1()
      {
      InitializeComponent();
      }

    //------------------------------------
    // Start the service.
    protected override void OnStart(string[] args)
      {
      //ServiceControllerStatus status = new ServiceControllerStatus();
      IntPtr handle = this.ServiceHandle;
      //status.currentState = (int)State.SERVICE_START_PENDING;
      //SetServiceStatus(handle, myServiceStatus);

      // Start a separate thread that does the actual work.
      if (mServerThread == null)
        {
#if LOGEVENTS
        EventLog.WriteEntry("jMonitorService.OnStart", DateTime.Now.ToLongTimeString() +
            " - Starting the service worker thread.");
#endif

        mServerThread = new Thread(new ThreadStart(ServerWorkerMethod));
        }

      //the thread is created one way or another...
      if (mServerThread != null)
        {
        mServerThread.Start();
#if LOGEVENTS
        EventLog.WriteEntry("jMonitorService.OnStart", DateTime.Now.ToLongTimeString() +
            " - Worker thread state = " +
            mServerThread.ThreadState.ToString());
#endif
        }
      //myServiceStatus.currentState = (int)State.SERVICE_RUNNING;
      //SetServiceStatus(handle, myServiceStatus);
      }

    //------------------------------------
    protected override void OnStop()
      {
      // TODO: Add code here to perform any tear-down necessary to stop your service.
      if (mServerThread != null)
        {
        mServerThread.Abort();
        //mServerThread.Join();
        mServerThread = null;
#if LOGEVENTS
        EventLog.WriteEntry("jMonitorService.OnStop", DateTime.Now.ToLongTimeString() +
            " - Worker thread aborted ");
#endif
        }
      }

    //------------------------------------
    private void ServerWorkerMethod()
      {
      System.Net.IPEndPoint ipep = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 5000);
      Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
      newsock.Bind(ipep);

      System.Net.IPEndPoint sender = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0);
      System.Net.EndPoint Remote = (System.Net.EndPoint)(sender);

      for (; ; )
        {
        byte[] data = new byte[1024];
#if LOGEVENTS
        EventLog.WriteEntry("jMonitorService.ServerWorkerThread", DateTime.Now.ToLongTimeString() +
            " - Waiting for a client...");
#endif
        int recv = newsock.ReceiveFrom(data, ref Remote);

#if LOGEVENTS
        EventLog.WriteEntry("jMonitorService.ServerWorkerThread", DateTime.Now.ToLongTimeString() +
            " - Message received");
#endif
        //Console.WriteLine("Message received from {0}:", Remote.ToString());
        string request = Encoding.ASCII.GetString(data, 0, recv);
        //Console.WriteLine("Check for: '" + request + "'");
        string component;
        string parameter;
        int p = request.IndexOf(':');
        if (p == -1)
          {
          EventLog.WriteEntry("jMonitorService.ServerWorkerMethod", DateTime.Now.ToLongTimeString() +
            " - WARNING missng ':', using component 'ProcessCheck'");
          component = "ProcessCheck";
          parameter = request;
          }
        else
          {
          component = request.Substring(0, p);
          parameter = request.Substring(p + 1);
          }

#if LOGEVENTS
        EventLog.WriteEntry("jMonitorService.ServerWorkerMethod", DateTime.Now.ToLongTimeString() +
    " - component='" + component+ "' parameter='" + parameter + "'");
#endif

        string response = "";
        try
          {
          ManualResetEvent waitonevent = new ManualResetEvent(false);
          LoadAssembly(component, parameter, waitonevent);
          waitonevent.WaitOne();
          response = UnloadAssembly();
#if LOGEVENTS
          EventLog.WriteEntry("jMonitorService.ServerWorkerMethod", DateTime.Now.ToLongTimeString() +
      " - response='" + response + "'");
#endif
          }
        catch (Exception ex)
          {
          EventLog.WriteEntry("jMonitorService.ServerWorkerMethod", DateTime.Now.ToLongTimeString() +
            " - Exception= '" + ex.Message + "'");
          response = "ERROR: " + ex.Message;
          }

        data = Encoding.ASCII.GetBytes(response);
        newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
        }
      }

    static void LoadAssembly(string name, string parameter, ManualResetEvent waitonevent)
      {
      System.Security.Policy.Evidence evidence = new System.Security.Policy.Evidence(AppDomain.CurrentDomain.Evidence);
      mDomain = AppDomain.CreateDomain(name, evidence);
      mDomain.SetData("Name", name);
      mDomain.SetData("Parameter", parameter);
      mDomain.SetData("WaitOnEvent", waitonevent);
      mDomain.DoCallBack(new CrossAppDomainDelegate(RunAssembly));
      }

    //---------------------------
    static string UnloadAssembly()
      {
      string response = (string)mDomain.GetData("Response");
      AppDomain.Unload(mDomain);
      return response;
      }

    //---------------------------
    static void RunAssembly()
      {
#if LOGEVENTS
      EventLog.WriteEntry("jMonitorService.LoadAssemblyIntoDomain", DateTime.Now.ToLongTimeString() +
  " - domainname = '" + AppDomain.CurrentDomain.FriendlyName + "'");
#endif

      AppDomain ad = AppDomain.CurrentDomain;
      if (ad == null)
        {
        Exception ex = new Exception("LoadAssemblyIntoDomain: LoadAssembly failed, returned null");
        throw ex;
        }
      string name = (string)ad.GetData("Name");
      string parameter = (string)ad.GetData("Parameter");
      ManualResetEvent waitonevent = (ManualResetEvent) ad.GetData("WaitOnEvent");

#if LOGEVENTS
      EventLog.WriteEntry("jMonitorService.LoadAssemblyIntoDomain", DateTime.Now.ToLongTimeString() +
  " - name='" + name + "' parm='" + parameter + "'");
#endif

      string cwd = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
      string path = cwd + "\\" + name + ".dll";
      string title_class = name + "." + name;
      string title_method = "Run";

      Assembly u = Assembly.LoadFrom(path);
      if (u == null)
        {
        throw new Exception("LoadAssemblyIntoDomain: LoadAssembly failed, returned null");
        }

      Type t = u.GetType(title_class);
      if (t == null)
        {
        throw new Exception("LoadAssemblyIntoDomain: GetType failed, returned null");
        }

      MethodInfo m = t.GetMethod(title_method);
      if (m == null)
        {
        throw new Exception("LoadAssemblyIntoDomain: GetMethod failed, returned null");
        }

      object[] myparam = new object[1];
      myparam[0] = parameter;
      string response = (string)m.Invoke(null, myparam);
      ad.SetData("Response", response);
      waitonevent.Set();
      }
    }
  }


ProcessCheck/ProcessCheck.cs

Synopsis
using System;
using System.Diagnostics;

//Must have a namespace with the same name as the .dll
namespace ProcessCheck
  {
  //Must have a class with the same name as the .dll
  public class ProcessCheck
    {
    //Must have a method signature "static string Run(string)"
    public static string Run(string parm)
      {
      EventLog.WriteEntry("jMonitorService.ProcessCheck", DateTime.Now.ToLongTimeString() +
    " - Run('" + parm + "')");
      string response = "";

      Process[] myProcesses = Process.GetProcesses();
      foreach (Process myProcess in myProcesses)
        {
        if (myProcess.ProcessName.StartsWith(parm))
          {
          //Console.WriteLine("Matched : " + myProcess.ProcessName);
          response += myProcess.ProcessName + "\n";
          }
        else
          {
          //Console.WriteLine("No Match: " + myProcess.ProcessName);
          }
        }
      //Console.WriteLine("\nMessage:\n" + response);

      return response;
      }

    //---------------------
    public static bool CheckResponse(string computer, string parameter, string response)
      {
      //Console.WriteLine("CheckResponse: computer=" + computer + " parm=" + parameter + " response=" + response);
      foreach (string l in response.Split('\n'))
        {
        if (l != "")
          {
          if (l.StartsWith(parameter))
            return true;
          }
        }

      return false;
      }
    }
  }






Contact me about content on this page using john_web-at-arrizza-dot-com
For Web Master or site problems contact: webadmin-at-arrizza-dot-com
Copyright John Arrizza (c) 2001-2010