我想检测何时创建新表单。
现在我使用Screen.ActiveFormChange
事件并检查Screen.CustomForms
中的新表单,但在表单的ActiveFormChange
事件后触发了OnShow
。
我想在OnShow
被解雇之前检测表单。有没有办法在不修改Vcl.Forms
单位的情况下执行此操作?
我想检测所有表单(也是Delphi模态消息等),因此无法从自定义类继承所有表单(如果我错了,请纠正我)。
或者,是否可以检测到某个TComponent.FComponents
列表中添加了新组件?
答案 0 :(得分:4)
您可以使用SetWindowsHookEx
函数安装WH_CBT
Hook,然后必须实现CBTProc callback函数,最后拦截此挂钩的一个可能代码值。在这种情况下,您可以尝试使用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
代码,则可以 拦截系统创建的任何窗口而不仅仅是“表单”。
答案 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(TOpenDialog
,TFontDialog
等)管理和显示的原生对话框是在VCL之外创建的,并且还要跟踪它们,您需要一个黑客单位。然后尝试this one。
答案 2 :(得分:1)
感谢David我找到了一个解决方案:线索是用自己的方法替换Screen.AddForm
方法。在这些SO答案中描述了如何做到这一点:
再次感谢!