2007. május 2., szerda

Get all classes registered on a form


Problem/Question/Abstract:

How can I get all classes that are currently registered in my application? Example: If I have a form with no components on it and I do something like ReadComponentRes and that *.dfm has a TEdit in it, I get an exception that TEdit is of unknown class. If I put one TEdit on that form and do ReadComponentRes again, everything goes OK. So, I guess TEdit is registered somewhere. Now I would like to find all registered classes so I would know which classes I can use in my *.dfm.

Answer:

There is no way to get at classes registered via RegisterClasses, since the list holding these is private to the classes unit. You can get at the classes registered on a form, however, since those use a table connected to the form classes class record. The following is based on some spelunking in the classes unit:

{defined in classes.pas}
type
  PFieldClassTable = ^TFieldClassTable;
  TFieldClassTable = packed record
    Count: Smallint;
    Classes: array[0..8191] of ^TPersistentClass;
  end;

function GetFieldClassTable(AClass: TClass): PFieldClassTable; assembler;
asm
  MOV EAX, [EAX].vmtFieldTable
  OR EAX, EAX
  JE @@1
  MOV EAX, [EAX + 2].Integer
  @@1:
end;
{end of quote from classes.pas}

procedure TForm1.Button1Click(Sender: TObject);

  procedure Display(const S: string);
  begin
    memo1.lines.add(S);
  end;

var
  pFCT: PFieldClassTable;
  aClass: TClass;
  i: SmallInt;
begin
  memo1.clear;
  aClass := Classtype;
  while aClass < > TPersistent do
  begin
    Display('Registered classes for class ' + aClass.Classname);
    pFCT := GetFieldClasstable(aClass);
    if not Assigned(pFCT) then
      Display('  No classes registered')
    else
    begin
      Display(format('  %d classes registered', [pFCT^.Count]));
      for i := 0 to pFCT^.Count - 1 do
        Display('  ' + pFCT^.Classes[i]^.ClassName);
    end;
    aClass := aClass.ClassParent;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése