Yes:
this gives you a starting point.
Did some trial and error and it appears that the above code results in some compiler problems; the TNotifyIconData record structure isn't correctly processed by the compiler.
If you redefine the structure locally it works

As a proof of concept, the code below works for me (lazarus 0.9.29, WinXP; FPC 2.3.1).
Just add 'Application.ShowMainForm := false;' to the program's initialization block.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Windows, ShellApi, Messages,
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs;
const
WM_ICONTRAY = WM_USER + 1;
type
MY_NOTIFYICONDATAA = record
cbSize: DWORD;
Wnd: HWND;
uID: UINT;
uFlags: UINT;
uCallbackMessage: UINT;
hIcon: HICON;
szTip: array [0..63] of Char;
end;
{ TForm1 }
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ private declarations }
// TrayIconData: TNotifyIconData;
TrayIconData: MY_NOTIFYICONDATAA;
public
{ public declarations }
procedure TrayMessage(var Msg: TMessage); message WM_ICONTRAY;
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
with TrayIconData do
begin
cbSize := SizeOf(TrayIconData);
uID := 0;
uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
uCallbackMessage := WM_ICONTRAY;
hIcon := Application.Icon.Handle;
StrPCopy(szTip, Application.Title);
end;
TrayIconData.Wnd := Handle;
Windows.Shell_NotifyIcon(NIM_ADD, @TrayIconData);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Windows.Shell_NotifyIcon(NIM_DELETE, @TrayIconData);
end;
procedure TForm1.TrayMessage(var Msg: TMessage);
begin
case Msg.lParam of
WM_LBUTTONDOWN:
begin
ShowMessage('Left button clicked - let''s SHOW the Form!');
Show;
end;
WM_RBUTTONDOWN:
begin
ShowMessage('Right button clicked - let''s HIDE the Form!');
Hide;
end;
end;
end;
initialization
{$I unit1.lrs}
end.