Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Zeiger auf Prozedur --> Prozedur ausführen


Andreas Pfau - So 28.09.03 13:10
Titel: Zeiger auf Prozedur --> Prozedur ausführen
Hallo,

es gibt da so einige WinAPI-Methoden, die einen Zeiger auf eine Methode wollen (Callback-Methoden). Wie führen die dann die Methoden aus? Ich habe es mal so probiert:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure ShowHelloWorld; stdcall;
begin
  ShowMessage('Hello world!');
end;

procedure TMain.SpeedButton1Click(Sender: TObject);
type
  TProcedure = procedure;
  PProcedure = ^TProcedure;
var
  Method: PProcedure;
begin
  Method := @ShowHelloWorld;
  Method^;
end;

Leider führt das nur zu einer Zugrifssverletzung. Was mache ich falsch?


Tino - Mo 29.09.03 09:50

So funktioniert es bei mir:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure ShowHelloWorld;
begin
  ShowMessage('Hello world!');
end;

procedure TForm1.Button1Click(Sender: TObject);
type
  TProcedure = procedure;
var
  Method: TProcedure;
begin
  Method := ShowHelloWorld;
  Method;
end;

Gruß
Tino


AndyB - Mo 29.09.03 10:47

Der Variablennamen ist hier ein wenig falsch gewählt, da eine Methode immer zu einer Klasse gehört. Mein Vorschlag (kein Muss) wäre hier: Proc oder Func.

Warum dein (Andreas Pfau) Code nicht funktioniert:

Du weist die Adresse der Prozedur ShowHelloWorld dem Zeiger Method zu. Nun dereferenzierst du den Zeiger ("^") und greifst somit auf die ersten 4 Bytes des Codes von ShowHelloWorld zu. Nun versuchst du diese 4 Bytes (die zum Stackframe der Prozedur gehören) als Prozedurzeiger aufzurufen. Das dass im Nirvana landet, ist dann wohl klar.
Des weiteren hast du TProcedure falsch deklariert. ShowHelloWorld benutzt die Aufrufkonvention stdcall. TProcedure hingegen den Vorgabewert register. Da du hier weder Parameter noch Rückgabewert hast, passiert hier zwar nichts. Das kann sich aber schlagartig ändern.


Andreas Pfau - Mo 29.09.03 15:55

Hallo,

vielen Dank, es klappt!

Nur noch was: Ich will desweiteren, dass ich vollkommen variante Parameter habe, also z.B. so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure ShowHelloWorld(Str: string);
begin
  ShowMessage(Str);
end;

procedure TMain.SpeedButton1Click(Sender: TObject);
  Proc: procedure;
begin
  Proc := ShowHelloWorld;
  Proc('Helo World');
end;

Das geht nicht, logo. Aber, wäre da irgendiwe machbar? Dass ich also eine beliebige Parameterliste übergebe? Oder geht so was net? Klar, ich könnte einen "array of const" übergeben, und je nach Methode die Parameter unterschiedlich auswerten, aber geht es auch so wie oben angedeutet?


maximus - Mo 29.09.03 16:07

Nein...so wie angedeutet wirst du kein glück haben :? Beim aufruf einer procedure wird eine parameterliste, mit einer festen grösse, erwartet. Ausserdem kommst du am compiler nicht vorbei, der dir verbietet abweichende parameter zu übergeben!

mit nem array pointer wäre aber eine reale möglichkeit...naja, halt auch nicht so schön..


barfuesser - Mo 29.09.03 17:11

Andreas Pfau hat folgendes geschrieben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure ShowHelloWorld(Str: string);
begin
  ShowMessage(Str);
end;

procedure TMain.SpeedButton1Click(Sender: TObject);
var
  Proc: procedure;
begin
  Proc := ShowHelloWorld;
  Proc('Helo World');
end;


sollte so aussehen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure ShowHelloWorld(AStr: string);
begin
  ShowMessage(Str);
end;

procedure TMain.SpeedButton1Click(Sender: TObject);
var
  Proc: procedure<span style="color: red">(AStr: String)</span>;
begin
  Proc := ShowHelloWorld;
  Proc('Helo World');
end;

barfuesser


Andreas Pfau - Mo 29.09.03 17:14

Hallo,

@maximus, nicht schön, aber es macht ja nix aus... das sind nur ("nur") ein paar Nanosekunden, wenn überhaupt, weil ich über mehr Speicheradressen gehen muss... Aber so werde ich es wohl machen müssen.

So, damit wäre das Thema erledigt. Vielen Dank für eire Hilfe!


maximus - Mo 29.09.03 17:53

@Andreas: ja genau!

@barfuesser: immer erst schön lesen...dann pos(t)en *g* ...das war von andreas schon so beabsichtigt.