Is there any event I could use so I'd catch the moment when ShowMessage
appears on the screen? I'd also need pass a reference to the TForm
which has shown the Message.
So far I tried OnDeactivate
, but it seems, ShowMessage
is not causing it...
In.NET there is methon on Application that catches every MessageBox (Application.AddFilterMessage or smth like this), I'd need something like this in delphi
What I'm trying to achive is: I must catch the moment while a dialog window appears (or just a modal window, but it's not that comfortable). I need to do couple of instructions then. Goal of those instructions is to give me a refference to the just recieved DialogWindow so I could for example get a number of buttons that lies on it.
In modern Delphi versions, on modern Windows versions, ShowMessage
results in a Windows dialog window. You can use a WH_CBT
hook to catch the activation of that dialog window.
function CBTProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
wnd: HWND;
ClassName: string;
begin
if nCode=HCBT_ACTIVATE then
begin
wnd := wParam;
SetLength(ClassName, 256);
SetLength(ClassName, GetClassName(wnd, PChar(ClassName), Length(ClassName)));
if (ClassName='#32770') or (ClassName='TMessageForm') then
Beep;
end;
Result := CallNextHookEx(0, nCode, wParam, lParam);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Hook: HHOOK;
begin
Hook := SetWindowsHookEx(WH_CBT, CBTProc, HInstance, GetCurrentThreadId);
if Hook=0 then
RaiseLastOSError;
try
ShowMessage('hello');
finally
if not UnhookWindowsHookEx(Hook) then
RaiseLastOSError;
end;
end;
Note that the actual window class name varies from system to system. On XP the class name will be TMessageForm
because the dialog is actually a Delphi TForm
. However, on Vista and later the dialog is a standard window message box dialog with window class name #32770
.
I've shown this wrapped around a single call to ShowMessage
, but you could install this at startup if you want to hook all message dialogs shown in your app.
You can also use an application-wide hook installed in the main form's OnCreate
event (uninstalled in OnDestroy
):
procedure TMainForm.FormCreate(Sender: TObject);
begin
...
Application.HookMainWindow(ApplicationHook);
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
...
Application.UnhookMainWindow(ApplicationHook);
end;
function TMainForm.ApplicationHook(var Message: TMessage): Boolean;
var
I: Integer;
begin
Result := False;
if (Message.Msg = WM_ENABLE) and not TWMEnable(Message).Enabled then // disabling
for I := 0 to Screen.FormCount - 1 do
with Screen.Forms[I] do
if Enabled and (ClassNameIs('TMessageForm') or // ShowMessage, MessageDlg
ClassNameIs('TForm') or // InputQuery
ClassNameIs('TMyLoginDialog')) then // your own dialogs, etc.
begin
Screen.Forms[I].Position := poScreenCenter; // for example
Result := True;
Break;
end;
end;
Why not just use OnActiveFormChange?
procedure TForm3.FormCreate(Sender: TObject);
begin
Screen.OnActiveFormChange := ScreenActiveFormChange;
end;
procedure TForm3.ScreenActiveFormChange(Sender: TObject);
begin
if Screen.ActiveForm is TOKRightDlg then
Screen.ActiveForm.Caption := 'Found';
end;
procedure TForm3.Button1Click(Sender: TObject);
begin
with TOKRightDlg.Create(nil) do
try
ShowModal;
finally
Free;
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With