| Autor |
Beitrag |
MaxiTB
      
Beiträge: 679
Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
|
Verfasst: Fr 04.04.03 10:48
Ich habe das Problem, daß ich alle Form-Klassen eines Projektes referenzieren muß.
Allerdings sind diese nicht registriert ... und das nachträglich zu machen, würde bedeuten 100.000 Zeilen Code durchzuwühlen (sprich: so gut wie unmöglich  ).
Hat jemand eine Idee, wie ich trotzdem ein FindClass hinbekommen könnte - vielleicht über Umwege ...
|
|
Klabautermann
      

Beiträge: 6366
Erhaltene Danke: 60
Windows 7, Ubuntu
Delphi 7 Prof.
|
Verfasst: Fr 04.04.03 11:33
Hallo,
ich bin nicht sicher ob ich dich richtig verstanden habe, aber vieleicht hilft dir ja dieser Code ein wenig weiter:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| VAR i : INTEGER; c : tObject; FormList : tStringList; begin FormList := tStringList.Create; WITH Application DO BEGIN FOR i := 0 TO ComponentCount - 1 DO BEGIN IF Components[i].tag > 0 THEN BEGIN c := Components[i]; IF (c IS TForm) THEN FormList.Add((c AS TForm).Name); END; // Wenn Form [...] |
Hier werden alle Objekte der Obersten ebene (auf dieser Befinden sich Forms) gesucht und wenn es sich um ein tForm handelt (es könnte ja auch ein Datamodule oder ähnliches sein) wird der NAme in eine Liste übernommen.
Gruß
Klabautermann
|
|
MaxiTB 
      
Beiträge: 679
Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
|
Verfasst: Fr 04.04.03 11:41
Titel: Nop - hast mich falsch verstanden ...
Ich hab erstens mal das Problem, daß die Forms nicht per Application.CreateForm erstellt werden - im Gegenteil, viele sogar dynamisch.
Das heißt - weder über Application noch über FindClass habe ich die Möglichkeit, alle Form Klassen als Referenz zu bekommen ...
|
|
MaxiTB 
      
Beiträge: 679
Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
|
Verfasst: Fr 04.04.03 11:46
Titel: Okay ...
... die Namen der Klassen hab ich aus dem MAP-File rausparsen können ...
Jetzt hab ich nur noch das Problem, wie ich zu dem Namen einen Referenz zur VMT bekomme. 
|
|
Klabautermann
      

Beiträge: 6366
Erhaltene Danke: 60
Windows 7, Ubuntu
Delphi 7 Prof.
|
Verfasst: Fr 04.04.03 11:49
Hi,
was noch nicht existiert, kannst du natürlich auch nicht finden.
Also wird dir nichts anderes übrtigbleiben als den Queltext nach Application.CreateForm zu durchsuchen. Wenn die Formulare über tMyFoern.Create erzeugt werden, wird das ganze aufwändiger da du nach .Create( suchen musst und dann selektieren musst ob es sich um ein Form handelt.
Der einzige Tipp den ich dir geben kann ist ein Hinweis auf die Funktion Suchen->In Dateien suchen....
Gruß
Klabautermann
|
|
maximus
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: Fr 04.04.03 17:06
Titel: Re: Nop - hast mich falsch verstanden ...
| MaxiTB hat folgendes geschrieben: | | Das heißt - weder über Application noch über FindClass habe ich die Möglichkeit, alle Form Klassen als Referenz zu bekommen ... |
Mit FindClass kannst du auch nur klassen finden, die delphi, oder du, vor mit RegisterClass registriert haben...instanzen schonmal garnicht.
Ich denke auch du kommst nicht drumrumm, da manuell reinzugehen und die instanzen irendwie zu registrieren.
Edit: Es sind aber alle TForm klassen in den rtti tabellen gespeichert...nützt dir aber nix da du die existierenden objekte haben willst 
_________________ mfg.
mâximôv
|
|
MaxiTB 
      
Beiträge: 679
Win2000, WinXp, Workbench ;-)
D7 Ent, VS2003 Arch.
|
Verfasst: Mo 07.04.03 10:00
Titel: Ich hab mal die Lösung des Problems aufgegabelt.
Aber Vorsicht:
Man beachte die schönen INOFFIZELL und den Assemblercode.
Also nix für Anfänger, nix ist sicher und obs mit D7 geht - weiß ich nicht - ich habs nicht ausprobiert ... mittlerweile habe ich mein Prob schon anders gelöst (MAP/DFM files parsing).
Hier die Antworten aus einem anderen Forum:
| Zitat: | Hagen Reddmann - 01:47pm Apr 5, 2003 MEZ (# 1 von 3)
type
TEnumTypeInfoCallback = function(UserData: Pointer; Info: PTypeInfo): Boolean; register; function GetBaseOfCode(Module: hModule; var CodeStart, CodeEnd: PChar): Boolean;
asm // get Codesegment pointers, check if module is a valid PE
PUSH EDI
PUSH ESI
AND EAX,not 3
JZ @@2
CMP Word Ptr [EAX],'ZM';
JNE @@1
MOV ESI,[EAX + 03Ch]
CMP Word Ptr [ESI + EAX],'EP'
JNE @@1
MOV EDI,[EAX + ESI + 014h + 008h]
ADD EAX,[EAX + ESI + 014h + 018h]
ADD EDI,EAX
MOV [EDX],EAX
MOV [ECX],EDI
XOR EAX,EAX
@@1: SETE AL
@@2: POP ESI
POP EDI
end; function EnumTypeInfo(Module: hModule; Callback: TEnumTypeInfoCallback; UserData: Pointer): PTypeInfo;
var
P,E,K,N: PChar;
L: Integer;
begin
Result := nil;
if Assigned(Callback) then
try
if GetBaseOfCode(Module, P, E) then
while P < E do
begin
DWord(P) := DWord(P) and not 3;
K := P + 4;
if (PDWord(P)^ = DWord(K)) and (PByte(K)^ > 0) and (PByte(K)^ < 1 then
// Info.Kind in ValidRange.D6
begin
L := PByte(K + 1)^; // length Info.Name
N := K + 2; // @Info.Name[1]
if (L > 0) and (N^ in ['_', 'a'..'z', 'A'..'Z']) then // valid ident ??
begin
repeat
Inc(N);
Dec(L);
until (L = 0) or not (N^ in ['_', 'a'..'z', 'A'..'Z', '0'..'9']);
if L = 0 then // length and ident valid
if Callback(UserData, Pointer(K)) then
// tell it and if needed abort iteration
begin
Result := Pointer(K);
Exit;
end else K := N;
end;
end;
P := K;
end;
except
end;
end; procedure Test; function MyEnum(Data: Pointer; Info: PTypeInfo): Boolean; register;
// wir suchen nur Klassen abgeleitet von TCustomForm
begin
Result := False;
if (Info.Kind = tkClass) and GetTypeData(Info).ClassType.InheritsFrom(TCustomForm) then
WriteLn( Info.Name );
end; begin
EnumTypeInfo(MainInstance, @MyEnum, nil);
// or with packages
// EnumTypeInfo(GetModuleHandle('vcl50.bpl'), @MyEnum, nil);
end;
Obiger Code nutz die "inoffiziellen" TypeInfo Strukturen des delphi Compilers. Diese werden im implementierenden Modul gespeichert. Mann kann mit obiger Struktur über alle Datentypen iterieren, also auch die Deklarationen von Sets, Enums, ordinale Typen und eben auch Klassen und Interfaces.
Der Trick bei der Geschichte ist das der Compiler ab dem Codestart des Codesegementes, eg. meistens $40000 +$200 +x diese Typeinfos speichert. Normalerweise sind die Typinfo Records aber NICHT untereinander verlinkt. Um denoch ausgehende von einem solchen Record den nächsten Record zu finden wird getrickst, s.o.
Der Code ist getestet mit D3,D4,D5,D6 und sollte auch unter D7 laufen.
ABER VORSICHT ! Wird ohne Packages compiliert und Units/Klassen eingebunden die NICHT benutzt werden so optimiert der Linker diese weg. D.h. in der fertigen Anwendung existieren diese Klassen überhaupt nicht mehr.
Wird mit Packages compiliert so muß mit SysUtils.EnumModules() über alle installierten Packages iteriert werden. In dieser Callback muß dann EnumTypeInfo() für jedes Package aufgerufen werden.
Gruß Hagen
Hagen Reddmann - 01:50pm Apr 5, 2003 MEZ (# 2 von 3)
Ach nochwas. Man kann obige Funktion "austricksen", d.h. einen Record im Codesegement erzeugen der für die Funktion wie ein TypeInfo-Record aussieht. Dadurch liefert die Funktion natürlich falsche Resultate ( Allerdings ist mir sowas noch nie untergekommen, d.h. es muß schon explizit gecodet werden.
Der Vorteil gegenüber MAP-Files liegt wohl auf der Hand. Keine externen Daten nötig, kein Debugbuild nötig und im Gegensatz zu MAP Dateien wird live das was tatsächlich in der Anwendung eincompiliert wurde ausgewertet. MAP Files sind dagegen weniger rubust, wird neu compiliert und die MAP datei aber nicht ersetzt reagiert das System absolut falsch.
Gruß Hagen
Hagen Reddmann - 02:01pm Apr 5, 2003 MEZ (# 3 von 3)
Falls man mit Callbacks arbeiten möchte die auf Klassen basieren kann man so vorgehen:
// 1. Beispiel Klasse type
TMyEnumClass = class(TObject)
class function Callback(Info: PTypeInfo): Boolean;
end; function TMyEnum.Callback(Info: PTypeInfo): Boolean;
begin
Result := False;
WriteLn( Info.Name );
end; begin
EnumTypeInfo(MainInstance, @TMyEnum.Callback, @TMyEnum);
end; // 2. Beispiel Objectinstance type
TMyEnum = class(TObject)
private
FList: TStringList;
function Callback(Info: PTypeInfo): Boolean;
public
constructor Create;
destructor Destroy; override;
procedure Enum(Module: hInstance);
property List: TStringList read FList;
end; function TMyEnum.Callback(Info: PTypeInfo): Boolean;
begin
Result := False;
FList.AddObject(Info.Name, Info);
end; constructor TMyEnum.Create;
begin
inherited Create;
FList := TStringList.Create;
end; destructor TMyEnum.Destroy;
begin
FreeAndNil(FList);
inherited Destroy;
end; procedure TMyEnum.Enum(Module: hInstance);
begin
EnumTypeInfo(Module, @TMyEnum.Callback, Self);
end; begin
with TMyEnum.Create do
try
Enum(MainInstance);
finally
Free;
end;
end;
usw. usw.
Gruß Hagen
PS: ich arbeite aber in diesem Falle lieber prozedural  |
|
|
|