Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Multi-Event-Liste (https://www.delphipraxis.net/191050-multi-event-liste.html)

Ghostwalker 2. Dez 2016 12:17

Multi-Event-Liste
 
Hi,

ich bin gerade drüber mir eine "Multi-Event-Liste" zu bauen, die verschiedene Event-Typen mehrfach
speichert und ggf. auch ausführt.


Delphi-Quellcode:
TYPE
  PEventEntry = ^TEventEntry;
  TEventEntry = record
                  method : TMethod;
                  ident : widestring;
  end;

  TIndexArray = array of Integer;


  TEventList = Class(TObject)
    private
       flist : TList;
    protected
       procedure Clear;

       function indexOf(value:TMethod;ident:widestring):integer;

    public
       Constructor Create;
       Destructor Destroy;override;

       Procedure Add(value:TMethod;ident:widestring);
       procedure Del(value:TMethod;ident:widestring);

       function getIdentCount(ident:widestring):integer;
       function getIdentIndexs(ident:widestring):TIndexArray;
       function getMethodByIdent(idx:integer;ident:widestring):TMethod;

    published
  End;
Nun würd ich gerne das ansprechen (Auslösen quasi) der einzelnen Eventhandler-Typen ebenfalls in die Liste verlagern (abfolge is ja immer gleich, nur die Parameter sind unterschiedlich).

Und genau da häng ich im Moment.

Ich würde das ganze gerne in form: eventlist.execute('TMyEventType',[param1,param2]) aufrufen.

TMethod als solches kennt aber keine Parameter, und den Typ des Events hab ich (im Moment) nur als String, so das ich hier auch nicht casten kann.

Hat jemand einen Lösungsansatz oder sowas für das Problem ?

Jens01 2. Dez 2016 13:41

AW: Multi-Event-Liste
 
Bei dem Spring4D-Projekt gibt es so ein Ding.

Ghostwalker 2. Dez 2016 17:42

AW: Multi-Event-Liste
 
Jep...und auch in DSharp. Beides ist für mich aber nicht wirklich brauchbar. Mein Delphi (und der Rechner) sind dafür schon ein bischen alt :)


Bei der Suche nach einer Lösung bin ich auf diesen Beitrag gestoßen:

http://www.delphipraxis.net/171641-a...orrekt-so.html

Problem ist der Parametertyp PParameters. Den kennt mein Delphi nicht, also hab ich das
mal einfach als Pointer definiert.

Damit kann ich eine Methode ohne Parameter (bzw. nur mit self als Parameter) aufrufen. Andere
Parameter mag er so aber nicht.

Kann mir da jemand sagen wie PParameter in neueren Delphis definiert ist ?

Ghostwalker 4. Dez 2016 23:07

AW: Multi-Event-Liste
 
So..hab ein wenig weiter probiert. Folgende Methode ist dabei soweit rausgekommen:

(Gekürzt...Problem ist der ASM-Teil):

Delphi-Quellcode:
procedure TEventList.CallInvoke(method: TMethod; params: array of const);
var
  :
  Regs     : array[plEAX..plECX] of Cardinal;
  doStack  : boolean;
  stack    : array[0..1023] of Byte;
  stacksize : integer;
  sc       : integer;
  p        : Pointer;


begin
  Regs[plEAX] := Cardinal(Method.data);
  if (doStack) then
  begin
    fillchar(stack,sizeof(stack),0);
    StackSize := Sizeof(TVarRec)*(Length(Params));
    sc := 0;
    for I := High(params) downto Low(Params) do
    begin
      move(params[i],stack[sc],sizeof(params[i]));
      inc(sc,sizeof(params[i]));
    end;
    p := @Stack;
    asm
            SUB    ESP,Stacksize
            MOV    p,ESP
    end;
    Regs[plEDX] := Cardinal(p);
    Regs[plECX] := Cardinal(Stacksize);
  end
  else
  begin
    for I := 0 to MethSig.ParamCount - 1 do
    begin
      if (MethSig.parameters[i].location <> plEax) AND (MethSig.parameters[i].ParamName <> 'Self') then
         Regs[MethSig.Parameters[i].Location] := GetValueAsCardinal(params[i-1]);
    end;
  end;
  // Do the call
  asm
            MOV    EAX,DWORD PTR Regs[0]
            MOV    EDX,DWORD PTR Regs[4]
            MOV    ECX,DWORD PTR Regs[8]
            CALL   Method.code
            MOV    DWORD PTR Regs[0],EAX
            MOV    DWORD PTR Regs[4],EDX
  end;
End;
Zum Testen verwendig ich folgenden Aufruf:

Delphi-Quellcode:
var
  rec : TTestRec;

begin
  rec.aInteger := 55779;
  rec.aString := 'More wide string to process';
  rec.aBool := TRUE;
  fevents.Execute('TEventType5',[150,333,42,'Schweine im Weltraum oder Trampen leicht gemacht',FALSE,1.5647,'Normal String','Another very wide String',@rec,2357]);
end;
TEventType5 ist so definiert:

Delphi-Quellcode:
   TEventType5 = Procedure(v1:integer;v2:integer;v3:integer;v4:Widestring;v5:boolean;v6:double;v7:string;v8:widestring;v9:TTestRec;v10:integer) of object;
Soweit so gut. Leider Schepperts beim Aufruf der obigen Methode mit diesem EvenType. Benutze ich
einen mit nur 2 oder 1 Parameter (egal was für ein Typ) funktioniert das ganze. Also hakt es mit
dem Stack-Teil. Könnte mir da jemand bitte helfen ?

Stevie 5. Dez 2016 12:14

AW: Multi-Event-Liste
 
Hol dir Delphi 10 Berlin Starter für lau und nimm Spring4D :mrgreen:

Zu deinem Problem:
du kannst nicht einfach alle Parametertypen gleich behandeln. Siehe http://www.guidogybels.eu/asmtable3.html

Ghostwalker 5. Dez 2016 12:46

AW: Multi-Event-Liste
 
Jup...weiß ich. Bin inzwischen ein wenig weiter gekommen.

Statt der Methode aus der ObjAuto, verwend ich deine Routine aus DSharp.

Dabei bau ich den PParameters selbst zusammen, anhand der Typen.

Delphi-Quellcode:
  //Fillup PParameters for calling the method and handling the stack
  //and calculating the Stacksize
  New(para);
  fillchar(para^,sizeof(para^),0);
  StackSize := 0;
  sc := 0;
  for i := MethSig.paramCount-1 downto 1 do
  begin
    case MethSig.Parameters[i].Location of
       plEDX : para^.Registers[plEDX] := GetValueAsCardinal(params[i-1]);
       plECX : Para^.Registers[plECX] := GetValueAsCardinal(params[i-1]);
    ELSE
      if(MethSig.Parameters[i].Location > plECX) then
      begin
        v := @params[i-1];
        MoveValue(v,para,stacksize);
      end;
    end;
  end;
  InvokeMethod(Method,para,stacksize);
  dispose(para);
Aufruf:

Delphi-Quellcode:
fevents.Execute('TEventType6',[150,333,42,true,'Wuptidupti']);
Das Problem ist der 3 Parameter im Array (also die 42), die wird einfach mit 0 übergeben. Der Rest passt.

Ghostwalker 5. Dez 2016 13:18

AW: Multi-Event-Liste
 
Jut...auch das Problem ist gelöst. Lag an der Stackgröße die bei Boolean und Char falsch berechnet wurde.....dafür ist nu ein neues aufgetreten.

Nämlich wenn ich mehrere Widestrings übergeben will....mal guggen.

Ghostwalker 5. Dez 2016 13:32

AW: Multi-Event-Liste
 
Auch erledigt. Bei Stringkonstanten (execute(...,['wupti']); wird automatisch ein AnsiString draus gemacht. Wenn die ZielMethode natürlich Widestring erwartet ist das nicht gut.

Ghostwalker 5. Dez 2016 14:03

AW: Multi-Event-Liste
 
Geschaft.....MultiEvent-Liste funktioniert soweit (siehe Testprojekt im Anhang).

Tests, Anregungen usw. sind natürlich immer willkommen :)

Auf meiner TODO-Liste dafür:


- Records als Parameter
- autom. Type-Konvertierung (versch. String-Typen z.B.)

DeddyH 5. Dez 2016 14:08

AW: Multi-Event-Liste
 
Anhang?

Ghostwalker 5. Dez 2016 14:09

AW: Multi-Event-Liste
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ja...kommt gleich....Browser streikt grad :)


So..da isser :)


Edit1: Zip updated: enthält jetzt auch die DFM

Edit2: HINWEIS: Das Projekt verwendet FastMM4 !

Stevie 5. Dez 2016 14:36

AW: Multi-Event-Liste
 
dfm fehlt.

Ghostwalker 5. Dez 2016 14:44

AW: Multi-Event-Liste
 
gefixt.

Stevie 5. Dez 2016 15:23

AW: Multi-Event-Liste
 
Bedenke übrigens, dass der Code ab Delphi 2009 grandios in die Luft fliegen wird, weil dort teilweise mit PChar statt PByte gearbeitet wird und die RTTI erweitert wurde - weitere virtuelle Methoden in TObject etc)

Ghostwalker 5. Dez 2016 15:36

AW: Multi-Event-Liste
 
Ich weiß.

Sobald ich eine neuere Delphi Version in die Finger bekomm, kann ich das entsprechend anpassen.

Stevie 6. Dez 2016 10:30

AW: Multi-Event-Liste
 
Ich würde übrigens statt strings als ident den PTypeInfo der events nutzen.

himitsu 6. Dez 2016 10:58

AW: Multi-Event-Liste
 
Zitat:

Zitat von Ghostwalker (Beitrag 1355381)
Edit2: HINWEIS: Das Projekt verwendet FastMM4 !

Du weißt aber, dass FastMM4 bereits im Delphi integriert ist?

In Delphi 2006 / Turbo Delphi wurde der DelphiMM durch eine angepasste Version des FastMM ersetzt.
(nur abgesehn von Delphi-Referenz durchsuchenReportMemoryLeaksOnShutdown fehlen viele Debuggingfunktionen)

Zitat:

Zitat von Ghostwalker (Beitrag 1355404)
Sobald ich eine neuere Delphi Version in die Finger bekomm, kann ich das entsprechend anpassen.

https://www.embarcadero.com/de/produ...ional-download

Ghostwalker 6. Dez 2016 11:11

AW: Multi-Event-Liste
 
@Stevie
Jaein.

Ich muss zumindest die Info mit in der Liste verwalten, damit ich die Parameterliste des Events mit
der Parameterliste des Eventhandlers abgleichen kann (und ggf. mit der beim Aufruf übergebenen Parametern) prüfen kann.

hmmm.....da werd ich wohl um ein redesign des ganze nicht ganz rumkommen.

Der String ist letztlich nur eine ID, die den Code etwas lesbarer macht :)


@Himitsu
Ja, deswegen verwende ich das "orginal", wegen Debugging/MemoryLeaks. Das erleichtert die Entwicklung doch
ungemein. und im Release sollte es normal keinen großen Unterschied machen.

Jup..ich weiß. Aber mit XP komm ich da nicht weit :) d.h. Ich müsste mich erstmal dazu durchringen,
alle Daten von der Kiste zu sichern, die Kiste platt machen und win7 (öhm...würde das überhaupt ausreichen ?) draufpacken. Summa sumarum erst mal 2-3 Tage arbeit.

himitsu 6. Dez 2016 11:22

AW: Multi-Event-Liste
 
Windows 7 wird noch von der IDE unterstützt.

Stevie 6. Dez 2016 15:33

AW: Multi-Event-Liste
 
Zitat:

Zitat von Ghostwalker (Beitrag 1355465)
Jaein.

Ich muss zumindest die Info mit in der Liste verwalten, damit ich die Parameterliste des Events mit
der Parameterliste des Eventhandlers abgleichen kann (und ggf. mit der beim Aufruf übergebenen Parametern) prüfen kann.

hmmm.....da werd ich wohl um ein redesign des ganze nicht ganz rumkommen.

Der String ist letztlich nur eine ID, die den Code etwas lesbarer macht :)

Ich find das jetzt nicht weniger lesbar:

Delphi-Quellcode:
 fevents.Execute(TypeInfo(TEventType5),[150,333,42,'Schweine im Weltraum oder Trampen leicht gemacht',FALSE,1.5647,'Normal String','Another very wide String',@rec,2357]);
als das

Delphi-Quellcode:
 fevents.Execute('TEventType5',[150,333,42,'Schweine im Weltraum oder Trampen leicht gemacht',FALSE,1.5647,'Normal String','Another very wide String',@rec,2357]);
Ganz im Gegenteil, wenn ich mich irgendwo vertippt habe oder ein Eventtyp umbenannt habe, dann gibts nen Compilerfehler, wohingegen beim String irgendwas zur Laufzeit schief laufen kann und erstmal Fehlersuche erforderlich macht.

Ghostwalker 6. Dez 2016 16:29

AW: Multi-Event-Liste
 
hmmm....da hast jetzt auch wieder recht.

Ghostwalker 8. Dez 2016 17:41

AW: Multi-Event-Liste
 
Liste der Anhänge anzeigen (Anzahl: 1)
Sooo....feddich.

Mit ein paar Einschränkungen funktioniert das ganze jetzt. :)


Einschränkungen:

Gleitkommawerte (Floats):

Da Delphi intern alles auf Extended castet, kann die Liste nur Parameter als Extended (od. Currency) handhaben.

Objectinstanzen, Interfaces und Klassen:

Werden als VAR-Parameter immer als Pointer zurückgegeben. Hab noch keine Idee wie man das
eventuell umgehen kann.


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:56 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz