[SOLVED] lNet Can't assign callbacks
lazarus / 38-Networking and Web Programming
----------------------------------------------------------------------
JoeJoeTV · 2019-09-02 21:15
I am trying to make a tcp server with lNet, but when I try to assign
the callback procedures it gives me the error incompatible types:
MY Code:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i //interface
of unit procedure tcpServerOnAccept(aSocket: TLSocket);procedure
tcpServerOnConnect(aSocket: TLSocket);procedure tcpServerOnError(const
msg: String; aSocket: TLSocket);procedure tcpServerOnReceive(aSocket:
TLSocket);procedure tcpServerOnDisconnect(aSocket: TLSocket);procedure
tcpServerOnCanSend(aSocket: TLSocket); //init function procedure
init;begin InitVideo; InitKeyboard; ClearScreen;
SetCursorPos(1,ScreenHeight-1); SetCursorType(crUnderLine); //Init
Vars delta_ms := 0; serverListenAddress := defaultAddress;
serverListenPort := defaultPort; if ParamCount >= 1 then begin
try tmpRegEx := TRegExpr.Create('(^\S+):(\d{1,5})$');
if tmpRegEx.Exec(ParamStr(1)) then begin
serverListenAddress := tmpRegEx.Match[1]; serverListenPort
:= StrToInt(tmpRegEx.Match[2]);
end; finally tmpRegEx.Free;
end; end; //Init Network Stuff tcpServer
:= TLTcp.Create(nil); tcpServer.OnAccept := @tcpServerOnAccept;
//ERROR HERE: unitmain.pas(117,25) Error: Incompatible types: got
"
" expected ""
tcpServer.OnConnect := @tcpServerOnConnect; //HERE TOO
tcpServer.OnCanSend := @tcpServerOnCanSend; //HERE TOO
tcpServer.OnDisconnect := @tcpServerOnDisconnect; //HERE TOO
tcpServer.OnError := @tcpServerOnError; //HERE TOO
tcpServer.OnReceive := @tcpServerOnReceive; //HERE TOO
tcpServer.Timeout := 0; if tcpServer.Listen(serverListenPort,
serverListenAddress) then begin writeLogMessage('Started
Listening on
'+serverListenAddress+':'+IntToStr(serverListenPort)+'...');
end else begin writeLogMessage('Couldnt start
listening!'); writeLogMessage('Exiting...'); exit;
end; draw;end;
I don't know what I'm doing wrong, i declared the procedure in
iterface like the TLSocketEvent and have an impimentation for each
function.
----------------------------------------------------------------------
Remy Lebeau · 2019-09-02 22:10
Quote from: JoeJoeTV on September 02, 2019, 11:15:16 pmI am trying to
make a tcp server with lNet, but when I try to assign the callback
procedures it gives me the error incompatible types:
...
I don't know what I'm doing wrong, i declared the procedure in
iterface like the TLSocketEvent and have an impimentation for each
function.
Your callbacks are declared as standalone procedures, but TLTcp is
expecting them to be non-static class methods instead. So move your
callbacks into a class, then create an instance of that class. For
example:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i type
TMyServerEvents = class procedure tcpServerOnAccept(aSocket:
TLSocket); procedure tcpServerOnConnect(aSocket: TLSocket);
procedure tcpServerOnError(const msg: String; aSocket: TLSocket);
procedure tcpServerOnReceive(aSocket: TLSocket); procedure
tcpServerOnDisconnect(aSocket: TLSocket); procedure
tcpServerOnCanSend(aSocket: TLSocket); end; ... procedure
TMyServerEvents.tcpServerOnAccept(aSocket: TLSocket);begin
//...end; procedure TMyServerEvents.tcpServerOnConnect(aSocket:
TLSocket);begin //...end; procedure
TMyServerEvents.tcpServerOnError(const msg: String; aSocket:
TLSocket);begin //...end; procedure
TMyServerEvents.tcpServerOnReceive(aSocket: TLSocket);begin
//...end; procedure TMyServerEvents.tcpServerOnDisconnect(aSocket:
TLSocket);begin //...end; procedure
TMyServerEvents.tcpServerOnCanSend(aSocket: TLSocket);begin
//...end; ... procedure init;begin ... //Init Network Stuff
tcpServer := TLTcp.Create(nil); tcpServerEvents :=
TMyServerEvents.Create(tcpServer); tcpServer.OnAccept :=
tcpServerEvents.tcpServerOnAccept; tcpServer.OnConnect :=
tcpServerEvents.tcpServerOnConnect; tcpServer.OnCanSend :=
tcpServerEvents.tcpServerOnCanSend; tcpServer.OnDisconnect :=
tcpServerEvents.tcpServerOnDisconnect; tcpServer.OnError :=
tcpServerEvents.tcpServerOnError; tcpServer.OnReceive :=
tcpServerEvents.tcpServerOnReceive; ... end;
You could then take this a step further by deriving a new class from
TLTcp and make the callbacks be members of that class instead, hooking
up its events in its own constructor.
If you don't want to take the class approach, if you still want to use
standalone procedures, there is an alternative via the TMethod record,
but it is more of a hack:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i // notice
the extra aSelf parameters!!!procedure tcpServerOnAccept(aSelf:
Pointer; aSocket: TLSocket);procedure tcpServerOnConnect(aSelf:
Pointer; aSocket: TLSocket);procedure tcpServerOnError(aSelf: Pointer;
const msg: String; aSocket: TLSocket);procedure
tcpServerOnReceive(aSelf: Pointer; aSocket: TLSocket);procedure
tcpServerOnDisconnect(aSelf: Pointer; aSocket: TLSocket);procedure
tcpServerOnCanSend(aSelf: Pointer; aSocket: TLSocket);
... procedure tcpServerOnAccept(aSelf: Pointer; aSocket:
TLSocket);begin //...end; procedure tcpServerOnConnect(aSelf:
Pointer; aSocket: TLSocket);begin //...end; procedure
tcpServerOnError(aSelf: Pointer; const msg: String; aSocket:
TLSocket);begin //...end; procedure tcpServerOnReceive(aSelf:
Pointer; aSocket: TLSocket);begin //...end; procedure
tcpServerOnDisconnect(aSelf: Pointer; aSocket: TLSocket);begin
//...end; procedure tcpServerOnCanSend(aSelf: Pointer; aSocket:
TLSocket);begin //...end; ... procedure init;var M: TMethod;begin
... //Init Network Stuff tcpServer := TLTcp.Create(nil);
M.Code := @tcpServerOnAccept; M.Data := nil; // or whatever you want
aSelf to point at... tcpServer.OnAccept := TLSocketEvent(M); M.Code
:= @tcpServerOnConnect; M.Data := ...; tcpServer.OnConnect :=
TLSocketEvent(M); M.Code := @tcpServerOnCanSend; M.Data := ...;
tcpServer.OnCanSend := TLSocketEvent(M); M.Code :=
@tcpServerOnDisconnect; M.Data := ...; tcpServer.OnDisconnect :=
TLSocketEvent(M); M.Code := @tcpServerOnError; M.Data := ...;
tcpServer.OnError := TLSocketErrorEvent(M); M.Code :=
@tcpServerOnReceive; M.Data := ...; tcpServer.OnReceive :=
TLSocketEvent(M); ... end;
----------------------------------------------------------------------
JoeJoeTV · 2019-09-03 20:01
Quote from: Remy Lebeau on September 03, 2019, 12:10:51 amQuote from:
JoeJoeTV on September 02, 2019, 11:15:16 pmI am trying to make a tcp
server with lNet, but when I try to assign the callback procedures it
gives me the error incompatible types:
...
I don't know what I'm doing wrong, i declared the procedure in
iterface like the TLSocketEvent and have an impimentation for each
function.
Your callbacks are declared as standalone procedures, but TLTcp is
expecting them to be non-static class methods instead. So move your
callbacks into a class, then create an instance of that class. For
example:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i type
TMyServerEvents = class procedure tcpServerOnAccept(aSocket:
TLSocket); procedure tcpServerOnConnect(aSocket: TLSocket);
procedure tcpServerOnError(const msg: String; aSocket: TLSocket);
procedure tcpServerOnReceive(aSocket: TLSocket); procedure
tcpServerOnDisconnect(aSocket: TLSocket); procedure
tcpServerOnCanSend(aSocket: TLSocket); end; ... procedure
TMyServerEvents.tcpServerOnAccept(aSocket: TLSocket);begin
//...end; procedure TMyServerEvents.tcpServerOnConnect(aSocket:
TLSocket);begin //...end; procedure
TMyServerEvents.tcpServerOnError(const msg: String; aSocket:
TLSocket);begin //...end; procedure
TMyServerEvents.tcpServerOnReceive(aSocket: TLSocket);begin
//...end; procedure TMyServerEvents.tcpServerOnDisconnect(aSocket:
TLSocket);begin //...end; procedure
TMyServerEvents.tcpServerOnCanSend(aSocket: TLSocket);begin
//...end; ... procedure init;begin ... //Init Network Stuff
tcpServer := TLTcp.Create(nil); tcpServerEvents :=
TMyServerEvents.Create(tcpServer); tcpServer.OnAccept :=
tcpServerEvents.tcpServerOnAccept; tcpServer.OnConnect :=
tcpServerEvents.tcpServerOnConnect; tcpServer.OnCanSend :=
tcpServerEvents.tcpServerOnCanSend; tcpServer.OnDisconnect :=
tcpServerEvents.tcpServerOnDisconnect; tcpServer.OnError :=
tcpServerEvents.tcpServerOnError; tcpServer.OnReceive :=
tcpServerEvents.tcpServerOnReceive; ... end;
You could then take this a step further by deriving a new class from
TLTcp and make the callbacks be members of that class instead, hooking
up its events in its own constructor.
If you don't want to take the class approach, if you still want to use
standalone procedures, there is an alternative via the TMethod record,
but it is more of a hack:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i // notice
the extra aSelf parameters!!!procedure tcpServerOnAccept(aSelf:
Pointer; aSocket: TLSocket);procedure tcpServerOnConnect(aSelf:
Pointer; aSocket: TLSocket);procedure tcpServerOnError(aSelf: Pointer;
const msg: String; aSocket: TLSocket);procedure
tcpServerOnReceive(aSelf: Pointer; aSocket: TLSocket);procedure
tcpServerOnDisconnect(aSelf: Pointer; aSocket: TLSocket);procedure
tcpServerOnCanSend(aSelf: Pointer; aSocket: TLSocket);
... procedure tcpServerOnAccept(aSelf: Pointer; aSocket:
TLSocket);begin //...end; procedure tcpServerOnConnect(aSelf:
Pointer; aSocket: TLSocket);begin //...end; procedure
tcpServerOnError(aSelf: Pointer; const msg: String; aSocket:
TLSocket);begin //...end; procedure tcpServerOnReceive(aSelf:
Pointer; aSocket: TLSocket);begin //...end; procedure
tcpServerOnDisconnect(aSelf: Pointer; aSocket: TLSocket);begin
//...end; procedure tcpServerOnCanSend(aSelf: Pointer; aSocket:
TLSocket);begin //...end; ... procedure init;var M: TMethod;begin
... //Init Network Stuff tcpServer := TLTcp.Create(nil);
M.Code := @tcpServerOnAccept; M.Data := nil; // or whatever you want
aSelf to point at... tcpServer.OnAccept := TLSocketEvent(M); M.Code
:= @tcpServerOnConnect; M.Data := ...; tcpServer.OnConnect :=
TLSocketEvent(M); M.Code := @tcpServerOnCanSend; M.Data := ...;
tcpServer.OnCanSend := TLSocketEvent(M); M.Code :=
@tcpServerOnDisconnect; M.Data := ...; tcpServer.OnDisconnect :=
TLSocketEvent(M); M.Code := @tcpServerOnError; M.Data := ...;
tcpServer.OnError := TLSocketErrorEvent(M); M.Code :=
@tcpServerOnReceive; M.Data := ...; tcpServer.OnReceive :=
TLSocketEvent(M); ... end;
Thank you very much, but why does lNet expect a class variable, is
there a specific reason?
----------------------------------------------------------------------
Remy Lebeau · 2019-09-03 23:18
Quote from: JoeJoeTV on September 03, 2019, 10:01:44 pmwhy does lNet
expect a class variable, is there a specific reason?
Because its event types are declared as " of object", eg:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i {
Callback Event procedure for errors } TLSocketErrorEvent =
procedure(const msg: string; aSocket: TLSocket) of object; {
Callback Event procedure for others } TLSocketEvent =
procedure(aSocket: TLSocket) of object; { Callback Event procedure
for progress reports} TLSocketProgressEvent = procedure (aSocket:
TLSocket; const Bytes: Integer) of object;
Which mean the events will pass an implicit Self parameter to any
assigned event handlers, just like most events in most components do.
So that is why your handlers must be members of a class (if you don't
use the TMethod hack), so they receive a pointer to the object they
belong to as their Self parameter.
----------------------------------------------------------------------
JoeJoeTV · 2019-09-24 15:58
Quote from: Remy Lebeau on September 04, 2019, 01:18:49 amQuote from:
JoeJoeTV on September 03, 2019, 10:01:44 pmwhy does lNet expect a
class variable, is there a specific reason?
Because its event types are declared as " of object", eg:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i {
Callback Event procedure for errors } TLSocketErrorEvent =
procedure(const msg: string; aSocket: TLSocket) of object; {
Callback Event procedure for others } TLSocketEvent =
procedure(aSocket: TLSocket) of object; { Callback Event procedure
for progress reports} TLSocketProgressEvent = procedure (aSocket:
TLSocket; const Bytes: Integer) of object;
Which mean the events will pass an implicit Self parameter to any
assigned event handlers, just like most events in most components do.
So that is why your handlers must be members of a class (if you don't
use the TMethod hack), so they receive a pointer to the object they
belong to as their Self parameter.
Thanks for clearing that up, everything now works perfectly.