Delphi: Detect when a new form has been created

delphi, vcl

Solution

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".

Problem

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?

Original source

Related problems