27 KiB
title | description | created | updated | draft | tags | thumbnail | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
The Windows Context Menu – Is It a Lost Cause? | We dive in deep into the Windows context menu and how to customize it to your liking. | 2023-08-13T15:51:19Z | 2024-02-18T21:32:12Z | false |
|
/images/blog/thumbnails/the-windows-context-menu.png |
The Windows context menu is... poorly made.
Third-party software developers adding oil into this dumpster fire aren't helping with it. It's not their fault, though, as there is no common standard and almost no documentation for adding entries to the context menu.
It's safe to say that currently, there's no salvation for it. At the very least, it's working and serving millions of users. The new Windows 11 context menu shows Microsoft keeps pressing onward with their all-time classic: writing new, less friendly, less extensible APIs from scratch, simultaneously piling up layers upon layers of untested code atop the previous versions they can't entirely get rid of due to deep backwards compatibility problems that will inevitably arise.
I want to dedicate this article to actually customizing the Windows 10 (incidentally, also 11 Legacy) context menu to your liking instead of just complaining about its inner workings. After reading this article completely, you should be able to bring your menu from this abomination...
...to this!
Be wary — there's plenty of registry digging involved. And the terrible part is...
Forget any logic when dealing with registry keys. Nowadays, registry structure is the least of all concerns. The idea of using registry as a coherent setting list has long since been abandoned, and nobody seems to care about it, as the end user doesn't. If someone does — they know what they're doing, and they will likely not complain, because they have abused registry the same way at least once. 😉
Whilst there are layers of abstraction applied to the most Windows settings, the context menu is, unfortunately, left aside. And much to our dismay, its backend is also janky, terrible and tangled up. The only fair question to reader from me is «Do you really think it's worth your time?». And if your answer is an astounding «Hell yeah», and you are as much of a perfectionist as I am, buckle up and prepare for several hours of pure joy.
::card
icon: warning title: Before we begin
Invoking sfc /scannow
or dism /restorehealth
will likely interfere with your context menu,
as Microsoft is peculiar — they had customization via direct registry manipulation in mind for more granular control,
but their tools aren't adapted to store so meticulously tweaked settings.
This isn't anything new — that hasn't changed ever since integrity checks were introduced in Windows XP.
No need to worry, though! The aforementioned tools will keep working; however, some of your tweaks might be reset
upon execution.
::
Context menu components
There are two main components the context menu is composed of:
- Shell entries — provided locally and managed by the registry;
- Context menu handlers — provided and managed by external software;
Neither of them is documented well, but there is some developer documentation for handlers available on Microsoft's website. It explains how they work internally, but that doesn't really help our case. As for the shell entries, I couldn't find anything.
Certainly a shame! Shell entries are so much more flexible and customizable. In fact, you don't get any customization with context menu handlers whatsoever, unless the developer was paid and bothered enough to read most of the documentation above.
To let you tweak context menu settings directly through their app, they have to implement both the handler and the endpoints for handler settings, which are commonly simple registry values. Microsoft hasn't provided any convention for software developers to follow, so you're at the mercy of them providing you with a friendly user interface to tweak the handler.
7-Zip serves as a neat example of great software design — the developer here allows you to extensively tweak their handler.
MobaXterm also is an illustrative example of the case where you can customize the shell integration from the application itself. The developers of that software use shell entries instead of context menu handlers, which seems like an odd choice for this case. It seems like someone was underpaid! 😊
In conclusion, there are three types of applications in terms of friendliness towards context menu customization:
- Apps using context menu handlers with customizable settings — the friendliest;
- Apps using shell entries — customizable through registry hacks;
- Apps using context menu handlers without settings — the entries are uneditable;
The first case is the simplest and isn't worth talking about — consult the documentation for the software in question to find all the necessary tweaks. The rest of the cases are discussed in this article.
Shell entries
For starters, all the tweaking happens inside HKEY_CLASSES_ROOT
— alias for HKEY_LOCAL_MACHINE\Software\Classes
.
That registry key contains all the data about shell components and file extension handlers.
For example, data under the exefile
key will exclusively apply to files with the .exe
extension.
A trusty old method «companion» viruses utilized back in the day to «accompany» their victims —
the executable (.exe
/.com
) files was a simple pass-through setup:
the virus executable was specified as the handler for all other executable files.
A belarusian virus from 2005, Neshta.A, worked exactly this way and caused heaps of damage.
Since all the settings inside the HKCR
key are divided into types,
editing the context menu for each file type and shell extension manually is unavoidable.
Yeah...
This is abysmal, and, unfortunately, there is no better approach. While you're likely already reconsidering your choices, let me try to pull you back in and explain the basics. That way you can at least tweak the menu for the extensions you work with the most and bring the most noticeable context menu areas up to par...
There are some minor generalizations present in the key. For instance, there are wildcard entries for every file system object, every image, every media file and so on. Nonetheless, Microsoft has taken a horrible approach with the context menu from the beginning. Even though such a disarray always annoyed me, I know full well there's no way for them to fix it now. That's how sometimes life is. We'll tackle the generalized keys a bit later, let's start simple.
General structure
The following figure is what seems to be the general structure of an extension registry key:
The structure may vary for some extensions, but you can almost be sure you're in the right place if the key contains the Shell
subkey.
Children of the Shell
subkey are the «shell entries» — locally provided customizable entries of the context menu.
::card
icon: info title: Clearing up the confusion
The terminology may be a little confusing, since Microsoft hasn't ever offered a standard nomenclature for the context menu. The article tosses plenty of loose terms around, so here's the nomenclature I have resorted to for better understanding:
- Shell is the Windows Explorer;
- Shell entry is a singular entry within the context menu — the atomic component;
- Shell integration is the general footprint of software within the context menu and may consist of one or more shell entries;
- Shell extension is a general term for a plugin for the Windows Explorer — the context menu handler is a particular case of a shell extension;
- Shell component is a broad term for a component that helps the shell interact with the system — that includes shell extensions, file extensions, protocols, etc.;
If this doesn't show how big of a predicament Microsoft is in with the context menu, I don't know what does. I tried my best to keep the technical language as clear as possible. 😒 ::
Editing entries
Locally provided entries always available for a quick and dirty edit are stored under the Shell
subkey.
Entries provided by software — the context menu handlers — are stored under the ShellEx
subkey.
Since registry key names are case-insensitive by design in Windows, capitalization plays no role. The value names, however, are — keep that in mind, as in some cases it might bite you. The context menu doesn't seem to care.
Truly an amazing specification!
Executing entries
A shell entry must contain the command
subkey to execute commands.
The default value of the subkey controls execution on click of the shell entry and follows Batch syntax...
to some extent. You cannot have «extended» Batch logic in the entries,
which immeasurably disappointed me, so much so, that I wrote two neat utilities called
quiet and elevatesudo for Windows anyone? for that specific purpose.
No matter how hard I tried, I could not find the exact specification of the incomplete Batch logic the default value uses.
My suggestion is to treat the default command
value as raw command line (e.g. Run box),
with an exception to the following two macros:
%1
— the absolute file path without quotes
If you right-clickC:\Users\bleh\p.txt
, execute the shell entry, the%1
in the context of the command line will be equivalent toC:\Users\bleh\p.txt
;%V
— the absolute directory path without quotes;
::card
icon: error title: Inconsistency
Keep in mind that the %1
macro is the Batch version of argv[1]
— the first item in the C argument vector.
When a context menu is invoked from within, say, a library, the argument vector stops making sense
because a library is a Windows Shell feature, meaning it's sophisticated. Opening a library internally
requires a different API to opening a folder, or even executing a file.
In such cases, the %1
macro does not exist in the context of the command line. This is also likely
the reason why libraries are in a separate category to folders in terms of shell entries.
The directory macro %V
also sometimes falls flat depending on the shell entry it's being invoked from.
Brilliant consistency!
::
On rare occasions, the default value is left unset, with DelegateExecute
alongside it containing a GUID.
When that's the case, the command handler is implemented through the IExecuteCommand
COM interface,
and you cannot customize it.
Why is that a thing? Ask me a simpler question. It could be a compatibility layer for C, but your guess is as good as mine.
Adding entries
Making new entries isn't as bad as managing existing ones, so I managed to scrabble it into a sort of algorithm, if that makes sense:
- Locate the target extension.
- Careful! Some extensions may be buried within other extensions.
As an example, the Folder Background extension is located under the Folder extension
Directory
key in theBackground
subkey. - Navigate to the
shell
key. If there is none, and you're confident there should be, try creating one — chances are high it isn't going to break Windows.(no, seriously) - Create a new key, the name must be alphanumeric. The name is case-insensitive.
- Create the
command
subkey. - Specify the command line you want to execute on click in the default value.
- The entry should appear in the context menu. If it does not, restart Explorer. If it still doesn't appear, you probably screwed up the procedure — return to step 1. If you verified everything for sure, then the extension is simply not registered in the shell.
Nesting entries
You can nest entries too!
- Repeat the first 4 steps from Adding entries.
Don't add the
command
key just yet. - Create another
shell
key. - Inside it, create a subkey called anything else, but
command
. - Working within the subkey, repeat steps 5–7.
- Navigate back to the root shell entry
- Create an empty
REG_SZ
value calledSubCommands
.
It's possible to have an entry include a single nested entry as well.
To control the parent context menu entry, use the outer Shell
subkey.
To control its children, use the inner Shell
subkeys.
Customizing entries further
There are a plethora of options when it comes to customizing the shell entries. Too bad they're all undocumented. By default, the context menu items borrow their names from the respective shell entries they're owned by.
Name
To override the default name,
you can either use the default value or specify a REG_SZ
value called MUIVerb
inside the respective shell
key
for the shell entry.
MUIVerb takes precedence over the default value.
When it comes to the name, the sky is the limit. Actually, Unicode is the limit. Either way, put in anything you want; it's going to work.
Icon
To enable the icon for your shell entry,
you should use the REG_SZ
value called Icon
inside the respective shell
key for the shell entry.
It uses that unmistakably distinct and clumsy WinAPI resource syntax to specify a direct link to the icon within a file containing resources.
PATH_TO_FILE_WITH_ICON_RESOURCES,INDEX
If you want to select the first icon (in that case, the INDEX
part is 0),
the INDEX
part can be omitted completely:
PATH_TO_FILE_WITH_ICON_RESOURCES
The following expressions are completely valid and are going to work:
"C:\Windows\system32\cmd.exe"
C:\Windows\regedit.exe
"C:\Windows\explorer.exe",0
C:\Windows\system32\cmd.exe,0
cmd.exe
shell32.dll,3
SHELL32.DLL,10
"C:\Windows\system32\SHELL32.DLL",9
You can omit the quotes and absolute paths depending on the %PATH%
variable that unholy concoction of an API uses.
Spoiler: they don't match against the system %PATH%
.
Only God knows what paths it's able to parse by default.
C:\Windows
and C:\Windows\system32
always work for sure, though.
It's still highly recommended to supply the absolute path, the %PATH%
variables of the shell icon picker and the
shell entry do not seem to correspond.
::card
icon: idea title: Tip
You can use the Explorer folder icon picker to acquire the icon DLL and visually calculate the offset
of the desired icon.
For instance, the one I selected on the screenshot has an index of 5
.
The indexing begins with 0 and ascends in columns.
::
It's also possible to pull resource strings from files containing string tables.
Separators
Another integral part of the context menu, which is hardly documented by anyone. Managing them is also rather quirky and takes getting used to. Separators in shell entries are relative to the item they're being enabled for and can overlap without any issue.
Use SeparatorBefore
and SeparatorAfter
empty REG_SZ
values
to add a separator before or after the shell entry being edited, respectively.
Appear in the Shift+Click context menu only
It's possible to «hide» the shell entry from an ordinary context menu right-click. Such a shell entry is called «extended».
Enable that functionality by creating an empty REG_SZ
value called Extended
inside the shell
key for the
respective shell entry.
Hide in safe mode
To disable the shell entry in safe mode,
create an empty REG_SZ
value called HideInSafeMode
inside the shell
key for the respective shell entry.
Never default
The bold context menu item shown at the top is considered to be the default action for the file type. An example of a default shell entry would be «Open» for folders.
There can be no default entry at all, and that's perfectly fine.
To disable the shell entry from becoming default,
add an empty REG_SZ
value called NeverDefault
inside the shell
key for the respective shell entry.
Pass to context menu handler
If there is a context handler available for invocation on shell entry click, it's possible to specify a so-called Verb Handler.
Create a new REG_SZ
value VerbHandler
inside the shell
key for the respective shell entry
and specify the GUID of the context menu handler in the value.
No working directory
Disables the working directory from being added to the environmental path in the context of the application being run.
To disable pass-through of the working directory to the application,
create an empty REG_SZ
value called NoWorkingDirectory
inside the shell
key for the respective shell entry.
Other options
Some options, though might sound obvious, have me scratching the back of my head. Please tag me on Twitter or send a mail my way if you have the knowledge.
A few examples:
CanonicalName
CommandStateHandler
CommandStateSync
Description
VerbName
Deleting entries
Even simpler — it's the opposite of adding one.
- Locate the target extension.
- Navigate to the
shell
subkey. - Find the shell entry to delete. The default value of the
command
key will usually contain the executable name, it's best to verify the target application before deletion. - Delete the key.
Multiple shell entries can sometimes correspond to the same item in the context menu, which might result in the item remaining in place despite the deletion.
Sorting entries
Now that's the funniest one. I even memed about it on Twitter. The only way to sort the context menu is via the alphabetical order of its respective shell entries in the registry. Yes. I am not kidding. Let the screenshots speak for themselves.
Yeah... I'd rather not comment on that.
Position override
Another silly and janky feature that has a limited number of use cases. You can manually override the position of your context menu item to be... either at the very top, or the very bottom. Not much better than alphabetical sorting if you ask me...
In your entry under shell, create a REG_SZ value called Position. If you want to force the context menu handler to the top, put Top as data, otherwise put Bottom.
Sometimes this may be necessary, as, for example, Microsoft dumps their regular alphabetical sorting strategy at the bottom of the context menu, where display and personalization settings reside. They simply specify the Bottom position for each of the entries. If I recall correctly, they're still sorted alphabetically between themselves, as position override takes precedence.
Bottom line
Some of the default shell entries like Powershell have specific keys
(for the sake of that example, ProgrammaticAccessOnly
) to control their appearance context menu.
As a rule of thumb, every time you're dealing with existing shell entries, I REALLY suggest that you search for a way to modify them online before resorting to any of the general cases I've described above. If you can't find anything even on the Internet, well, anything works.
Uneditable entries
As for the Context Menu handlers, there's actually not much you can do. They're located under the shellex\ContextMenuHandlers subkey.
Most of the time, the only data they contain is a lonely GUID. That doesn't help much.
So, to remove the Context Menu handler, you should delete the subkey under ContextMenuHandlers. I strongly suggest you save the GUID it contained so that you could roll back at any time later.
Adding your own... Well, that's complicated. You actually have to write your own handler in a language supporting Windows API or any sort of abstraction of it. For example, C# is a decent choice. I don't suggest you waste time on this, unless you're making full-on software that you want to make more accessible to Windows users.
Dealing with locked keys
If the registry key is locked, and you don't have write permissions for it, it's owned by TrustedInstaller, and you have to manually reclaim ownership of the key and allow yourself to make edits to it.
Optimal way: Using Process Hacker with the TrustedInstaller plugin or Winaero Tweaker, run regedit as Trusted Installer and perform the necessary tweaks.
General solution:
Navigate to the key you want to take ownership of Open the «Properties» window Head over to the Advanced tab At the top of the Advanced Security Settings it states Owner: TrustedInstaller. Click Change Input your username into the Enter the object name to select (examples) text area. Click OK Check the «Replace owner on subcontainers and objects» checkbox Check the «Replace all child object permission entries» checkbox Click OK Select Administrators (PC_NAME\Administrators) in the group selector and then check Full Control box in the Permissions window down below Click OK After performing above steps, you must have gotten full and almost complete (some registry values and keys are still protected after the general procedure) access to the desired key.
Common registry paths
Here is a list of the most common registry paths.
Desktop Background — bottom rows
Computer\HKEY_CLASSES_ROOT\DesktopBackground
Folder Background
Computer\HKEY_CLASSES_ROOT\Directory\Background
Folder
Computer\HKEY_CLASSES_ROOT\Directory
Folder Item
This extends Folder.
Computer\HKEY_CLASSES_ROOT\Folder
Drive
Computer\HKEY_CLASSES_ROOT\Drive
Library Folder
Computer\HKEY_CLASSES_ROOT\LibraryFolder
Library Background
Computer\HKEY_CLASSES_ROOT\LibraryFolder\background
Library background inherits from Folder Background,
but can't parse the %V
macro, which results in the following error.
This is Microsoft's fault.
To my knowledge, there is no way to fix that.
All Files
Computer\HKEY_CLASSES_ROOT\*
All Filesystem Objects
That's different from All Files — it's a further generalization that includes system drives and symbols.
Computer\HKEY_CLASSES_ROOT\AllFilesystemObjects
Type associations
Text: Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text
Images: Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\image
Documents: Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\document
Audio: Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\audio
Video: Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\video
Cleaning up the context menu
Most obnoxious default entries can be cleaned up using Winaero Tweaker. I suggest you use it to make the process way more bearable for yourself.
Areas Winaero Tweaker is unable to reach to
Remove «Open PowerShell window here» Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\Powershell Unlock key (The Windows Context Menu > Dealing with locked keys) Create a new REG_SZ value ProgrammaticAccessOnly without any data Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell Unlock key Create a new REG_SZ value ProgrammaticAccessOnly without any data Remove «Open Linux shell here» Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL Unlock key Delete WSL key altogether Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell Unlock key Create a new REG_SZ value ProgrammaticAccessOnly without any data Edit the «Edit» text context menu command Navigate to Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell\edit Make sure you've read the article thoroughly, then do anything you want with it.
Bottom line
No matter how terrible the context menu API might be for Windows, there's still a way to customize it. Hope you found the tricks useful!
If you've spotted a mistake (be it orthographical, factual or any other) in this article or want to add some important details or share any important knowledge on the subject, please contact me on Twitter: @endermanch or hit me up on e-mail: blogs@enderman.ch