program TraySample;

uses
  Windows, Messages, pinger;

{$R tsample.res}

const
 WM_TIMER = $0113;
 TIMER_ID = $2BA3;
 WM_TRAYICON=WM_APP+1; // сообщение от трей иконки
 TRAY_ID=$A77E; // идентификатор иконки в трее
 MY_CLASS='MyTClass'; // класс для регистрации в системе
 MY_NAME='TraySample'; // так меня зовут 
 TIMER_INTERVAL_VALUE=60000; // период срабатывания в миллисекундах
 pinghost = 'www.yandex.ru'; // хост, который пингуем

var
 MainMsg: TMSG;      // для передачи сообщений

type
  PNotifyIconData = ^TNotifyIconData; // структура для работы с иконкой в трее
  TNotifyIconData = record
    cbSize: DWORD;
    Wnd: HWND;
    uID: UINT;
    uFlags: UINT;
    uCallbackMessage: UINT;
    hIcon: HICON;
    szTip: array [0..63] of AnsiChar;
  end;

 // Служебные функции -----------------------------------------

function Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL; stdcall; external 'shell32.dll' name 'Shell_NotifyIconA';

 // добавить иконку в трей
function TaskBarAddIcon(hWindow: HWND; ID: Cardinal; ICON: hIcon;
 CallbackMessage: Cardinal; Tip: PChar): Boolean;
var
  NID: TNotifyIconData;
begin
  FillChar(NID, SizeOf(TNotifyIconData), 0);
  with NID do begin
    cbSize := SizeOf(TNotifyIconData);
    Wnd   := hWindow;
    uID    := ID;
    uFlags := 7; // MESSAGE or ICON or TIP
    uCallbackMessage := CallbackMessage;
    hIcon  := Icon;
    lstrcpyn(szTip, Tip, SizeOf(szTip));
  end;
  Result := Shell_NotifyIcon(0, @NID); // AddIcon
end;

 // удалить иконку из трея
function TaskBarDeleteIcon(hWindow: HWND; ID: Integer): Boolean;
var
  NID: TNotifyIconData;
begin
  FillChar(NID, SizeOf(TNotifyIconData), 0);
  with NID do begin
    cbSize := SizeOf(TNotifyIconData);
    Wnd    := hWindow;
    uID    := ID;
  end;
  Result := Shell_NotifyIcon(2, @NID); // DeleteIcon
end;

 // всплывалка менюшки
procedure PopupMenu(hWin: HWND);
var
 Menu: hMenu;
 Popup: hMenu;
 P: TPoint;
begin
 Menu := LoadMenu(hInstance, 'MAINMENU');
 Popup := GetSubMenu(Menu, 0);
 GetCursorPos(P);
 SetForegroundWindow(hWin);
 TrackPopupMenu(Popup, TPM_LEFTBUTTON, P.X, P.Y, 0, hWin, NIL);
 PostMessage(hWin, WM_NULL, 0, 0);
 DestroyMenu(Menu);
end;


 // Основные функции -------------------------------------------------

procedure OnTimer(hWin: hwnd);
begin
  // тут действие по таймеру
  if ping(pinghost)=-1 then
    MessageBox(0, pinghost+' не отвечает!','Караул!',0);
end;

procedure OnCreate(hWin: hwnd); // Вызывается при старте программы
begin
  // пихаем иконку в трей
  TaskBarAddIcon(hWin, TRAY_ID, LoadIcon(hInstance, 'MAINICON'),
  WM_TRAYICON, MY_NAME);
  SetTimer(hWin, TIMER_ID, TIMER_INTERVAL_VALUE, nil);
end;

procedure OnDestroy(hWin: hwnd); // Вызывается при выходе из программы
begin
  TaskBarDeleteIcon(hWin, TRAY_ID); // прибить иконку
  KillTimer(hWin, TIMER_ID); // остановить таймер
end;

// Обработка сообщений windows
function MainWndProc(hWin: HWND; uMsg: UINT; wp: WPARAM; lp: WPARAM): Integer; stdcall; export;
begin
  Result:=0;
  case uMsg of
    WM_CREATE: OnCreate(hWin); // при старте программы
    WM_TIMER: OnTimer(hWin);   // по таймеру
    WM_TRAYICON: if wp=TRAY_ID then // при клике по трей иконке
      case lp of
        WM_RBUTTONDOWN: PopupMenu(hWin); //всплыть менюшке
        WM_LBUTTONDBLCLK: PostMessage(hWin, WM_COMMAND, 29, 0); //def в меню
      end;
    WM_COMMAND: // вызов комманды меню
      case LoWord(wp) of
        29: MessageBox(hWin, 'Я слежу за '+ pinghost,'Pinger',0);
        30: PostMessage(hWin, WM_DESTROY, 0, 0); // выход
      end;
    WM_DESTROY: begin // умираем
        OnDestroy(hWin);
        PostQuitMessage(0); // умереть
      end;
    else Result:=DefWindowProc(hWin, uMsg, wp, lp); // прочие события
  end;
end;

procedure RegMWindow; // создать главное окно
var WClass:  TWndClass; // описатель главного окна
begin
  FillChar(wClass, SizeOf(wClass), 0);
  wClass.lpfnWndProc:=@MainWndProc;
  wClass.hInstance:=HInstance;
  wClass.lpszClassName:=MY_CLASS;
  RegisterClass(wClass); // регестрируемся в системе
  CreateWindowEx(WS_EX_TOOLWINDOW,MY_CLASS,MY_NAME,
                 WS_POPUP, 0, 0, 0, 0, 0, 0, hInstance, nil); // создаем окно
  //SetPriorityClass(GetCurrentProcess, IDLE_PRIORITY_CLASS); // низкие приоритет
end;

BEGIN
  // тут проверяем, если уже запущены, то отваливаем
  if FindWindow(MY_CLASS,nil)<>0 then Halt;

  RegMWindow; // создать окно

  while GetMessage(MainMsg,0,0,0) do begin // цикл обработки сообщений
    TranslateMessage(MainMsg);
    DispatchMessage(MainMsg);
  end;
END.
