Delphi: Открива кога е създадена нова форма

Бих искал да открия кога е създаден нов формуляр.

Сега използвам събитието Screen.ActiveFormChange и проверявам за нови формуляри в Screen.CustomForms, но ActiveFormChange се задейства след събитието OnShow на формуляра.

Бих искал да открия формата още преди OnShow да бъде уволнен. Има ли някакъв начин да направите това, без да модифицирате единицата Vcl.Forms?

Бих искал да открия всички форми (също модални съобщения на Delphi и т.н.), следователно наследяването на всички форми от потребителски клас не е възможно (поправете ме, ако греша).

Като алтернатива, възможно ли е да се открие, че нов компонент е добавен към някакъв списък TComponent.FComponents?


person oxo    schedule 20.07.2012    source източник
comment
обикновено имате контрол върху създаването на формуляри, защо е необходимо откриване?   -  person whosrdaddy    schedule 20.07.2012
comment
не точно. ако извикате ShowMessage, диалоговият прозорец се създава някъде в модула Dialogs.   -  person oxo    schedule 20.07.2012
comment
вашият код извиква showmessage, нали? така че ИМАТЕ контрол... можете да създадете функция за обвивка за това. (DetectShowMessage или нещо подобно)   -  person whosrdaddy    schedule 20.07.2012
comment
@whosrdaddy Това води до много и много обвиващ код   -  person David Heffernan    schedule 20.07.2012
comment
@whosrdaddy Дейвид е прав. ShowMessage беше само пример. Методът трябва да се използва в различни delphi приложения, които стартират всякакви диалогови прозорци, така че обвивката не е възможна. Това, което искам да открия, е когато се добави нов формуляр към Screen.CustomForms и да се закачи с stackoverflow.com/questions/8743876/ към него.   -  person oxo    schedule 20.07.2012
comment
Чудя се, че няма Screen.OnFormCreated или нещо подобно. Това биха били може би 5 допълнителни реда код в модула Forms...   -  person oxo    schedule 20.07.2012
comment
@oxo Не мисля, че има нещо вградено. Ще трябва да направите малко VCL хакване.   -  person David Heffernan    schedule 20.07.2012
comment
@DavidHeffernan да, очаквах го. Търсих чрез модула Forms за съобщение, което би било изпратено до обекта Application или нещо подобно, но все още не съм намерил нищо... Мислите ли, че е възможно да постигна целта си, без да променя VCL кода?   -  person oxo    schedule 20.07.2012
comment
@oxo Със сигурност можете да го направите, без да модифицирате VCL кода, но може да се наложи да приложите някои куки за изпълнение на код, за да го направите!   -  person David Heffernan    schedule 20.07.2012
comment
@DavidHeffernan Проблемът е, че трябва да се закача към частна процедура вътре в обект (TScreen.AddForm). Вече използвах stackoverflow.com/questions/6905287/ - но само за замяна на нормална процедура, а не процедура на обект. Има ли подобна кука, която мога да приложа на TScreen.AddForm?   -  person oxo    schedule 20.07.2012
comment
Мисля, че ще трябва да използвате помощник на класа, за да разбиете този частен метод   -  person David Heffernan    schedule 20.07.2012
comment
Благодаря за информацията - намерих вашия отговор на SO, ще го пробвам.   -  person oxo    schedule 20.07.2012
comment
Да, спомням си, че веднъж писах нещо по тази тема тук, но не можах да се справя с търсенето. Браво, че го намери! Дано помогне.   -  person David Heffernan    schedule 20.07.2012
comment
Да, успях да го направя с ваша помощ! Благодаря много. Можете да напишете вашите коментари като отговор, за да мога да го приема и да получите някои точки :) Ключът беше да използвате stackoverflow.com/questions/10156430/, за да получа TScreen. AddForm указател и го коригирайте с stackoverflow.com/questions/6905287/ - сега мога да отменя TScreen.AddForm! Благодаря за съветите!   -  person oxo    schedule 20.07.2012
comment
Всъщност не съм толкова притеснен да напиша отговор и да получа точки тук. Винаги можете да гласувате за отговорите, които са ви помогнали, ако искате.   -  person David Heffernan    schedule 20.07.2012
comment
TThemeManager на Майк Лишке използва серия от техники за откриване на нови форми в програмата. (Трябваше да знае за нови форми, за да може да инструментира рутинните процедури за рисуване на своите компоненти и да приложи XP теми.) Може да си струва да проверите този код, за да видите как се прави.   -  person Rob Kennedy    schedule 20.07.2012


Отговори (3)


Можете да използвате SetWindowsHookEx функция за инсталиране на WH_CBT Hook, тогава трябва да внедрите обратно извикване на CBTProc и накрая прихване една от възможните кодови стойности за тази кука. в този случай можете да опитате с HCBT_ACTIVATE или HCBT_CREATEWND.

Проверете тази проба за кода HCBT_ACTIVATE.

var
 hhk: HHOOK;

function CBT_FUNC(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
const
  ClassNameBufferSize = 1024;
var
 hWindow: HWND;
 RetVal : Integer;
 ClassNameBuffer: Array[0..ClassNameBufferSize-1] of Char;
begin
   Result := CallNextHookEx(hhk, nCode, wParam, lParam);
   if nCode<0 then exit;
   case nCode of
     HCBT_ACTIVATE:
     begin
       hWindow := HWND(wParam);
       if (hWindow>0) then
       begin
          RetVal := GetClassName(wParam, ClassNameBuffer, SizeOf(ClassNameBuffer));
          if RetVal>0 then
          begin
            //do something  
            OutputDebugString(ClassNameBuffer);                     
          end;
       end;
     end;
   end;

end;

Procedure InitHook();
var
  dwThreadID : DWORD;
begin
  dwThreadID := GetCurrentThreadId;
  hhk := SetWindowsHookEx(WH_CBT, @CBT_FUNC, hInstance, dwThreadID);
  if hhk=0 then RaiseLastOSError;
end;

Procedure KillHook();
begin
  if (hhk <> 0) then
    UnhookWindowsHookEx(hhk);
end;

initialization
  InitHook();

finalization
  KillHook();

end.

Забележка: ако вместо това използвате кода HCBT_CREATEWND, ще прихванете всеки прозорец, създаден от системата, а не само "форми".

person RRUZ    schedule 20.07.2012
comment
Благодаря, това е МНОГО хубав подход. Въпреки че има някои недостатъци: използването на HCBT_ACTIVATE обвързва кода //do something след събитието OnShow. И когато използвате HCBT_CREATEWND, FindControl(hWindow) на delphi не намира нищо. - person oxo; 20.07.2012
comment
Това е така, защото HCBT_CREATEWND се задейства по време на създаването на HWND, преди VCL да има шанс да го асоциира с TWinControl обект. - person Remy Lebeau; 20.07.2012
comment
Това е абсолютно вярно, но все пак е недостатък... Въпреки това според мен е много по-добро решение от използването на OnIdle. За VCL формуляри има приблизително същия ефект като Screen.ActiveFormChange. - person oxo; 21.07.2012

Песен Screen.CustomFormCount в Application.OnIdle:

  private
    FPrevFormCount: Integer;
  end;

procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
  if Screen.CustomFormCount > FPrevFormCount then
    Caption := Caption + ' +1';
  if Screen.CustomFormCount <> FPrevFormCount then
    FPrevFormCount := Screen.CustomFormCount;
end;

procedure TForm1.TestButton1Click(Sender: TObject);
begin
  TForm2.Create(Self).Show;
end;

procedure TForm1.TestButton2Click(Sender: TObject);
begin
  ShowMessage('Also trackable?');  // Yes!
end;

procedure TForm1.TestButton3Click(Sender: TObject);
begin
  OpenDialog1.Execute; // Doesn't update Screen.CustomFormCount
end;

Родните диалогови прозорци, управлявани и показвани от Windows (TOpenDialog, TFontDialog и т.н...), се създават отделно от VCL и за да ги проследявате също, имате нужда от хакерско устройство. Тогава опитайте този.

person NGLN    schedule 20.07.2012
comment
OnIdle НЕ работи по начина, по който го описах във въпроса - OnIdle се задейства след OnShow (тествано с основна форма). Мисля, че закачането на VCL, както Дейвид предложи в коментарите, е единственият правилен начин това да работи. Но все пак благодаря, че отбелязахте собствените диалози. - person oxo; 20.07.2012

Благодарение на Дейвид намерих решение: Уликата е да замените Screen.AddForm метода със свой собствен. Начинът, по който да го направите, е описан в тези SO отговори:

Благодаря отново!

person oxo    schedule 20.07.2012
comment
Опитахте ли да инсталирате WH_CBT кука с SetWindowsHookEx функция? - person RRUZ; 20.07.2012
comment
Добре, ще публикувам отговор по тази тема. - person RRUZ; 20.07.2012