Delphi: Detect when a new form has been created

自古美人都是妖i 提交于 2019-12-02 03:22:36

问题


I'd like to detect when a new form has been created.

Now I use the Screen.ActiveFormChange event and check for new forms in Screen.CustomForms but ActiveFormChange is fired after the OnShow event of the form.

I'd like to detect the form even before OnShow was fired. Is there any way to do this without modifying the Vcl.Forms unit?

I'd like to detect all forms (also Delphi modal messages etc.) therefore inheriting all forms from a custom class is not possible (correct me if I am wrong).

Alternatively, is it possible to detect that a new component was added to some TComponent.FComponents list?


回答1:


You can use the SetWindowsHookEx function to install a WH_CBT Hook, then you must implement a CBTProc callback function and finally intercept one of the possible code values for this hook. in this case you can try with HCBT_ACTIVATE or HCBT_CREATEWND.

Check this sample for the HCBT_ACTIVATE Code.

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.

Note : if you uses the HCBT_CREATEWND code instead you will intercept any window created by the system not just "forms".




回答2:


Track Screen.CustomFormCount in 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;

Native dialogs managed and shown by Windows (TOpenDialog, TFontDialog, etc...) are created apart from the VCL and to track them also, you need a hacking unit. Try this one then.




回答3:


Thanks to David I found a solution: The clue is to replace Screen.AddForm method with your own. The way how to do it is described in these SO answers:

  • How I can patch a private method of a delphi class?
  • How to change the implementation (detour) of an externally declared function
  • Patch routine call in delphi

Thanks again!



来源:https://stackoverflow.com/questions/11575699/delphi-detect-when-a-new-form-has-been-created

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!