Like the events of most other components, the events of Indy components expect class methods, not standalone functions.
You could go the way that others have recommended, where creating a TDataModule at design-time and using it at run-time would be the easiest.
But, even if you were to simply write a class in code to wrap the events, note that you don't actually need to instantiate such a class at run-time, you can declare its methods with the class directive instead, eg:
program IndyConsoleApp;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, IdContext, IdBaseComponent, IdComponent, IdCustomTCPServer,
IdTCPServer, IdGlobal;
var
IdTCPServer1: TIdTCPServer;
procedure ShowStartServerdMessage;
begin
WriteLn('START SERVER @' + TimeToStr(now));
end;
procedure StopStartServerdMessage;
begin
WriteLn('STOP SERVER @' + TimeToStr(now));
end;
type
TCPServerEvents = class
class procedure OnExecute(AContext: TIdContext);
end;
class procedure TCPServerEvents.OnExecute(AContext: TIdContext);
var
LLine: String;
begin
LLine := AContext.Connection.IOHandler.ReadLn();
writeln(LLine);
AContext.Connection.IOHandler.WriteLn('OK');
end;
begin
try
IdTCPServer1 := TIdTCPServer.Create;
try
with IdTCPServer1.Bindings.Add do
begin
IP := '127.0.0.1';
Port := 6000;
end;
IdTCPServer1.OnExecute := TCPServerEvents.OnExecute;
IdTCPServer1.Active := True;
try
ShowStartServerdMessage;
Readln;
finally
IdTCPServer1.Active := False;
StopStartServerdMessage;
end;
finally
IdTCPServer1.Free;
end;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
end.
However, there IS actually a way to use a standalone function instead, but it involves a little trickery using Delphi's TMethod record:
program IndyConsoleApp;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, IdContext, IdBaseComponent, IdComponent, IdCustomTCPServer,
IdTCPServer, IdGlobal;
var
IdTCPServer1: TIdTCPServer;
procedure ShowStartServerdMessage;
begin
WriteLn('START SERVER @' + TimeToStr(now));
end;
procedure StopStartServerdMessage;
begin
WriteLn('STOP SERVER @' + TimeToStr(now));
end;
procedure TCPServerExecute(ASelf: Pointer; AContext: TIdContext); // NOTE THE EXTRA PARAMETER!
var
LLine: String;
begin
LLine := AContext.Connection.IOHandler.ReadLn();
WriteLn(LLine);
AContext.Connection.IOHandler.WriteLn('OK');
end;
var
ExecuteFct: TMethod;
begin
try
IdTCPServer1 := TIdTCPServer.Create;
try
with IdTCPServer1.Bindings.Add do
begin
IP := '127.0.0.1';
Port := 6000;
end;
ExecuteFct.Data := nil; // or anything you want to pass to the ASelf parameter...
ExecuteFct.Code := @TCPServerExecute;
IdTCPServer1.OnExecute := TIdServerThreadEvent(ExecuteFct);
IdTCPServer1.Active := True;
try
ShowStartServerdMessage;
Readln;
finally
IdTCPServer1.Active := False;
StopStartServerdMessage;
end;
finally
IdTCPServer1.Free;
end;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
end.