(* Program to demonstrate the use of the
  Delphi interface to Windows Task Scheduler 2.0

  © Dr. J. Rathlev, D-24222 Schwentinental (kontakt(a)rathlev-home.de)

  The contents of this file may be used under the terms of the
  Mozilla Public License ("MPL") or
  GNU Lesser General Public License Version 2 or later (the "LGPL")

  Software distributed under this License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  the specific language governing rights and limitations under the License.

  Vers. 1.0 - Oct. 2017
*)

unit TaskMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.Buttons,
  Vcl.ExtCtrls, WinTask, System.ImageList, Vcl.ImgList, RzStatus, BOsU;

type
  TfrmTaskMain = class(TForm)
    gbDetails: TGroupBox;
    Label1: TLabel;
    edUserAccount: TLabeledEdit;
    edComment: TLabeledEdit;
    edCreator: TLabeledEdit;
    edStatus: TLabeledEdit;
    edApplication: TLabeledEdit;
    edParameters: TLabeledEdit;
    edWorkDir: TLabeledEdit;
    lbTriggers: TListBox;
    btnDelete: TBitBtn;
    btbEdit: TBitBtn;
    btbCancel: TBitBtn;
    lvTasks: TListView;
    edCompat: TLabeledEdit;
    GroupBox1: TGroupBox;
    lblEdtServiceName: TLabeledEdit;
    lblEdtEventID: TLabeledEdit;
    lblEdtGmailAccount: TLabeledEdit;
    lbledtGmailPassword: TLabeledEdit;
    lblEdtEmailTo: TLabeledEdit;
    BitBtnEdit: TBitBtn;
    BitBtnSave: TBitBtn;
    GlystatEmail: TRzGlyphStatus;
    GlyStatEventID: TRzGlyphStatus;
    GlyStatGmail: TRzGlyphStatus;
    ilStatusDaten: TImageList;
    GlyStatGPass: TRzGlyphStatus;
    GlystatServiceName: TRzGlyphStatus;
    TabControl1: TTabControl;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure btbCancelClick(Sender: TObject);
    procedure lvTasksSelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
    procedure FormResize(Sender: TObject);
    procedure btbEditClick(Sender: TObject);
    procedure btnDeleteClick(Sender: TObject);
    procedure lvTasksCustomDrawItem(Sender: TCustomListView; Item: TListItem;
      State: TCustomDrawState; var DefaultDraw: Boolean);
    procedure BitBtnSaveClick(Sender: TObject);
    procedure BitBtnEditClick(Sender: TObject);
  private
    { Private-Deklarationen }
    WinTasks: TWinTaskScheduler;
    SelectedTaskIndex: integer;
    un: string;
    procedure UpdateListeView(AIndex: integer);
    procedure ShowData(Item: TListItem; Selected: Boolean);
    procedure ShowErrors(const AErrors: TArray<String>);
    function GetCustomer: TCustomer;
    procedure EnablelblEditControls(const AValue: Boolean);
    function CheeckEmpty: Boolean;
  public
    { Public-Deklarationen }
  end;

var
  frmTaskMain: TfrmTaskMain;

implementation

{$R *.dfm}

uses System.Win.ComObj, System.DateUtils, Vcl.FileCtrl, Winapi.ActiveX,
  WinApiUtils, CreateScript, Winapi.ShlObj, ErrorsMessageFormU, ValidatorU;

procedure TfrmTaskMain.FormCreate(Sender: TObject);
var
  hr: HResult;
begin
  // CoInitializeEx(nil,COINIT_MULTITHREADED);
  hr := CreateWinTaskScheduler(WinTasks);
  if failed(hr) then
  begin
    if hr = NotAvailOnXp then
    begin
      MessageDlg('Windows Task Scheduler 2.0 requires at least Windows Vista',
        mtError, [mbOK], 0);
      Halt(1)
    end
    else
    begin
      // MessageDlg('Error initializing TWinTaskScheduler - '+SystemErrorMessage(hr),mtError,[mbOK],0);
      Halt(2)
    end;
  end;
  un := UserFullname;
  un := Username;
end;

procedure TfrmTaskMain.FormDestroy(Sender: TObject);
begin
  WinTasks.Free;
  // CoUninitialize;
end;

procedure TfrmTaskMain.FormResize(Sender: TObject);
begin
  with lvTasks do
  begin
    Columns[1].Width := 80;
    Columns[2].Width := 150;
    Columns[3].Width := 150;
    Columns[0].Width := Width - 401;
  end;
end;

procedure TfrmTaskMain.FormShow(Sender: TObject);
begin
  // UpdateListeView(0);
  if not CheeckEmpty then BitBtnEdit.Enabled:=false

end;

procedure TfrmTaskMain.UpdateListeView(AIndex: integer);
var
  i: integer;
begin
  lvTasks.Clear;
  with WinTasks.TaskFolder do
  begin
    for i := 0 to TaskCount - 1 do
      with Tasks[i] do
      begin
        if TaskName = 'Alert-Service' then
          with lvTasks.Items.Add do
          begin
            Caption := TaskName;
            Data := pointer(i);
            SubItems.Add(StatusAsString);
            SubItems.Add(LastRunTimeAsString);
            SubItems.Add(NextRunTimeAsString);
          end;
      end;
    with lvTasks do
    begin
      if AIndex >= Items.Count then
        AIndex := Items.Count - 1;
      ItemIndex := AIndex;
      Invalidate;
      Selected.MakeVisible(false);
    end;
  end;
end;

procedure TfrmTaskMain.lvTasksCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  // if (Item.Index > 1) then
  // exit;
  with lvTasks.Canvas.Brush do
  begin
    case Item.Index of
      0:
        Color := clYellow;
      1:
        Color := clGreen;
      2:
        Color := clRed;
    end;
  end;
end;

procedure TfrmTaskMain.lvTasksSelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  ShowData(Item, Selected);
end;

procedure TfrmTaskMain.ShowData(Item: TListItem; Selected: Boolean);
var
  i: integer;

  procedure ShowText(AEdit: TCustomEdit; const AText: string);
  begin
    with AEdit do
    begin
      Text := MinimizeName(AText, self.Canvas, Width);
      ShowHint := length(AText) > length(Text);
      if ShowHint then
        Hint := AText;
    end;
  end;

begin
  if Assigned(Item) and Selected then
  begin
    with WinTasks.TaskFolder.Tasks[integer(Item.Data)], Definition do
    begin
      gbDetails.Caption := 'Properties of task: ' + TaskName;
      ShowText(edStatus, StatusAsString);
      ShowText(edUserAccount, UserId);
      ShowText(edComment, Description);
      ShowText(edCreator, Author);
      ShowText(edStatus, DateAsString);
      ShowText(edCompat, CompatibilityAsString);
      // cbReRun.Checked:=RunIfMissed;
      if ActionCount > 0 then
        with Actions[0] do
          if ActionType = taExec then
            with TWinTaskExecAction(Actions[0]) do
            begin
              ShowText(edApplication, ApplicationPath);
              ShowText(edParameters, Arguments);
              ShowText(edWorkDir, WorkingDirectory);
            end
          else
          begin
            edApplication.Text := '';
            edParameters.Text := '';
            edWorkDir.Text := '';
          end;
      lbTriggers.Clear;
      for i := 0 to TriggerCount - 1 do
        with Triggers[i] do
        begin
          lbTriggers.Items.Add(TriggerString);
        end;
      SelectedTaskIndex := TaskIndex;
    end;
  end
end;

procedure TfrmTaskMain.ShowErrors(const AErrors: TArray<String>);
begin
  ErrorsMessageForm.Errors := AErrors;
  ErrorsMessageForm.ShowModal;
end;

function TfrmTaskMain.GetCustomer: TCustomer;
begin
  Result := TCustomer.Create;
  Result.Email := lblEdtEmailTo.Text;
  // Result.Lastname := LabeledEdit2.Text;
  Result.Gmail := lblEdtGmailAccount.Text;
  Result.EventID := lblEdtEventID.Text;
  Result.GmailPassword := lbledtGmailPassword.Text;
  Result.ServiceName := lblEdtServiceName.Text;

end;

procedure TfrmTaskMain.EnablelblEditControls(const AValue: Boolean);
begin
  lblEdtServiceName.ReadOnly := AValue;
  lbledtGmailPassword.ReadOnly := AValue;
  lblEdtEmailTo.ReadOnly := AValue;
  lblEdtEventID.ReadOnly := AValue;
  lblEdtGmailAccount.ReadOnly := AValue;
end;

procedure TfrmTaskMain.BitBtnEditClick(Sender: TObject);
begin
  EnablelblEditControls(false);
  BitBtnSave.Enabled := true;
end;

procedure TfrmTaskMain.BitBtnSaveClick(Sender: TObject);
var
  LCustomer: TCustomer;
  LErrors: TArray<string>;
begin
  LCustomer := GetCustomer;
  try
    LErrors := [];
    if TValidator.Validate(LCustomer, LErrors, 'RegisterContext') then
    begin
      GlyStatGmail.imageindex := 1;
      GlystatEmail.imageindex := 1;
      GlyStatGPass.imageindex := 1;
      GlystatServiceName.imageindex := 1;
      GlyStatEventID.imageindex := 1;
      BitBtnSave.Enabled := false;
      EnablelblEditControls(true);

    end
    else
    begin
      if (GlystatEmail.imageindex = -1) then
        GlystatEmail.imageindex := 0;

      if (GlyStatGmail.imageindex = -1) then
        GlyStatGmail.imageindex := 0;

      if (GlyStatEventID.imageindex = -1) then
        GlyStatEventID.imageindex := 0;

      if (GlyStatGPass.imageindex = -1) then
        GlyStatGPass.imageindex := 0;

      if (GlystatServiceName.imageindex = -1) then
        GlystatServiceName.imageindex := 0;

      ShowErrors(LErrors);
      exit;
    end;
  finally
    LCustomer.Free;

  end;
end;

procedure TfrmTaskMain.btbCancelClick(Sender: TObject);
begin
  Close;
end;

function GetSpecialFolderPath(CSIDLFolder: integer): string;
var
  FilePath: array [0 .. MAX_PATH] of char;
begin
  SHGetFolderPath(0, CSIDLFolder, 0, 0, FilePath);
  Result := FilePath;
end;

function GetWinDir: string;
var
  dir: array [0 .. MAX_PATH] of char;
begin
  GetWindowsDirectory(dir, MAX_PATH);
  Result := StrPas(dir);
end;

function SystemDir: string;
var
  dir: array [0 .. MAX_PATH] of char;
begin
  GetSystemDirectory(dir, MAX_PATH);
  Result := StrPas(dir);
end;

function TfrmTaskMain.CheeckEmpty: Boolean;
begin
  Result := (lblEdtEventID.Text <> '') and (lblEdtServiceName.Text <> '') and
    (lblEdtEmailTo.Text <> '') and (lblEdtGmailAccount.Text <> '') and
    (lbledtGmailPassword.Text <> '');
end;

procedure TfrmTaskMain.btbEditClick(Sender: TObject);
var
  td: TWinTask;
  n: integer;
  user, pwd: string;
  mydatatime: Tdatetime;
  psScriptname: string;
  pathWindows, pathSystem: string;
  AEventID, AEventData, AEmailTo, AGmailAccount, AGmailPassword: string;
begin

  // pathWindows:=GetSpecialFolderPath(CSIDL_WINDOWS);

  if (CheeckEmpty) then
  begin
    AEventID := lblEdtEventID.Text;
    AEventData := lblEdtServiceName.Text;
    AEmailTo := lblEdtEmailTo.Text;
    AGmailAccount := lblEdtGmailAccount.Text;
    AGmailPassword := lbledtGmailPassword.Text;
  end else exit;

  pathWindows := IncludeTrailingBackslash(GetWinDir);
  psScriptname := pathWindows + 'ServiceAlert.ps1';

  CreatePsScript(psScriptname, AEventID, AEventData, AEmailTo, AGmailAccount,
    AGmailPassword);

  user := '';
  pwd := '';;
  if SelectedTaskIndex >= 0 then
    with WinTasks do
    begin
      td := NewTask; // Tasks[SelectedTaskIndex];
      with td do
      begin
        UserId := Username;
        Description := 'Email Me By Service Problem';
        LogOnType := ltToken; // as current user
        Author := UserId;
        Date := Now;
        with TWinTaskExecAction(NewAction(taExec)) do
        begin
          ApplicationPath := 'powershell.exe';
          Arguments := '-windowstyle hidden -ExecutionPolicy Bypass ' +
            psScriptname + ' -RunType $true';
        end;
        with NewTrigger(ttEvent) do
        begin
          Subscription :=
            '<QueryList>'#13#10'<Query Id="0" Path="System">'#13#10'<Select Path="System">*[System[(Level=2 or Level=0) and (EventID='
            + AEventID + ')]] and *[EventData[Data[1]=' + QuotedStr(AEventData)
            + ']]</Select>'#13#10'</Query>'#13#10'</QueryList>';


          // mydatatime := EncodeDate(YearOf(Now), MonthOf(Now), DayOf(Now)) + EncodeTime(10, 00, 00, 00);
          // StartTime := mydatatime;
          // mydatatime := EncodeDate(YearOf(Now), MonthOf(Now), DayOf(Now)) + EncodeTime(10, 30, 00, 00);
          // EndTime := mydatatime;
          /// /          DaysOfWeek := 5;
          // Duration := 300; // 5 min lang
          // Interval := 60; // after 1 min gone reapeat
          // Delay := 1;

        end;
      end;
      n := TaskFolder.RegisterTask('Alert-Service', td, user, pwd);
      if n < 0 then
        MessageDlg(TaskFolder.ErrorMessage, mtError, [mbOK], 0)
      else
      begin
        UpdateListeView(n);
        ShowData(lvTasks.Items[n], true);
      end;
    end;
end;

procedure TfrmTaskMain.btnDeleteClick(Sender: TObject);
begin
  if SelectedTaskIndex >= 0 then
    with WinTasks.TaskFolder do
    begin
      if failed(DeleteTask(Tasks[SelectedTaskIndex].TaskName)) then
        MessageDlg(ErrorMessage, mtError, [mbOK], 0)
      else
      begin
        UpdateListeView(SelectedTaskIndex);
      end;
    end;
end;

end.
