unit MainForm;
{*******************************************************************************
  ProcessChecker Demo
  Written by David Clegg, davidclegg@optusnet.com.au.

  This program primarily demonstrates the use of the System.Diagnostics.Process
  class to control and monitor processes. It provides the ability to specify a
  list of  processes to monitor, and will restart them if they are not running,
  or not responding. Each monitored process can also have a list of dependant
  processes associated with it, and these dependant processes will be terminated
  if the monitored process is to be restarted.

  As a side effect, examples of the following techniques & classes can also be
  found:
  -	Object serialization and deserialization to a data file using the
	  System.Runtime.Serialization.Formatters.Binary.BinaryFormatter and
	  System.IO.FileStream classes (ProcessCheckerSettings.cs).
  - Raising standard and custom events (ProcessChecker.cs,
	  ProcessCheckerSettings.cs).
  - Reading file version information using the System.IO.FileInfo class
	  (AboutForm.cs)
  - Implementing a strongly typed collection class that implements the
	  System.Collections.CollectionBase class (ProcessClasses.cs).
  - Various controls in System.Windows.Forms.

*******************************************************************************}
interface

uses
  System.Drawing, System.Collections, System.ComponentModel,
  System.Windows.Forms, System.Data, System.Resources, ProcessCheckerClass,
  ProcessCheckerSettings;

type
  TMainForm = class(System.Windows.Forms.Form)
  {$REGION 'Designer Managed Code'}
  strict private
    /// <summary>
    /// Required designer variable.
    /// </summary>
    Components: System.ComponentModel.Container;
    colDetails: System.Windows.Forms.ColumnHeader;
    colTime: System.Windows.Forms.ColumnHeader;
    lvMain: System.Windows.Forms.ListView;
    panel1: System.Windows.Forms.Panel;
    btnClose: System.Windows.Forms.Button;
    btnClear: System.Windows.Forms.Button;
    cbEnabled: System.Windows.Forms.CheckBox;
    miSetup: System.Windows.Forms.MenuItem;
    miClose: System.Windows.Forms.MenuItem;
    menuItem5: System.Windows.Forms.MenuItem;
    miAbout: System.Windows.Forms.MenuItem;
    menuItem3: System.Windows.Forms.MenuItem;
    menuItem1: System.Windows.Forms.MenuItem;
    mmMain: System.Windows.Forms.MainMenu;
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    procedure InitializeComponent;
    procedure btnClose_Click(sender: System.Object; e: System.EventArgs);
    procedure TMainForm_Load(sender: System.Object; e: System.EventArgs);
    procedure cbEnabled_CheckedChanged(sender: System.Object; e: System.EventArgs);
    procedure cbEnabled_Click(sender: System.Object; e: System.EventArgs);
    procedure btnClear_Click(sender: System.Object; e: System.EventArgs);
    procedure miSetup_Click(sender: System.Object; e: System.EventArgs);
    procedure miAbout_Click(sender: System.Object; e: System.EventArgs);
  {$ENDREGION}
  strict protected
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    procedure Dispose(Disposing: Boolean); override;
  strict private
    FProcessChecker: TProcessChecker;
    procedure DoOnEvent(Sender: TObject; const EventMessage: string);
    procedure DoOnSettingsSaved(Sender: TObject; Args: EventArgs);
    procedure PopulateControls;
    procedure AddEvent(const pEventDetails: string);
    procedure InitProcessChecker(pSettings: TProcessCheckerSettings);
  public
    constructor Create;
  end;

implementation

uses
  System.Globalization, SetupForm, AboutForm, SysUtils;

{$REGION 'Windows Form Designer generated code'}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure TMainForm.InitializeComponent;
type
  TSystem_Windows_Forms_MenuItemArray = array of System.Windows.Forms.MenuItem;
  TSystem_Windows_Forms_ColumnHeaderArray = array of System.Windows.Forms.ColumnHeader;
var
  resources: System.Resources.ResourceManager;
begin
  resources := System.Resources.ResourceManager.Create(TypeOf(TMainForm));
  Self.panel1 := System.Windows.Forms.Panel.Create;
  Self.btnClose := System.Windows.Forms.Button.Create;
  Self.btnClear := System.Windows.Forms.Button.Create;
  Self.cbEnabled := System.Windows.Forms.CheckBox.Create;
  Self.miSetup := System.Windows.Forms.MenuItem.Create;
  Self.miClose := System.Windows.Forms.MenuItem.Create;
  Self.menuItem5 := System.Windows.Forms.MenuItem.Create;
  Self.miAbout := System.Windows.Forms.MenuItem.Create;
  Self.menuItem3 := System.Windows.Forms.MenuItem.Create;
  Self.menuItem1 := System.Windows.Forms.MenuItem.Create;
  Self.mmMain := System.Windows.Forms.MainMenu.Create;
  Self.lvMain := System.Windows.Forms.ListView.Create;
  Self.colTime := System.Windows.Forms.ColumnHeader.Create;
  Self.colDetails := System.Windows.Forms.ColumnHeader.Create;
  Self.panel1.SuspendLayout;
  Self.SuspendLayout;
  // 
  // panel1
  // 
  Self.panel1.Controls.Add(Self.btnClose);
  Self.panel1.Controls.Add(Self.btnClear);
  Self.panel1.Controls.Add(Self.cbEnabled);
  Self.panel1.Dock := System.Windows.Forms.DockStyle.Bottom;
  Self.panel1.Location := System.Drawing.Point.Create(0, 170);
  Self.panel1.Name := 'panel1';
  Self.panel1.Size := System.Drawing.Size.Create(712, 40);
  Self.panel1.TabIndex := 2;
  // 
  // btnClose
  // 
  Self.btnClose.Anchor := (System.Windows.Forms.AnchorStyles((System.Windows.Forms.AnchorStyles.Bottom 
      or System.Windows.Forms.AnchorStyles.Right)));
  Self.btnClose.Location := System.Drawing.Point.Create(624, 8);
  Self.btnClose.Name := 'btnClose';
  Self.btnClose.TabIndex := 2;
  Self.btnClose.Text := 'Close';
  Include(Self.btnClose.Click, Self.btnClose_Click);
  // 
  // btnClear
  // 
  Self.btnClear.Location := System.Drawing.Point.Create(104, 8);
  Self.btnClear.Name := 'btnClear';
  Self.btnClear.TabIndex := 1;
  Self.btnClear.Text := 'Clear';
  Include(Self.btnClear.Click, Self.btnClear_Click);
  // 
  // cbEnabled
  // 
  Self.cbEnabled.Location := System.Drawing.Point.Create(16, 8);
  Self.cbEnabled.Name := 'cbEnabled';
  Self.cbEnabled.Size := System.Drawing.Size.Create(72, 24);
  Self.cbEnabled.TabIndex := 0;
  Self.cbEnabled.Text := 'Enabled';
  Include(Self.cbEnabled.Click, Self.cbEnabled_Click);
  Include(Self.cbEnabled.CheckedChanged, Self.cbEnabled_CheckedChanged);
  // 
  // miSetup
  // 
  Self.miSetup.Index := 0;
  Self.miSetup.Text := 'Setup...';
  Include(Self.miSetup.Click, Self.miSetup_Click);
  // 
  // miClose
  // 
  Self.miClose.Index := 2;
  Self.miClose.Text := 'Close';
  Include(Self.miClose.Click, Self.btnClose_Click);
  // 
  // menuItem5
  // 
  Self.menuItem5.Index := 1;
  Self.menuItem5.MenuItems.AddRange(TSystem_Windows_Forms_MenuItemArray.Create(Self.miAbout));
  Self.menuItem5.Text := 'Help';
  // 
  // miAbout
  // 
  Self.miAbout.Index := 0;
  Self.miAbout.Text := 'About...';
  Include(Self.miAbout.Click, Self.miAbout_Click);
  // 
  // menuItem3
  // 
  Self.menuItem3.Index := 1;
  Self.menuItem3.Text := '-';
  // 
  // menuItem1
  // 
  Self.menuItem1.Index := 0;
  Self.menuItem1.MenuItems.AddRange(TSystem_Windows_Forms_MenuItemArray.Create(Self.miSetup, Self.menuItem3, Self.miClose));
  Self.menuItem1.Text := 'File';
  // 
  // mmMain
  // 
  Self.mmMain.MenuItems.AddRange(TSystem_Windows_Forms_MenuItemArray.Create(Self.menuItem1, Self.menuItem5));
  // 
  // lvMain
  // 
  Self.lvMain.Columns.AddRange(TSystem_Windows_Forms_ColumnHeaderArray.Create(Self.colTime, Self.colDetails));
  Self.lvMain.Dock := System.Windows.Forms.DockStyle.Fill;
  Self.lvMain.FullRowSelect := True;
  Self.lvMain.Location := System.Drawing.Point.Create(0, 0);
  Self.lvMain.Name := 'lvMain';
  Self.lvMain.Size := System.Drawing.Size.Create(712, 170);
  Self.lvMain.TabIndex := 4;
  Self.lvMain.View := System.Windows.Forms.View.Details;
  // 
  // colTime
  // 
  Self.colTime.Text := 'Event Time';
  Self.colTime.Width := 150;
  // 
  // colDetails
  // 
  Self.colDetails.Text := 'Details';
  Self.colDetails.Width := 500;
  // 
  // TMainForm
  // 
  Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 13);
  Self.ClientSize := System.Drawing.Size.Create(712, 210);
  Self.Controls.Add(Self.lvMain);
  Self.Controls.Add(Self.panel1);
  Self.Icon := (System.Drawing.Icon(resources.GetObject('$this.Icon')));
  Self.Menu := Self.mmMain;
  Self.Name := 'TMainForm';
  Self.StartPosition := System.Windows.Forms.FormStartPosition.CenterScreen;
  Self.Text := 'Process Checker';
  Include(Self.Load, Self.TMainForm_Load);
  Self.panel1.ResumeLayout(False);
  Self.ResumeLayout(False);
end;
{$ENDREGION}

procedure TMainForm.Dispose(Disposing: Boolean);
begin
  if Disposing then
  begin
    if Components <> nil then
      Components.Dispose();
  end;
  inherited Dispose(Disposing);
end;

constructor TMainForm.Create;
begin
  inherited Create;
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent;
  //
  // TODO: Add any constructor code after InitializeComponent call
  //
end;

procedure TMainForm.miAbout_Click(sender: System.Object; e: System.EventArgs);
begin
  TAboutForm.ShowAboutForm;
end;

procedure TMainForm.miSetup_Click(sender: System.Object; e: System.EventArgs);
var
  lSettings: TProcessCheckerSettings;
begin
  //Temporarily disable process checking while we are in the
  //setup screen.
  FProcessChecker.Suspended := True;
  try
    lSettings := FProcessChecker.Settings;
    if TSetupForm.ShowSetupForm(lSettings) <> System.Windows.Forms.DialogResult.OK then
      InitProcessChecker(lSettings);
  finally
    FProcessChecker.Suspended := False;
  end;
end;

procedure TMainForm.btnClear_Click(sender: System.Object; e: System.EventArgs);
begin
  lvMain.Items.Clear;
end;

/// <summary>
/// Set the ProcessCheckerSettings.Enabled property. This is done here rather
/// than in CheckBox.Check, as that event fires whenever CheckBox.Checked
/// changes. This event only fires if CheckBox.Checked changes as a result of
/// the CheckBox being clicked by the user.
/// </summary>
procedure TMainForm.cbEnabled_Click(sender: System.Object; e: System.EventArgs);
begin
  FProcessChecker.Settings.Enabled := cbEnabled.Checked;
  FProcessChecker.Settings.Save;
end;

procedure TMainForm.cbEnabled_CheckedChanged(sender: System.Object; e: System.EventArgs);
begin
  if cbEnabled.Checked then
    AddEvent('Processing Enabled')
  else
    AddEvent('Processing Disabled');
end;

procedure TMainForm.TMainForm_Load(sender: System.Object; e: System.EventArgs);
var
  lSettings: TProcessCheckerSettings;
begin
  AddEvent('Process Checker started');
  //Attempt to load the application settings
  try
    lSettings := TProcessCheckerSettings.Load;
  except on E: Exception do
    begin
      MessageBox.Show(Format('There was an error loading the settings from disk:'
        + #13#10#10 + '%s' + #13#10#10 + 'The settings have been reverted to ' +
        'their default values.', [E.Message]));
      lSettings := TProcessCheckerSettings.Create;
    end;
  end;

  InitProcessChecker(lSettings);
end;

/// <summary>
/// Create the ProcessChecker instance
/// </summary>
procedure TMainForm.InitProcessChecker(pSettings: TProcessCheckerSettings);
begin
  FProcessChecker := TProcessChecker.Create(pSettings);
  FProcessChecker.OnEvent := DoOnEvent;
  Include(FProcessChecker.Settings.SettingsSaved, DoOnSettingsSaved);
  PopulateControls;
end;

procedure TMainForm.DoOnEvent(Sender: TObject; const EventMessage: string);
begin
  AddEvent(EventMessage);
end;

/// <summary>
/// To ensure the cbEnabled CheckBox is always indicative of the
/// ProcessCheckerSettings.Enabled property, we will check its property
/// everytime the settings have been saved (e.g a problem was encountered
/// setting the Timers interval in the ProcessChecker instance).
/// </summary>
procedure TMainForm.DoOnSettingsSaved(Sender: TObject; Args: EventArgs);
begin
  AddEvent('Settings Saved');
  cbEnabled.Checked := FProcessChecker.Settings.Enabled;
end;

procedure TMainForm.PopulateControls;
begin
  //Enable/Disable processing
  cbEnabled.Checked := FProcessChecker.Settings.Enabled;
end;

/// <summary>
/// Add a detail line to the ListView
/// </summary>
procedure TMainForm.AddEvent(const pEventDetails: string);
var
  lItem: ListViewItem;
begin
  lItem := ListViewItem.Create(DateTime.Now.ToString);
  lItem.SubItems.Add(pEventDetails);
  lvMain.Items.Add(lItem);
end;

procedure TMainForm.btnClose_Click(sender: System.Object; e: System.EventArgs);
begin
  Close;
end;

end.










