Delphi:检测何时创建新表单

时间:2012-07-20 08:32:57

标签: delphi vcl

我想检测何时创建新表单。

现在我使用Screen.ActiveFormChange事件并检查Screen.CustomForms中的新表单,但在表单的ActiveFormChange事件后触发了OnShow

我想在OnShow被解雇之前检测表单。有没有办法在不修改Vcl.Forms单位的情况下执行此操作?

我想检测所有表单(也是Delphi模态消息等),因此无法从自定义类继承所有表单(如果我错了,请纠正我)。

或者,是否可以检测到某个TComponent.FComponents列表中添加了新组件?

3 个答案:

答案 0 :(得分:4)

您可以使用SetWindowsHookEx函数安装WH_CBT Hook,然后必须实现CBTProc callback函数,最后拦截此挂钩的一个可能代码值。在这种情况下,您可以尝试使用HCBT_ACTIVATEHCBT_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代码,则可以   拦截系统创建的任何窗口而不仅仅是“表单”。

答案 1 :(得分:2)

跟踪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(TOpenDialogTFontDialog等)管理和显示的原生对话框是在VCL之外创建的,并且还要跟踪它们,您需要一个黑客单位。然后尝试this one

答案 2 :(得分:1)

感谢David我找到了一个解决方案:线索是用自己的方法替换Screen.AddForm方法。在这些SO答案中描述了如何做到这一点:

再次感谢!