Delphi: Detect when a new form has been created

后端 未结 3 1164
暖寄归人
暖寄归人 2021-01-20 09:46

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

相关标签:
3条回答
  • 2021-01-20 10:20

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

    0 讨论(0)
  • 2021-01-20 10:24

    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!

    0 讨论(0)
  • 2021-01-20 10:26

    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.

    0 讨论(0)
提交回复
热议问题