按名称捕获 Windows 条已注册的消息

Capture Windows registered messages by name

在 Windows tablets 上有两个屏幕键盘应用程序(我知道),c:\program files\common files\microsoft shared\ink\tabtip.exe 和 C:\Windows\System32\OSK.exe.

我想捕获这些应用程序在启动、放置在我的应用程序顶部以及关闭时发送到我的应用程序的消息。

然后我可以检查 IsIconic 作为保险,尽可能地知道键盘处于什么状态,以便我可以相应地调整我的应用程序显示。

使用 spy++ 我为 TabTip 捕获了以下消息:

<000050> 00130426 P message:0xC298 [Registered:"ImmersiveFocusNotification"] wParam:FFFFFFFC lParam:00000000

<000051> 00130426 P message:0xC297 [Registered:"TipCloseMenus"] wParam:00000000 lParam:00000000

<000052> 00130426 P message:0xC061 [Registered:"TabletInputPanelOpening"] wParam:00000000 lParam:00000000

我认为有一个 Windows API 调用允许我在 OS 上注册以在我的应用程序的 window 过程中接收这些消息,或者使用消息处理程序 proc 获取通知,但我似乎找不到它。

尽管这些消息出现在我应用程序的 spy++ 消息队列中,但我似乎无法在我的 WindowProc 中识别它们,并且 Delphi 不允许我为这些消息指定消息处理过程id 在 49xxx 范围内。

有谁知道用名字注册这些消息的方法吗?我认为可以通过

这样的字符串来实现

TabletInputPanelOpening

TipCloseMenus

以便当 OS 处理该名称的消息时,我的应用程序可以接收/处理它?

谢谢。

更新: 使用 Application.OnMessage 处理程序,如果我忽略消息发送到的句柄,我可以接收消息。我假设这意味着这是一条广播消息(?)。

我仍然需要知道如何注册以接收以下消息:

1) Sent by PostMessage or SendMessage

2) Established with the system by using RegisterWindowMessage

3) Have a named constant that identifies the message, such as 'TipCloseMenus' or 'TaskbarCreated'

更新#2: 我发现了一个旧示例,该示例显示 RegisterWindowMessage 和 GetClipboardFormatName 似乎使用相同的内部 table 来存储已注册的 window 消息和剪贴板格式。使用 TMsg.message 作为参数调用 GetClipboardFormatName 以查找 messageid 的标签。因此,显然在某种程度上,这些消息存储在同一个内部 table 中。下面是一些示例代码来说明:

function GetRegisteredWindowMessageLabel(var Msg: TMsg): UnicodeString;
var
  ay: array[0..99] of Char;
  i: Integer;
begin
  Result := '';
  if (Msg.message <= $FFFF) and (Msg.message >= $C000) then
  begin
    i := GetClipboardFormatName(Msg.message,ay,Pred(SizeOf(ay)));
    if i > 0 then
      Result := StrPas(ay);
  end;
end;

谢谢。

您不能为已注册消息编写编译时消息处理程序,因为它们不使用静态消息 ID。您必须在运行时调用 RegisterWindowMessage() 然后使用注册的 ID 过滤收到的消息,例如:

var
  msgImmersiveFocusNotification: UINT = 0;
  msgTipCloseMenus: UINT = 0;
  msgTabletInputPanelOpening: UINT = 0;
  msgTaskbarCreated: UINT = 0;

procedure TMainForm:FormCreate(Sender: TObject);
begin
  msgImmersiveFocusNotification := RegisterWindowMessage('ImmersiveFocusNotification');
  msgTipCloseMenus := RegisterWindowMessage('TipCloseMenus');
  msgTabletInputPanelOpening := RegisterWindowMessage('TabletInputPanelOpening');
  msgTaskbarCreated := RegisterWindowMessage('TaskbarCreated');
end;

procedure TMainForm.WndProc(var Message: TMessage);
begin
  inherited;
  if (msgImmersiveFocusNotification <> 0) and (Message.Msg = msgImmersiveFocusNotification) then
  begin
    //...
  end
  else if (msgTipCloseMenus <> 0) and (Message.Msg = msgTipCloseMenus) then
  begin
    //...
  end
  else if (msgTabletInputPanelOpening <> 0) and (Message.Msg = msgTabletInputPanelOpening) then
  begin
    //...
  end
  else if (msgTaskbarCreated <> 0) and (Message.Msg = msgTaskbarCreated) then
  begin
    //...
  end;
end;