Autor Beitrag
MaxiTB
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 679

Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
BeitragVerfasst: Di 22.04.03 11:36 
Grüße !

Ich hab mal wieder was gefinkeltes (diesesmal aber ziemlich simple eigentlich - nur irgendwie hab ich gerade ein Kopf vor dem Brett ... ähm ... oder so).

Ich bräuchte eine Methode:
ausblenden Quelltext
1:
function ContainsAbstractMethods(AClass: TObject): boolean					


Diese sollte mir einfach True zurückgeben, wenn eine oder mehrere abstrakten Methoden zur Laufzeit vorhanden sind.

Hab schon ein paar Versuche mit der VMT probiert, allerdings war das konstruktivste ein schöner Blue-Screen. *g*

Hat da jemand eine Idee ?

_________________
Euer Mäxchen
Wer früher stirbt, ist länger tot.
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Di 22.04.03 16:29 
Mit der VMT geht das schon recht schwierig. Aber mit Hilfe der [url=www.sf.net/projects/jcl]Jedi Code Library[/url] wird es zu Kinderspiel. Man muss nur die Adresse der System-internen Prozedur _AbstractError ermitteln und kann dann die VMT und DMT Einträge vergleichen.

ausblenden volle Höhe 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:
30:
31:
32:
33:
34:
uses JclSysUtils;


type
  TAbstractClass = class(TObject)
    procedure AbstractMethod; virtual; abstract;
  end;

function IsAbstractClass(AClass: TClass): Boolean;
var
  AbstractError: Pointer;
  i, Count: Integer;
  dynTbl: PDynamicAddressList;
begin
  i := GetVirtualMethodCount(TAbstractClass) - 1;
  AbstractError := GetVirtualMethod(TAbstractClass, i);

  Result := True;
 // virtual method table
  for i := 0 to GetVirtualMethodCount(AClass) - 1 do
    if GetVirtualMethod(AClass, i) = AbstractError then Exit;

 // dynamic method table
  Count := GetDynamicMethodCount(AClass);
  if Count > 0 then
  begin
    dynTbl := GetDynamicAddressList(AClass);
    if dynTbl <> nil then
      for i := 0 to Count - 1 do
        if dynTbl^[i] = AbstractError then Exit;
  end;

  Result := False;
end;

_________________
Ist Zeit wirklich Geld?
MaxiTB Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 679

Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
BeitragVerfasst: Mi 23.04.03 13:49 
Titel: Danke schön !
Hier der Code für alle, die wissen wollen was im Hintergrund abläuft (aus der JCL):

ausblenden volle Höhe 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:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
{$IFDEF VER150} uses System; {$ENDIF}

type
  TDynamicAddressList = array[0..MaxInt div 16] of Pointer;
  PDynamicAddressList = ^TDynamicAddressList;

function ContainsAbstractMethods(AClass: TClass): boolean;

  function nAbstractErrorAddress: Pointer; assembler;
  asm
    LEA EAX, System.@AbstractError
  end;

  function nGetVirtualMethodCount(AClass: TClass): integer;
  var
    lBeginVmt: longint;
    lEndVmt: longint;
    lTablePointer: longint;
    lIndex: integer;
  begin
    lBeginVmt := longint(AClass);

    lEndVmt := PLongint(longint(AClass) + vmtClassName)^;
    lIndex := vmtSelfPtr + SizeOf(Pointer);
    repeat
      lTablePointer := PLongint(longint(AClass) + lIndex)^;
      if (lTablePointer <> 0) and (lTablePointer >= lBeginVmt) and
        (lTablePointer < lEndVmt) then
        lEndVmt := longint(lTablePointer);
      Inc(lIndex, SizeOf(Pointer));
    until lIndex >= vmtClassName;

    Result := (lEndVmt - lBeginVmt) div SizeOf(Pointer);
  end;

  function nGetVirtualMethod(AClass: TClass; const AIndex: integer): Pointer;
  begin
    Result := PPointer(integer(AClass) + AIndex * SizeOf(Pointer))^;
  end;

  function nGetDynamicMethodCount(AClass: TClass): integer; assembler;
  asm
    MOV     EAX, [EAX].vmtDynamicTable
    TEST    EAX, EAX
    JE      @@Exit
    MOVZX   EAX, WORD PTR [EAX]
    @@Exit:
  end;

  function nGetDynamicAddressList(AClass: TClass): PDynamicAddressList; assembler;
  asm
    MOV     EAX, [EAX].vmtDynamicTable
    MOVZX   EDX, Word ptr [EAX]
    ADD     EAX, EDX
    ADD     EAX, EDX
    ADD     EAX, 2
  end;

var
  lIndex: integer;
  lCount: integer;
  lDynTbl: PDynamicAddressList;
begin
  Result := true;
  for lIndex := 0 to nGetVirtualMethodCount(AClass) - 1 do
    if nGetVirtualMethod(AClass, lIndex) = nAbstractErrorAddress then
      exit;

  lCount := nGetDynamicMethodCount(AClass);
  if lCount > 0 then
  begin
    lDynTbl := nGetDynamicAddressList(AClass);
    if lDynTbl <> nil then
      for lIndex := 0 to lCount - 1 do
        if lDynTbl[lIndex] = nAbstractErrorAddress then
          exit;

  end;
  Result := false;
end;

_________________
Euer Mäxchen
Wer früher stirbt, ist länger tot.


Zuletzt bearbeitet von MaxiTB am Do 24.04.03 16:34, insgesamt 1-mal bearbeitet
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Mi 23.04.03 22:37 
Titel: Re: Danke schön !
MaxiTB hat folgendes geschrieben:
ausblenden Quelltext
1:
2:
uses
  System;

Das ist nie nötig, und führt sogar zu einer Fehlermeldung, da die System-Unit vom Compiler bereits eingefügt wird. :wink:

_________________
Ist Zeit wirklich Geld?
MaxiTB Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 679

Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
BeitragVerfasst: Do 24.04.03 09:03 
Titel: Also bei mir ...
... gehts (D7 Enterprise). Nix Fehlermeldung, nix nix gehen. :wink:

Obs unnötig ist, okay, darüber kann man streiten. *lol*

_________________
Euer Mäxchen
Wer früher stirbt, ist länger tot.
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Do 24.04.03 16:13 
Dann habe die da was geändert.
Delphi 6: Bezeichner redefiniert: 'System'

_________________
Ist Zeit wirklich Geld?
MaxiTB Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 679

Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
BeitragVerfasst: Do 24.04.03 16:32 
Wurscht.

Daran wirds bei keinem Scheitern :wink: !
Besser so ?

_________________
Euer Mäxchen
Wer früher stirbt, ist länger tot.