Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Reguläre Prozedur in Methodenzeiger umwandeln (https://www.delphipraxis.net/192843-regulaere-prozedur-methodenzeiger-umwandeln.html)

Schwedenbitter 24. Mai 2017 14:48

Reguläre Prozedur in Methodenzeiger umwandeln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

ich habe mich - wie angekündigt - des Themas Verzeichnisüberwachung angenommen und das ganze ohne TObject in einen Thread gepackt. In einer Windows-Anwendung mit VCL klappt das ganze prima. Ich brauche es aber für die Konsole und da geht "der Spaß" erst richtig los.
Wenn ich versuche, meine Prozedur mit exakt dem definierten Kopf zu übergeben, bekomme ich die Fehlermeldung
Delphi-Quellcode:
E2009 Inkompatible Typen: 'Methodenzeiger und reguläre Prozedur'
. Wenn ich den Lösungsvorschlag von hier nutze, wird das Programm zwar kompiliert, es kommt aber kein Ereignis an :wall:

Es geht um folgenden Code(ausschnitt):
Delphi-Quellcode:
Program DirMon.nonVCL;

{$APPTYPE CONSOLE}

Uses
   System.SysUtils,
   DirMonitor in '..\DirMonitor.pas';

Procedure ShowChange(Action: TAction; FileName: String);
Var
   S               : String;
Begin
   S:= FormatDateTime('yyyy.mm.dd hh:nn:ss ', Now);
   Case Action Of
      faADDED            : S:= '[ADD] "' + FileName + '"';
      faREMOVED         : S:= '[DEL] "' + Filename + '"';
      faMODIFIED         : S:= '[MOD] "' + FileName + '"';
      faRENAMED_OLD_NAME: S:= '[REN] "' + FileName + '" (old name)';
      faRENAMED_NEW_NAME: S:= '[REN] "' + FileName + '" (new name)';
   End;
   WriteLn(S);
End;

Var
   T               : TMethod;
   Run            : Boolean = True;
   KeyBuffer      : String = '';
   KeyInput         : Char;
Begin
   Try
      T.Code:= @ShowChange;   // <- https://www.entwickler-ecke.de/viewtopic.php?t=31378
      With TDirMonitor.Create('C:\', TDirEvent(T)) Do // <- Ereignisse kommen nicht an
      With TDirMonitor.Create('C:\', ShowChange) Do // <- wird nicht kompiliert
      Try
         While Run Do                              // ständig wiederholen
         Begin
            Sleep(60);                              // kurz schlafen legen

// Programm einfach am "Leben" erhalten ...

         End;
      Finally
         Free;                                       // das Thread-Objekt freigeben
      End;
   Except
      On E: Exception Do Writeln(E.ClassName, ': ', E.Message);
   End;
End.
Wie löst man das Problem?

Ich habe allein in der DP 3 Funde zu diesem Thema gefunden und natürlich gelesen. Diese landen allesamt auf vorderen Plätzen bei der google-Suche. Aber ich komme auf keine Lösung. Die VCL-Variante klapp. Ich habe mal den Code als zip-Datei angehängt.

DeddyH 24. Mai 2017 14:58

AW: Reguläre Prozedur in Methodenzeiger umwandeln
 
Eine Methode gehört zu einer Klasse. Man löst das Problem also am einfachsten, indem man eine solche mit einer kompatiblen Methode deklariert, instanziert und dann das Event dieser Methode zuweist.
Delphi-Quellcode:
type
  TMyClass = class
  public
    procedure ShowChange(Action: TAction; FileName: string);
  end;

...

Monitor := nil;
MyClass := TMyClass.Create;
try
  Monitor := TDirMonitor.Create('C:\', MyClass.ShowChange);
  ...
finally
  Monitor.Free;
  MyClass.Free;
end;
Sollte so in etwa funktionieren.

Namenloser 24. Mai 2017 15:00

AW: Reguläre Prozedur in Methodenzeiger umwandeln
 
Die einzige, saubere Lösung ist, die Routine in eine Klasse zu packen und dann eine Instanz davon zu erzeugen.

Der Grund, warum man nicht einfach eine reguläre Prozedur in eine Methode casten kann, ist, dass bei der Methode immer ein impliziter Self-Parameter als erstes Argument übergeben wird.

Delphi-Quellcode:
type
TFoobar = class
  procedure SayHello(Name: String);
end;

procedure TFoobar.SayHello(Name: String);
begin
  WriteLn("Hello, ", Name);
end;
wird intern zu

Delphi-Quellcode:
type
TFoobar = class
end;

procedure TFoobar_SayHello(Self: TFoobar, Name: String);
begin
  WriteLn("Hello, ", Name);
end;
Wenn du einfach castest, dann steht in den Parametern also nur Murks.

Schwedenbitter 24. Mai 2017 21:22

AW: Reguläre Prozedur in Methodenzeiger umwandeln
 
Danke DeddyH und Namenloser für die schnelle Hilfe.

Ich habe jetzt ein weiteres Problem, das evtl. nicht unmittelbar die Ausgangsfrage betrifft:
Aus irgend einem Grund kommen die Ereignisse nicht an. D.h. genauer gesagt kommt immer nur ein Ereignis an. Aber auch das nicht während das Programm läuft, sondern erst wenn das Programm beendet wird.

Das ist kurios, weil ich immer dasselbe Grundgerüst für solche Konsolenprogramme/-tests nutze und dort andere Komponenten wie z.B. die Indys - genauer deren Ereignisse - durchkommen.

Stevie 25. Mai 2017 16:59

AW: Reguläre Prozedur in Methodenzeiger umwandeln
 
class methods (ohne static) können auch einer TMethod bzw einem Event zugewiesen werden, die haben nämlich auch den Self Pointer (in dem Fall auf die Klasse anstatt das Objekt).

Zacherl 26. Mai 2017 12:39

AW: Reguläre Prozedur in Methodenzeiger umwandeln
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1372692)
Das ist kurios, weil ich immer dasselbe Grundgerüst für solche Konsolenprogramme/-tests nutze und dort andere Komponenten wie z.B. die Indys - genauer deren Ereignisse - durchkommen.

Probier statt
Delphi-Quellcode:
while Run do
begin
  Sleep();
end;
mal bitte
Delphi-Quellcode:
var
  Msg: TMsg;
..
begin
..
  while GetMessage(Msg, 0, 0, 0) do
  begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:39 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