Added new icons, improved the blog
|
@ -1 +1 @@
|
||||||
[{"D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\transitions.scss":"1","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\TransitionY.vue":"2","D:\\Software\\Development\\Websites\\enderman.ch\\index\\app.vue":"3","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\EMail.vue":"4","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\about.vue":"5","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\index.vue":"6","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\projects.vue":"7","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\social.vue":"8","D:\\Software\\Development\\Websites\\enderman.ch\\index\\layouts\\Card.vue":"9","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Options.vue":"10","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Flooter.vue":"11","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\SwipeControls.vue":"12","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Logo.vue":"13","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Route.vue":"14","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\animations\\Portal.vue":"15","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\ui\\Icon.vue":"16","D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\vuetify.scss":"17","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\[...slug].vue":"18","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\index.vue":"19","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\[slug].vue":"20"},{"size":165,"mtime":1700688268778,"hashOfConfig":"21"},{"size":1513,"mtime":1700430002840,"hashOfConfig":"21"},{"size":1550,"mtime":1700850776284,"hashOfConfig":"21"},{"size":804,"mtime":1700688952880,"hashOfConfig":"21"},{"size":2135,"mtime":1700689265787,"hashOfConfig":"21"},{"size":3117,"mtime":1700689271383,"hashOfConfig":"21"},{"size":2304,"mtime":1700689265769,"hashOfConfig":"21"},{"size":3232,"mtime":1700689265781,"hashOfConfig":"21"},{"size":1623,"mtime":1700748530633,"hashOfConfig":"21"},{"size":3065,"mtime":1708254606285,"hashOfConfig":"22"},{"size":1132,"mtime":1708254584095,"hashOfConfig":"22"},{"size":1269,"mtime":1708255068679,"hashOfConfig":"22"},{"size":1147,"mtime":1708248797872,"hashOfConfig":"22"},{"size":979,"mtime":1706003786966,"hashOfConfig":"22"},{"size":16968,"mtime":1708180277353,"hashOfConfig":"22"},{"size":935,"mtime":1706445231843,"hashOfConfig":"22"},{"size":120,"mtime":1706789613657,"hashOfConfig":"23"},{"size":1988,"mtime":1708191547889,"hashOfConfig":"22"},{"size":2560,"mtime":1708202402381,"hashOfConfig":"22"},{"size":983,"mtime":1708206997656,"hashOfConfig":"22"},"5tgxr3","1nljphs","1lk8nat"]
|
[{"D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\transitions.scss":"1","D:\\Software\\Development\\Websites\\enderman.ch\\index\\app.vue":"2","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\EMail.vue":"3","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\about.vue":"4","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\index.vue":"5","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\projects.vue":"6","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\social.vue":"7","D:\\Software\\Development\\Websites\\enderman.ch\\index\\layouts\\Card.vue":"8","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Options.vue":"9","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Flooter.vue":"10","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\SwipeControls.vue":"11","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Logo.vue":"12","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Route.vue":"13","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\animations\\Portal.vue":"14","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\ui\\Icon.vue":"15","D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\vuetify.scss":"16","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\[...slug].vue":"17","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\index.vue":"18","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\[slug].vue":"19","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\content\\Card.vue":"20"},{"size":165,"mtime":1700688268778,"hashOfConfig":"21"},{"size":1550,"mtime":1700850776284,"hashOfConfig":"21"},{"size":804,"mtime":1700688952880,"hashOfConfig":"21"},{"size":2135,"mtime":1700689265787,"hashOfConfig":"21"},{"size":3117,"mtime":1700689271383,"hashOfConfig":"21"},{"size":2304,"mtime":1700689265769,"hashOfConfig":"21"},{"size":3232,"mtime":1700689265781,"hashOfConfig":"21"},{"size":1623,"mtime":1700748530633,"hashOfConfig":"21"},{"size":3065,"mtime":1708262194629,"hashOfConfig":"22"},{"size":1132,"mtime":1708254584095,"hashOfConfig":"22"},{"size":1269,"mtime":1708255068679,"hashOfConfig":"22"},{"size":1147,"mtime":1708248797872,"hashOfConfig":"22"},{"size":979,"mtime":1706003786966,"hashOfConfig":"22"},{"size":16968,"mtime":1708180277353,"hashOfConfig":"22"},{"size":935,"mtime":1706445231843,"hashOfConfig":"22"},{"size":120,"mtime":1706789613657,"hashOfConfig":"23"},{"size":1988,"mtime":1708191547889,"hashOfConfig":"22"},{"size":2560,"mtime":1708202402381,"hashOfConfig":"22"},{"size":983,"mtime":1708206997656,"hashOfConfig":"22"},{"size":1912,"mtime":1708290866348,"hashOfConfig":"22"},"5tgxr3","1nljphs","1lk8nat"]
|
4
app.vue
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const config = useAppConfig()
|
const config = useAppConfig()
|
||||||
const vdisp = ref(useVDisplay())
|
|
||||||
const theme = useVThemeSSR()
|
const theme = useVThemeSSR()
|
||||||
|
const vdisp = ref(useVDisplay())
|
||||||
const { reader } = storeToRefs(usePageStore())
|
const { reader } = storeToRefs(usePageStore())
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
|
@ -49,7 +49,7 @@ useHead({
|
||||||
enter="animate__animated animate__delay-1s animate__fadeInUpBig animate__slow"
|
enter="animate__animated animate__delay-1s animate__fadeInUpBig animate__slow"
|
||||||
leave="animate__animated animate__fadeOutDown"
|
leave="animate__animated animate__fadeOutDown"
|
||||||
>
|
>
|
||||||
<Flooter v-if="vdisp.smAndUp" class="floaty mb-2 px-2" />
|
<Flooter v-if="vdisp.smAndUp && !reader" class="floaty mb-2 px-2" />
|
||||||
</AClientOnly>
|
</AClientOnly>
|
||||||
|
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
|
|
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 47 KiB |
|
@ -22,7 +22,7 @@
|
||||||
--animate-repeat: 1;
|
--animate-repeat: 1;
|
||||||
--bs-font-sans-serif: 'Lato', 'Times New Roman';
|
--bs-font-sans-serif: 'Lato', 'Times New Roman';
|
||||||
--bs-font-monospace: 'JetBrains Mono', 'Courier New';
|
--bs-font-monospace: 'JetBrains Mono', 'Courier New';
|
||||||
--bs-body-font-size: 18px;
|
--bs-body-font-size: 20px;
|
||||||
--bs-body-line-height: 1.5;
|
--bs-body-line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,15 @@ body {
|
||||||
max-height: 100% !important;
|
max-height: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.nobr {
|
.nobr {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
@ -364,14 +373,29 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
|
:is(p, li) {
|
||||||
|
a {
|
||||||
|
@extend %link;
|
||||||
|
|
||||||
|
color: cornflowerblue;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: royalblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:is(h1, h2, h3, h4, h5, h6) {
|
:is(h1, h2, h3, h4, h5, h6) {
|
||||||
font-family: Alexandria, sans-serif;
|
font-family: Alexandria, sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@extend %link;
|
@extend %link;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: indianred;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|
|
@ -18,10 +18,10 @@ const mailTemplate = `I've just found a bug on ${config.url} and would like to r
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<div v-bind="props" class="options clickable">
|
<div v-bind="props" class="options clickable">
|
||||||
<img
|
<img
|
||||||
class="logo user-select-none"
|
|
||||||
draggable="false"
|
draggable="false"
|
||||||
:src="cogIcon"
|
:src="cogIcon"
|
||||||
alt="Options"
|
alt="Options"
|
||||||
|
class="logo user-select-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,10 +33,10 @@ const mailTemplate = `I've just found a bug on ${config.url} and would like to r
|
||||||
<div class="overlay background"></div>
|
<div class="overlay background"></div>
|
||||||
<VCardText class="overlay content">
|
<VCardText class="overlay content">
|
||||||
<img
|
<img
|
||||||
class="icon-badge user-select-none"
|
|
||||||
draggable="false"
|
draggable="false"
|
||||||
:src="pearlIcon"
|
:src="pearlIcon"
|
||||||
alt="Pearl"
|
alt="Pearl"
|
||||||
|
class="icon-badge user-select-none"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
|
||||||
|
import warningIcon from '~/assets/images/icons/accent/warning.png'
|
||||||
|
import errorIcon from '~/assets/images/icons/accent/error.png'
|
||||||
|
import infoIcon from '~/assets/images/icons/accent/info.png'
|
||||||
|
import helpIcon from '~/assets/images/icons/accent/help.png'
|
||||||
|
import checkIcon from '~/assets/images/icons/accent/checkmark.png'
|
||||||
|
import ideaIcon from '~/assets/images/icons/accent/idea.png'
|
||||||
|
|
||||||
|
type IconOptions = 'warning' | 'error' | 'info' | 'help' | 'checkmark' | 'idea'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
icon: {
|
||||||
|
type: String as PropType<IconOptions>,
|
||||||
|
default: 'warning',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: 'Important',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let cardIcon = warningIcon
|
||||||
|
let color = 'rgba(255 246 147 / 60%)'
|
||||||
|
|
||||||
|
switch (props.icon) {
|
||||||
|
case 'error':
|
||||||
|
cardIcon = errorIcon
|
||||||
|
color = 'rgb(255 113 113 / 60%)'
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'info':
|
||||||
|
cardIcon = infoIcon
|
||||||
|
color = 'rgb(94 162 255 / 60%)'
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'help':
|
||||||
|
cardIcon = helpIcon
|
||||||
|
color = 'rgb(178 104 255 / 60%)'
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'checkmark':
|
||||||
|
cardIcon = checkIcon
|
||||||
|
color = 'rgba(69 255 255 / 60%)'
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'idea':
|
||||||
|
cardIcon = ideaIcon
|
||||||
|
color = 'rgba(255 255 255 / 60%)'
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'warning':
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="tilt d-flex flex-row align-items-center gap-2 mb-0 mb-sm-2 mb-md-4"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
draggable="false"
|
||||||
|
:src="cardIcon"
|
||||||
|
:alt="`Download`"
|
||||||
|
class="icon-image"
|
||||||
|
/>
|
||||||
|
<h3 class="mb-0 nobr">{{ props.title }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box p-4 rounded-4 mb-4">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.tilt {
|
||||||
|
transform: rotate(-2deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
> p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 1px ridge;
|
||||||
|
border-right: 1px ridge;
|
||||||
|
border-color: v-bind(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
&-image {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,13 +8,21 @@ tags: ['windows', 'context-menu', 'customization', 'registry', 'shell', 'shell-e
|
||||||
thumbnail: '/images/blog/thumbnails/the-windows-context-menu.png'
|
thumbnail: '/images/blog/thumbnails/the-windows-context-menu.png'
|
||||||
---
|
---
|
||||||
|
|
||||||
#### The Windows context menu is... poorly done.
|
# 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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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 article to _actually customizing_ the Windows 10
|
||||||
|
(incidentally, also 11 Legacy) context menu to your liking
|
||||||
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...
|
instead of just complaining about its inner workings.
|
||||||
|
After reading this article completely, you should be able to bring your menu from this abomination...
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -22,109 +30,269 @@ I want to dedicate this blog post to _actually customizing_ the Windows 10/11 Le
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Be aware - there's _plenty_ of registry digging involved. And the truly worst part is...
|
Be wary — there's _plenty_ of registry digging involved. And the terrible 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.
|
**Forget any logic when dealing with registry keys.**
|
||||||
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.
|
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. 😉
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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.
|
::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.
|
||||||
|
::
|
||||||
|
|
||||||
Shell entries & Context Menu handlers
|
## Context menu components
|
||||||
There are two main ways to insert entries into the context menu:
|
There are two main components the context menu is composed of:
|
||||||
|
|
||||||
Shell entries
|
* **Shell entries** — provided locally and managed by the registry;
|
||||||
Context Menu handlers
|
* **Context menu handlers** — provided and managed by external software;
|
||||||
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.
|
Neither of them is documented well, but
|
||||||
|
there is some developer documentation for handlers available [on Microsoft's website](https://go.enderman.ch/Fm4t3).
|
||||||
|
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](https://go.enderman.ch/7-zip) serves as a neat example of great software design —
|
||||||
|
the developer here allows you to extensively tweak their handler.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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](https://go.enderman.ch/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!_ 😊
|
||||||
|
|
||||||
MobaXterm Context Menu Settings.png
|

|
||||||
|
|
||||||
And so, there are 3 types of applications in terms of their context menu customization-friendliness:
|
In conclusion, there are three types of applications in terms of friendliness towards context menu customization:
|
||||||
|
|
||||||
Context Menu handler apps with in-app settings (the easiest)
|
* **Apps using context menu handlers with customizable settings** — the friendliest;
|
||||||
Apps using shell entries (customizable via registry hacks or from within software)
|
* **Apps using shell entries** — customizable through registry hacks;
|
||||||
Context Menu handler apps without anything (uneditable entries)
|
* **Apps using context menu handlers without settings** — the entries are uneditable;
|
||||||
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.
|
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.**
|
||||||
|
|
||||||
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.
|
### 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.
|
||||||
|
|
||||||
Even though the incompleteness always annoyed me, unfortunately, that's how sometimes life is.
|
For example, data under the `exefile` key will exclusively apply to files with the `.exe` extension.
|
||||||
|
A trusty old method [«companion» viruses](https://go.enderman.ch/Kvo3u) 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](https://go.enderman.ch/2WeQ0), worked exactly this way and caused heaps of damage.
|
||||||
|
|
||||||
This is how the general structure of an extension looks like:
|
Since all the settings inside the `HKCR` key are divided into types,
|
||||||
EXE File Registry Structure.png
|
editing the context menu for each file type and shell extension manually is unavoidable.
|
||||||
|
|
||||||
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!
|
_Yeah..._
|
||||||
|
|
||||||
Sort of editable entries?
|
This is **abysmal**, and, unfortunately, there is no better approach.
|
||||||
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.
|
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...
|
||||||
|
|
||||||
Directory.png
|
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.
|
||||||
|
|
||||||
Each shell entry contains the command subkey, default value of which controls what executes upon clicking on the context menu entry.
|
#### General structure
|
||||||
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.
|
The following figure is what seems to be the general structure of an extension registry key:
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Sometimes command's default value is left unused for DelegateExecute to take its place.
|
::card
|
||||||
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.
|
---
|
||||||
|
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.;
|
||||||
|
|
||||||
DelegateExecute.png
|
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. 😒
|
||||||
|
::
|
||||||
|
|
||||||
Adding entries
|
#### Editing entries
|
||||||
Locate the extension (be it a file, or a shell one) you want to target.
|
Locally provided entries always available for a quick and dirty edit are stored under the `Shell` subkey.
|
||||||
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.
|
Entries provided by software — the context menu handlers — are stored under the `ShellEx` subkey.
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Nested Entries.png
|
_Truly an amazing specification!_
|
||||||
|
|
||||||
To control the parent context menu entry, use the outer Shell entry subkey.
|
|
||||||
|
|
||||||
Nested Entries Order.png
|
#### 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](https://go.enderman.ch/elevate) and [elevate](https://go.enderman.ch/elevate)<sup>sudo for Windows [anyone](https://go.enderman.ch/XuDXW)?</sup> for that specific purpose.
|
||||||
|
|
||||||
To control its children, use the inner Shell entry subkeys.
|
No matter how hard I tried, I could not find the exact specification of the incomplete Batch logic the default value uses.
|
||||||
|
|
||||||
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
|
My suggestion is to treat the default `command` value as **raw command line** (e.g. Run box),
|
||||||
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.
|
with an exception to the following two macros:
|
||||||
|
* `%1` — the absolute file path without quotes
|
||||||
|
If you right-click `C:\Users\bleh\p.txt`, execute the shell entry,
|
||||||
|
the `%1` in the context of the command line will be equivalent to `C:\Users\bleh\p.txt`;
|
||||||
|
* `%V` — the absolute directory path without quotes;
|
||||||
|
|
||||||
You can put in anything you want, it's going to work.
|
::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](https://go.enderman.ch/KuKR4)** 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!**
|
||||||
|
::
|
||||||
|
|
||||||
Icon
|
On rare occasions, the default value is left unset, with `DelegateExecute` alongside it containing a GUID.
|
||||||
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.
|
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:
|
||||||
|
|
||||||
|
1. Locate the target extension.
|
||||||
|
2. **Careful!** Some extensions may be buried within other extensions.
|
||||||
|
As an example, the [Folder Background](#folder-background) extension is located under the [Folder](#folder) extension `Directory` key in the `Background` subkey.
|
||||||
|
3. 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.<sub>(no, seriously)</sub>
|
||||||
|
4. Create a new key, the name **must be alphanumeric**. The name is case-insensitive.
|
||||||
|
5. Create the `command` subkey.
|
||||||
|
6. Specify the command line you want to execute on click in the **default value**.
|
||||||
|
7. 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!
|
||||||
|
1. Repeat the first 4 steps from [Adding entries](#adding-entries).
|
||||||
|
Don't add the `command` key just yet.
|
||||||
|
2. Create another `shell` key.
|
||||||
|
3. Inside it, create a subkey **called anything else, but** `command`.
|
||||||
|
4. Working within the subkey, repeat steps 5–7.
|
||||||
|
5. Navigate back to the root shell entry
|
||||||
|
6. Create an empty `REG_SZ` value called `SubCommands`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
```csv
|
||||||
PATH_TO_FILE_WITH_ICON_RESOURCES,INDEX
|
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:
|
```
|
||||||
|
|
||||||
|
If you want to select the first icon (in that case, the `INDEX` part is 0),
|
||||||
|
the `INDEX` part can be omitted completely:
|
||||||
|
```csv
|
||||||
PATH_TO_FILE_WITH_ICON_RESOURCES
|
PATH_TO_FILE_WITH_ICON_RESOURCES
|
||||||
For example, the following expressions are completely valid and are going to work:
|
```
|
||||||
|
|
||||||
|
The following expressions are completely valid and are going to work:
|
||||||
|
```csv
|
||||||
"C:\Windows\system32\cmd.exe"
|
"C:\Windows\system32\cmd.exe"
|
||||||
C:\Windows\regedit.exe
|
C:\Windows\regedit.exe
|
||||||
"C:\Windows\explorer.exe",0
|
"C:\Windows\explorer.exe",0
|
||||||
|
@ -133,212 +301,277 @@ cmd.exe
|
||||||
shell32.dll,3
|
shell32.dll,3
|
||||||
SHELL32.DLL,10
|
SHELL32.DLL,10
|
||||||
"C:\Windows\system32\SHELL32.DLL",9
|
"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.
|
```
|
||||||
|
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.
|
||||||
|
|
||||||
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.
|
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**.
|
||||||
|
|
||||||
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.
|
::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**.
|
||||||
|
::
|
||||||
|
|
||||||
Indexing begins with 0 and ascends in columns.
|

|
||||||
|
|
||||||
Icon Viewer.png
|
It's also possible to pull resource strings from files containing string tables.
|
||||||
|
|
||||||
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 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.
|
||||||
|
|
||||||
Separators
|
Use `SeparatorBefore` and `SeparatorAfter` empty `REG_SZ` values
|
||||||
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.
|
to add a separator before or after the shell entry being edited, respectively.
|
||||||
|
|
||||||
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.
|
##### 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».
|
||||||
|
|
||||||
Separators.png
|
Enable that functionality by creating an empty `REG_SZ` value called `Extended` inside the `shell` key for the
|
||||||
|
respective shell entry.
|
||||||
|
|
||||||
Appear in the Shift+Click context menu only
|
##### Hide in safe mode
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Position override
|
##### Never default
|
||||||
See The Windows Context Menu > Sorting entries > Position override
|
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.
|
||||||
|
|
||||||
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
|
There can be no default entry at all, and that's perfectly fine.
|
||||||
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
|
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.
|
||||||
|
|
||||||
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 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.
|
||||||
|
|
||||||
Pass through to Context Menu handlers
|
Create a new `REG_SZ` value `VerbHandler` inside the `shell` key for the respective shell entry
|
||||||
If you know what context handler you want to invoke on shell entry click, you can specify a so-called Verb Handler.
|
and specify the GUID of the context menu handler in the value.
|
||||||
|
|
||||||
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
|
##### No working directory
|
||||||
I am not ashamed to admit that I have absolutely zero idea what some of the options do, even though they might sound obvious.
|
Disables the working directory from being added to the environmental path in the context of the application being run.
|
||||||
|
|
||||||
If you do have the knowledge, please contact me on Twitter: @endermanch or send a mail my way: blogs@enderman.ch
|
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.
|
||||||
|
|
||||||
For example:
|
##### Other options
|
||||||
NoWorkingDirectory - could be hiding the working directory from the app it's starting?
|
Some options, though might sound obvious, have me scratching the back of my head.
|
||||||
CanonicalName
|
Please tag me on [Twitter](https://go.enderman.ch/twitter) or [send a mail](mailto:contact@enderman.ch) my way if you
|
||||||
CommandStateHandler
|
have the knowledge.
|
||||||
CommandStateSync
|
|
||||||
Description
|
|
||||||
VerbName
|
|
||||||
|
|
||||||
Deleting entries
|
**A few examples:**
|
||||||
Pretty much the opposite of adding one.
|
* `CanonicalName`
|
||||||
|
* `CommandStateHandler`
|
||||||
|
* `CommandStateSync`
|
||||||
|
* `Description`
|
||||||
|
* `VerbName`
|
||||||
|
|
||||||
Locate the extension (be it a file, or a shell one) you want to target.
|
#### Deleting entries
|
||||||
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.
|
Even simpler — it's the opposite of adding one.
|
||||||
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.
|
1. Locate the target extension.
|
||||||
Delete the key.
|
2. Navigate to the `shell` subkey.
|
||||||
Sorting entries
|
3. 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.
|
||||||
|
4. 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.
|
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.
|
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
|
Yeah... I'd rather not comment on that.
|
||||||
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...
|
|
||||||
|
##### 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.
|
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.
|
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.
|
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
|
##### 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.
|
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.
|
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
|
### Uneditable entries
|
||||||
As for the Context Menu handlers, there's actually not much you can do. They're located under the shellex\ContextMenuHandlers subkey.
|
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.
|
Most of the time, the only data they contain is a lonely GUID. 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.
|
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.
|
||||||
|
|
||||||
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.
|
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
|
## 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.
|
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.
|
Optimal way: Using Process Hacker with the TrustedInstaller plugin or Winaero Tweaker,
|
||||||
|
run regedit as Trusted Installer and perform the necessary tweaks.
|
||||||
|
|
||||||
General solution:
|
General solution:
|
||||||
|
|
||||||
Navigate to the key you want to take ownership of
|
Navigate to the key you want to take ownership of
|
||||||
Open the Properties window
|
Open the «Properties» window
|
||||||
Head over to the Advanced tab
|
Head over to the Advanced tab
|
||||||
At the top of the Advanced Security Settings it states Owner: TrustedInstaller. Click Change
|
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.
|
Input your username into the Enter the object name to select (examples) text area.
|
||||||
Click OK
|
Click OK
|
||||||
Check the Replace owner on subcontainers and objects checkbox
|
Check the «Replace owner on subcontainers and objects» checkbox
|
||||||
Check the Replace all child object permission entries checkbox
|
Check the «Replace all child object permission entries» checkbox
|
||||||
Click OK
|
Click OK
|
||||||
Select Administrators (PC_NAME\Administrators) in the group selector and then check Full Control box in the Permissions window down below
|
Select Administrators (PC_NAME\Administrators) in the group selector and then check Full Control box in the Permissions window down below
|
||||||
Click OK
|
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.
|
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
|
## Common registry paths
|
||||||
Bottom line of desktop:
|
Here is a list of the most common registry paths.
|
||||||
Computer\HKEY_CLASSES_ROOT\DesktopBackground
|
|
||||||
Desktop Background.png
|
|
||||||
|
|
||||||
Folder Background
|
#### Desktop Background — bottom rows
|
||||||
Computer\HKEY_CLASSES_ROOT\Directory\Background\shell
|
`Computer\HKEY_CLASSES_ROOT\DesktopBackground`
|
||||||
Directory Background.png
|
|
||||||
|
|
||||||
Folder
|

|
||||||
Computer\HKEY_CLASSES_ROOT\Directory\shell
|
|
||||||
Folder.png
|
|
||||||
|
|
||||||
Folder Item (extends Folder)
|
#### Folder Background
|
||||||
Computer\HKEY_CLASSES_ROOT\Folder
|
`Computer\HKEY_CLASSES_ROOT\Directory\Background`
|
||||||
File Item.png
|
|
||||||
|
|
||||||
Drive
|

|
||||||
Computer\HKEY_CLASSES_ROOT\Drive
|
|
||||||
Drive.png
|
|
||||||
|
|
||||||
Library folder
|
#### Folder
|
||||||
Computer\HKEY_CLASSES_ROOT\LibraryFolder
|
`Computer\HKEY_CLASSES_ROOT\Directory`
|
||||||
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
|
#### Folder Item
|
||||||
Computer\HKEY_CLASSES_ROOT\*
|
This extends [Folder](#folder).
|
||||||
All Files.png
|
`Computer\HKEY_CLASSES_ROOT\Folder`
|
||||||
|
|
||||||
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
|
#### Drive
|
||||||
Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text
|
`Computer\HKEY_CLASSES_ROOT\Drive`
|
||||||
|
|
||||||
Image Files
|

|
||||||
Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\image
|
|
||||||
|
|
||||||
Document Files
|
#### Library Folder
|
||||||
Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\document
|
`Computer\HKEY_CLASSES_ROOT\LibraryFolder`
|
||||||
|
|
||||||
Audio Files
|

|
||||||
Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\audio
|
|
||||||
|
|
||||||
Video Files
|
#### Library Background
|
||||||
Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\video
|
`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.
|
||||||
|
|
||||||
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
|
#### All Files
|
||||||
Remove "Open PowerShell window here"
|
`Computer\HKEY_CLASSES_ROOT\*`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### All Filesystem Objects
|
||||||
|
That's different from [All Files](#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
|
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\Powershell
|
||||||
Unlock key (The Windows Context Menu > Dealing with locked keys)
|
Unlock key (The Windows Context Menu > Dealing with locked keys)
|
||||||
Create a new REG_SZ value ProgrammaticAccessOnly without any data
|
Create a new REG_SZ value ProgrammaticAccessOnly without any data
|
||||||
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell
|
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell
|
||||||
Unlock key
|
Unlock key
|
||||||
Create a new REG_SZ value ProgrammaticAccessOnly without any data
|
Create a new REG_SZ value ProgrammaticAccessOnly without any data
|
||||||
Remove "Open Linux shell here"
|
Remove «Open Linux shell here»
|
||||||
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL
|
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL
|
||||||
Unlock key
|
Unlock key
|
||||||
Delete WSL key altogether
|
Delete WSL key altogether
|
||||||
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell
|
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell
|
||||||
Unlock key
|
Unlock key
|
||||||
Create a new REG_SZ value ProgrammaticAccessOnly without any data
|
Create a new REG_SZ value ProgrammaticAccessOnly without any data
|
||||||
Edit the "Edit" text context menu command
|
Edit the «Edit» text context menu command
|
||||||
Navigate to Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell\edit
|
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.
|
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
|
## Bottom line
|
||||||
If you've spotted a mistake (be it orthographical, factual or any other) in this article or want to add
|
No matter how terrible the context menu API might be for Windows, there's still a way to customize it.
|
||||||
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.
|
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
|
||||||
|
|
|
@ -62,6 +62,33 @@ export default defineNuxtConfig({
|
||||||
markdown: {
|
markdown: {
|
||||||
remarkPlugins: ['remark-reading-time'],
|
remarkPlugins: ['remark-reading-time'],
|
||||||
},
|
},
|
||||||
|
highlight: {
|
||||||
|
theme: {
|
||||||
|
// Default theme (same as single string)
|
||||||
|
default: 'github-light',
|
||||||
|
// Theme used if `html.dark`
|
||||||
|
dark: 'github-dark',
|
||||||
|
// Theme used if `html.sepia`
|
||||||
|
sepia: 'monokai',
|
||||||
|
},
|
||||||
|
langs: [
|
||||||
|
'c',
|
||||||
|
'cpp',
|
||||||
|
'java',
|
||||||
|
'csv',
|
||||||
|
'xml',
|
||||||
|
'json',
|
||||||
|
'js',
|
||||||
|
'ts',
|
||||||
|
'html',
|
||||||
|
'css',
|
||||||
|
'vue',
|
||||||
|
'shell',
|
||||||
|
'mdc',
|
||||||
|
'md',
|
||||||
|
'yaml',
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
nitro: {
|
nitro: {
|
||||||
prerender: {
|
prerender: {
|
||||||
|
|
After Width: | Height: | Size: 29 KiB |
|
@ -1,6 +1,6 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
import aboutIcon from '~/assets/images/icons/info.png'
|
import aboutIcon from '~/assets/images/icons/accent/info.png'
|
||||||
import projectIcon from '~/assets/images/icons/defrag.png'
|
import projectIcon from '~/assets/images/icons/defrag.png'
|
||||||
import socialIcon from '~/assets/images/icons/user.png'
|
import socialIcon from '~/assets/images/icons/user.png'
|
||||||
import blogIcon from '~/assets/images/icons/book.png'
|
import blogIcon from '~/assets/images/icons/book.png'
|
||||||
|
|