【问题标题】:How to get a pop-up menu's owner window如何获取弹出菜单的所有者窗口
【发布时间】:2018-01-05 00:23:51
【问题描述】:

当打开一个弹出菜单时,使用函数TrackPopupMenu,它接受参数“拥有该菜单的窗口的句柄”。

我想知道屏幕上可见的任何弹出菜单的所有者窗口是什么。

是否可以获得这样的窗口的句柄,即使它属于另一个进程?

我已经尝试了以下 WinAPI 调用但没有成功:

GetParent(menuHWND) ; //returns null
GetWindow(menuHWND, GW_OWNER) ; //returns null
GetAncestor(menuHWND, GA_ROOTOWNER) ; //returns menuHWND

编辑:
我使用函数WindowFromPoint获得了菜单句柄

【问题讨论】:

  • 在您的示例中,您是如何获得 menuHWND 的?您不是在问如何从 HMENU 获取 menuHWND 吗?
  • 你是如何识别菜单的?
  • 你如何获得弹出菜单的句柄?
  • @Michael,我在 10 分钟前编辑了这个问题,提到了这个细节。
  • HMENU 不是“子窗口”,因此您可以通过这样的功能获得其父窗口。传递给 TrackPopupMenu 的值只是菜单关闭时发送消息的句柄,而不是真正的“父级”。

标签: windows winapi popupmenu


【解决方案1】:

GetGUIThreadInfo知道:

static DWORD CALLBACK MenuPeekerThread(LPVOID)
{
  Sleep(1500); // Wait for menu to show because this is just a silly example
  POINT pt = { 2, 2 };
  HWND hwndMenu = WindowFromPoint(pt);
  GUITHREADINFO gti = { sizeof(GUITHREADINFO), };
  DWORD tid = GetWindowThreadProcessId(hwndMenu, NULL);
  if (tid && GetGUIThreadInfo(tid, &gti))
  {
    printf("owner is %p\n", gti.hwndMenuOwner);
  }
  return 0;
}

static void TestMenuThing(HWND hwnd)
{
  CloseHandle(CreateThread(NULL, 0, MenuPeekerThread, NULL, 0, NULL));
  HMENU hMenu = CreatePopupMenu();
  AppendMenu(hMenu, 0, 1, TEXT("Foo"));
  AppendMenu(hMenu, 0, 1, TEXT("Bar"));
  TrackPopupMenu(hMenu, 0, 0, 0, 0, hwnd, NULL);
  DestroyMenu(hMenu);
}

GetGUIThreadInfo 是在 Windows 2000 中添加的,如果您需要支持任何旧版本,则需要 hook 并在为 WM_INITMENU/WM_INITMENUPOPUP 消息调用挂钩时比较 HMENU 参数。

【讨论】:

  • TPM_NONOTIFY+TPM_RETURNCMD 可能会破坏旧平台上建议的 hook hack。
  • 我也想到了使用GetWindowThreadProcessId然后EnumThreadWindows的可能性。第一个枚举窗口应该是线程中最顶层的窗口,也应该是拥有菜单的窗口。这会检索到与您的代码相同的结果吗?
  • EnumThreadWindows 枚举的窗口顺序是未记录的 AFAIK。您至少可能会遇到在“活动”窗口之前枚举的始终位于顶部窗口的问题。
猜你喜欢
  • 1970-01-01
  • 2016-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
相关资源
最近更新 更多