Autor Beitrag
Hami04
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Mi 12.05.10 09:59 
Hallo,
ich habe ein Problem mit Pointern auf Methoden-Pointer.
Ein Methoden-Pointer in Delphi besteht ja aus einem Record mit zwei Pointern: einen auf die Funktion und einen auf das Objekt. Diese Methoden-Pointer möchte ich in eine Struktur packen. Die Struktur nimmt allerdings nur einfache Pointer auf. Ich versuche also, einen Pointer auf den Methoden-Pointer, also auf den Record, zu nehmen und diesen in die Struktur zu packen. Wenn ich den Pointer jetzt dereferenziere bekomme ich einen Zugriffsverletzung.

Hier etwas Beispielcode:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure test
type
   TMethod = procedure of object;
var
   Method: TMethod;
   Method2: TMethod;
   pMethod: ^TMethod;
begin
   Method := MyObject.MyMethod;
   pMethod := @Method;
   Method2 := pMethod^;

   Method; // funktioniert, es wird erfolgreich MyObject.MyMethod aufgerufen
   Method2; // Zugrifssverletzung
end;


Kann sich irgendjemand, das erklären. Ich nämlich leider nicht.

Viele Grüße
Philipp
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 12.05.10 10:04 
Gib mal bitte den gemischten Assembler-Code aus dem CPU-Fenster für diese Routine. Dann kann ich Dir sagen, was Delphi da baut. Ich denk mal, der wird einmal zu wenig Dereferenzieren. Aber mehr mit ASM-Code dazu.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Hami04 Threadstarter
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Mi 12.05.10 10:39 
Problem ist gelöst. Es muss ein @@ genommen werden.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure test
type
   TMethod = procedure of object;
var
   Method: TMethod;
   Method2: TMethod;
   pMethod: ^TMethod;
begin
   Method := MyObject.MyMethod;
   pMethod := @@Method; // hier werden zwei @@ eingfügt
   Method2 := pMethod^;

   Method; // funktioniert, es wird erfolgreich MyObject.MyMethod aufgerufen
   Method2; // Zugrifssverletzung
end;
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 12.05.10 10:52 
Hier der komplette Assemblercode:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
Unit244.pas.38begin
00457E54 83C4F0           add esp,-$10
Unit244.pas.39: MyObject := TTest.Create;
00457E57 B201             mov dl,$01
00457E59 A1547C4500       mov eax,[$00457c54]
00457E5E E8C5B9FAFF       call TObject.Create
Unit244.pas.40: Method := MyObject.MyMethod;
00457E63 89442404          mov [esp+$04],eax
00457E67 C70424947E4500   mov [esp],$00457e94
Unit244.pas.41: pMethod := @Method;
00457E6E 8B0424           mov eax,[esp]
Unit244.pas.42: Method2 := pMethod^;
00457E71 8B10             mov edx,[eax]
00457E73 89542408          mov [esp+$08],edx
00457E77 8B5004           mov edx,[eax+$04]
00457E7A 8954240C          mov [esp+$0c],edx
Unit244.pas.44: Method; // funktioniert, es wird erfolgreich MyObject.MyMethod aufgerufen
00457E7E 8B442404         mov eax,[esp+$04]
00457E82 FF1424           call dword ptr [esp]
Unit244.pas.45: Method2; // Zugrifssverletzung
00457E85 8B44240C         mov eax,[esp+$0c]
00457E89 FF542408         call dword ptr [esp+$08]
Unit244.pas.46end;
00457E8D 83C410           add esp,$10
00457E90 C3               ret 
00457E91 8D4000           lea eax,[eax+$00]
Unit244.pas.52: ShowMessage('aa');
00457E94 B8A87E4500       mov eax,$00457ea8
00457E99 E89644FDFF       call ShowMessage
Der Delphicode dazu:
ausblenden Delphi-Quelltext
 
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
{ ... }
procedure TForm244.Button1Click(Sender: TObject);
type
  TMethod = procedure of object;
var
  Method: TMethod;
  Method2: TMethod;
  pMethod: ^TMethod;
  MyObject: TTest;
begin
  MyObject := TTest.Create;
  Method := MyObject.MyMethod;
  pMethod := @Method;
  Method2 := pMethod^;

  Method; // funktioniert, es wird erfolgreich MyObject.MyMethod aufgerufen
  Method2; // Zugrifssverletzung
end;

{ TTest }

procedure TTest.MyMethod;
begin
  ShowMessage('aa');
end;
// Ich sehe schon die Antwort, aber ich poste es einfach einmal trotzdem inkl. Ergänzung:
Mit @@ dann sieht der Code so aus:
ausblenden Delphi-Quelltext
 
9:
10:
11:
{ ... }
00457E67 C70424907E4500   mov [esp],$00457e90
Unit244.pas.41: pMethod := @@Method;
00457E6E 8BC4             mov eax,esp
Man sieht also, dass jetzt direkt der Wert aus esp genommen wird statt dem Wert an der referenzierten Speicherstelle.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 12.05.10 12:32 
Jap. Der Delphi-Compiler vergisst bei der Zuweisung TROTZ dem angegebenen @ einmal die Adresse zu bilden. Manchmal kann einem die Compiler-Magic wirklich auf den Keks gehen.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.