I want to use a custom TIdIOHandler
for my Indy TCP client and I don't know how to set it up. I create a new IOHandler class, I registered with TIdIOHandler.RegisterIOHandler
, and then I use TIdTCPClient.CreateIOHandler
with my new handler reference. Now, when I try to write to the TIdTCPClient.Socket
I get "Abstract error" exception... Do I need to configure other things besides my example ?
TIdEnhancedIOHandler = class(TIdIOHandlerSocket)
public
function Acknowledge(Command: Cardinal = 0): Boolean;
end
{this is a client in a thread}
constructor TMyTCPClient.Create(const AHost: String; APort: Word);
begin
inherited Create;
FreeOnTerminate:= True;
TIdEnhancedIOHandler.RegisterIOHandler;
TCPClient:= TIdTCPClient.Create;
TCPClient.CreateIOHandler(TIdEnhancedIOHandler);
TCPClient.ConnectTimeout:= 1000;
TCPClient.ReadTimeout:= -1;
TCPClient.Host:= AHost;
TCPClient.Port:= APort;
RetSuccess:= False;
RetMessage:= 'Unknown error.';
end;
procedure TMainClient.Execute;
var CMD: Cardinal;
begin
TCPClient.Connect;
TCPClient.Socket.Write(CMD);
end;
From the Indy Help I understand that ...
The help is old, and has outdated information.
I must use
CreateIOHandler
and specify my custom IOHandler class.
You can do that, but you don't actually need to. You can simply assign an instance of your custom class directly to the TIdTCPClient.IOHandler
property, before calling TIdTCPClient.Connect()
, eg:
TCPClient := TIdTCPClient.Create;
TCPClient.IOHandler :- TIdEnhancedIOHandler.Create(TCPClient);
...
I do that and I get an exception which says that this class is not installed.
That means Indy's internal GIOHandlerClassList
does not contain any class types that derive from the class type you specify to CreateIOHandler()
.
How cand I install it ? The variable
GIOHandlerClassList
that holds the list is private...
You would need to call the public RegisterIOHandler()
or SetDefaultClass()
class method on your custom class type at runtime, such as in your unit's initialization
section, eg:
initialization
TIdEnhancedIOHandler.RegisterIOHandler();
However, the only thing in Indy that actually uses CreateIOHandler()
is TIdSimpleServer
, so there is no need to "register" your custom class in this situation.
On the other hand, TIdTCPClient.Connect()
does call TIdIOHandler.MakeDefaultIOHandler()
if no IOHandler
is assigned, and that uses GIOHandlerClassDefault
, which is set by TIdIOHandler.SetDefaultClass()
(which also calls RegisterIOHandler()
). So, if you want TIdTCPClient
to create an object of your custom class type for you, you would need to call SetDefaultClass()
at least, eg:
initialization
TIdEnhancedIOHandler.SetDefaultClass();
Either way, RegisterIOHandler()
/SetDefaultClass()
should be called only one time, such as at program startup.
UPDATE: you are getting an abstract error because you are deriving your class from TIdIOHandlerSocket
, which is an abstract class, as it does not implement the ReadDataFromSource()
and WriteDataToTarget()
methods that are declared as abstract
in TIdIOHandler
. You need to derive your class from TIdIOHandlerStack
instead, which derives from TIdIOHandlerSocket
and implements those methods.