【问题标题】:How to disable copy/paste commands in the Windows edit control context menu?如何在 Windows 编辑控件上下文菜单中禁用复制/粘贴命令?
【发布时间】:2015-10-07 11:47:49
【问题描述】:

如何在本机 Windows 操作系统编辑控件的上下文菜单中禁用这 3 个标准剪切/复制/粘贴命令?

我还需要禁用与剪贴板相关的等效命令,例如 CTRL+C/CTRL+V。

是否有一种特殊的编辑控件样式或其他任何我们可以通过一个简单的设置来禁用所有复制/粘贴操作的方法?

【问题讨论】:

  • @DavidHeffernan,这是一些最终用户的要求;)。在一般情况下,我们还需要将自定义项添加到默认的操作系统上下文菜单中。
  • 奇怪的用户!用您自己的菜单替换整个菜单可能最容易。
  • @DavidHeffernan,你想让我自己实现所有那些特定的命令,比如“从右到左的阅读顺序”吗??
  • 我怀疑你的用户想要这些,对吧?
  • 闻起来像是试图阻止用户粘贴密码的错误尝试。

标签: winapi contextmenu clipboard editcontrol


【解决方案1】:

通常,当控件显示弹出菜单时,会生成 WM_INITPOPUPMENU 消息,“允许应用程序在菜单显示之前对其进行修改,而无需更改整个菜单。” p>

不幸的是,标准的 Win32 编辑控件不会为其默认弹出菜单生成该消息,正如 2000 年 11 月 MSDN 杂志的一篇文章所证实的那样(MSDN 上的链接本身已失效,但此链接来自Internet Archive):

MSDN Magazine, November 2000, C++ Q&A:

问:为什么右键单击编辑控件时不生成 WM_INITMENUPOPUP 消息?

A:我不能告诉你为什么没有,但我可以确认这是真的......编辑控件不发送 WM_INITMENUPOPUP。编辑控件必须使用空 HWND 句柄和/或 TPM_NONOTIFY 调用 TrackPopupMenu,它告诉菜单不要发送通知。有可能(我只是在猜测)作者试图通过减少消息流量来提高性能......无论如何,假设您想将自己的菜单项添加到编辑控件上下文菜单中。你怎么做呢?唉,你别无选择,只能重新发明轮子

因此,唯一可用的选项是将编辑控件子类化并处理WM_CONTEXTMENU 消息,根据需要创建和显示您自己的自定义弹出菜单。这意味着您必须手动复制要显示在自定义菜单中的任何标准菜单项的功能。

更新:毕竟有一种方法可以访问和修改编辑控件的标准弹出菜单(我刚刚测试过它并且它工作)。 TecMan 提供了一个指向 VBForums discussion 的链接,该链接讨论了它,但是它有一些细节错误。我从PureBasic forum discussion 那里得到了正确的详细信息。

正确做法如下:

  1. 子类化编辑控件以拦截WM_CONTEXTMENU 消息。可以使用SetWindowSubClass()SetWindowLongPtr(GWL_WNDPROC),但the first is preferred

  2. 当收到WM_CONTEXTMENU 消息时,调用SetWindowsHookEx() 来安装线程本地挂钩(hMod 参数使用0,GetCurrentThreadId() 参数使用dwThreadId)。可以使用WH_CBTWH_CALLWNDPROC 挂钩。然后通过DefSubclassProc()CallWindowProc()WM_CONTENTMENU 分派给默认消息处理程序以调用标准弹出菜单。

  3. 在钩子过程中,当收到HCBT_CREATEWNDWH_CBT钩子)或WM_CREATEWH_CALLWNDPROC钩子)通知时,将提供的HWND传递给GetClassName()。如果类名是#32768(菜单的标准窗口类名,如documented on MSDN),发布(非常重要!)使用PostMessage()的自定义窗口消息,指定菜单窗口的@消息的WPARAMLPARAM 参数中的987654369@ 到您控制的任何 HWND,例如您的主窗口,甚至是编辑控件本身(因为它已经是子类)。在下一步中,您将需要菜单的 HWND。你现在可以选择卸载这个钩子,或者等待DefSubclassProc()/CallWindowProc()退出(菜单被关闭后它会退出)。您需要使用PostMessage(),因为此时菜单窗口尚未创建其HMENUPostMessage() 将下一步延迟到 HMENU 准备好之后。

  4. 当收到自定义窗口消息时,发送一条MN_GETMENU消息通过SendMessage()到你从钩子获得的菜单的HWND。你现在有了菜单的HMENU,可以用它做任何你想做的事情。

  5. 要禁用CutCopyPaste 菜单项,请致电EnableMenuItem()。它们的菜单项标识符分别与WM_CUTWM_COPYWM_PASTE 消息的值相同(Microsoft 没有记录,但在 Windows 版本中是一致的)。

更新:我刚刚找到了一个更简单的解决方案(在我测试时也有效)。

  1. 子类化编辑控件以拦截WM_CONTEXTMENU,如上所述。

  2. 收到消息后,调用SetWinEventHook()安装线程本地事件钩子(将hmodWinEventProc参数设置为0,idProcess参数设置为GetCurrentProcessId()idThread参数设置为GetCurrentThreadId()dwFlags 参数为 0 - 不是 WINEVENT_INCONTEXT!)。将eventMineventMax 参数都设置为EVENT_SYSTEM_MENUPOPUPSTART,以便它是您收到的唯一事件。然后将消息发送到默认处理程序以调用弹出菜单。

  3. 当你的事件回调被调用时,菜单已经完全初始化,所以你可以将MN_GETMENU消息发送到提供的HWND,这将是菜单的窗口(回调的idObject参数将为OBJID_CLIENTidChild 参数将为0)。

  4. 根据需要操作HMENU

  5. 如前所述,在使用完事件挂钩后取消挂钩。


正如您在此处看到的,这确实有效。

修改菜单前:

禁用菜单项后:

甚至删除菜单项:

【讨论】:

  • 通过 vbforums.com 的链接查看我的答案。也许,您知道一种更好的和/或记录在案的方法来检索编辑控件的上下文菜单的句柄?
  • @TecMan:获得窗口弹出菜单的一种记录方法是MN_GETMENU 消息。诀窍是获取弹出菜单的HWND,这样您就可以获取它的HMENU。挂钩是唯一的方法。但是,您提供的 VBForums 链接中提供的详细信息有些错误。我已使用正确的详细信息更新了我的答案。
  • @RemyLebeau:您的解决方案对我不起作用,因为调用 DefSubclassProc/CallWindowProc 会使上下文菜单打开,但脚本也会停止,直到下次单击。因此,只有在菜单关闭后才会调用操作它。我做错了吗?
  • @Salvador:如果没有看到您的实际代码,我无法回答这个问题。但正如我在回答中所说,我测试了我描述的两种钩子方法,它们对我来说都很好。该技术确定弹出菜单的HWND,并在菜单显示之前将延迟窗口消息发送回应用程序。然后,菜单的模式消息循环会将该消息发送到应用程序,然后消息处理程序可以从HWND 检索HMENU 并在菜单处于活动状态时对其进行操作。我添加了截图来证明这是可行的。
  • @amaninlove 我不知道它的菜单 ID 是什么。但是您可以使用GetMenuItemCount()GetMenuItemInfo() 来枚举菜单项,直到找到您感兴趣的项,然后您将获得它的ID(和索引),以便根据需要对其进行操作。
【解决方案2】:

您可以让选项保持可见,但锁定剪贴板以防使用。
如果此解决方案适合您,您只需编写一个程序,通过调用OpenClipboard(NULL) 打开剪贴板。为了释放剪贴板调用CloseClipboard()

【讨论】:

  • 谨防意外后果。许多应用程序都依赖于剪贴板,如记录的那样工作。因此,长时间锁定剪贴板会导致冲突、崩溃等。您甚至没有预料到的应用程序,例如远程桌面,可能会出现异常。
【解决方案3】:

一种方法(类似于 hypmir 的想法,但不那么具有侵入性)是在剪贴板更新时简单地用“DATA REMOVED BY TecMan”覆盖剪贴板。您可以作为已注册的剪贴板查看器执行此操作。
打开剪贴板,清除所有格式,在通知中添加CF_TEXT,关闭它。 我会使用短暂的延迟(可能是计时器回调),以便您在系统上任何其他注册的剪贴板查看器处理第一个更新之后进行更新。 您的里程可能会有所不同。 像这样滥用剪贴板绝不是一个好主意。

【讨论】:

    【解决方案4】:

    我在 vbforums.com 上发现了一个关于如何获取编辑控件上下文菜单句柄的有趣想法:

    http://www.vbforums.com/showthread.php?776385-RESOLVED-Modify-right-click-context-menu-in-standard-controls

    它演示了如何将自定义上下文菜单项添加到标准操作系统上下文菜单中。我想,这个想法也可以用来修改菜单。理论上我需要枚举菜单项并禁用与复制/粘贴命令相关的项目。问题是如何知道菜单项是否与复制/粘贴有关?获取菜单项文本是个坏主意;)

    该代码的另一个问题是它基于一些未记录的 Windows 功能。我已经检查了解决方案,它在 Windows 10 中仍然有效,但谁知道在操作系统的未来更新中如何更改编辑控件上下文菜单...

    【讨论】:

    • 虽然 VBForum 的讨论确实讨论了获取标准编辑控件的HMENU 的技术,但有些细节是错误的。我已使用正确的详细信息更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 2012-07-03
    • 2010-09-14
    相关资源
    最近更新 更多