【问题标题】:PostMessage for all instances of a specific form (ClassName):PostMessage 用于特定表单(ClassName)的所有实例:
【发布时间】:2018-01-09 13:57:44
【问题描述】:

在 VCL Forms 程序中,我有一个 Form,它实现了一种处理 windows 消息和更新 Form 上的某些控件的方法,例如:

procedure OnMsgTest (var Msg: TMessage); message WM_CUSTOMTEST;

我使用PostMessage 向此表单发送自定义消息,使用如下代码:

  h := FindWindow('TFrmTest', nil);    
  if IsWindow(h) then begin    
    PostMessage(h, WM_CUSTOMTEST, 0, 0);    
  end;

当多次实例化Form时,使用上述代码发送消息,只有一个Form实例更新屏幕上的信息。我希望所有打开和实例化的表单都能接收到消息。

重要提示:PostMessage 可以出现在 Form 进程本身中,也可以来自另一个进程。所以,我相信通过表格的循环是行不通的。

实现我的目标的最佳方法是什么?

【问题讨论】:

  • 使用EnumerateWindows 查找所有顶级窗口。检查它们是否有匹配的类名。希望世界上没有其他人使用与您相同的表单名称。
  • 一个更简单、更安全的选择是使用RegisterWindowMessage()PostMessage(HWND_BROADCAST)。让操作系统为你做枚举,只有感兴趣的窗口会对消息做出反应,其他窗口会忽略它。然后类名无关紧要。但是,由于RegisterWindowMessage 是动态的,因此您不能使用message 处理程序,因此请让Form 覆盖虚拟WndProc 方法。
  • 我赞同雷米所说的

标签: delphi delphi-10.1-berlin


【解决方案1】:

您必须枚举所有正在运行的顶级窗口,将消息分别发布到每个匹配的窗口。您可以为此使用EnumWindows()FindWindow/Ex() 循环,但更简单的解决方案是使用PostMessage(HWND_BROADCAST) 来广播使用RegisterWindowMessage() 注册的消息。只有处理注册消息的窗口才会对它做出反应,其他窗口会简单地忽略它。例如:

type
  TMyForm = class(TForm)
  protected
    procedure WndProc(var Msg: TMessage); override;
  end;

...

var
  WM_CUSTOMTEST: UINT = 0;

procedure TMyForm.WndProc(var Msg: TMessage);
begin
  if (Msg.Msg = WM_CUSTOMTEST) and (WM_CUSTOMTEST <> 0) then
  begin
    ...
  end else
    inherited;
end;

initialization
  WM_CUSTOMTEST := RegisterWindowMessage('SomeUniqueNameHere');

然后你可以在需要的时候这样做:

if WM_CUSTOMTEST <> 0 then
  PostMessage(HWND_BROADCAST, WM_CUSTOMTEST, 0, 0);    

【讨论】:

  • 谢谢@Remy Lebeau 和 David Heffernan,你们俩都很棒!
猜你喜欢
  • 2011-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 2017-02-06
  • 1970-01-01
  • 2011-10-24
  • 1970-01-01
相关资源
最近更新 更多