Skicka delphi-meddelanden. Delphi

Skicka delphi-meddelanden. Delphi

Meddelandebearbetningssekvens i Delphi
Alla Delphi-klasser har en inbyggd meddelandehanteringsmekanism som kallas meddelandehanterare. Klassen tar emot ett meddelande och anropar en av en uppsättning definierade metoder beroende på det mottagna meddelandet. Om motsvarande metod inte är definierad anropas standardhanteraren. Mer detaljerat fungerar denna mekanism enligt följande.

Efter att ett meddelande har tagits emot gör VCL-meddelandesystemet mycket förarbete för att bearbeta det.

Som noterats ovan behandlas meddelandet initialt av metoden TApplication.ProcessMessage, som väljer det från kön i huvudmeddelandeslingan. Samtidigt kontrollerar den innehållet i FOnMessage-fältet (kontrollerar faktiskt om det finns en hanterare för OnMessage-händelsen) och, om den inte är tom, anropar den hanteraren för denna händelse, och om fältet är tomt ( Noll), anropar sedan DispatchMessage(Msg) API-funktionen. Detta händer inte när du skickar ett meddelande.

Om OnMessage-händelsehanteraren inte är definierad anropas DispatchMessage API-funktionen för att behandla det mottagna meddelandet, vilket skickar meddelandet till fönstrets huvudprocedur.

Låt oss överväga meddelandebearbetningsslingan efter att den kommit till komponentens huvudfönster. Meddelandebearbetningssekvensen visas i följande figur:

Det kan ses att meddelandet skickas till MainWndProc, sedan till WndProc, sedan till Dispatch och sedan till DefaultHandler.

Delphi har en huvudsaklig icke-virtuell metod MainWndProc(Var Message: TMessage) för fönstret för varje komponent. Den innehåller ett undantagshanteringsblock som skickar meddelandestrukturen från Windows till den virtuella metoden som definieras i egenskapen WindowProc. Den här metoden hanterar dock alla undantag som inträffar under meddelandebehandling genom att anropa programmets HandleException-metod. Från denna plats kan du tillhandahålla Special behandling meddelanden, om det krävs av logiken i ditt program. Vanligtvis ändras bearbetningen i detta skede för att förhindra att standard VCL-bearbetning äger rum.

Som standard initieras värdet på objektets WindowProc-egenskap till adressen för den virtuella metoden WndProc. Om det inte finns några registrerade TWindowHook-meddelandehakar, anropar WndProc den virtuella metoden TObject.Dispatch, som, med hjälp av Msg-fältet i strukturen för inkommande meddelanden, avgör om detta meddelande finns i listan över meddelandehanterare för detta objekt. Om objektet inte hanterar meddelandet undersöks listan över förfadermeddelandehanterare. Om en sådan metod till slut hittas, anropas den, annars anropas den virtuella DefaultHandler-metoden.

Slutligen når meddelandet det lämpliga bearbetningsförfarandet, där den bearbetning som är avsedd för det utförs. Genom att använda nyckelordÄrvt skickas det vidare för bearbetning i förfäder. Efter det hamnar meddelandet också i DefaultHandler-metoden, som utför de sista åtgärderna vid meddelandebehandling och skickar det till DefWindowProc (DefMDIProc)-proceduren för standard Windows-bearbetning.

Hantera meddelanden med Delphi-komponenter
Således, kort beskrivning meddelandebehandlingssekvensen är som följer. Alla meddelanden passerar initialt genom metoden vars adress anges i egenskapen WindowProc. Som standard är detta WndProc-metoden. Därefter separeras de och skickas enligt deras meddelandemetoder. I slutet konvergerar de igen i DefaultHandler-metoden om de inte bearbetades tidigare eller om den ärvda hanteraren (Inherited) anropas i hanterarna. Därför har Delphi-komponenter följande funktioner för att hantera meddelanden:
a) Innan någon meddelandehanterare ser meddelandet. I det här fallet krävs antingen ersättning av metodadressen i egenskapen WindowProc eller ersättning av metoden TControl.WndProc.
WindowProc-egenskapen deklareras enligt följande:

Toure TWndMethod= procedur(Var Message: TMessage) av objekt;
fast egendom WindowProc: TWndMethod;

Faktum är att med WindowProc-egenskapen kan du skapa en metod av typen TWndMethod och tillfälligt ersätta den ursprungliga metoden med den skapade, men eftersom metodadressen inte lagras i WindowProc-egenskapen måste du först lagra originalets adress WndProc-metoden så att den kan återställas senare.

OldWndProc: TWndMethod;
procedure NewWndProc(var Meddelande: TMessage);
procedure TForm1.NewWndProc(var Meddelande: TMessage);
var Ch: char;
Börja
om message.Msg= WM_MOUSEMOVE så börja
Edit1.Text:='x='+inttostr(meddelande.LParamLo)+', y='+inttostr(meddelande.LParamHi);
slutet
else WndProc(Meddelande);
slutet;

procedur TForm1.FormCreate(Avsändare: TObject);
Börja
OldWndProc:=WindowProc;
slutet;

procedure TForm1.CheckBox1Click(Avsändare: TObject);
Börja
Om CheckBox1.Checked då WindowProc:= NewWndProc
else WindowProc:= OldWndProc;
slutet;

b) Inuti motsvarande meddelandemetod.
Låt oss ta ett annat liknande exempel.
Använd meddelandet som skickats till komponenter för att rita om WMPAINT.

I klassen TForml kommer vi att deklarera denna metod för att åsidosätta den och presentera implementeringen av den åsidosatta meddelandemetoden:

Skriv TForml=Klass(TForm)
… // Alla andra nödvändiga förklaringar
skyddad
Procedur WMPaint(Var Msg: TWMPaint); Meddelande WM_PAINT; slutet;
Procedur TForml.WMPaint(Var Msg: TWMPaint); Börja
If CheckBox1.Checked Then ShowMessage('O6pa6o meddelandekontroll!');
Ärvt;
slutet;

När du åsidosätter specifika meddelandehanterare är det alltid en bra idé att ringa Inherited för att utföra den grundläggande meddelandebehandling som Windows behöver.

c) Efter att var och en av metoderna som motsvarar meddelandet ser det.

I det här fallet måste du åsidosätta DefaultHandler.

procedure DefaultHandler(varMessage); åsidosätta;
procedure TForm1.DefaultHandler(var Message);
var i:integer;
Börja
om Cardinal(Meddelande)=WM_defh då
för i:= 0 till 10 börjar
pip;
sömn(100);
slutet
annan
ärvt;
slutet;

procedur TForm1.Button5Click(Avsändare: TObject);
Börja
SendMessage(Handle,WM_defh,0,0);
slutet;

Kommunikation mellan meddelanden och händelser
Många Delphi VCL-händelser är direkt relaterade till Windows-meddelanden. I hjälpsystem Delphi listar dessa matchningar. De presenteras i tabell.1.

bord 1

VCL-evenemangWindows meddelandeVCL-evenemangWindows meddelande
PåAktiveraWM_ACTIVATEOnKeyPressWM_CHAR
onclickWM_LBUTTONDOWNOnKeyUpWM_KEYUP
OnCreateWM_CREATEOnPaintWM_PAINT
OnDblClickWM_LBUTTONDBLCLKPå Ändra storlekWM_SIZE
OnKeyDownWM_KEYDOWNPå timerWM_TIMER

Du bör inte skapa meddelandehanterare om det finns en fördefinierad händelse för det. I dessa fall är det vettigt att använda händelsehantering eftersom det är mindre restriktivt.

När man utvecklar applikationer kan det finnas en situation där en applikation behöver skicka ett meddelande antingen till sig själv eller till en annan användarapplikation. Vissa kan bli förbryllade över det tidigare uttalandet: varför ska en ansökan skicka ett meddelande till sig själv när du helt enkelt kan ringa till lämplig procedur? Detta bra fråga, och det finns flera svar på det. För det första är användningen av meddelanden en mekanism för att stödja verklig polymorfism eftersom det inte kräver någon kunskap om typen av objekt som tar emot meddelandet. Således har meddelandetekniken samma kraft som den virtuella metodmekanismen, men har mycket mer flexibilitet. För det andra tillåter meddelanden valfri bearbetning - om mottagarobjektet inte behandlar det inkommande meddelandet kommer inget hemskt att hända. Och för det tredje låter meddelanden dig sända till flera mottagare och organisera parallelllyssning, vilket är ganska svårt att implementera med hjälp av proceduranropsmekanismen.

Använda meddelanden i en applikation

Att få en applikation att skicka ett meddelande till sig själv är väldigt enkelt - använd bara funktionerna API-gränssnitt Win32 SendMessage() eller PostMessage(), eller metoden Perform(). Meddelandet måste ha ett ID i intervallet WM_USER+100 till $7FFFF (som Windows reserverar för användarmeddelanden). Till exempel: konst

SX_MYMESSAGE = WM_USER + 100;

SomeForm.Perform(SX_MYMESSAGE, 0, 0);

SendMessage(SomeForm.Handle, SX_MYMESSAGE, 0, 0);

PostMessage(SomeForm.Handle, SX_MYMESSAGE, 0, 0);

Sedan, för att fånga upp det här meddelandet, skapa en normal hanterarprocedur som utför de nödvändiga åtgärderna i formuläret:

TForm1 = klass(TForm)

procedure SXMyMessage(var Msg: TMessage); meddelande SX_MYMESSAGE;

procedure TForm1.SXMyMessage(var Msg: TMessage);

MessageDlg('Hon gjorde mig till en vattensalamander!',

mtInformation, , 0);

Som du kan se i exemplet är det liten skillnad i hur ett inbyggt meddelande behandlas från ett standard Windows-meddelande. De består av att använda identifierare som sträcker sig från WM_USER+100 och uppåt, samt att ge varje meddelande ett namn som på något sätt kommer att återspegla dess betydelse.

Skicka aldrig meddelanden med ett WM_USER-värde större än $7FFF om du inte är helt säker på att mottagaren kan behandla meddelandet korrekt. Eftersom varje fönster självständigt kan välja de värden det använder, är det mycket sannolikt att subtila buggar uppstår om du inte skapar tabeller med meddelandeidentifierare i förväg som alla avsändare och mottagare av meddelanden kommer att arbeta med.

Meddelanden mellan applikationer

Om du behöver utbyta meddelanden mellan två eller flera applikationer bör du använda API-funktionen RegisterWindowMessage() i dem. Denna metod säkerställer att för en given meddelandetyp kommer varje applikation att använda samma meddelandenummer(meddelandenummer).

Funktionen RegisterWindowMessage() tar som en parameter en sträng med

avslutas med ett nolltecken och returnerar ett ID i intervallet $C000 - $FFFF för det nya meddelandet. Detta innebär att det räcker att anropa denna funktion med samma sträng som en parameter i vilken applikation som helst för att garantera samma meddelandenummer i alla applikationer som deltar i utbytet. En annan fördel med en sådan funktion är att systemet garanterar att identifieraren som är tilldelad en given rad är unik. Detta gör att broadcast-meddelanden kan skickas till alla befintliga fönster i systemet utan rädsla för oönskade bieffekter. nackdel den här metodenär en komplikation med att bearbeta sådana meddelanden. Summan av kardemumman är att meddelande-ID endast är känt när applikationen körs, så det är inte möjligt att använda standardrutinerna för meddelandehantering. För att arbeta med sådana meddelanden måste du definiera om standardmetoder WndProc() eller DefaultHandler() kontroller, eller motsvarande fönsterklassprocedurer.

PÅ EN NOTERA

Numret som returneras av funktionen RegisterWindowMessage() genereras dynamiskt och kan ta olika betydelser likgiltig Windows-sessioner, vilket innebär att det inte kan fastställas förrän programmet körs.

Sänd meddelanden

Alla klasser som härrör från klassen TWinControl tillåter användning av metoden Broadcast() för att skicka sänd meddelande(sändningsmeddelande) till någon kontroll som den är ägare till. Denna teknik används när det krävs att samma meddelande skickas till en grupp komponenter. Till exempel, för att skicka ett anpassat meddelande med namnet um_Foo till alla kontroller som hör till Panel1-objektet, kan du använda följande kod:

Meddelande:= UM_FOO;

Utveckla ett program som kommer att tillhandahålla ett gränssnitt för att använda Win2000/XP-standardkommandot net send messaging. Tillåt användaren att ange mottagarens adress, meddelandetext och antalet meddelanden som ska skickas. Ge även möjligheten att sätta ett block för att ta emot meddelanden från andra datorer.

Formutveckling

Skapa ett nytt Delphi-projekt. Ändra formulärets titel (Caption-egenskapen) till Net Sender. Placera tre etikettkomponenter av kategorin ovanför varandra längs formulärets vänstra kant standard och ställ in deras Caption-egenskap till IP Address:, Message: och Quantity:.

Bredvid var och en av etiketterna placerar du en redigeringskomponent för kategorin standard. Namnge den översta ip (namnegenskap) och tilldela värdet 192.168.0.1 till egenskapen Text; namnge mittfältet txt och tilldela viss standardmeddelandetext till egenskapen Text; Ge det nedre fältet ett namn och ställ in egenskapen Text till 1.

Placera kategorin Kryssrutakomponent under de listade komponenterna standard. Namnge den säker, ställ in Caption-egenskapen till Inaktivera mottagning av meddelanden och ställ in den Checked-egenskapen till True.

Placera en knapp längst ner i formuläret (Knappkomponenten i standard) genom att ställa in dess Caption-egenskap till Skicka. Vi behöver också en timer (timerkomponenten i Systemet), för vilken egenskapen Interval ska ställas in på 10.

Den resulterande formen bör motsvara fig. 15.1.

Ris. 15.1. Formulär för programmet att skicka meddelanden till lokalt nätverk

Utveckling av programkod

Först av allt, låt oss skriva vår egen bombprocedur som kommer att läsa alla inställningar och skicka ett meddelande. Deklarera denna procedur som en privat medlem av formulärklassen:

Vi behöver också en global variabel i av typen heltal:

Låt oss nu skapa en implementering av bombproceduren i implementeringssektionen:

procedur TForm1.bomb();
om how.Text= "" sedan how.Text:= "1";
om ip.Text = "" då ip.Text:= "127.0.0.1";(om ip-adressen inte anges skickar vi den till den lokala datorn)
WinExec(PChar("net send " + ip.Text + """ + txt.Text + """), 0);//skicka meddelande

Denna procedur kontrollerar om alla obligatoriska fält är ifyllda. Om det inte finns någon meddelandetext, ställ in tecknet "!"; om IP-adressen inte anges skickar vi ett meddelande till den lokala datorn med adressen 127.0.0.1; om antalet meddelanden inte anges skickar vi ett meddelande. Meddelanden skickas med hjälp av standardkommandot net send, som har följande syntax:

nät skicka ip-adress meddelande.

Låt oss nu hantera timerns OnTimer-händelse:

h: HWND;//lagrar fönster-ID
om det inte är säkert. Kontrolleras då//om kryssrutan inte är markerad
Timer1.Enabled:= False;//inaktivera övervakning
om det är säkert. Kontrolleras då//om kryssrutan är markerad
//leta efter fönster med meddelanden
h:= FindWindow(noll, "Meddelandetjänst ");// stäng alla hittade fönster
om h<>

Om kryssrutan Inaktivera mottagning av meddelanden är markerad, börjar vi övervaka fönster vars titel säger att detta är ett meddelande och stänger alla hittade fönster. Om kryssrutan inte är markerad är övervakningen inaktiverad.

För att kunna växla mellan dessa två lägen måste du skapa en säker.OnClick-händelsehanterare:

om det är säkert. Kontrolleras då//om kryssrutan är markerad...
Timer1.Enabled:= Sant;//... aktivera övervakning

När du trycker på en knapp skicka vi kallar bara bombproceduren:

För att göra livet enklare för användaren ser vi till att meddelandet också skickas genom att trycka på knappen i valfritt textinmatningsfält. För att göra detta måste du skapa en OnKeyPress-händelsehanterare för vart och ett av fälten. Koden för denna hanterare för ip-fältet, som sedan kan tilldelas till txt- och hur-fälten:

om nyckel= #13 då//om en tangent trycks ned
bomba;//skicka meddelande

Hela modulens källkod

Den fullständiga koden för LAN-meddelandeprogrammodulen visas i Lista 15.1.

Notering 15.1. Programmodul för LAN-meddelanden

Windows, meddelanden, SysUtils, varianter, klasser, grafik, kontroller, formulär, dialogrutor, StdCtrls, ExtCtrls;

procedure Timer1Timer(Avsändare: TObject);
procedure secureClick(Avsändare: TObject);
procedure ipKeyPress(Avsändare: TObject; var Key: Char);
procedure txtKeyPress(Avsändare: TObject; var Key: Char);
procedure howKeyPress(Sender: TObject; var Key: Char);
procedure Button1Click(Avsändare: TObject);


// kontrollera om textmeddelandet inte är tomt
om txt.Text = "" då txt.Text:= "!";
//om kvantiteten inte är specificerad, skicka ett meddelande
if how.Text= "" then how.Text:= "1";
om ip.Text = "" då ip.Text:= "127.0.0.1"; (om ip-adressen inte anges skickar vi den till den lokala datorn)
//skicka det angivna antalet meddelanden
för i:=1 till StrToInt(how.Text) gör
WinExec(PChar("net send " + ip.Text + """ + txt.Text + """), 0); //skicka meddelande

procedur TForm1.Timer1Timer(Avsändare: TObject);
h: HWND; //lagrar fönster-ID
om inte säkert. Markerad då //om kryssrutan inte är markerad
Timer1.Enabled:= False; //inaktivera övervakning
if secure. Checked then //om kryssrutan är markerad
//leta efter fönster med meddelanden
h:= FindWindow(noll, "Meddelandetjänst "); // stäng alla hittade fönster
om h<>0 sedan PostMessage(h, WM_QUIT, 0, 0);

procedur TForm1.secureClick(Avsändare: TObject);
om säker. Markerad då //om kryssrutan är markerad...
Timer1.Enabled:= Sant; //... aktivera övervakning

procedure TForm1.ipKeyPress(Avsändare: TObject; var Key: Char);
om tangent = #13 så //om en tangent trycks ned
bomba; //skicka meddelande

procedure TForm1.Button1Click(Avsändare: TObject);

⊚ Alla projektfiler och den körbara filen för det aktuella programmet finns på CD:n som bifogas boken i mappen Kapitel 15.

Ofta använder delphi-program e-post. Den här artikeln kommer att förklara fullständigt hur din e-post skickas till en annan användare. använder delphi. I det här fallet kommer vi endast att använda standardkomponenter från Delphi.

Till att börja med, låt oss skapa ett nytt projekt och döpa det till \"Skicka e-post med delphi\". Sedan måste flera komponenter 1x Memo, 3x Edit, 2x Botton överföras till formuläret, och IdSMTP, IdAntiFreeze, IdMessage måste också överföras. Därefter, på onclick-händelsen för valfri knapp, skriver vi:

//välja SMTP-server. I det här ögonblicket kostar yandex. IdSMTP1.Host:= "smtp.yandex.ru"; //din inloggning (för vissa är det nödvändigt att skriva med en domän). IdSMTP1.Användarnamn:=" [e-postskyddad]"; //mail-lösenord. IdSMTP1.Password:= "qwerty123"; //port, vi rekommenderar att du använder 587. IdSMTP1.Port:=587; //ämnet för meddelandet kommer att passa in i Edit2. IdMessage1.Subject:= Edit2 .Text; // Edit1 kommer att innehålla mottagarens adress. IdMessage1.Recipients.EMailAddresses:= Edit1.Text; //din e-post som avsändaren kommer från. IdMessage1.From.Address:= " [e-postskyddad]"; // memo1 kommer att innehålla texten du vill skicka. IdMessage1.Body.Text:= memo1.Text ; // Edit3 kommer att innehålla din elektronisk signatur(Namn). IdMessage1.From.Name:= Edit3.Text; //connect IdSMTP1.connect; //send IdSMTP1.Send(IdMessage1); //koppla IdSMTP1.Koppla bort;

Om IdMessage visar frågetecken

Denna bugg är relaterad till det faktum att du skriver in ryska bokstäver och memokomponenten kan inte läsa dem korrekt, för detta måste du ange Utf8-kodningen.

// set encoding IdMessage1.Charset:="UTF-8"; // översätt texten till den obligatoriska kodningen IdMessage1.Body.Text:=UTF8Encode(memo1.text);

någonstans så

IdTCPClient1.Host:= "127.0.0.1"; IdTCPClient1.Connect;// ansluten IdTCPClient1.Socket.WriteLn("kommando"); // skickade kommandokommando och radmatning //Vänta på svar och stäng anslutningen txtResults.Lines.Append(IdTCPClient1.Socket.ReadLn); IdTCPClient1.Disconnect;

i det här fallet är kommandot bara text med en nyrad. Detta gör det mycket lättare att ta emot ett kommando från andra sidan (bara ReadLn). I det allmänna fallet måste du uppfinna (eller använda ett färdigt) protokoll.

ovanför var det en klient. Och nu servern. Med servern är saker och ting lite mer komplicerade. Det är tydligt att det är normalt att en server servar mer än en klient, många. Och det finns flera "scheman" för detta.

    Klassisk - en klient - en tråd. Kretsen är lätt att koda, intuitiv. Den är väl parallelliserad över kärnorna. Nackdelen är att det vanligtvis är väldigt svårt att skapa många trådar, och det begränsar antalet klienter. För 32-bitarsprogram är den övre gränsen någonstans runt 1500 (ett och ett halvt tusen) trådar per process. Men i det här fallet kan omkostnaderna för att byta dem "äta" hela procentandelen. Detta är schemat som används i indy.

    Den andra klassiska - alla klienter på en stream. Detta schema är ofta mer komplext i kodning, men med rätt tillvägagångssätt låter det dig behålla 20-30 000 "långsamma användare" med praktiskt taget ingen belastning på kärnan. Ett starkt plus med detta schema är att du kan klara dig utan mutexes och andra synkroniseringsprimitiver. Detta schema används av NodeJS och standardklasser för nätverk i Qt.

    Blandad. I det här fallet skapas flera trådar, som var och en betjänar ett visst antal klienter. Den svåraste i kodning, men låter dig använda järnresurser maximalt.

Hur det går till i Indy. Indy tcp-server för varje anslutning skapar en separat tråd (TThread) och ytterligare arbete med klienten går i den. Indy döljer detta på ett bra sätt, och lämnar bara behovet för användaren att implementera metoden IdTCPServer.onExecute. Men, som jag sa ovan, lanseras denna metod i en separat tråd, och varje klient har sin egen personliga. Detta betyder följande:

  • sömn kan anropas med denna metod och endast en klient väntar. Allt annat kommer att fungera (men om du ringer sömn i knappen klicka hanteraren, då är resultatet känt)
    • det är bättre att bara komma åt globala variabler genom synkroniseringsprimitiver.
    • gui-element måste hanteras varsamt och korrekt. Det är bättre att inte göra det direkt (vissa komponenter låter dig komma åt dem från andra trådar, men du måste noggrant läsa bryggorna).
    • du behöver komma åt andra klienter genom ett lås (för om två trådar vill skriva till samma användare kommer det inget bra ur det).

Låt oss titta på ett mycket enkelt exempel. Vi svarar på alla klientförfrågningar på samma sätt och stänger anslutningen (en sådan ekoserver).

Procedur TForm1.IdTCPServer1Execute(AContext: TIdContext); var strText: String; begin //Ta emot en sträng från klienten strText:= AContext.Connection.Socket.ReadLn; //Answer AContext.Connection.Socket.WriteLn(strText); //Stäng anslutningen med användaren AContext.Connection.Disconnect; slutet;

AContext är ett speciellt objekt som innehåller all nödvändig information om klienten. Själva idTcpServer innehåller en lista över dessa sammanhang och kan nås. Låt oss överväga en mer komplex sändning. Det vill säga skicka ett meddelande till alla

VarClients:TList; i: heltal; begin // idiotsäker :) om inte Assigned(IdTCPServer1.Contexts) avsluta då; // få en lista över klienter och lås den Clients:=IdTCPServer1.Contexts.LockList; försök för i:= 0 till Clients.Count-1 försök //LBuffer är av typen TBytes och innehåller förberedd data att skicka // men WriteLn kan också användas. TIdContext(Clients[i]).Connection.IOHandler.Write(LBuffer); förutom att // logik måste läggas till här. Klienten kan koppla från under slutet; äntligen // viktigt! listan måste vara upplåst, annars kommer andra metoder inte att kunna gå utöver Contexts.LockList IdTCPServer1.Contexts.UnlockList; slutet; slutet;

indie innehåller BytesToString() och ToBytes() för att konvertera String och TIdBytes till varandra.

Listan är låst så att andra inte kan ändra den. Annars blir själva cykeln mycket mer komplicerad. Och viktigast av allt, glöm inte att låsa upp!

Den sista frågan återstår. Hur man skickar ett meddelande till en specifik klient. För att göra detta måste du lära dig hur du identifierar anslutningen. Detta kan göras på flera sätt - titta på ip/port. Men det finns bättre. IdContext (mer exakt, dess förfader idTask) har en Data-egenskap av typen TObject. Du kan skriva ditt objekt till det och lagra all nödvändig data där. Typiskt exempel användning kommer nästa. När klienten precis har anslutit är detta fält tomt. När den klarat namn-lösenordskontrollen skapar vi ett objekt (vårt eget), sparar namnet där och skriver det till Data-egenskapen. Och sedan, när du behöver gå igenom de anslutna klienterna, subtraherar vi det helt enkelt. Om det finns tusentals användare blir det naturligtvis dyrt att se alla användare varje gång. Men hur man gör det mer optimalt är ämnet för en annan stor artikel.