![]() |
Eigene Callback Funktion schreiben.
Liste der Anhänge anzeigen (Anzahl: 1)
Gegeben ist eine typisierte Datei mit Datensätzen. Alle Operationen mit dieser Datei sind in eine Klasse gekapselt (hinzufügen, löschen, modifizieren, auslesen, etc.). Nun kann es aber auch vorkommen, dass der Benutzer dieser Klasse alle Datensätze braucht. Er könnte nun in einer Schleife alle Datensätze durchgehen und sie mit der "Lesen"-Methode anzeigen. Dies wollte ich dem Benutzer der Klasse allerdings abnehmen und dachte dabei an eine Callback Funktion. Callback deswegen, damit man beispielsweise eine Fortschrittsanzeige implementieren kann oder so.
Mein erster etwas kläglicher Versuch sieht jetzt so aus:
Delphi-Quellcode:
Drei bis vier Probleme:
const
TCM_MAXRECORDS = WM_USER+74; TCM_ENUMRECORDS = WM_USER+75; function TTypedFile.EnumRecords(hWnd: Cardinal; var Data: TRecord): Boolean; var i : Integer; begin result := TRUE; SendMessage(hWnd, TCM_MAXRECORDS, 0, FRecordsCount); for i := 1 to FRecordsCount-1 do begin seek(f, i); read(f, Data); SendMessageCallback(hWnd, TCM_ENUMRECORDS, 0, 0, @EnumRecords, 0); end; end; 1. Er kompiliert es mir nicht, weil der 5. Parameter von SendMessageCallback nicht stimmt. 2. Wie rufe ich ich sie im Programm auf? 3. Wie muß die Funktion im Programm aussehen, welche die Nachrichten von meiner Callback empfängt? 4. Wie bekomme ich den Record aus der Callback in die Funktion, die die Nachrichten meiner Callback empfängt, um sie dann irgendwo auszuwerten / anzuzeigen? Im Anhang mal das Demo zu der TTypedFiles Unit mit der Klasse zum Arbeiten mit typisierten Dateien. Edit: Auch wenn es sich eventuell anderes lösen läßt, ich hätte es schon gerne mit einer Callback, weil ich es selbst mal verstehen will. Später soll noch eine Sortier-Routzine rein und da bräuchte ich dann auch wieder eine Callback Funktion. |
Moin Luckie,
zu 3. Deklaration aus dem PSDK für die an SendMessageCallback zu übergebene Funktion: VOID SendAsyncProc(HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult); In Delphi dann den stdcall nicht vergessen (mach' ich zu gerne :? ) Diese Funktion wird von Windows aus aufgerufen, sobald das angesprochene Fenster die Message vearbeitet hat, wobei lResult angibt, was das angesprochene als Ergebnis der Message zurückgibt, die anderen Parameter entsprechen denen, die Du mitgeschickt hast. |
Hm, ja danke. Das habe ich auch schon gesehen, bin nur noch nicht so ganz damit klar gekommen.
|
Aber Achtung! Du implementierst EnumRecords als eine Methode! Eine Methode hat noch einen impliziten Parameter - den Self-Pointer!
|
Dafür hatte ich dir doch die kleine Demo geschrieben!
Hat eigentlich alles richtig gemacht, außer das ich dort auch das stdcall vergessen habe, aber bei mir scheint sich das nicht negativ auf das Verhalten auszuwirken... Also gut, zu 1: Warum gibst du denn als Antwortprozedur auch die aufrufprozedur an? Das gibt eine Endlosschleife! Das Prinzip von Callbacks ist folgendermaßen: Du läufst durch die Gegend. Plötzlich siehst du ein Reh und schickst jemandem 'n Brief und läufst anschließend weiter. In dem Brief stand eine Adresse, an die auf jeden fall eine Antwort geschickt wird. Der andere kriegt jetzt den Brief und macht darauf hin was (holt sein Gewehr raus :twisted: ) und du kriegst an diese Adresse wieder einen Brief. Im Programmierleben sieht das dann so aus: Message an hWnd, Programm läuft weiter. hWnd kriegt Message, schnappt sie sich und macht was. @SendAsyncProc wird aufgerufen, falls angegeben. Und bei deinem speziellen Beispiel sieht das so aus: Lese Record, sende Nachricht. Nachricht wird bearbeitet und EnumRecords wird erneut aufgerufen (während es noch läuft, ob Windows da automatisch 'nen Thread erzeugt, weiß ich nicht). Jeder Aufruf einer Schleife ruft die Schleife erneut auf, und dieser Aufruf erzeugt wieder so viele Schleifen wie es Durchläuft gibt usw. Und irgendwann ist dein Stack voll. Im Prinzip ist es für dich doch uninteressant, ob der User etwas mit der TCM_ENUMRECORDS-Message gemacht hat, oder nicht, also musst du auch keine Prozedur angeben, mit der du die Antwort erhälst, einfach losschicken und weiter machen. Bearbeitet der User deiner Klasse dann deine Message nicht, stört dich das nicht, bearbeitet er sie (zeigt Dialog oder weiß der Geier was), ist auch nicht schlimm. Korrekt also:
Delphi-Quellcode:
Zu 2: Was aufrufen? Die Nachricht (TCM_ENUMRECORDS) wird wie jede andere Nachricht an das Fenster geschickt und kann bearbeitet werden, entweder in der WndProc, oder bei VCL über eine message-procedure ("message TCM_ENUMPROCS;" hinter Deklaration schreiben).
SendMessageCallback(hWnd, TCM_ENUMRECORDS, 0, 0, nil, 0); // oder 0, bin mir grad' nicht sicher
Und wie du EnumRecords aufrufst, sollte wohl klar sein:
Delphi-Quellcode:
:mrgreen:
procedure TForm1.Button1Click(Sender: TObject);
begin MyTypedFile.EnumRecords; end; 3: SDK unter SendCallbackMessage, die Demo von mir für dir oder Christians Antwort ;-) 4: Pointer im dwData. Guckst du PSDK: Zitat:
Delphi-Quellcode:
Dann steht im wParam der Pointer auf das Record, und du kannst das lesen. Allerdings weiß ich nicht, ob der Speicherinhalt gelöscht wird, wenn die Schleife weiterläuft (d.h. mit Sicherheit wird er das...), daher würde ich ein Array of Record nehmen und dieses übergeben. Dann macht auch die Callbackprozedur wieder sinn, denn wenn der Record dann vom Programm bearbeitet wurde, wird die aufgerufen und kann den Record wieder entfernen und somit für den nächsten freimachen.
function TTypedFile.EnumRecords(hWnd: Cardinal; var Data: TRecord): Boolean;
var i : Integer; begin result := TRUE; SendMessage(hWnd, TCM_MAXRECORDS, 0, FRecordsCount); for i := 1 to FRecordsCount-1 do begin seek(f, i); read(f, Data); SendMessageCallback(hWnd, TCM_ENUMRECORDS, 0, Integer(@data), 0, 0); end; end; Wenn der Record allerdings 4 Byte groß ist und in den wParam passt, ist's kein Problem *g* Alle Klarheiten beseitigt? *g* Edit: Oh, hab' 3 falsch interpretiert, im Programm sieht die Prozedur, die die Nachricht von deiner Callback gar nicht aus, denn das Callback ist der 5. Parameter. Wie die Prozedur aussieht, die deine Message abfängt, müsstest du am besten wissen: wie jede andere Prozedur, die eine Nachricht abfängt, auch -> WndProc bei nonVCL ;-) Edit2: Copy&Paste-Fehler bereinigt. Edit3: (hopefully) completed neverending quest for error-free posts :mrgreen: |
So, das hat mir jetzt keine Ruhe gelassen und hab's nu' selbst ausprobiert, anhand deines Quellcodes.
"Sie haben Post". Ach ne, du hast ja gar nicht AOL *g* |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:56 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz