How to disable copy/paste commands in the Windows edit control context menu?
Asked Answered
D

4

6

How can I disable those 3 standard cut/copy/paste commands in the context menu of the native Windows OS edit control?

enter image description here

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?

Dutchman answered 7/10, 2015 at 11:47 Comment(6)
@DavidHeffernan, it's the requirement of some end-users ;). In the general case, we also need to add our custom items to that default OS context menu.Dutchman
Strange users! Probably easiest to replace the entire menu with your own.Williawilliam
@DavidHeffernan, do you want me to implement all those specific commands like "Right to left Reading order" by myself??Dutchman
I doubt your users want those, right?Williawilliam
This is folly. What about apps that use a non-native GUI? How about toolbar buttons? There is no way to 100% identify and disable these.Schmuck
Smells like a misguided attempt to stop users pasting passwords.Iinden
A
14

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."

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):

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

Q: Why isn't a WM_INITMENUPOPUP message generated when you right-click an edit control?

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

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.

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.

The correct approach is as follows:

  1. subclass the edit control to intercept the WM_CONTEXTMENU message. Either SetWindowSubClass() or SetWindowLongPtr(GWL_WNDPROC) can be used, though the first is preferred.

  2. 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.

  3. 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.

  4. 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.

  5. 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).

  1. subclass the edit control to intercept WM_CONTEXTMENU, as described above.

  2. 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.

  3. 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).

  4. manipulate the HMENU as needed.

  5. unhook the event hook when done using it, as described above.


As you can see here, this does work.

Before modifying the menu:

before modifying the menu

After disabling the menu items:

Disabling the menu items

Even deleting the menu items:

Deleting the menu items

Arvy answered 7/10, 2015 at 16:49 Comment(8)
See my answer with the link to vbforums.com. Perhaps, you know a better and/or documented way to retrieve the handle of the edit control's context menu?Dutchman
@TecMan: one documented way to get a window's popup menu is the MN_GETMENU message. The trick is to get the popup menu's HWND so you can then get its HMENU. Hooking is the only way to do that. However, the details provided in the VBForums link you provided are a little wrong. I have updated my answer with the correct details.Arvy
@RemyLebeau: your solution doesn't work for me because calling DefSubclassProc/CallWindowProc makes the context menu open but also the script STOP until next click. Thus only after the menu is closed there are calls to manipulate it. Am I doing something wrong?Carpetbag
@Salvador: I can't answer that without seeing your actual code. But as I stated in my answer, I tested both hook approaches that I described, and they work fine for me. The technique determines the popup menu's HWND and posts a delayed window message back to the app before the menu is displayed. The menu's modal message loop will then dispatch that message to the app, and the message handler can then retrieve the HMENU from the HWND and manipulate the menu while it is active. I have added screenshots to prove this works.Arvy
After hard work I wrote a C version of the second approach. This should be definitely chosen like answer.Carpetbag
Nice Remy. Method works well. How to remove this "Reconversion" menu? what menu ID does that have?Ferrite
@amaninlove I have no idea what its menu ID is. But you can use GetMenuItemCount() and GetMenuItemInfo() to enumerate the menu items until you find the item you are interested in, then you will have its ID (and index) with which to manipulate it as needed.Arvy
Its good solution Remy. However, deleting items in that way is a bit sloppy since the callback is called after the menu has already been displayed. So it flashes available then removed. Your solution 1 using SetWindowsHookEx will probably work better since it catches the menu on the creation rather than after it had been displayed to the user. Disabling is fine though.Ferrite
S
0

You could leave the options visible but lock the clipboard from usage.
If this solution suits you all you need to do is make a program that opens the clipboard by calling OpenClipboard(NULL). In order to release the clipboard call CloseClipboard().

Sigismundo answered 7/10, 2015 at 20:42 Comment(1)
Beware of unintended consequences. Lots of applications count on the clipboard working as documented. So locking the clipboard for long periods of time is going to cause conflicts, crashes, etc.. Apps that you don't even expect, like Remote Desktop, may misbehave.Schmuck
S
0

One approach (similar to hypmir's idea but not quite as intrusive) is to simply overwrite the clipboard with "DATA REMOVED BY TecMan" whenever it is updated. You could do this as a registered clipboard viewer.
Open the clipboard, clear all formats, add CF_TEXT with the notice, close it. I would use a short delay (maybe a timer callback) so that you make your update AFTER the first update has been processed by any other registered clipboard viewers on the system. Your mileage may vary. Abusing the clipboard like this is never a good idea.

Schmuck answered 7/10, 2015 at 20:58 Comment(0)
D
0

I found one interesting idea of how to get the handle of the edit control's context menu on vbforums.com:

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

It demonstrates how to add custom context menu items to the standard OS context menu. I think, this idea can be used to modify the menu too. Theoretically I need to enumerate the menu items and disable the items related to the copy/paste commands. The question is how to know whether a menu item is related to copy/paste? Getting the menu item text is a bad idea ;)

Another problem of that code is that it is based on some Windows features that are not documented. I've checked the solution, it still works in Windows 10, but who knows how the edit control context menu may be changed in the future updates of the OS...

Dutchman answered 8/10, 2015 at 8:8 Comment(1)
Although that VBForum discussion does discuss a technique for getting a standard edit control's HMENU, some of the details are wrong. I have updated my answer with the correct details.Arvy

© 2022 - 2024 — McMap. All rights reserved.