Autor Beitrag
Barzi
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 22.12.09 21:42 
Hallo!
Ich bin im Moment dabei einen Server mit Hilfe von der IdTCPServer-Komponente zu programmieren, den man über eine Konsole steuern kann.

Die Eingabe der Befehle erfolgt über eine ComboBox, sodass man z.B. den String "START_SERVER(84)" als Befehl erhält.
Damit nun der Server auf Port 84 gestartet wird hab ich mir bisher folgendes überlegt:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
type
  TServer = class
  public
    function SendCommand(Line: String): TStringList;
  published
    function START_SERVER(Parameter: String): TStringList;
    function STOPP_SERVER(Parameter: String): TStringList;
    function HELP(Parameter: String): TStringList;
    function CLEAR(Parameter: String): TStringList;
    function VERSION(Parameter: String): TStringList;
  end;

In der Klasse TServer sind neben der Funktion zum Absenden eines Befehls ein Haufen von Unterbefehlen definiert, die man in die Konsole eingeben kann. Die Funktionen geben alle eine StringList zurück, die im Konsolenfenster angezeigt wird.
Die Funktion SendCommand ist nun wie folgt definiert:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
function TServer.SendCommand(Line: String): TStringList;
  var
    State: TStringList;
    c: function(Parameter: String):TStringList;
begin
  Result:= TStringList.Create; 
  try
     State:= TStringList.Create;
     c:= TServer.MethodAddress('START_SERVER');
     State:= c('bla');
     if State.Count <> 0 then
      Result.AddStrings(state);
     State.Free;
  except
    Result.Add('Fehler: %Details noch nicht implementiert%');
  end;
end;

Ich ermittle also mit MethodAddress die entsprechende Funktion START_SERVER und rufe sie auf.
Bis hierhin klappt auch alles wunderbar. Alle Befehle werden ausgeführt (z.B. "CLEAR" oder "VERSION"). Auch "START_SERVER" wird fehlerlos aufgerufen, allerdings macht mir der Parameter Probleme. Ich kann nicht auf "Parameter" zugreifen ohne Zugriffsverletzungen zu verursachen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function TServer.START_SERVER(Parameter: String): TStringList;
begin
  Result:= TStringList.Create;
  Result.Add(Parameter + 'test'); 
  // müsste ja eigentlich "blatest" ergeben, verursacht aber EAccessViolation
end;

Irgendwas scheint bei der Parameterübergabe falsch zu laufen, den auch der Debugger zeigt für die Parametervariable nur wirres Zeug an.
Habt ihr eine Idee, was falsch laufen könnte? Die ganze Lösung ist zugegeben ja etwas ungewöhnlich - ich habe sie übringens von hier übernommen.

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 23.12.09 00:06 
Moin!

user profile iconBarzi hat folgendes geschrieben Zum zitierten Posting springen:
Die Funktionen geben alle eine StringList zurück,
Das ist keine so gute Idee, denn spätestens hier schießt du dir selbst damit ins Bein:
user profile iconBarzi hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
function TServer.SendCommand(Line: String): TStringList;
  var
    State: TStringList;
    c: function(Parameter: String):TStringList;
begin
  Result:= TStringList.Create; 
  try
     State:= TStringList.Create; // Objekt anlegen...
     c:= TServer.MethodAddress('START_SERVER');
     State:= c('bla'); // ...und direkt "wegwerfen" (weil da ein neues in der Funktion angelegt wird) -> MemoryLeak!
     if State.Count <> 0 then
      Result.AddStrings(state);
     State.Free;
  except
    Result.Add('Fehler: %Details noch nicht implementiert%');
  end;
end;
Du solltest besser die Stringliste als Parameter mitgeben. Und was machst du, wenn das Objekt in den Funktionen nicht angelegt werden kann? :nixweiss:

user profile iconBarzi hat folgendes geschrieben Zum zitierten Posting springen:
Ich ermittle also mit MethodAddress die entsprechende Funktion START_SERVER und rufe sie auf.
Bis hierhin klappt auch alles wunderbar. Alle Befehle werden ausgeführt (z.B. "CLEAR" oder "VERSION"). Auch "START_SERVER" wird fehlerlos aufgerufen, allerdings macht mir der Parameter Probleme. Ich kann nicht auf "Parameter" zugreifen ohne Zugriffsverletzungen zu verursachen:
[...]
Habt ihr eine Idee, was falsch laufen könnte? Die ganze Lösung ist zugegeben ja etwas ungewöhnlich - ich habe sie übringens von hier übernommen.
Interessanter Ansatz (schon etwas quer :?), aber nicht zuende gelesen, oder? ;) Da wird eine Methode zurückgeliefert, das ist was anderes, als eine normale Funktion! :les: :idea:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Barzi
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.12.09 00:35 
Danke für deine schnelle Antwort! :)
Also ich habe mir ja schon irgendwie gedacht das diese Lösung mit den StringLists suboptimal ist. Werde das wohl auf Parameterübergabe umstellen - irgendwie auch viel geschickter ;)

Zitat:

Interessanter Ansatz (schon etwas quer :?), aber nicht zuende gelesen, oder? ;) Da wird eine Methode zurückgeliefert, das ist was anderes, als eine normale Funktion! :les: :idea:

Ich verstehe nicht was du mir damit sagen willst? Ich habe schon bemerkt, dass das eine Funktion ist im Gegensatz zum Original, wo eine Prozedur verwendet wird. Aber sie sind trotzdem beide in einer Klasse (heißt das dann nicht Methode? :?) und der Aufruf funktioniert ja - bis auf die Parameterübergabe. Also was ist jetzt der Fehler? Funktioniert es nur mit Prozeduren? Mir fehlt wahrscheinlich ein wenig die OOP-Theorie :?
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Mi 23.12.09 00:58 
ich glaube, er meint, du sollst c als c: function(Parameter: String):TStringList; of object; deklarieren.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 23.12.09 01:06 
Moin!

user profile iconBarzi hat folgendes geschrieben Zum zitierten Posting springen:
Also ich habe mir ja schon irgendwie gedacht das diese Lösung mit den StringLists suboptimal ist. Werde das wohl auf Parameterübergabe umstellen
Dann aber auch gleich auf TStrings, ist praktischer. :idea: ;)

user profile iconBarzi hat folgendes geschrieben Zum zitierten Posting springen:
Ich verstehe nicht was du mir damit sagen willst? Ich habe schon bemerkt, dass das eine Funktion ist im Gegensatz zum Original, wo eine Prozedur verwendet wird. Aber sie sind trotzdem beide in einer Klasse (heißt das dann nicht Methode?
Das ist schon richtig, Methoden sind Mitglieder einer Klasse (ob Prozedur oder Funktion ist erstmal egal), aber eine Delphi-Methode besteht aus zwei Zeigern, einmal die Selbstreferenz auf die Klasseninstanz und den Zeiger auf den auszuführenden Code. ;)

user profile iconBarzi hat folgendes geschrieben Zum zitierten Posting springen:
und der Aufruf funktioniert ja - bis auf die Parameterübergabe. Also was ist jetzt der Fehler? Funktioniert es nur mit Prozeduren? Mir fehlt wahrscheinlich ein wenig die OOP-Theorie :?
Nicht böse sein, aber wenn man die Interna der Delphi-OOP-Implementation nicht kennt, sollte man besser die Finger davon lassen. :? :nixweiss:

Ich schätze mal, du meinst irgendwie sowas (wobei natürlich die Parameter an die untergeordnete Funktion dann aus dem übergebenen String an SendCommand() extrahiert werden sollen): :?:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
type
  TServer = class(TObject)
  public
    procedure SendCommand(const ACmdLine: String; AOutput: TStrings);
  published
    procedure START_SERVER(const ACmdLine: String; AOutput: TStrings);
  end;

implementation

procedure TServer.SendCommand(const ACmdLine: String; AOutput: TStrings);
  var
    TheMethod: procedure(Self: TServer; const ACmdLine: String; AOutput: TStrings);
begin
  TheMethod := TServer.MethodAddress(ACmdLine);
  if Assigned(TheMethod) then
    TheMethod(Self,'MyParam',AOutput) // MyParam ist hier nur Platzhalter
  else
    AOutput.Add('Unbekanntes Kommando!');
end;

procedure TServer.START_SERVER(const ACmdLine: String; AOutput: TStrings);
begin
  AOutput.Add('START_SERVER -> '+ACmdLine);
end;

procedure TForm1.Button1Click(Sender: TObject);
  var
    Server: TServer;
begin
  Server := TServer.Create;
  try
    Server.SendCommand(Edit1.Text,Memo1.Lines);
  finally
    Server.Free;
  end;
end;
cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 23.12.09 01:13 
user profile iconBarzi hat folgendes geschrieben Zum zitierten Posting springen:
Ich verstehe nicht was du mir damit sagen willst?
Dann schau dir den letzten Post im verlinkten Thread an, darkstone dürfte nämlich recht haben ;) . of object kennzeichnet einen Methodenzeiger (also das, was du brauchst), der noch einen versteckten Self-Parameter mitschleppt. Deswegen kracht es auch: Du übergibst nur einen Parameter, obwohl die Funktion in Wirklichkeit zwei erwartet.
Da du aber wohl sowieso keine TServer-Instanz brauchst, kannst du deinen SendCommand-Code so lassen und die restlichen Methoden als
ausblenden Delphi-Quelltext
1:
class function START_SERVER(Parameter: String): TStringList; static// oder eben mit TStringList-Parameter					

usw. deklarieren.

/edit
@Boldar: Das dürfte nicht funktionieren, weil dir der Self-Zeiger fehlt. Da musst du über TMethod gehen: docs.embarcadero.com...ess@ShortString.html

/edit²
@Narses: Wenn der Parameter so einfach ans Licht geholt werden kann, ok. Ist mir aber etwas zu sehr von Compiler-Interna abhängig... was natürlich mehr oder weniger auf alle bisherigen Vorschläge zutrifft ;) .

_________________
>λ=
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 23.12.09 01:15 
Moin!

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Wenn der Parameter so einfach ans Licht geholt werden kann, ok. Ist mir aber trotzdem etwas zu sehr von Compiler-Interna abhängig ;) .
Jap. ;) Deshalb mein Hinweis, besser die Finger von sowas zu lassen. :nixweiss:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Barzi
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.12.09 01:24 
Ah Super - ihr seit genial! Vielen Dank! :D
Tut mir leid das ich mich mit meinem Halbwissen und copy&paste Hals über Kopf in diese Aufgabe gestürzt habe :?
Naja, wieder was gelernt - nochmals vielen Dank :P