--- title: The Windows Context Menu – Is It a Lost Cause? description: We dive in deep into the Windows context menu and how to customize it to your liking. created: 2023-08-13T15:51:19Z updated: 2024-02-18T21:32:12Z draft: false tags: ['windows', 'context-menu', 'customization', 'registry', 'shell', 'shell-extensions', 'context-menu-handlers'] thumbnail: '/images/blog/thumbnails/the-windows-context-menu.png' --- #### The Windows context menu is... poorly done. And third-party software developers adding oil into the dumpster fire aren't helping with it. It's not their fault, though. There's no common standard and almost no documentation for adding entries into the context menu. At this point, there's no return and no salvation for it. At very least it's working. What actually doesn't help is that Microsoft continued with their all time classic - piling up layers upon layers of indirection with their all new Windows 11 context menu, which is also poorly done and even more enclosed in terms of the API. I want to dedicate this blog post to _actually customizing_ the Windows 10/11 Legacy context menu to your liking instead of simply complaining about its inner workings. Using methods described in this article, you will be able to bring your menu from this abomination... ![Before](/images/blog/assets/the-windows-context-menu/before.png) **...to this!** ![After](/images/blog/assets/the-windows-context-menu/after.png) Be aware - there's _plenty_ of registry digging involved. And the truly worst part is... **Forget any logic when dealing with registry keys.** The idea of registry's structural integrity has long since been abandoned and nobody seems to care about it as, well, the end user is never going to care about it, and if they do - they know what they're doing and they will not complain. While 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 believe it's worth your time?". And if your answer is yes, and you're as much of a perfectionist as I am, buckle up and get ready for upcoming few hours of pure joy. Please note that any sfc /scannow or dism /restorehealth invocations will probably interfere with your context menu as Microsoft are really weird - they seem to allow customization of it, but still don't fully support it. It's been like this for at least 20 years. Shell entries & Context Menu handlers There are two main ways to insert entries into the context menu: Shell entries Context Menu handlers Both of them are very poorly documented, but the idea is very simple: whereas Shell entries are managed by the registry, the Context Menu handlers are managed by the software in question. Shell entries are much, much better in terms of flexibility and customization (in fact, you don't get any customization with Context Menu handlers at all, unless the developer was nice enough to let you tweak context menu settings through their app or provide necessary documentation for registry endpoints). 7-Zip would serve as a neat example of good software design, as the creator allows you to tweak settings of their handler. ![7-Zip Context Menu Settings.png](/images/blog/assets/the-windows-context-menu/7-zip-context-menu-settings.png) MobaXterm would also serve as a nice example for the case, where shell entries are used, but you can tweak them from the app itself. MobaXterm Context Menu Settings.png And so, there are 3 types of applications in terms of their context menu customization-friendliness: Context Menu handler apps with in-app settings (the easiest) Apps using shell entries (customizable via registry hacks or from within software) Context Menu handler apps without anything (uneditable entries) The first case is the simplest - you just have to consult the documentation of software you're using to find out whether it supports context menu customization or not. The other two cases is what I'm going to tackle in this write-up. For starters, all modifications are done under HKEY_CLASSES_ROOT (the HKEY_LOCAL_MACHINE\Software\Classes alias). That hive contains data about shell components and file extensions. For example, any data under exefile will apply to all executable files. That's one of the methods companion viruses utilized back in the day to accompany their victims - the .exe/.com files. Either way, since the HKCR hive is basically divided into file/shell extensions, we will have to edit context menu for each file and shell extension manually. Yeah. This is absolutely abysmal. There is no better way to approach this. And while you might already be reconsidering your choices, let me teach you the basics so you could at least bring your most used extensions and most noticeable context menu areas up to par... Some generalizations are also made within the registry. For instance, there are wildcard entries for ALL files, or for ALL images and so on. That still does not excuse the horrible approach Microsoft has taken with the file extensions from the beginning. Even though the incompleteness always annoyed me, unfortunately, that's how sometimes life is. This is how the general structure of an extension looks like: EXE File Registry Structure.png Editable entries are stored under the Shell key. Uneditable/highly customizable (thanks to the developer) entires are stored under ShellEx. Capitalization plays no role, the Windows registry key names is case-insensitive. The value names, however, are. What a nice spec! Sort of editable entries? The structure varies from extension to extension, but you know you've found it when you see the Shell key. Subkeys of it represent the "shell entries" - or, well, customizable entries of the context menu. Directory.png Each shell entry contains the command subkey, default value of which controls what executes upon clicking on the context menu entry. The default entry follows the Batch syntax, albeit very poorly. You cannot have extended Batch logic in the entries, which made me immeasurably sad and also made me write utilities called quiet and elevate for that specific purpose. No matter how hard I tried, I could not find the spec for the extents of the Batch logic in the default value for command. Shell Entry Structure.png Command Verb.png In general, I'd suggest you to treat the command value as the raw command line, but with the %1 macro for the full input file path without quotation marks (e.g. if you right-click C:\Users\bleh\p.txt, and click on your own shell entry, the %1 within command will be equivalent to C:\Users\bleh\p.txt) and %V for the full directory path. That must be one of the few values to be consistent across all the shell entries. Sometimes command's default value is left unused for DelegateExecute to take its place. If that's the case, that means the command handler is implemented as an IExecuteCommand COM object, or, well, you can't really customize it. All it contains is the UUID of the read-only object. DelegateExecute.png Adding entries Locate the extension (be it a file, or a shell one) you want to target. Careful! Some extensions can be buried within other extensions. For example, the folder background extension is located inside the folder extension under the Background key. Navigate to the shell key. If there is none and you're confident there should be one (by feel!), try creating one (it's highly likely not going to affect the system stability). Create a new entry, you can call it whatever you want, but it should be alphanumeric. Create a command key. Specify the command line you want to execute upon the click of your entry. The entry should appear in the context menu. If it does not, restart Explorer. If it still doesn't appear, you've probably messed up the procedure or the extension isn't registered in Windows. Nesting entries You can nest entries too! Repeat the first 4 steps from The Windows Context Menu > Adding entries, but don't add the command key yet. Instead, create another shell key, and then inside of it create a key not called command. And working in that new key, repeat last 3 steps. Finally, get back to your initial ancestor entry and add an empty REG_SZ value called SubCommands. Nested Entries Structure.png SubCommands.png You can make an entry have only a single nested entry as well, I've tested it. Nested Entries.png To control the parent context menu entry, use the outer Shell entry subkey. Nested Entries Order.png To control its children, use the inner Shell entry subkeys. Nested Entries Order 2.png Editing entries Now you're probably wondering how to name the entries and add nice little icons next to them. By default, the context menu entries duplicate their names from their respective shell subkeys. Name To override the default name, you can use either the (Default) or MUIVerb REG_SZ values inside the respective shell entry (not command). MUIVerb takes precedence over the default value. You can put in anything you want, it's going to work. Icon To enable the icon for your shell entry, you should use the Icon REG_SZ value inside the respective shell entry. It uses that weird WinAPI resource syntax to create a direct link to the icon. 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, as in: PATH_TO_FILE_WITH_ICON_RESOURCES For example, 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 full paths depending on the %PATH% variable that unholy concoction of an API uses. Only God knows what paths it's able to parse by default. C:\Windows, C:\Windows\system32 work for sure, though. I still highly suggest supplying the full path to file, as even the %PATH%s of the Explorer's icon picker and the Icon value do not seem to correspond. Tip: you can use the Explorer folder icon picker to acquire the icon DLL and calculate the offset of the desired icon. For example, the one I've selected in the screenshot has an index of 5. Indexing begins with 0 and ascends in columns. Icon Viewer.png You can also pull resource strings from files the same way for MUI Verbs and default values. DLL Syntax.png Separators Another integral part of the context menu, which is hardly documented by anyone. Managing them is also rather quirky, but you get used to it after some time. Separators in shell entries are relative to the element you're enabling them for and can overlap without any issue. Use SeparatorBefore and SeparatorAfter empty REG_SZ values to add a separator before or after the entry you're editing, respectively. Separators.png Appear in the Shift+Click context menu only You can make your shell entry be "hidden" from a normal context menu click. Such entry is called "extended". It's possible to enable that functionality by creating an empty REG_SZ value called Extended inside the respective shell entry. Position override See The Windows Context Menu > Sorting entries > Position override Hide in Safe Mode To hide the context menu entry in safe mode, create an empty REG_SZ value called HideInSafeMode inside the respective shell entry. Never default An example of a default entry would be "Open" for folders, or generally the bold context menu entry shown at the top. That's the entry Windows will default to when you open the file with a certain extension. Media.png There can be no default entry at all, and that's perfectly fine. If you don't want your entry to show up as a default one, add an empty REG_SZ value called NeverDefault into the respective shell entry. Pass through to Context Menu handlers If you know what context handler you want to invoke on shell entry click, you can specify a so-called Verb Handler. Create a new REG_SZ value VerbHandler and specify the context menu handler's UUID as data. Context Menu Handler 1.png Context Menu Handler 2.png Other options I am not ashamed to admit that I have absolutely zero idea what some of the options do, even though they might sound obvious. If you do have the knowledge, please contact me on Twitter: @endermanch or send a mail my way: blogs@enderman.ch For example: NoWorkingDirectory - could be hiding the working directory from the app it's starting? CanonicalName CommandStateHandler CommandStateSync Description VerbName Deleting entries Pretty much the opposite of adding one. Locate the extension (be it a file, or a shell one) you want to target. Sometimes multiple locations can correspond to the same place in the context menu, which might result in the entry remaining in place, even though you've deleted it. Navigate to the shell key. Find the shell entry you want to delete. You can find out the application behind it by looking into the default value of the command key. Delete the key. 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. Alphabetical Sort 1.png Alphabetical Sort 2.png Yeah... I'd rather not comment that. Position override Another silly and janky feature that has a limited amount 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. Position Override.png 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 you to 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. Context Menu Handler 3.png Most of the times, the only data they contain is a lonely UUID. That doesn't help much. Context Menu Handler 4.png So, to remove the Context Menu handler, you should just delete the subkey under ContextMenuHandlers. I strongly suggest you save the UUID it contained so that you could roll back at any time later. Context Menu Handler 5.png 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 an 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 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. Registry paths involved Bottom line of desktop: Computer\HKEY_CLASSES_ROOT\DesktopBackground Desktop Background.png Folder Background Computer\HKEY_CLASSES_ROOT\Directory\Background\shell Directory Background.png Folder Computer\HKEY_CLASSES_ROOT\Directory\shell Folder.png Folder Item (extends Folder) Computer\HKEY_CLASSES_ROOT\Folder File Item.png Drive Computer\HKEY_CLASSES_ROOT\Drive Drive.png Library folder Computer\HKEY_CLASSES_ROOT\LibraryFolder Library Item.png 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. Library Background.png Explorer Error.png All Files Computer\HKEY_CLASSES_ROOT\* All Files.png All Filesystem Objects (yep, that's different from All Files - it's a generalization that includes drives and symbols) Computer\HKEY_CLASSES_ROOT\AllFilesystemObjects All Filesystem Objects.png Text Files Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text Image Files Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\image Document Files Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\document Audio Files Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\audio Video Files 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. Winaero 1.png Winaero 2.png Areas Winaero Tweaker does not reach 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! Contact If you've spotted a mistake (be it orthographical, factual or any other) in this article or want to add And third-party software developers adding oil into the dumpster fire aren't helping with it. It's not their fault, though. There's no common standard and almost no documentation for adding entries into the context menu.