Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Geting a reference to a dialog window form (ShowMessage, MsgDialog etc)

Tags:

events

delphi

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.

like image 997
Jacek Kwiecień Avatar asked Mar 09 '12 09:03

Jacek Kwiecień


3 Answers

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.

like image 168
David Heffernan Avatar answered Nov 09 '22 13:11

David Heffernan


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;
like image 5
Ondrej Kelle Avatar answered Nov 09 '22 11:11

Ondrej Kelle


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;
like image 2
GDF Avatar answered Nov 09 '22 11:11

GDF