在MessageBox中检测帮助按钮的点击?

4
在Delphi XE7中,我需要在MessageBox中使用帮助按钮。MSDN说明如下:

MB_HELP 0x00004000L 将帮助按钮添加到消息框中。当用户单击帮助按钮或按F1键时,系统会向所有者发送WM_HELP消息。

然而,当我在MessageBox中单击帮助按钮时,似乎没有向应用程序发送WM_HELP消息:
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
  if Msg.message = WM_HELP then
    CodeSite.Send('ApplicationEvents1Message WM_HELP');
end;

procedure TForm1.btnShowMessageBoxClick(Sender: TObject);
begin
  MessageBox(Self.Handle, 'Let''s test the Help button.', 'Test', MB_ICONINFORMATION or MB_OK or MB_HELP);
end;

那么我如何获取MessageBox帮助按钮的点击事件,并且如何检测它来自哪个MessageBox?
2个回答

5
文档中强调说:
系统向所有者发送 WM_HELP 消息。
这是指消息被同步直接传递到窗口过程。换句话说,它是使用 SendMessage 或等效的 API 发送的。
您尝试在 TApplicationEvents.OnMessage 中处理它,该方法用于拦截异步消息。这些消息通常使用 PostMessage 放置在消息队列中。
因此,您从未在 TApplicationEvents.OnMessage 中看到该消息的原因是该消息从未放置在队列中。相反,您需要在所有者窗口的窗口过程中处理该消息。在 Delphi 中,最简单的方法是:
type
  TForm1 = class(TForm)
  ....
  protected
    procedure WMHelp(var Message: TWMHelp); message WM_HELP;
  end;
....
procedure TForm1.WMHelp(var Message: TWMHelp);
begin
  // your code goes here
end;

关于如何检测哪个消息框导致消息被发送,使用 MessageBox 没有简单的方法。也许最好的方法是切换到 MessageBoxIndirect。这允许您在 MSGBOXPARAMSdwContextHelpId 字段中指定一个 ID。该 ID 将传递给 WM_HELP 消息的接收者,如 文档 中所述。
如果您要显示帮助文件中的主题,以响应用户按下帮助按钮,则可以考虑 VCL 函数 MessageDlg。这允许您传递帮助上下文 ID,并且框架将显示应用程序帮助文件,并传递该帮助上下文 ID。

感谢David和Denis提供详尽且专业的回答! - user1580348
David,你在回答的第一段和第二段中都使用了“同步”的术语,这是一个笔误吗?还是其中一个应该是“异步”? - user1580348
@user1580348 您说得对。谢谢您。我现在已经修复了它。 - David Heffernan

2

最小工作示例:

type
  TForm20 = class(TForm)
    procedure FormCreate(Sender: TObject);
  protected
    procedure WMHelp(var Message: TWMHelp); message WM_HELP;
  end;

procedure TForm20.FormCreate(Sender: TObject);
begin
  MessageBox(Handle, 'Help test', nil, MB_OK or MB_HELP);
end;

procedure TForm20.WMHelp(var Message: TWMHelp);
begin
  Caption := 'Help button works';
end;

谢谢Denis。那么为什么这个在TApplicationEvents中不起作用呢?我如何检测消息来自哪个MessageBox?(而不必在调用MessageBox之前设置变量)。 - user1580348

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接