[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.