Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi AccessViolation bei CallBack (https://www.delphipraxis.net/119512-accessviolation-bei-callback.html)

blackdrake 27. Aug 2008 21:26


AccessViolation bei CallBack
 
Hallo.

Ich versuche gerade etwas mit Callbacks zu machen, erhalte aber eine AV...

Delphi-Quellcode:
type
  TDownloadCallBackStatus = procedure(FilesDownloaded: Integer) of object;
  PDownloadCallBackStatus = ^TDownloadCallBackStatus;

  Txxx = class(T...)
  private
    {...}
  public
    {...}
    procedure DownloadOrSynchronize(SearchString: string; OnlySync: boolean;
      CallBackStatus: PDownloadCallBackStatus);
  end;

procedure Txxx.DownloadOrSynchronize(SearchString: string;
  OnlySync: boolean; CallBackStatus: PDownloadCallBackStatus);
var
begin
  {...}

  if Assigned(CallBackStatus) then
  begin
     CallBackStatus^(j); // <-- EACCESSVIOLATION
  end;

  {...}

end;

procedure CallBack(FilesDownloaded: Integer);
begin
  MainForm.label_x.Caption := inttostr(FilesDownloaded);
end;

procedure TMainForm.btn_download_click(Sender: TObject);
begin
  {...}
  AOBJ.DownloadOrSynchronize(edt_tags.Text, chk_nodownload.Checked, @CallBack);
  {...}
end;
(Hintergrund: DownloadOrSynchronize ist eine Funktion, die in einer gemeinsam genutzten PAS-Datei steht. Die einzelnen Projekte, die auf diese Funktion zurückgreifen, haben jeweils ihre eigene Art, dem Benutzer den aktuellen Status in Labels zu vermitteln. Daher Callback)

Ich habe jetzt schon relativ viele Varianten zu Callbacks gesehen, aber nicht alle Funktionieren bei mir. Dieser Code ist nun der erste, den ich Kompilieren konnte.

Hat jemand eine Idee, wie das geht?

Gruß
blackdrake

omata 27. Aug 2008 21:39

Re: AccessViolation bei CallBack
 
Las mal den Zeiger weg, dann klappt das auch.

Delphi-Quellcode:
type
  TDownloadCallBackStatus = procedure(FilesDownloaded: Integer) of object;

  Txxx = class(T...)
  private
    {...}
    FDownloadCallBackStatus:TDownloadCallBackStatus;
  public
    {...}
    property OnDownloadCallBackStatus:TDownloadCallBackStatus
      read FDownloadCallBackStatus write FDownloadCallBackStatus;
    procedure DownloadOrSynchronize(SearchString: string; OnlySync: boolean);
  end;

procedure Txxx.DownloadOrSynchronize(SearchString: string; OnlySync: boolean);
var
begin
  {...}

  if Assigned(FDownloadCallBackStatus) then
    FDownloadCallBackStatus(j);

  {...}
end;

procedure CallBack(FilesDownloaded: Integer);
begin
  MainForm.label_x.Caption := inttostr(FilesDownloaded);
end;

procedure TMainForm.btn_download_click(Sender: TObject);
begin
  {...}
  AOBJ.OnDownloadCallBackStatus:=CallBack;
  AOBJ.DownloadOrSynchronize(edt_tags.Text, chk_nodownload.Checked);
  {...}
end;

Apollonius 27. Aug 2008 21:42

Re: AccessViolation bei CallBack
 
Erstens muss du dich entscheiden, ob dein Callback-Parameter freie Routinen oder Methoden annehmen soll. Mit der Klausel "of object" sagst du, dass es eine Methode sein muss, aber du willst dann eine freie Routine übergeben.
Zweitens: Wozu ein Zeiger auf einen Zeiger? Das ist hier absolut unnötig. @Callback gibt den Funktionszeiger zurück, aber nicht die zusätzliche Indirektion, die du eingebaut hast. Daher kommt auch die Zugriffsverletzung.

blackdrake 27. Aug 2008 22:41

Re: AccessViolation bei CallBack
 
Hallo omata und Apollonius.

@omata: Vielen Dank für die Korrektur! Funktioniert prima. Ich musste lediglich das "of object" noch wegnehmen.

Zitat:

Zitat von Apollonius
Erstens muss du dich entscheiden, ob dein Callback-Parameter freie Routinen oder Methoden annehmen soll. Mit der Klausel "of object" sagst du, dass es eine Methode sein muss, aber du willst dann eine freie Routine übergeben.

Leider habe ich von der Materie sehr wenig Ahnung. Was ist denn der Unterschied zwischen einer (freien) Routine und einer Methode? Ich dachte immer Routinen und Methoden seien das Selbe.

Zitat:

Zitat von Apollonius
Zweitens: Wozu ein Zeiger auf einen Zeiger? Das ist hier absolut unnötig. @Callback gibt den Funktionszeiger zurück, aber nicht die zusätzliche Indirektion, die du eingebaut hast. Daher kommt auch die Zugriffsverletzung.

Leider verstehe ich da nur Bahnhof. :| Ich habe so lange mit Referenzierung (@) und De-Referenzierung (^) herumgespielt, bis ich kompilieren konnte. Im Internet gab es auch unzählige Varianten von CallBacks, teilweise mit stdcall, teilweise mit und ohne Pointern.

Ich finde die Ausführung von omata mit den properties elegant gelöst, da ich ja sowieso in einer Klasse arbeite. Deswegen werde ich diesen Code auch so behalten.

Aber wie würde mein Code in funktionierender Fassung aussehen, wenn ich eine Methode/Routine Prozedur/Funktion direkt an eine Funktion weitergeben möchte, ohne diese vorher als Property oder Variable zu setzen? Ist Interessehalber, ich möchte ja irgendwie auch was dabei gelernt haben...

Gruß
blackdrake

mkinzler 27. Aug 2008 22:45

Re: AccessViolation bei CallBack
 
Zitat:

Leider habe ich von der Materie sehr wenig Ahnung. Was ist denn der Unterschied zwischen einer (freien) Routine und einer Methode? Ich dachte immer Routinen und Methoden seien das Selbe.
Du scheinst wohl auch zu der neuen Gattung von Programmierern zu gehören, die ohne Grundlagenwissen lustig drauflosprogrammieren.
Eine Methode gehört zu einer Klasse und eine freie Prozedur nicht (deshalb ist sie auch frei)

omata 27. Aug 2008 22:52

Re: AccessViolation bei CallBack
 
Zitat:

Zitat von blackdrake
Vielen Dank für die Korrektur! Funktioniert prima. Ich musste lediglich das "of object" noch wegnehmen.

Ok, das habe ich übersehen. Wenn deine Callbackroutine zur Klasse gehören soll oder es eine Methode in einem Formular ist, dann solltest bzw. musst du aber das "of object" beibehalten.

Delphi-Quellcode:
type
  TDownloadCallBackStatus = procedure(FilesDownloaded: Integer) of object;

  Txxx = class(T...)
  private
    {...}
    FDownloadCallBackStatus:TDownloadCallBackStatus;
  public
    {...}
    property OnDownloadCallBackStatus:TDownloadCallBackStatus
      read FDownloadCallBackStatus write FDownloadCallBackStatus;
    procedure DownloadOrSynchronize(SearchString: string; OnlySync: boolean);
  end;

  TMainForm = class(TForm)
  private
    procedure CallBack(FilesDownloaded: Integer);
  public
  end;

procedure Txxx.DownloadOrSynchronize(SearchString: string; OnlySync: boolean);
var
begin
  {...}

  if Assigned(FDownloadCallBackStatus) then
    FDownloadCallBackStatus(j);

  {...}
end;

procedure TMainForm.btn_download_click(Sender: TObject);
begin
  {...}
  AOBJ.OnDownloadCallBackStatus:=CallBack;
  AOBJ.DownloadOrSynchronize(edt_tags.Text, chk_nodownload.Checked);
  {...}
end;

procedure TMainForm.CallBack(FilesDownloaded: Integer);
begin
  Label_x.Caption := inttostr(FilesDownloaded);
end;


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