Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Wie Callback-Funktion schreiben?


Jacdelad - Mi 05.07.06 19:49
Titel: Wie Callback-Funktion schreiben?
Hallöle,

ich progge in Delphi und XProfan. So, meistens erstelle ich DLLs in Delphi, wenn die XProfan-Funktion dafür entweder zu langsam oder nicht vorhanden ist. So, meine Frage ist nun: Wie kann ich eine Prozeduradresse, die ich übergeben bekomme dann in der DLL aufrufen???

Jac

PS: Ich hoffe, ihr wisst was ich meine...


BenBE - Mi 05.07.06 19:58

Du Meinst sowas hier?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
Function Callback(Foo: Integer): Boolean;
begin

end;

type TCallbackProc = function (Something: Integer): Boolean;

procedure LocalProc(Func: TCallbackProc);
var
    I: Integer;
begin
    For I := 0 to 9 do Func(I);
end;

//Aufruf:
LocalProc(@Callback);


MrSaint - Mi 05.07.06 21:06

Hier musst du natürlich auf die Aufrufkonventionen der Procedures aufpassen. Siehe z.B. stdcall in der OH.


MrSaint


Jacdelad - Do 06.07.06 19:25

Uhh, ich blick in dem Beispiel grad nicht durch. Mir gehts darum, dass ich die Adresse direkt aus dem Profaunaufruf übergebe (also Non-Delphi) und dann die Funktion/Prozedur in Delphi aufrufen will...


BenBE - Do 06.07.06 20:34

Dann brauchst Du in deinem Delphi-Programm Zeilen 6 bis 13 meines Beispiels ...

Zeilen 1-4 und Zeile 15 sind die Dinge aus dem externen Programm. Wie Zeile 15 in XProfan heißt, weiß ich nicht ...


Jacdelad - Do 06.07.06 21:48

Ah, ich glaube ich habs verstanden. Ich melde mich wieder wenns klappt......oder ich völlig am Boden zerstört bin.

Danke,
Jac


Delete - Fr 07.07.06 00:17

Hier: http://www.michael-puff.de/Developer/Artikel/Callback.shtml das ganze noch mal etwas ausführlicher.


Jacdelad - Fr 07.07.06 15:26

Oh, vielen Dank. Ich wurschtel mich jetzt erstmal da durch und melde mich nochmal!

Danke und schönes Wochenende,
Jac


Jacdelad - Sa 08.07.06 17:39

So weit, so gut funktioniert alles. Nun habe ich aber ein neues Problem: Wie erkenne ich, wenn statt eines Zeiger eine "0" übergeben wird (die Callback-Funktion soll also nicht aufgerufen werden...)???Habs mit 0 und NIL probiert...geht irgendwie nicht...

Jac


fidionael - Sa 08.07.06 19:17

Ich weiß nicht genau was du meinst, vielleicht sowas?:

Delphi-Quelltext
1:
2:
3:
4:
5:
function Aufruf(x: TCallbackProc) : Integer;
begin
  if @x <> nil then Result:=x
  else Result:=-1;
end;


Jacdelad - So 09.07.06 12:21

Wunderbar, genau das habe ich gesucht. Danke, ich muss mich echt mal in die Ürpblematik Zeiger und so reinknien!

Jac


Motzi - Mi 12.07.06 10:36

Zum Thema Zeiger kann ich dir mein Tutorial auf http://www.manuel-poeter.de empfehlen.

Zum Überprüfen ob ein Zeiger undefiniert ist (als nil) kann man "Assigned" verwenden, dabei ist es dann egal ob es sich um einen "normalen" Zeiger oder einen Funktions/Methodenzeiger handelt. Dadurch spart man sich dann solche Konstrukte wie

Delphi-Quelltext
1:
if @x <> nil then                    


Gruß, Motzi


BenBE - Mi 12.07.06 16:22

Assigned prüft aber auch nur auf nil ... Korrekt wäre aber auf DWORD(@x) and $FFFFF000 <> 0 zu prüfen, da die gesamte erste Speicherpage eine PAGE_FAULT auslöst ...


Motzi - Mi 12.07.06 18:08

Das schon.. aber weißt du einem nicht initialisierten Zeiger jemals einen anderen Wert als nil zu? Und ein Zeiger, dem gar kein Wert zugewiesen wurde (auch nicht nil), kann sowieso überall hin zeigen - da bringt es dann auch nichts zu prüfen ob er irgendwo in die erste Seite zeigt da die Wahrscheinlichkeit das dies der Fall ist doch sehr gering ist! :roll:


BenBE - Mi 12.07.06 21:00

user profile iconMotzi hat folgendes geschrieben:
Das schon.. aber weißt du einem nicht initialisierten Zeiger jemals einen anderen Wert als nil zu?

Jup, passiert bei indirekt über Records addressierte Pointer ... Nicht um sonst Erzeugt TForm(nil).Show nicht bei exakt $00000000 die AV, sondern bei (IIRC) $0000024B...
user profile iconMotzi hat folgendes geschrieben:
Und ein Zeiger, dem gar kein Wert zugewiesen wurde (auch nicht nil), kann sowieso überall hin zeigen - da bringt es dann auch nichts zu prüfen ob er irgendwo in die erste Seite zeigt da die Wahrscheinlichkeit das dies der Fall ist doch sehr gering ist! :roll:
Jup. Korrekterweise müsste man auf einen Zielbereich innerhalb einer GENERIC_READ-Page in einem Code\Daten-Segment prüfen ... Den Aufwand treibt aber keiner ...


Motzi - Do 13.07.06 10:47

TForm(nil).Show erzeugt deshalb eine AV bei $000002EC weil in diesem Code:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TCustomForm.SetVisible(Value: Boolean);
begin
  if fsCreating in FFormState then
    if Value then
      Include(FFormState, fsVisible) else
      Exclude(FFormState, fsVisible)
  else
  begin
    if Value and (Visible <> Value) then SetWindowToMonitor;
    inherited Visible := Value;
  end;
end;

in der Markierten Zeile auf das private Feld FFormState zugegriffen wird. Da aber der Self-Pointer nil ist liegt die Adresse in der ersten Speicherseite - soweit hast du recht.

ABER - gehts du jetzt ernsthaft her und überprüfst DWORD(@Self.FFormState) and $FFFFF000 <> 0 oder nicht einfach doch Self <> nil?? :roll:

Wenn man mit Objekten oder Zeigern auf Records arbeitet deren Adressen nil sind, so wird in 90% aller Fälle eine AV an einer Adresse ungleich $00000000 ausgelöst, weil die Felder unterschiedliche Offsets haben. Aber das bedeutet nicht, dass ich dies nicht einfach verhindern kann indem ich die Adresse auf nil überprüfe (egal ob manuell oder mit Assigned)!

Gruß, Motzi


BenBE - Do 13.07.06 21:30

Die Anmerkung war auch eher zur Verdeutlichung, bzw. Erklärung der Funktionsweise der Access Violations unter Windows gedacht ... Im Normalfall ist keiner so verrückt, Zugriffe bis auf das letzte Bit auf Korrektheit zu prüfen ...

Nur zur Ergänzung: Windows bietet zwei Funktionen: IsBadReadPtr und IsBadWritePtr. Wie sie funktionieren, sollte selbsterklärend sein ...


Motzi - Do 13.07.06 21:42

Also ich glaube es führt bei Leuten die sich noch nicht so gut auskennen eher zu mehr Verwirrung als zu besserem Verständnis.. ;)

Und IsBadRead/WritePtr bringt dich auch nicht wirklich viel weiter, da ein nicht initialisierter Zeiger ja auch in einen benutzten Speicherbereich zeigen kann - dann kriegst du oft auch keine AV (zumindest nicht sofort) sondern haust dir einfach irgendwelche anderen Daten zusammen.

Gruß, Motzi


Jacdelad - Fr 14.07.06 17:58

Hm, ja jetzt bin ich verwirrt. Meine DLL funktioniert mit @ und NIL und so ganz prima, hatte bisher noch keinen Fehler. Das mit Assigned schau ich mir aber mal an...