【问题标题】:Subclassing the System Menu子类化系统菜单
【发布时间】:2012-10-12 13:51:37
【问题描述】:

我已经定义了一个所有者绘制的菜单类。该类考虑了this article 中定义的系统菜单的MeasureItem 问题(即根据菜单是否为系统菜单调整自定义测量值)。但是我遇到的问题是在正确的时间对系统菜单进行子类化。

目前我已使用以下两个代码 sn-ps 尝试对其进行子类化(在覆盖的 CFrameWnd::LoadFrame 中):

  1. 尝试1:mSysMenuCMenu的子类,它还重写了Attach自动设置菜单为所有者绘制(bool参数只是传递来通知它是否是系统菜单)

    mSysMenu.Attach(GetSystemMenu(FALSE)->GetSafeHmenu(), true);
    

    当我右键单击任务栏按钮时,此选项失败,在wincore.cppCWnd::OnMeasureItem)中生成 3 个断言,以及一个丑陋、变形的所有者绘制菜单 - 与 _AFX_THREAD_STATE 类有关。 但是,当我从OnLButtonDown 调用TrackPopupMenu 之前,我右键单击任务栏,一切都很好。

  2. 尝试 2:这只是创建了一个类似变形的菜单测量,但没有任何所有者绘制尝试的迹象

    CVSPMenu* sysMenu = (CVSPMenu*)CMenu::FromHandle(GetSystemMenu(FALSE)->GetSafeHmenu());
    sysMenu->SetOwnderDrawn(true);
    

我也尝试过在OnInitMenuPopup 中做事,但传入的菜单指针似乎并没有使用(只是导致断言和失败)。

所以我的问题是,我如何以及在哪里子类化系统菜单?

【问题讨论】:

  • 这听起来像是一个非常艰难的方法。您确定需要对菜单进行子类化,而不仅仅是从子类化窗口自定义它吗?
  • 很酷,我解决了这个问题。事实证明,只有通过 TrackPopupMenu 调用才能正确测量自定义绘制的系统菜单(显然在某些隐藏级别上,系统菜单通过替代方法显示)。所以我覆盖了未记录的 0x0313 消息并在那里调用了 TrackPopupMenu ,它正确地测量了它等等 :)
  • 如果您之前没有调用 GetSystemMenu() 并且无法修改,则传递给系统菜单的 OnInitMenuPopup 的菜单指针是默认的 SystemMenu。 blogs.msdn.com/b/oldnewthing/archive/2010/05/28/10016691.aspx
  • 这是非常有用的信息!在系统菜单上很难找到信息,干杯!!

标签: c++ windows winapi mfc menu


【解决方案1】:

因为那个MSDN链接失效了,我通过web.archive把它复活了,下面贴了相关文字。

https://web.archive.org/web/20140413053140/http://blogs.msdn.com/b/oldnewthing/archive/2010/05/28/10016691.aspx

我上次提到了治疗方面的优化 显着减少菜单数量的系统菜单 系统。

当一个窗口具有 WS_SYSMENU 窗口样式时,它有一个系统菜单, 但是直到有人在那个窗口上调用 GetSystemMenu,没有人知道 它的菜单句柄是什么。在那之前,窗口管理器不会 实际上必须承诺为窗口创建一个菜单;它可以 假装窗口有一个。 (这种技术很花哨 命名延迟初始化。)

窗口管理器创建一个全局默认系统菜单,其中包含 标准系统菜单项。如果有人按 Alt+Space 或 否则为从未有过的窗口调用系统菜单 GetSystemMenu 调用它,窗口管理器只是使用全局 默认系统菜单,因为它知道没有人自定义 菜单。 (你不能自定义一个你没有句柄的菜单!)因为 大多数人从不自定义他们的系统菜单,这个优化 避免桌面堆与相同的相同副本混乱 菜单。这是早期特别重要的优化 16 位时代,所有窗口管理器对象都必须放入一个单一的 64KB 堆(称为系统资源)。

如果你真的很狡猾,你可以瞥见难以捉摸的 全局默认系统菜单,因为它呼啸而过:与任何其他弹出窗口一样 菜单,正在显示的菜单的句柄将传递给您的 窗口的 WM_INITMENUPOPUP,如果您的程序从未调用过 GetSystemMenu,你会看到的句柄是全局默认的 系统菜单。请注意,您不能对这个菜单做太多事情,因为 窗口管理器阻止任何修改它的尝试。 (否则,您的 程序的菜单修改会对 其他程序的菜单!)

因此,如果您的程序有修改其系统的习惯 菜单在其 WM_INITMENUPOPUP 处理程序中,你应该坚持一个虚拟调用 在您的 WM_CREATE 处理程序中获取 GetSystemMenu 以强制您的系统菜单 从伪装的系统菜单更改为真实的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2022-06-29
    • 2018-09-08
    相关资源
    最近更新 更多