Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Вниз

задачка   Найти похожие ветки 

 
Vuk ©   (2004-04-20 15:38) [80]

to Игорь Шевченко ©   (20.04.04 15:31) [78]:
>А параметры ? :))))
Если мне мой склероз не изменяет, нету их тама. :o)
Параметры методов, как они объявлены, можно вытащить только для RTTI-enabled интерфейсов начиная с D6.


 
Игорь Шевченко ©   (2004-04-20 15:38) [81]

MBo ©   (20.04.04 15:33)

Подобный код я тоже вчера вечером написал, а вот сопоставление TypeData от свойств с конкретными именами/адресами методов у меня не вышло без одного из тех двух способов в [76] :)


 
Игорь Шевченко ©   (2004-04-20 15:42) [82]

Vuk ©   (20.04.04 15:38)


> Параметры методов, как они объявлены


Можно вытащить из TypeInfo/TypeData свойства, как это делает DeDe


 
Vuk ©   (2004-04-20 15:47) [83]

Ну это только по факту привязки метод-свойство выявляется, за счет предположения, что заголовок метода совпадает с заголовком типа для свойства. У интерфейсов можно вытащить вообще все. Я, помнится, чуть ли не исходный текст интерфейса восстанавливал.
:o)


 
Игорь Шевченко ©   (2004-04-20 15:49) [84]

Vuk ©   (20.04.04 15:47)

С интерфейсами я не пробовал, ничего не могу сказать, а вот синтаксис свойства-метода с незапамятных времен в RTTI живет, и даже в TypInfo описан :)


 
Vuk ©   (2004-04-20 15:51) [85]

И я про то, что описаны параметры свойства-метода, но не параметры published метода.


 
Igorek ©   (2004-04-20 16:11) [86]

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   Memo1: TMemo;
   procedure FormCreate(Sender: TObject);
   procedure FormShow1(Sender: TObject);
 private
   procedure FormShow2(Sender: TObject);
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}
procedure ListMethods(Cls: TClass; Strings: TStrings);
var
PVMT: Pointer;
i, Num, len: Integer;
MName: string;
begin
if Cls = nil then Exit;
PVMT := Pointer(Cls);
Inc(PByte(PVMT), vmtMethodtable);
PVMT := Pointer(PVMT^);
if PVMT = nil then Exit;
Num := PWord(PVMT)^;
Strings.Add(Format("класс %s, методов: %d ", [Cls.ClassName, Num]));
Inc(PWord(PVMT));
for i := 0 to Num - 1 do begin
  len := PWord(PVMT)^;
  Inc(PByte(PVMT),7);
  SetLength(MName, len - 7);
  Move(PVMT^, MName[1], len - 7);
  Strings.Add(Format("%d: %d %s", [i, len, MName]));
  Inc(PByte(PVMT), len - 7);
end;
ListMethods(Cls.ClassParent, Strings);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 OnShow := FormShow2;
end;

procedure TForm1.FormShow1(Sender: TObject);
begin
//  dummy
end;

procedure TForm1.FormShow2(Sender: TObject);
begin
 ListMethods(TForm1, Memo1.Lines);
end;

end.

Кто что думает насчет этого кода?


 
Igorek ©   (2004-04-20 16:32) [87]

А насчет этого:
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 StdCtrls;

type
 TDummy = class(TComponent)
   procedure FormShow1(Sender: TObject);
 end;

 TForm1 = class(TForm)
   Memo1: TMemo;
   procedure FormCreate(Sender: TObject);
 private
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}
procedure ListMethods(Cls: TClass; Strings: TStrings);
var
PVMT: Pointer;
i, Num, len: Integer;
MName: string;
begin
if Cls = nil then Exit;
PVMT := Pointer(Cls);
Inc(PByte(PVMT), vmtMethodtable);
PVMT := Pointer(PVMT^);
if PVMT = nil then Exit;
Num := PWord(PVMT)^;
Strings.Add(Format("класс %s, методов: %d ", [Cls.ClassName, Num]));
Inc(PWord(PVMT));
for i := 0 to Num - 1 do begin
  len := PWord(PVMT)^;
  Inc(PByte(PVMT),7);
  SetLength(MName, len - 7);
  Move(PVMT^, MName[1], len - 7);
  Strings.Add(Format("%d: %d %s", [i, len, MName]));
  Inc(PByte(PVMT), len - 7);
end;
ListMethods(Cls.ClassParent, Strings);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 with TDummy.Create(Self) do
   OnShow := FormShow1;
end;

{ TDummy }

procedure TDummy.FormShow1(Sender: TObject);
begin
 ListMethods(TForm1, Form1.Memo1.Lines);
end;

end.


 
Игорь Шевченко ©   (2004-04-20 18:18) [88]

Для экземпляра класса что-то получилось - не судите строго:
unit main;

interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, TypInfo;

type
 TfMain = class(TForm)
   ListBox1: TListBox;
   Button3: TButton;
   procedure Button3Click(Sender: TObject);
 private
   procedure SpyMethods(AClass: TClass; Strings: TStrings);
   procedure SpyRootComponentMethods(AClass: TObject; Strings: TStrings);
   procedure SpyComponentMethods(AClass: TObject; Strings, Methods: TStrings);
   procedure SpyInstanceMethods(AClass: TObject; Strings, Methods: TStrings);
   function ParseMethodProp(AProp: PPropInfo;
     const MethodName: string): string; overload;
   function ParseMethodProp(AProp: PPropInfo): string; overload;
 end;

var
 fMain: TfMain;

implementation
uses
 ChildForm;

{$R *.dfm}

{ TfMain }

type
 TMethodDesc = packed record
   MethodDescSize: Word;
   MethodAddress: Pointer;
   MethodName: ShortString;
 end;
 PMethodDesc = ^TMethodDesc;

 TMethodTable = packed record
   MethodCount: Word;
   Data: TMethodDesc;
 end;
 PMethodTable = ^TMethodTable;
 PPMethodTable = ^PMethodTable;

procedure TfMain.SpyMethods(AClass: TClass; Strings: TStrings);
var
 Methods: PMethodTable;
 MethodDesc: PMethodDesc;
 I: Integer;
begin
 Methods := PPMethodTable(PChar(AClass) + vmtMethodTable)^;
 if Assigned(Methods) then begin
   MethodDesc := @Methods^.Data;
   for I:=0 to Pred(Methods^.MethodCount) do begin
     Strings.AddObject(
       Format("%s.%s", [AClass.ClassName, MethodDesc^.MethodName]),
         TObject(MethodDesc^.MethodAddress));
     MethodDesc := PMethodDesc(PChar(MethodDesc) + MethodDesc^.MethodDescSize);
   end;
 end;
 if AClass.ClassParent <> nil then
   SpyMethods(AClass.ClassParent, Strings);
end;

function MethodKindToString (const Value: TMethodKind): string;
const
 MethodKindNames: array[TMethodKind] of string = ("procedure", "function",
   "constructor", "destructor", "class procedure", "class function",
   "procedure", "function");
begin
 Result := MethodKindNames[Value];
end;

type
 TParamDesc = packed record
   Flags: TParamFlags;
   ParamName: ShortString;
   TypeName: ShortString;
 end;
 PParamDesc = ^TParamDesc;

function TfMain.ParseMethodProp(AProp: PPropInfo;
 const MethodName: string): string;
var
 MethodTypeData: PTypeData;
 ParamCount: Integer;
 ParamDesc: PParamDesc;
 Param, Params: string;
 ResultType: PShortString;
 I: Integer;
 TypeName: PShortString;
begin
 MethodTypeData := GetTypeData(AProp^.PropType^);
 ParamCount := MethodTypeData^.ParamCount;
 ParamDesc := @MethodTypeData^.ParamList;
 ResultType := PShortString(ParamDesc);
 for I:=0 to Pred(ParamCount) do begin
   if pfVar in ParamDesc^.Flags then
     Param := "var "
   else if pfConst in ParamDesc^.Flags then
     Param := "const "
   else
     Param := "";
   TypeName := PShortString(PChar(ParamDesc) + SizeOf(TParamFlags) +
     Length(ParamDesc^.ParamName) + SizeOf(Char));
   if pfArray in ParamDesc^.Flags then
     Param := Param + Format("%s: array of %s", [ParamDesc^.ParamName,
       TypeName^])
   else
     Param := Param + Format("%s: %s", [ParamDesc^.ParamName,
       TypeName^]);
   if I <> 0 then
     Params := Params + "; ";
   Params := Params + Param;
   ParamDesc := PParamDesc(PChar(ParamDesc) + SizeOf(TParamFlags) +
     Length(ParamDesc^.ParamName) + Length(TypeName^) +
     SizeOf(Char) * 2);
   ResultType := PShortString(ParamDesc);
 end;
 if Length(Params) <> 0 then
   Params := "(" + Params + ")";
 if MethodTypeData^.MethodKind in
     [mkFunction, mkClassFunction, mkSafeFunction] then
   Params := Format("%s: %s;", [Params, ResultType^])
 else
   Params := Params + ";";
 if MethodTypeData^.MethodKind in [mkSafeProcedure, mkSafeFunction] then
   Params := Params + "safecall;";
 Result := Format("%s %s: %s", [
   MethodKindToString(MethodTypeData^.MethodKind), MethodName, Params]);
end;

function TfMain.ParseMethodProp(AProp: PPropInfo): string;
begin
 Result := ParseMethodProp(AProp, AProp^.Name);
end;

procedure TfMain.SpyInstanceMethods(AClass: TObject;
 Strings, Methods: TStrings);

 function GetFullMethodName(const Methods: TStrings; Address: Pointer): string;
 var
   I: Integer;
 begin
   for I:=0 to Pred(Methods.Count) do
     if Pointer(Methods.Objects[I]) = Address then begin
       Result := Methods[I];
       Break;
     end;
 end;

var
 Props: TPropList;
 I: Integer;
 NumMethods: Integer;
 Method: TMethod;
 FullMethodName: string;
begin
 NumMethods := GetPropList(AClass.ClassInfo, tkMethods, @Props);
 for I:=0 to Pred(NumMethods) do begin
   Method := GetMethodProp(AClass, Props[I]);
   if Assigned(Method.Code) then begin
     FullMethodName := GetFullMethodName(Methods, Method.Code);
     if Length(FullMethodName) <> 0 then
       Strings.Add (ParseMethodProp(Props[I], FullMethodName));
   end;
 end;
end;

procedure TfMain.Button3Click(Sender: TObject);
var
 Strings: TStrings;
begin
 Strings := TStringList.Create;
 try
   SpyRootComponentMethods(fChild, Strings);
   ListBox1.Items.Assign(Strings);
 finally
   Strings.Free;
 end;
end;

procedure TfMain.SpyComponentMethods(AClass: TObject;
 Strings, Methods: TStrings);
var
 I: Integer;
begin
 SpyInstanceMethods(AClass, Strings, Methods);
 if AClass is TComponent then
   for I:=0 to Pred(TComponent(AClass).ComponentCount) do
     SpyComponentMethods(TComponent(AClass).Components[I], Strings, Methods);
end;

procedure TfMain.SpyRootComponentMethods(AClass: TObject;
 Strings: TStrings);
var
 MethodStrings: TStrings;
begin
 MethodStrings := TStringList.Create;
 try
   SpyMethods(AClass.ClassType, MethodStrings);
   SpyComponentMethods(AClass, Strings, MethodStrings);
 finally
   MethodStrings.Free;
 end;
end;

end.


 
Игорь Шевченко ©   (2004-04-20 18:20) [89]

В проекте созданы три формы: главная (текст в студии),
и две формы для иерархии
unit ChildForm;

interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
 Dialogs, ParentForm, ExtCtrls;

type
 TfChild = class(TfParent)
   Timer: TTimer;
   procedure TimerTimer(Sender: TObject);
 end;

var
 fChild: TfChild;

implementation

{$R *.dfm}

procedure TfChild.TimerTimer(Sender: TObject);
begin
 Beep;
end;

end.


и ее родитель:
unit ParentForm;

interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
 Dialogs;

type
 TfParent = class(TForm)
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   procedure FormActivate(Sender: TObject);
 end;

var
 fParent: TfParent;

implementation

{$R *.dfm}

procedure TfParent.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree;
end;

procedure TfParent.FormActivate(Sender: TObject);
begin
 ShowMessage("I am activated");
end;

end.


Все формы создаются в AutoCreate


 
Игорь Шевченко ©   (2004-04-20 18:21) [90]

Как тоже самое сделать не для экземпляра класса, а для класса, легко и просто - не знаю :)


 
-SeM-   (2004-04-21 09:50) [91]

[88] Игорь Шевченко ©   (20.04.04 18:18)

А может еще добавить?


>  for I:=0 to Pred(ParamCount) do begin
>    if pfVar in ParamDesc^.Flags then
>      Param := "var "
>    else if pfConst in ParamDesc^.Flags then
>      Param := "const "


    if pfOut in ParamDesc^.Flags then
      Param:="out ";


>    else
>      Param := "";


 
Игорь Шевченко ©   (2004-04-21 10:17) [92]

-SeM-   (21.04.04 09:50)

Да, спасибо, можно добавить. Может, я его просмотрел. А вот как отображаются в исходном виде параметры pfAddress и pfReference я даже не представляю :)


 
Igorek ©   (2004-04-21 10:38) [93]

Я тут подумал, что в принципе какая-то логика (хотя и имхо неправильная) в постановке Ю.З. есть. Скажем "вывести все методы класса, которые могут выступать в качестве обработчиков". Вот если в форме есть 100 методов, по сигнатуре подходящих для события напр. OnFormCreate, то все их вывести. Но вы же понимаете что только один в конкретный момент может выступать обработчиком. Более того, строго говоря, даже то что на метод указывает поле, хранящее обработчик, этот метод еще не есть обработчиком. Он станет таковым в момент вызова. А до того момента значение поля может сто раз поменяться (что и было продемонстрировано в приведенном мною коде). :-)


 
-SeM-   (2004-04-21 10:44) [94]

[92] Игорь Шевченко ©   (21.04.04 10:17)
А это где, в интерфейсах?


 
Игорь Шевченко ©   (2004-04-21 10:45) [95]

-SeM-   (21.04.04 10:44)

В описании TParamFlag :)


 
Игорь Шевченко ©   (2004-04-21 10:45) [96]


> Вот если в форме есть 100 методов, по сигнатуре подходящих
> для события напр. OnFormCreate, то все их вывести.


А сигнатуру как узнать ? :))


 
-SeM-   (2004-04-21 10:55) [97]


> [93] Igorek ©   (21.04.04 10:38)


> Он станет таковым в момент вызова.


Правильно, но задача то "строить список вообще любых published-методов. То есть - всех доступных данному классу, включая и унаследованные", как я понимаю, на момент исследования.


 
-SeM-   (2004-04-21 10:57) [98]


> [95] Игорь Шевченко ©   (21.04.04 10:45)

Не, я в смысле используется :)


 
Igorek ©   (2004-04-21 13:01) [99]


> Игорь Шевченко ©   (21.04.04 10:45) [96]
> А сигнатуру как узнать ? :))

 TForm1 = class(TForm)
   Memo1: TMemo;
   procedure FormCreate(Sender: TObject);
 private
 public
 published
   procedure FormShow1(Sender: TObject);
   procedure FormShow2(Sender: TObject);
   procedure FormShow3(Sender: TObject);
 end;

А потом RTTI, если не ошибаюсь.


 
Игорь Шевченко ©   (2004-04-21 13:55) [100]

Igorek ©   (21.04.04 13:01)

Дело в том, что по условию задачи сигнатура мне неизвестна. Произвольный обработчик может иметь произвольный процедурный тип.


 
Igorek ©   (2004-04-21 14:25) [101]


> Игорь Шевченко ©   (21.04.04 13:55) [100]
> Igorek ©   (21.04.04 13:01)
>
> Дело в том, что по условию задачи сигнатура мне неизвестна.
> Произвольный обработчик может иметь произвольный процедурный
> тип.

Как? Тип обработчика определяется типом события.
Т.е. или нам надо вывести все публикуемые методы данного класса, которые могут выступать в роли обработчиков для событий обьектов данного класса. Или нам надо вывести сигнатуры (без названий методов) обработчиков которые подходят для всех событий (иными словами типы событий).


 
Игорь Шевченко ©   (2004-04-21 14:28) [102]

Igorek ©   (21.04.04 14:25)

Вроде, я попытался решить задачу, правда, с несколько измененными начальными условиями, используя не класс (VMT), а экземпляр класса (TObject). Я не совсем понимаю, какой смысл в дополнениях к условиям ?


 
Igorek ©   (2004-04-21 14:39) [103]


> Игорь Шевченко ©   (21.04.04 14:28) [102]
Я не совсем понимаю, какой смысл в дополнениях
> к условиям ?

Просто я привык перед решением четко сформулировать задачу. Что и стараюсь после вчерашнего (а то остался неприятный осадок, и думаю не только у меня). Без формулировки у меня лично нету ни малейшего желания даже браться за задачу.


 
Юрий Зотов ©   (2004-04-21 15:15) [104]

Все же исходная постановка задачи в [42] была правильной - без привязки к TypeData можно построить список параметров для методов RTTI-интерфейсов (см. [80]), а для методов произвольных объектов, как сказал Игорь, нужно либо сканировать ресурсы ручками, либо создавать экземпляр - иначе привязаться к TypeData и получить параметры не удается.

Тем не менее, обоими методами можно получить решение именно для класса, а не для объекта. Естественно, параметры будут получены только для тех методов, которые в этом классе являются обработчиками событий (о чем, собственно, сразу и говорилось в [42]).

Привожу свое решение для обоих вариантов (переключаются опцией ParseDfmIndirect). Чтобы не загромождать код непринципиальными деталями, сканируются только события самих форм. Опция AutoRegisterForms указывает, должна ли быть использована автоматическая регистрация форм (можно либо отключить эту опцию, либо взять пример кода авторегистрации в "Кладовке").

================ Код см. в продолжении ================


 
Юрий Зотов ©   (2004-04-21 15:16) [105]

================ Продолжение ================

Проект состоит из стандартного DPR, модуля главной формы и трех модулей форм, входящих в иерархию. Модуль главной формы такой:

unit Main;

interface

uses
 Classes, Controls, Forms, StdCtrls;

type
 TAppMainForm = class(TForm)
   ListBox1: TListBox;
   Button1: TButton;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 end;

var
 AppMainForm: TAppMainForm;

implementation

{$R *.dfm}

{$DEFINE ParseDfmIndirect}
// {$DEFINE AutoRegisterForms}

uses
 Windows, SysUtils, TypInfo, First, Third,
{$IFDEF AutoRegisterForms}
 ClassReg;
{$ELSE AutoRegisterForms}
 Second;
{$ENDIF AutoRegisterForms}

var
 FormsModule: Cardinal;

procedure GetAllHandlers(Strings: TStrings; AClass: TClass);

 function GetHandlers(Strings: TStrings; AClass: TClass): Boolean;

   procedure IncPtr(var P: Pointer; Value: integer);
   begin { IncPtr }
     P := Pointer(Integer(P) + Value)
   end; { IncPtr }

   function ExtractShortString(var P: Pointer): string;
   begin { GetShortString }
     Result := ShortString(P^);
     IncPtr(P, Byte(P^) + 1)
   end; { GetShortString }

   function GetMethodParams(MethodName: string; AClass: TClass): string;

{$IFDEF ParseDfmIndirect}
     function GetHandlerName(PropName: string; AClass: TClass): string;
     var
       ResourceStream: TResourceStream;
       StringStream: TStringStream;
       Fmt: TStreamOriginalFormat;
       i: integer;
     begin
       Result := "";
       if (AClass = nil) or (FindResource(FormsModule, PChar(AClass.ClassName + #0), RT_RCDATA) = 0) then
         Exit;
       StringStream := TStringStream.Create("");
       try
         ResourceStream := TResourceStream.Create(FormsModule, AClass.ClassName, RT_RCDATA);
         try
           Fmt := sofText;
           ObjectResourceToText(ResourceStream, StringStream, Fmt)
         finally
           ResourceStream.Free
         end;
         i := Length(PropName) + 2;
         with StringStream do
         begin
           Position := Pos(PropName, DataString) + i;
           if Position > i then
           begin
             i := Position;
             while DataString[i] in ["_", "0".."9", "A".."Z", "a".."z"] do Inc(i);
             Result := Copy(DataString, Position, i - Position)
           end
           else Result := GetHandlerName(PropName, AClass.ClassParent)
         end
       finally
         StringStream.Free
       end
     end;
{$ELSE ParseDfmIndirect}
     function GetHandlerAddress(PropInfo: PPropInfo): Pointer;
     var
       Component: TComponent;
     begin { GetHandlerAddress }
       Component := ReadComponentRes(AClass.ClassName, nil);
       try
         Result := GetMethodProp(Component, PropInfo).Code
       finally
         Component.Free
       end
     end; { GetHandlerAddress }
{$ENDIF ParseDfmIndirect}
   var
     PropList: PPropList;
     PropCount, i, ParamCount, j: integer;
     P: Pointer;
   begin { GetMethodParams }
     Result := "";
     PropCount := GetPropList(AClass.ClassInfo, tkMethods, nil);
     if PropCount = 0 then Exit;
     GetMem(PropList, PropCount * SizeOf(PPropInfo));
     try
       GetPropList(AClass.ClassInfo, tkMethods, PropList);
       for i := 0 to PropCount - 1 do
{$IFDEF ParseDfmIndirect}
         if SameText(MethodName, GetHandlerName(PropList^[i].Name, AClass)) then
{$ELSE ParseDfmIndirect}
         if AClass.MethodAddress(MethodName) = GetHandlerAddress(PropList^[i]) then
{$ENDIF ParseDfmIndirect}
         begin
           P := GetTypeData(PropList^[i]^.PropType^);
           IncPtr(P, SizeOf(TMethodKind));
           ParamCount := Byte(P^);
           IncPtr(P, 1);
           for j := 0 to ParamCount - 1 do
           begin
             if pfVar in TParamFlags(P^) then
               Result := Result + "var "
             else
               if pfConst in TParamFlags(P^) then
                 Result := Result + "const "
               else
                 if pfOut in TParamFlags(P^) then
                   Result := Result + "out ";
             IncPtr(P, SizeOf(TParamFlags));
             Result := Format("%s%s: %s; ", [Result, ExtractShortString(P), ExtractShortString(P)])
           end;
           SetLength(Result, Length(Result) - 2);
           Exit
         end
     finally
       FreeMem(PropList)
     end
   end; { GetMethodParams }

 var
   P: Pointer;
   MethodCount, i: Word;
   MethodName: string;
 begin { GetHandlers }
   Result := False;
   P := AClass;
   IncPtr(P, vmtMethodTable);
   P := Pointer(P^);
   if P = nil then Exit;
   MethodCount := Word(P^);
   if MethodCount = 0 then Exit else Result := True;
   IncPtr(P, SizeOf(Word));
   for i := 0 to MethodCount - 1 do
   begin
     IncPtr(P, SizeOf(Word) + SizeOf(Pointer));
     MethodName := ExtractShortString(P);
     if Pos(MethodName, Strings.Text) = 0 then
       Strings.Add(Format("%s.%s(%s);", [AClass.ClassName, MethodName,
         GetMethodParams(MethodName, AClass)]))
   end
 end; { GetHandlers }

begin { GetAllHandlers }
 Strings.BeginUpdate;
 try
   Strings.Clear;
   while AClass <> nil do
   begin
     GetHandlers(Strings, AClass);
     AClass := AClass.ClassParent
   end
 finally
   Strings.EndUpdate
 end
end; { GetAllHandlers }

{$IFDEF AutoRegisterForms}
function RegisterForms(AClass: TClass; Data: Pointer): Boolean;
begin
 Result := True;
 if AClass.InheritsFrom(TFirstForm) then Classes.RegisterClass(TPersistentClass(AClass))
end;
{$ENDIF AutoRegisterForms}

{ TForm1 }

procedure TAppMainForm.FormCreate(Sender: TObject);
begin
 FormsModule := FindClassHInstance(TFirstForm);
{$IFDEF AutoRegisterForms}
 EnumClasses(FormsModule, RegisterForms, nil)
{$ELSE AutoRegisterForms}
 RegisterClasses([TFirstForm, TSecondForm, TThirdForm])
{$ENDIF AutoRegisterForms}
end;

procedure TAppMainForm.Button1Click(Sender: TObject);
begin
 GetAllHandlers(ListBox1.Items, TThirdForm)
end;

end.


================ Модули с формами иерархии см. в окончании ================


 
Юрий Зотов ©   (2004-04-21 15:18) [106]

================ Окончание ================

unit First;

interface

uses
 Forms;

type
 TFirstForm = class(TForm)
   procedure FormCreate(Sender: TObject);
   procedure FormCanResize(Sender: TObject; var NewWidth, NewHeight: Integer; var Resize: Boolean);
 end;

implementation

{$R *.dfm}

procedure TFirstForm.FormCreate(Sender: TObject);
begin
 Width := 500
end;

procedure TFirstForm.FormCanResize(Sender: TObject; var NewWidth, NewHeight: Integer; var Resize: Boolean);
begin
 Resize := True
end;

end.

unit Second;

interface

uses
 Forms, First;

type
 TSecondForm = class(TFirstForm)
   procedure FormCreate(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 end;

implementation

{$R *.dfm}

procedure TSecondForm.FormCreate(Sender: TObject);
begin
 Width := 500
end;

procedure TSecondForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree
end;

end.

unit Third;

interface

uses
 Classes, Forms, Second;

type
 TThirdForm = class(TSecondForm)
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
 end;

implementation

{$R *.dfm}

procedure TThirdForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree
end;

procedure TThirdForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
 Key := 0
end;

end.


 
Игорь Шевченко ©   (2004-04-21 15:33) [107]

Юрий Зотов ©   (21.04.04 15:16)

Respect!

Про ReadComponentRes я не додумал, спасибо за науку :)


 
euru ©   (2004-04-21 15:58) [108]

Вопрос не по теме, а по коду.

Почему для определения собственных условий компиляции используется конструкция


{$DEFINE condition}

{$IFDEF condition}
{$ENDIF}


вместо


const
  condition = True;

{$IF condition}
{$IFEND}


 
Vuk ©   (2004-04-21 16:20) [109]

to euru ©   (21.04.04 15:58) [108]:
>Почему для определения собственных условий компиляции
>используется конструкция
Потому, что то, что определяется через $DEFINE можно компилятору с командной строки передать.


 
euru ©   (2004-04-21 16:55) [110]

>Vuk ©   (21.04.04 16:20) [109]
А как через командную строку можно определить условие типа

{$IF condition > 5}


 
Игорь Шевченко ©   (2004-04-21 17:05) [111]

euru ©   (21.04.04 16:55)

А у меня компилятор выдает Invalid compiler directive $IF. Отгадайте с трех раз, почему ?


 
Vuk ©   (2004-04-21 17:15) [112]

to euru ©   (21.04.04 16:55) [110]:
>А как через командную строку можно определить условие типа
>{$IF condition > 5}
Для {$IF condition > 5} - никак. Для {$IF Defined(VARIABLE)} и {$IFDEF VARIABLE} - при помощи -D

И вообще, dcc32.exe


 
euru ©   (2004-04-21 17:24) [113]

>Игорь Шевченко ©   (21.04.04 17:05) [111]
Думаю, у вас Delphi v1-v6.

>Игорь Шевченко ©   (21.04.04 17:05) [111]
>Vuk ©   (21.04.04 17:15) [112]
Спасибо за предоставленную информацию.


 
VMcL ©   (2004-04-21 17:32) [114]

>>euru ©  (21.04.04 17:24) [113]

В D6 уже появилась {$IF}.


 
Igorek ©   (2004-04-21 17:45) [115]


2 Юрий Зотов ©   (21.04.04 15:18) [106]

Однако я смотрю этот вопрос для Вас стал принципиальным. :-)
Не умаляя достоинств приведенного кода, позволю себе не согласиться, что это решение задачи в постановке [42]. Там ничего не говорилось про RTTI. Соотв. был и мой пост [53].
Повторю касательно постановки 42. В роли обработчиков могут выступать и не публикуемые методы.
Поймите меня правильно. Я не придираюсь, а просто, отбросив обиды, пытаюсь обьективно найти истину.


 
Игорь Шевченко ©   (2004-04-21 18:00) [116]


> В роли обработчиков могут выступать и не публикуемые методы.


Вот теперь я понял всю глубину задачи:)

Юрий Зотов в задаче и в дополнениях к ней специально сделал акцент на класс, а не на экземпляр. У класса формы в роли обработчиков событий компонент(ов) могут выступать только published-методы.


 
Igorek ©   (2004-04-21 18:30) [117]


> Игорь Шевченко ©   (21.04.04 18:00) [116]
> У класса формы в роли
> обработчиков событий компонент(ов) могут выступать только
> published-методы.

Ты не прав. Не публикуемые методы тоже могут выступать в такой роли. Просто присвоить их событиям можно только динамически.


 
McSimm ©   (2004-04-21 18:34) [118]


> Просто присвоить их событиям можно только динамически.

классу ?


 
Игорь Шевченко ©   (2004-04-21 18:34) [119]


> Просто присвоить их событиям можно только динамически.


Ты сказал (с) Евангелие.

В момент разбора VMT нету экземпляров класса, следовательно о динамическом присвоении речи быть не может :)


 
Игорь Шевченко ©   (2004-04-21 18:37) [120]

Игорь Шевченко ©   (21.04.04 18:34)

Следует читать: При разборе VMT не имеет значения, есть ли экземпляры класса или нет.



Страницы: 1 2 3 4 вся ветка

Форум: "Потрепаться";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.73 MB
Время: 0.049 c
3-1082555269
}|{yk
2004-04-21 17:47
2004.05.16
Master-detail в FIBPlus


14-1082838560
Thor
2004-04-25 00:29
2004.05.16
металлоискатели все стран....


14-1082787568
gn
2004-04-24 10:19
2004.05.16
Новая технология защиты кредитных карт с распознаванием голоса


1-1083426139
Viner
2004-05-01 19:42
2004.05.16
Возможность вставки рисунков


3-1082627971
ИМХО
2004-04-22 13:59
2004.05.16
Не могу понять с DAO.DBEngine.36





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский