问题描述
如何在本机Windows OS编辑控件的上下文菜单中禁用这3个标准的剪切/复制/粘贴命令?
How can I disable those 3 standard cut/copy/paste commands in the context menu of the native Windows OS edit control?
我还需要禁用与剪贴板相关的等效命令,例如CTRL + C/CTRL + V.
I also need to disable the equivalent clipboard-related commands like CTRL+C/CTRL+V.
是否有一种特殊的编辑控件样式,或者可以通过一种简单的设置来禁用所有复制/粘贴操作的其他功能?
Is there a special edit control style or anything else we can use to disable all copy/paste operations with one easy setting?
推荐答案
通常,当控件显示弹出菜单时, WM_INITPOPUPMENU
消息,该消息"允许应用程序在显示菜单之前对其进行修改,而无需更改整个菜单."
Typically, when a control displays a popup menu, a WM_INITPOPUPMENU
message is generated which "allows an application to modify the menu before it is displayed, without changing the entire menu."
不幸的是,标准的Win32 Edit控件不会为其默认弹出菜单生成该消息,正如2000年11月的《 MSDN杂志》所证实的那样(MSDN上的链接本身已失效,但是此链接来自 Internet存档):
Unfortunately, a standard Win32 Edit control does not generate that message for its default popup menu, as confirmed in a November 2000 article of MSDN Magazine (the link on MSDN itself is dead, but this link is from the Internet Archive):
A:我不能告诉你为什么没有一个,但是我可以确认这是真的...编辑控件不会发送WM_INITMENUPOPUP .编辑控件必须正在使用具有空HWND句柄和/或TPM_NONOTIFY的TrackPopupMenu进行调用,这将告诉菜单不发送通知.作者有可能(也是在我的猜测中)作者试图通过减少消息流量来提高性能……无论如何,假设您想将自己的菜单项添加到编辑控件上下文菜单中.你怎么做呢? las,您别无选择,只能重新发明轮子
A: I can't tell you why there isn't one, but I can confirm it's true ... edit controls don't send WM_INITMENUPOPUP. The edit control must be calling TrackPopupMenu with a null HWND handle and/or TPM_NONOTIFY, which tells the menu not to send notifications. It's possible (and again I'm only guessing) that the authors were trying to improve performance by reducing message traffic ... In any case, suppose you want to add your own menu items to the edit control context menu. How do you do it? Alas, you have no choice but to reinvent the wheel
因此,唯一可用的选项是对编辑控件进行子类化并处理 WM_CONTEXTMENU
消息,并根据需要创建并显示您自己的自定义弹出菜单.这意味着您必须手动复制要显示在自定义菜单中的任何标准菜单项的功能.
So the only option available is to subclass the edit control and handle the WM_CONTEXTMENU
message instead, creating and displaying your own custom popup menu as needed. Which means you have to manually duplicate the functionality of any standard menu items that you want to appear in your custom menu.
更新:毕竟,有一种方法可以访问和修改编辑控件的标准弹出菜单(我刚刚对其进行了测试,并且可以正常工作). TecMan提供了指向 VBForums讨论对此进行了讨论,但是它弄错了一些细节.我从 PureBasic论坛讨论中获得了正确的详细信息.
Update: there is a way to access and modify the edit control's standard popup menu after all (I just tested it and it worked). TecMan provided a link to a VBForums discussion that talks about it, however it gets a few details wrong. I got the correct details from a PureBasic forum discussion.
正确的方法如下:
-
子类化编辑控件以拦截
WM_CONTEXTMENU
消息.SetWindowSubClass()
或SetWindowLongPtr(GWL_WNDPROC)
//blogs.msdn.com/b/oldnewthing/archive/2003/11/11/55653.aspx"rel =" nofollow noreferrer>首选第一个.
当收到WM_CONTEXTMENU
消息时,呼叫 SetWindowsHookEx()
安装线程本地挂钩(对于hMod
参数使用0,对于dwThreadId
参数使用GetCurrentThreadId()
).可以使用WH_CBT
或WH_CALLWNDPROC
挂钩.然后通过 DefSubclassProc()
将WM_CONTENTMENU
分派到默认消息处理程序或 CallWindowProc()
进行调用标准弹出菜单.
when the WM_CONTEXTMENU
message is received, call SetWindowsHookEx()
to install a thread-local hook (use 0 for the hMod
parameter and GetCurrentThreadId()
for the dwThreadId
parameter). Either a WH_CBT
or WH_CALLWNDPROC
hook can be used. Then dispatch WM_CONTENTMENU
to the default message handler via DefSubclassProc()
or CallWindowProc()
to invoke the standard popup menu.
,当收到HCBT_CREATEWND
(WH_CBT
挂钩)或WM_CREATE
(WH_CALLWNDPROC
挂钩)通知时,将提供的HWND
传递给 GetClassName()
.如果类名是#32768
(菜单的标准窗口类名,如记录在MSDN上),发布(非常重要!),使用 PostMessage()
,在消息的WPARAM
或LPARAM
参数中将菜单窗口的HWND
指定为您可以控制的任何 HWND
,例如主窗口,甚至是编辑控件本身(因为它已经被子类化了).下一步将需要菜单的HWND
.现在,您可以选择此时卸载该挂接,或等待DefSubclassProc()
/CallWindowProc()
退出(退出菜单后它将退出).您需要使用PostMessage()
,因为菜单窗口目前尚未创建其HMENU
. PostMessage()
将下一步推迟到HMENU
准备就绪之后.
inside the hook procedure, when a HCBT_CREATEWND
(WH_CBT
hook) or WM_CREATE
(WH_CALLWNDPROC
hook) notification is received, pass the provided HWND
to GetClassName()
. If the class name is #32768
(the standard window class name for menus, as documented on MSDN), post (very important!) a custom window message using PostMessage()
, specifying the menu window's HWND
in the message's WPARAM
or LPARAM
parameter, to any HWND
that you control, such as your main window, or even the edit control itself (since it is already subclassed). You will need the menu's HWND
in the next step. You can optionally now uninstall the hook at this time, or wait for DefSubclassProc()
/CallWindowProc()
to exit (it will exit after the menu has been dismissed). You need to use PostMessage()
because the menu window has not created its HMENU
yet at this time. PostMessage()
delays the next step until after the HMENU
is ready.
在收到自定义窗口消息时,发送一个 MN_GETMENU
消息通过 SendMessage()
到从钩子获得的菜单的HWND
.现在,您有了菜单的HMENU
,并可以使用它进行任何操作.
when the custom window message is received, send a MN_GETMENU
message via SendMessage()
to the menu's HWND
that you obtained from the hook. You now have the menu's HMENU
and can do whatever you want with it.
要禁用Cut
,Copy
和Paste
菜单项,请调用 EnableMenuItem()
.它们的菜单项标识符分别与WM_CUT
,WM_COPY
和WM_PASTE
消息具有相同的值(Microsoft并未对此进行记录,但是在Windows版本之间是一致的).
to disable the Cut
, Copy
, and Paste
menu items, call EnableMenuItem()
. Their menu item identifiers are the same values as the WM_CUT
, WM_COPY
and WM_PASTE
messages, respectively (this is not documented by Microsoft, but is consistent across Windows versions).
更新:我刚刚找到了一个简单得多的解决方案(在我测试它时也可以使用).
Update: I just found a much simpler solution (which also worked when I tested it).
-
将编辑控件子类化以拦截
WM_CONTEXTMENU
,如上所述.
收到消息后,请致电 SetWinEventHook()
安装线程本地事件挂钩(将hmodWinEventProc
参数设置为0,将idProcess
参数设置为GetCurrentProcessId()
,将idThread
参数设置为GetCurrentThreadId()
,并且将dwFlags
参数设置为为0-不是WINEVENT_INCONTEXT
!).将eventMin
和eventMax
参数都设置为EVENT_SYSTEM_MENUPOPUPSTART
,这样它是您收到的唯一事件.然后将消息分派到默认处理程序以调用弹出菜单.
when the message is received, call SetWinEventHook()
to install a thread-local event hook (set the hmodWinEventProc
parameter to 0, the idProcess
parameter to GetCurrentProcessId()
, the idThread
parameter to GetCurrentThreadId()
, and the dwFlags
parameter to 0 - not WINEVENT_INCONTEXT
!). Set the eventMin
and eventMax
parameters both to EVENT_SYSTEM_MENUPOPUPSTART
so that it is the only event you receive. Then dispatch the message to the default handler to invoke the popup menu.
在调用事件回调时,菜单已经完全初始化,因此您可以将MN_GETMENU
消息发送到提供的HWND
,这将是菜单的窗口(回调的idObject
参数将为OBJID_CLIENT
,而idChild
参数将为0).
when your event callback is called, the menu has already been fully initialized, so you can send the MN_GETMENU
message to the provided HWND
, which will be the menu's window (the callback's idObject
parameter will be OBJID_CLIENT
and the idChild
parameter will be 0).
根据需要操纵HMENU
.
使用完事件钩子后,将其解钩,如上所述.
unhook the event hook when done using it, as described above.
正如您在这里看到的那样,它确实有效.
As you can see here, this does work.
在修改菜单之前:
禁用菜单项后:
甚至删除菜单项:
这篇关于如何在Windows编辑控件上下文菜单中禁用复制/粘贴命令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!