获取对话框窗口表单的引用(ShowMessage,MsgDialog等)

Jac*_*ień 5 delphi events

有没有我可以使用的事件所以我会抓住ShowMessage屏幕上显示的那一刻?我还需要传递对TForm已显示消息的引用.

到目前为止我试过了OnDeactivate,但似乎ShowMessage并没有引起它......

在.NET中有一个关于Application的方法可以捕获每个MessageBox(Application.AddFilterMessage或类似这样的smth),我在delphi中需要这样的东西

我想要实现的是: 我必须抓住一个对话窗口出现的那一刻(或者只是一个模态窗口,但它并不那么舒服).我需要做几个指令.这些说明的目标是给我一个刚刚收到的DialogWindow的参考,所以我可以得到一些位于它上面的按钮.

Dav*_*nan 6

在现代的Delphi版本中,在现代Windows版本中,ShowMessage会产生Windows对话窗口.您可以使用WH_CBT钩子来捕获该对话框窗口的激活.

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;
Run Code Online (Sandbox Code Playgroud)

请注意,实际的窗口类名称因系统而异.在XP上,类名将是TMessageForm因为对话框实际上是一个Delphi TForm.但是,在Vista上以后,该对话框是一个带窗口类名称的标准窗口消息框对话框#32770.

我已经在一次调用中显示了这个ShowMessage,但如果你想挂钩应用程序中显示的所有消息对话框,你可以在启动时安装它.

  • +1.`ShowMessage`(Dialogs)创建一个窗口类`TMessageForm`.我也相信你需要在`CBTProc`中调用`Result:= CallNextHookEx`. (2认同)

Ond*_*lle 5

您还可以使用主窗体OnCreate事件中安装的应用程序范围的挂钩(已卸载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;
Run Code Online (Sandbox Code Playgroud)