Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Probleme beim Aufruf von Funktionen per String
Delete - Di 22.12.09 21:42
Titel: Probleme beim Aufruf von Funktionen per String
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:
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:
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:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| function TServer.START_SERVER(Parameter: String): TStringList; begin Result:= TStringList.Create; Result.Add(Parameter + 'test'); 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 [
http://www.delphipraxis.net/topic6798.html] übernommen.
Moderiert von
Narses: Code- durch Delphi-Tags ersetzt
Narses - Mi 23.12.09 00:06
Moin!
Barzi hat folgendes geschrieben : |
| 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:
Barzi hat folgendes geschrieben : |
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; | |
Du solltest besser die Stringliste als Parameter mitgeben. Und was machst du, wenn das Objekt in den Funktionen nicht angelegt werden kann? :nixweiss:
Barzi hat folgendes geschrieben : |
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 [http://www.delphipraxis.net/topic6798.html] ü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
Delete - 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 - Mi 23.12.09 00:58
ich glaube, er meint, du sollst c als c: function(Parameter: String):TStringList; of object; deklarieren.
Narses - Mi 23.12.09 01:06
Moin!
Barzi hat folgendes geschrieben : |
| 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: ;)
Barzi hat folgendes geschrieben : |
| 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. ;)
Barzi hat folgendes geschrieben : |
| 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): :?:
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) 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
Kha - Mi 23.12.09 01:13
Barzi hat folgendes geschrieben : |
| 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
Delphi-Quelltext
1:
| class function START_SERVER(Parameter: String): TStringList; static; |
usw. deklarieren.
/edit
@Boldar: Das dürfte nicht funktionieren, weil dir der Self-Zeiger fehlt. Da musst du über TMethod gehen:
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/System__TObject__MethodAddress@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 - Mi 23.12.09 01:15
Moin!
Kha hat folgendes geschrieben : |
| 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
Delete - 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
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!