Blog slowly looming over

This commit is contained in:
Andrew Illarionov 2024-02-19 22:49:55 +03:00
parent b58407d358
commit 44c60f7069
11 changed files with 552 additions and 131 deletions

17
app.vue
View File

@ -3,12 +3,23 @@ const config = useAppConfig()
const theme = useVThemeSSR() const theme = useVThemeSSR()
const vdisp = ref(useVDisplay()) const vdisp = ref(useVDisplay())
const { reader } = storeToRefs(usePageStore()) const { reader } = storeToRefs(usePageStore())
const route = useRoute()
useHead({ useHead({
titleTemplate: (chunk?) => { titleTemplate: (chunk?) => {
return chunk === config.title.short if (route.fullPath === '/') return config.title.full
? config.title.full
: `${chunk} ${config.title.short}` console.log(route.fullPath.split('/'))
if (route.fullPath.split('/').length === 2)
switch (route.fullPath.split('/')[1]) {
case 'blog':
return 'The Enderchest'
default:
return `${chunk} ${config.title.short}`
}
return chunk!
}, },
}) })
</script> </script>

View File

@ -244,6 +244,10 @@ body {
border-radius: 8px; border-radius: 8px;
background-color: rgb(255 255 255 / 15%); background-color: rgb(255 255 255 / 15%);
} }
&::-webkit-scrollbar-button {
color: white;
}
} }
@media (prefers-color-scheme: light) { @media (prefers-color-scheme: light) {
@ -307,6 +311,9 @@ body {
} }
.post { .post {
scroll-snap-type: both mandatory;
scroll-snap-stop: normal;
&-box { &-box {
position: relative; position: relative;
@ -363,16 +370,52 @@ body {
} }
} }
&-details {
}
&-preamble { &-preamble {
&-thumb { display: flex;
max-width: 800px; flex-direction: column;
justify-content: flex-end;
align-items: flex-start;
position: relative;
width: 100%;
min-height: 400px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
background-attachment: fixed;
border-radius: 1em;
scroll-snap-align: end;
text-shadow: black 1px 1px 7px;
iconify-icon {
filter: drop-shadow(1px 2px 3px rgb(0 0 0 / 100%));
}
&-share {
position: absolute;
top: 0;
left: 0;
}
&-control {
position: absolute;
top: 0;
right: 0;
} }
} }
&-content { &-content {
scroll-snap-align: start;
:is(p, li) { :is(p, li) {
a { a {
@extend %link; @extend %link;
@ -383,6 +426,21 @@ body {
color: royalblue; color: royalblue;
} }
} }
code {
padding: 0.25em;
border-radius: 0.5em;
cursor: pointer;
background-color: rgb(83 35 162 / 10%);
transition: 0.3s ease;
&:hover {
background-color: rgb(138 71 245 / 20%);
}
}
} }
:is(h1, h2, h3, h4, h5, h6) { :is(h1, h2, h3, h4, h5, h6) {
@ -399,8 +457,90 @@ body {
} }
img { img {
max-width: 100%;
max-height: 400px; max-height: 400px;
} }
blockquote {
padding: 0.75em 1em;
border-left: 0.25em solid rgb(153 153 255 / 60%);
border-top-right-radius: 0.5em;
border-bottom-right-radius: 0.5em;
background-color: rgb(153 153 255 / 10%);
transition: 0.3s ease;
&:hover {
border-left-color: rgb(153 153 255 / 100%);
background-color: rgb(153 153 255 / 15%);
}
:last-child {
margin-bottom: 0;
}
}
pre {
font-size: 14px;
padding: 1em;
border-radius: 0.5em;
background-color: rgb(83 35 162 / 5%);
position: relative;
overflow-x: auto;
code {
counter-reset: step;
counter-increment: step 0;
scroll-padding: 0.5em;
.line::before {
content: counter(step);
counter-increment: step;
display: inline-block;
text-align: right;
color: rgb(238 246 250 / 40%);
width: 1rem;
margin-right: 1.5rem;
}
}
.button {
position: absolute;
top: 0;
right: 0;
margin: 0.5em;
padding: 0.5em;
cursor: pointer;
background-color: rgb(153 153 255 / 10%);
border: 1px solid rgb(153 153 255 / 60%);
border-radius: 0.5em;
opacity: 0;
transition: 0.3s ease;
}
&:hover {
.button {
opacity: 1;
}
}
}
} }
} }
@ -470,7 +610,7 @@ body {
&-description { &-description {
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 4;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@ -1,11 +1,16 @@
--- ---
title: The Windows Context Menu Is It a Lost Cause? 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. description: A deep dive into the Windows context menu API and customization options it offers. Shell components for beginners and context menu cleanup.
authors: ['Enderman']
created: 2023-08-13T15:51:19Z created: 2023-08-13T15:51:19Z
updated: 2024-02-18T21:32:12Z updated: 2024-02-18T21:32:12Z
draft: false draft: false
tags: ['windows', 'context-menu', 'customization', 'registry', 'shell', 'shell-extensions', 'context-menu-handlers'] tags: ['windows', 'context menu', 'customization', 'registry', 'windows tweaks', 'shell', 'shell extensions', 'shell components', 'context menu handlers', 'windows 10', 'windows 11']
thumbnail: '/images/blog/thumbnails/the-windows-context-menu.png' thumbnail: /images/blog/thumbnails/the-windows-context-menu.png
ogImage:
component: BlogImage
props:
image: /images/blog/thumbnails/the-windows-context-menu.png
--- ---
# The Windows context menu is... poorly made. # The Windows context menu is... poorly made.
@ -63,7 +68,7 @@ upon execution.
There are two main components the context menu is composed of: There are two main components the context menu is composed of:
* **Shell entries** — provided locally and managed by the registry; * **Shell entries** — provided locally and managed by the registry;
* **Context menu handlers** — provided and managed by external software; * **Context menu handlers** — provided and managed by external software.
Neither of them is documented well, but Neither of them is documented well, but
there is some developer documentation for handlers available [on Microsoft's website](https://go.enderman.ch/Fm4t3). there is some developer documentation for handlers available [on Microsoft's website](https://go.enderman.ch/Fm4t3).
@ -97,7 +102,7 @@ In conclusion, there are three types of applications in terms of friendliness to
* **Apps using context menu handlers with customizable settings** — the friendliest; * **Apps using context menu handlers with customizable settings** — the friendliest;
* **Apps using shell entries** — customizable through registry hacks; * **Apps using shell entries** — customizable through registry hacks;
* **Apps using context menu handlers without settings** — the entries are uneditable; * **Apps using context menu handlers without settings** — the entries are uneditable.
The first case is the simplest and isn't worth talking about — 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. consult the documentation for the software in question to find all the necessary tweaks.
@ -154,7 +159,7 @@ for better understanding:
* **Shell extension** is a general term for a plugin for the Windows Explorer — the **context menu handler** is a * **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; 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 component** is a broad term for a component that helps the shell interact with the system — that includes
shell extensions, file extensions, protocols, etc.; 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. 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. 😒 I tried my best to keep the technical language as clear as possible. 😒
@ -167,7 +172,7 @@ Entries provided by software — the context menu handlers — are stored under
![Directory.png](/images/blog/assets/the-windows-context-menu/directory.png) ![Directory.png](/images/blog/assets/the-windows-context-menu/directory.png)
Since registry key names are case-insensitive by design in Windows, capitalization plays no role. 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 value names, however, are** — keep that in mind, as in some cases it might bite.
The context menu doesn't seem to care. The context menu doesn't seem to care.
_Truly an amazing specification!_ _Truly an amazing specification!_
@ -189,9 +194,9 @@ No matter how hard I tried, I could not find the exact specification of the inco
My suggestion is to treat the default `command` value as **raw command line** (e.g. Run box), 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: with an exception to the following two macros:
* `%1` — the absolute file path without quotes * `%1` — the absolute file path without quotes
If you right-click `C:\Users\bleh\p.txt`, execute the shell entry, When the shell entry is executed after a right-click on `C:\Users\bleh\p.txt`,
the `%1` in the context of the command line will be equivalent to `C:\Users\bleh\p.txt`; the `%1` in the context of the command line is equivalent to `C:\Users\bleh\p.txt`;
* `%V` — the absolute directory path without quotes; * `%V` — the absolute directory path without quotes.
::card ::card
--- ---
@ -210,7 +215,7 @@ The directory macro `%V` also sometimes falls flat depending on the shell entry
On rare occasions, the default value is left unset, with `DelegateExecute` alongside it containing a GUID. 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, When that's the case, the command handler is implemented through the `IExecuteCommand` COM interface,
and you cannot customize it. and hence cannot be customized by normal means.
**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. **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.
@ -281,17 +286,20 @@ you should use the `REG_SZ` value called `Icon` inside the respective `shell` ke
It uses that unmistakably distinct and clumsy **WinAPI resource syntax** to specify a direct link to the icon within It uses that unmistakably distinct and clumsy **WinAPI resource syntax** to specify a direct link to the icon within
a file containing resources. a file containing resources.
```csv ```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), If you want to select the first icon (in that case, the `INDEX` part is 0),
the `INDEX` part can be omitted completely: the `INDEX` part can be omitted completely:
```csv ```csv
PATH_TO_FILE_WITH_ICON_RESOURCES PATH_TO_FILE_WITH_ICON_RESOURCES
``` ```
The following expressions are completely valid and are going to work: The following expressions are completely valid and are going to work:
```csv ```csv
"C:\Windows\system32\cmd.exe" "C:\Windows\system32\cmd.exe"
C:\Windows\regedit.exe C:\Windows\regedit.exe
@ -302,6 +310,7 @@ 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 absolute paths depending on the `%PATH%` variable that unholy concoction of an API uses. 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%`. **Spoiler:** they don't match against the system `%PATH%`.
Only God knows what paths it's able to parse by default. Only God knows what paths it's able to parse by default.
@ -381,11 +390,11 @@ Please tag me on [Twitter](https://go.enderman.ch/twitter) or [send a mail](mail
have the knowledge. have the knowledge.
**A few examples:** **A few examples:**
* `CanonicalName` * `CanonicalName`;
* `CommandStateHandler` * `CommandStateHandler`;
* `CommandStateSync` * `CommandStateSync`;
* `Description` * `Description`;
* `VerbName` * `VerbName`.
#### Deleting entries #### Deleting entries
Even simpler — it's the opposite of adding one. Even simpler — it's the opposite of adding one.
@ -400,86 +409,195 @@ Even simpler — it's the opposite of adding one.
which might result in the item remaining in place despite the deletion. which might result in the item remaining in place despite the deletion.
#### Sorting entries #### Sorting entries
Now that's the funniest one. I even memed about it on Twitter. That's easily the most hilarious procedure of them all. I even [tweeted](https://go.enderman.ch/3hcO9) about it.
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 items is...
**by managing the alphabetical order of their respective shell entries in the registry**.
Seriously, I am not kidding.
Let the screenshots speak for themselves.
![Alphabetical Sort 1.png](/images/blog/assets/the-windows-context-menu/alphabetical-sort-1.png) ![Alphabetical Sort 1.png](/images/blog/assets/the-windows-context-menu/alphabetical-sort-1.png)
![Alphabetical Sort 2.png](/images/blog/assets/the-windows-context-menu/alphabetical-sort-2.png) ![Alphabetical Sort 2.png](/images/blog/assets/the-windows-context-menu/alphabetical-sort-2.png)
Yeah... I'd rather not comment on that. _Yeah... I'd rather leave all the obscene comments aside._
##### Position override ##### Position override
Another silly and janky feature that has a limited number of use cases. Another silly feature with a limited number of use cases
You can manually override the position of your context menu item to be... that's likely been created due to all prior mess Microsoft has created.
It's possible to manually override the position of a context menu item to be...
either at the very top, or the very bottom. either at the very top, or the very bottom.
Not much better than alphabetical sorting if you ask me... _Still doesn't top off the alphabetical sorting between the registry peers..._
In your entry under shell, create a REG_SZ value called Position. In the `shell` subkey under the respective shell entry, 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. To enforce the context menu item to appear at the very top,
insert `Top` into the value data, otherwise insert `Bottom`.
Sometimes this may be necessary, as, for example, Microsoft dumps their regular alphabetical sorting strategy at Sometimes directly enforcing the position happens to be necessary.
the bottom of the context menu, where display and personalization settings reside. For instance, Microsoft dumps the usual sorting strategy at the very bottom of the context menu,
They simply specify the Bottom position for each of the entries. where the display and personalization settings reside.
If I recall correctly, they're still sorted alphabetically between themselves, as position override takes precedence. They simply set the `Bottom` position for each of the entries.
**What happens when there are multiple shell entries enforced to be in a set position?**
The alphabetical sorting makes a comeback,
it occurs between the shell entries with overridden positions just the same way.
![Position Override.png](/images/blog/assets/the-windows-context-menu/position-override.png) ![Position Override.png](/images/blog/assets/the-windows-context-menu/position-override.png)
##### Bottom line ### Context menu handlers
Some of the default shell entries like Powershell have specific keys Compared to shell entries, there isn't much to be tweaked via registry in context menu handlers.
(for the sake of that example, `ProgrammaticAccessOnly`) to control their appearance context menu. Their general location is the `ContextMenuHandlers` subkey under the `shellex` key in the respective shell entry.
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.
![Context Menu Handler 3.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-3.png) ![Context Menu Handler 3.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-3.png)
Most of the time, the only data they contain is a lonely GUID. That doesn't help much. Most of the time, the only piece of data they contain is a lonely GUID of the respective handler.
![Context Menu Handler 4.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-4.png) ![Context Menu Handler 4.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-4.png)
So, to remove the Context Menu handler, you should delete the subkey under ContextMenuHandlers. #### Removing handlers
I strongly suggest you save the GUID it contained so that you could roll back at any time later.
A context menu handler always directly corresponds to some child under the `ContextMenuHandlers` key.
Therefore, all that has to be done to remove a handler is removal of the **respective child key**.
I strongly suggest writing **the GUID** and **the location** of the removed entry down somewhere,
so that there is a way to roll back any time later.
![Context Menu Handler 5.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-5.png) ![Context Menu Handler 5.png](/images/blog/assets/the-windows-context-menu/context-menu-handler-5.png)
Adding your own... #### Adding handlers
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. Adding a custom handler is complicated.
For example, C# is a decent choice. It's not as trivial as adding a shell entry —
I don't suggest you waste time on this, it requires implementing a handler interface using a language
unless you're making full-on software that you want to make more accessible to Windows users. supporting Windows API or an abstraction layer on top of it.
C# would be a decent choice precisely for this task.
However, it's just a waste of time to implement a handler for a single shell entry,
unless there's software to go along with it.
The idea behind context menu handlers is to **make native application experience nicer** for Windows users.
In other words, Microsoft failed to implement an accessible API for the context menu,
so they did what they do best — shifted the responsibility to the developers writing third-party software.
This is how a partial implementation of the `IContextMenu` interface in C++ looks like:
```cpp
STDMETHODIMP CShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) {
BOOL fEx = FALSE;
BOOL fUnicode = FALSE;
if(lpcmi->cbSize == sizeof(CMINVOKECOMMANDINFOEX)) {
fEx = TRUE;
if (lpcmi->fMask & CMIC_MASK_UNICODE) fUnicode = TRUE;
}
if (!fUnicode && HIWORD(lpcmi->lpVerb)) {
if (StrCmpIA(lpcmi->lpVerb, m_pszVerb)) return E_FAIL;
}
else if (fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX *) lpcmi)->lpVerbW)) {
if (StrCmpIW(((CMINVOKECOMMANDINFOEX *)lpcmi)->lpVerbW, m_pwszVerb)) return E_FAIL;
}
else if (LOWORD(lpcmi->lpVerb) != IDM_DISPLAY) {
return E_FAIL;
}
else {
MessageBox(
lpcmi->hwnd,
"The File Name",
"File Name",
MB_OK | MB_ICONINFORMATION
);
}
return S_OK;
}
```
The `InvokeCommand()` method is called when a user clicks a context menu item.
I've taken that example from [Microsoft](https://go.enderman.ch/TArYX).
That whole thing isn't too bad — the logic is far more robust and understandable
compared to its surface-level registry counterpart, but it certainly requires getting used to WinAPI.
**By definition, it's a requirement to implement interfaces entirely.**
However, since we're dealing with Microsoft,
the «interface» in question is actually an _abstract class_ and can be implemented partially.
The `IContextMenu` interface has three methods:
* `GetCommandString()` — retrieves the canonical name of the command (optional);
* `InvokeCommand()` — handles the command (required);
* `QueryContextMenu()` — adds items to the context menu (required).
The `IContextMenu` interface is the most common one, but there are others,
such as `IContextMenu2` and `IContextMenu3`.
Essentially, this is how the context menu handlers work inside.
While all of this is just a brief overview of the API,
you can learn everything about them and more in the [Shell Developer's Guide](https://go.enderman.ch/W50xJ).
## 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, If the registry key is locked, the user you're logged in as is excluded from the ACL.
and you have to manually reclaim ownership of the key and allow yourself to make edits to it. Commonly, when the key is locked, it's owned by `TrustedInstaller`.
When that's the case, it's necessary to reclaim ownership of the key to allow making edits to the ACL.
There are plenty of ways to do that, I will list two common ones.
Optimal way: Using Process Hacker with the TrustedInstaller plugin or Winaero Tweaker, ### Using external tools
run regedit as Trusted Installer and perform the necessary tweaks. The idea here is to run `regedit` — the registry editor as the `TrustedInstaller` user directly.
You can think of `TrustedInstaller` as the Windows equivalent of `root` in Unix-like systems —
the superuser.
General solution: While Windows generally has more granular control over permissions,
and the idea of having a superuser — **the ultimate authority of the system** — is less prominent and unannounced,
`TrustedInstaller` is the closest object to a superuser Windows has.
Navigate to the key you want to take ownership of For those wondering, I've already explained [here](https://go.enderman.ch/o2KGt) why
Open the «Properties» window «sudo for Windows» makes no sense.
Head over to the Advanced tab
At the top of the Advanced Security Settings it states Owner: TrustedInstaller. Click Change ##### Process Hacker <sub>[download](https://go.enderman.ch/process-hacker)</sub>
Input your username into the Enter the object name to select (examples) text area. ![Process Hacker.png](/images/blog/assets/the-windows-context-menu/process-hacker.png)
Click OK
Check the «Replace owner on subcontainers and objects» checkbox ![Process Hacker 2.png](/images/blog/assets/the-windows-context-menu/process-hacker-2.png)
Check the «Replace all child object permission entries» checkbox
Click OK ##### Winaero Tweaker <sub>[download](https://go.enderman.ch/winaero)</sub>
Select Administrators (PC_NAME\Administrators) in the group selector and then check Full Control box in the Permissions window down below ![winaero-tweaker.png](/images/blog/assets/the-windows-context-menu/winaero-tweaker.png)
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. [Sergey](https://go.enderman.ch/Dr0iS) makes an entirely valid point in his Winaero Tweaker:
> **Warning!!!**
>
> Running programs under TrustedInstaller privileges, especially a file manager app or Regedit,exe can be
> VERY risky and harmful for your OS. It is like a God mode in a first-person shooter game, where nothing can
> stop your actions, so if you execute a malware infected file as TrustedInstaller, it can cause damage to the
> Windows operating system. Use this mode only if you perfectly understand what you are doing and if there is
> no simpler way than running it as Trusted Installer.
This is exactly the reason I resort to setting permissions manually.
It's a bit more time-consuming, but it's safer.
### Setting permissions manually
The trusty old way to do it is to manually set permissions for the key.
Once you get the hang of it, it really isn't that difficult.
![Permissions.png](/images/blog/assets/the-windows-context-menu/permissions.png)
##### General procedure
1. Navigate to the key you want to claim ownership of;
2. Open the «Properties» window;
3. Head over to the «Advanced» tab;
4. The current owner is shown at the top of the «Advanced Security Settings» window. Click «Change»;
5. Type out your username in the text area with the «Enter the object name to select (examples)» label;
6. Click «OK»;
7. Tick the «Replace owner on subcontainers and objects» checkbox;
8. Tick the «Replace all child object permission entries» checkbox;
9. Click «OK»;
10. Pick `Administrators (PC_NAME\Administrators)` in the group selector and then tick «Full Control» checkbox
in the «Permissions» window at the bottom;
11. You're done! Click «OK» and dismiss any warnings.
## Common registry paths ## Common registry paths
Here is a list of the most common registry paths. Here is a list of the most common registry paths.
There are as many «sections» as there are extensions, but these are the most common ones.
They should cover most of your context menu.
#### Desktop Background — bottom rows #### Desktop Background — bottom rows
`Computer\HKEY_CLASSES_ROOT\DesktopBackground` `Computer\HKEY_CLASSES_ROOT\DesktopBackground`
@ -497,7 +615,7 @@ Here is a list of the most common registry paths.
![Folder.png](/images/blog/assets/the-windows-context-menu/folder.png) ![Folder.png](/images/blog/assets/the-windows-context-menu/folder.png)
#### Folder Item #### Folder Item
This extends [Folder](#folder). Extends [Folder](#folder).
`Computer\HKEY_CLASSES_ROOT\Folder` `Computer\HKEY_CLASSES_ROOT\Folder`
![File Item.png](/images/blog/assets/the-windows-context-menu/file-item.png) ![File Item.png](/images/blog/assets/the-windows-context-menu/file-item.png)
@ -513,14 +631,15 @@ This extends [Folder](#folder).
![Library Item.png](/images/blog/assets/the-windows-context-menu/library-item.png) ![Library Item.png](/images/blog/assets/the-windows-context-menu/library-item.png)
#### Library Background #### Library Background
Inherits from [Folder Background](#folder-background).
`Computer\HKEY_CLASSES_ROOT\LibraryFolder\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.
![Library Background.png](/images/blog/assets/the-windows-context-menu/library-background.png) ![Library Background.png](/images/blog/assets/the-windows-context-menu/library-background.png)
Despite the inheritance, it cannot parse the `%V` macro, which results in the following error.
Blame Microsoft for being as consistent as ever.
To my knowledge, there is no way to fix that.
![Explorer Error.png](/images/blog/assets/the-windows-context-menu/explorer-error.png) ![Explorer Error.png](/images/blog/assets/the-windows-context-menu/explorer-error.png)
#### All Files #### All Files
@ -529,12 +648,13 @@ To my knowledge, there is no way to fix that.
![All Files.png](/images/blog/assets/the-windows-context-menu/all-files.png) ![All Files.png](/images/blog/assets/the-windows-context-menu/all-files.png)
#### All Filesystem Objects #### All Filesystem Objects
That's different from [All Files](#all-files) — it's a further generalization that includes system drives and symbols. Different from [All Files](#all-files) — it's a further generalization that includes system drives,
symbolic links and other objects.
`Computer\HKEY_CLASSES_ROOT\AllFilesystemObjects` `Computer\HKEY_CLASSES_ROOT\AllFilesystemObjects`
![All Filesystem Objects.png](/images/blog/assets/the-windows-context-menu/all-filesystem-objects.png) ![All Filesystem Objects.png](/images/blog/assets/the-windows-context-menu/all-filesystem-objects.png)
#### Type associations #### File type associations
Text: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text` Text: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text`
Images: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\image` Images: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\image`
Documents: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\document` Documents: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\document`
@ -542,36 +662,58 @@ Audio: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\audio`
Video: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\video` Video: `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\video`
## Cleaning up the context menu ## Cleaning up the context menu
Most obnoxious default entries can be cleaned up using Winaero Tweaker. The least fan-favorite default entries can be removed using Winaero Tweaker.
I suggest you use it to make the process way more bearable for yourself. I suggest using it to make the whole cleanup slightly more bearable.
![Winaero 1.png](/images/blog/assets/the-windows-context-menu/winaero-1.png) ![Winaero 1.png](/images/blog/assets/the-windows-context-menu/winaero-1.png)
![Winaero 2.png](/images/blog/assets/the-windows-context-menu/winaero-2.png) ![Winaero 2.png](/images/blog/assets/the-windows-context-menu/winaero-2.png)
#### Areas Winaero Tweaker is unable to reach to ### Some extra common areas
Remove «Open PowerShell window here» The following are fairly common areas Winaero Tweaker doesn't cover.
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\Powershell
Unlock key (The Windows Context Menu > Dealing with locked keys) ::card
Create a new REG_SZ value ProgrammaticAccessOnly without any data ---
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell icon: idea
Unlock key title: Tip
Create a new REG_SZ value ProgrammaticAccessOnly without any data ---
Remove «Open Linux shell here» As a rule of thumb, whenever you're dealing with existing shell entries, I _really_ suggest
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL **searching for a way to manage them online** before resorting to any measures I elaborated on in this article.
Unlock key Now if you can't find anything useful online, then anything works.
Delete WSL key altogether ::
Navigate to Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell
Unlock key #### Remove «Open PowerShell window here»
Create a new REG_SZ value ProgrammaticAccessOnly without any data 1. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\shell\Powershell`;
Edit the «Edit» text context menu command 2. [Unlock the key](#dealing-with-locked-keys);
Navigate to Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell\edit 3. Create a new `REG_SZ` value called `ProgrammaticAccessOnly` and leave it empty;
Make sure you've read the article thoroughly, then do anything you want with it. 4. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell`;
5. [Unlock the key](#dealing-with-locked-keys);
6. Create a new `REG_SZ` value called `ProgrammaticAccessOnly` and leave it empty.
#### Remove «Open Linux shell here»
1. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL`;
2. [Unlock the key](#dealing-with-locked-keys);
3. Remove the key;
4. Navigate to `Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\WSL`;
5. [Unlock the key](#dealing-with-locked-keys);
6. Create a new `REG_SZ` value called `ProgrammaticAccessOnly` and leave it empty.
#### Edit the «Edit» text context menu command
1. Navigate to `Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell\edit`;
2. Replace all mentions of the previous editor in default values with **Notepad++**
or any other text editor you prefer.
## Bottom line ## Bottom line
No matter how terrible the context menu API might be for Windows, there's still a way to customize it. The context menu is a mess, and it's not going to change.
Hope you found the tricks useful! It's a part of Windows that's been around for a long time and has been left behind by Microsoft.
Shell entries are like differential equations — there's never a general solution.
They're a pain to learn, but the acquired skill is worth it.
If you've spotted a mistake (be it orthographical, factual or any other) No matter how terrible the context menu API is in Windows, there's still a way to customize it to your liking.
in this article or want to add some important details or share any important knowledge on the subject, Hopefully you learned something new from this article
please contact me on Twitter: @endermanch or hit me up on e-mail: blogs@enderman.ch and are now able to make your context menu **a bit** more bearable.
**Spotted a mistake?**
Want to add important details I missed or share extra knowledge on the subject?
Tag me on [Twitter](https://go.enderman.ch/twitter) or [e-mail me](mailto:contact@enderman.ch)!
All contributions welcome. 😉

View File

@ -59,34 +59,38 @@ export default defineNuxtConfig({
'nuxt-link-checker', 'nuxt-link-checker',
], ],
content: { content: {
documentDriven: true,
markdown: { markdown: {
remarkPlugins: ['remark-reading-time'], remarkPlugins: ['remark-reading-time'],
}, },
highlight: { highlight: {
theme: { theme: 'github-dark',
// 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: [ langs: [
'shell',
'batch',
'vb',
'ini',
'asm',
'c', 'c',
'cpp', 'cpp',
'java', 'java',
'python',
'csv', 'csv',
'xml', 'xml',
'json', 'json',
'js', 'yaml',
'ts',
'html', 'html',
'css', 'css',
'sass',
'php',
'js',
'ts',
'vue', 'vue',
'shell',
'mdc',
'md', 'md',
'yaml', 'mdc',
'pascal',
'lisp',
'sql',
], ],
}, },
}, },

View File

@ -1,24 +1,111 @@
<script setup lang="ts"> <script setup lang="ts">
import { formatDate } from 'date-fns'
const { slug } = useRoute().params const { slug } = useRoute().params
const config = useAppConfig()
const content = useContent()
const meta = {
title: `${content.page.title}`,
description: content.page.description,
image: content.page.thumbnail,
url: `${config.url}/blog`,
}
defineOgImage()
// Hydrate the rendered items.
onMounted(() => {
document.querySelectorAll('pre').forEach((pre) => {
const icon = document.createElement('iconify-icon')
icon.setAttribute('icon', 'mdi:content-copy')
icon.setAttribute('inline', 'true')
icon.classList.add('button')
pre.appendChild(icon)
})
document
.querySelectorAll('code:not(pre *), pre > iconify-icon.button')
.forEach((code) => {
if (code instanceof HTMLElement) {
code.onclick = () => {
const area = document.createElement('textarea')
area.textContent =
code.nodeName && code.nodeName.toLowerCase() === 'code'
? code.textContent
: code.parentElement!.textContent
// It's necessary to create the textarea element every time you copy to get access to the select() method.
area.setSelectionRange(0, 99999) // An iOS gotcha.
area.select()
// Copy the text inside the textarea.
navigator.clipboard.writeText(area.value)
// TODO: Alert the user text has been successfully copied.
// Remove the textarea element.
area.remove()
}
}
})
})
onUnmounted(() => {
document.querySelectorAll('code').forEach((code) => {
code.onclick = null
})
document.querySelectorAll('pre').forEach((pre) => {
pre.querySelector('.clipboard')?.remove()
})
})
</script> </script>
<template> <template>
<article <article
class="scrollbar fade-mask-sm d-flex flex-column gap-3 flex-grow-1 overflow-x-hidden overflow-y-auto py-sm-4 pe-sm-3" class="post scrollbar fade-mask-sm d-flex flex-column gap-3 flex-grow-1 overflow-x-hidden overflow-y-auto py-sm-4 pe-sm-3"
> >
<ContentDoc :path="`/blog/${slug}`"> <ContentDoc :path="`/blog/${slug}`">
<template #default="{ doc }"> <template #default="{ doc }">
<div class="post-preamble"> <div
<h3 class="alex">{{ doc.title }}</h3> class="post-preamble"
<img :style="{ backgroundImage: 'url(' + doc.thumbnail + ')' }"
draggable="false" >
:src="doc.thumbnail" <div class="p-2">
:alt="doc.title" <h3 class="alex">{{ doc.title }}</h3>
class="post-preamble-thumb rounded-4" <div class="d-flex flex-row row-gap-0 column-gap-2 flex-wrap">
/> <div class="d-flex flex-row gap-1 align-items-center">
<iconify-icon icon="mdi:calendar" />
<strong class="nobr font-small">
{{ formatDate(doc.created, 'LLLL do, y &ndash; HH:mm') }}
</strong>
</div>
<div class="d-flex flex-row gap-1 align-items-center">
<iconify-icon icon="mdi:clock-outline" />
<strong class="nobr font-small">
{{ doc.readingTime.text.split(' ')[0] + ' minutes to read' }}
</strong>
</div>
</div>
</div>
<NuxtLink
:href="`https://twitter.com/share?url=${config.url}/blog/${slug}&text=${doc.title}&hashtags=${doc.tags.slice(0, 3).join(',').replace(/ /g, '')}`"
target="_blank"
class="link post-preamble-share px-2 py-1"
>
<iconify-icon icon="mdi:twitter"></iconify-icon>
</NuxtLink>
<NuxtLink to="/blog" class="link post-preamble-control px-2 py-1">
<iconify-icon icon="icon-park-solid:back"></iconify-icon>
</NuxtLink>
</div> </div>
<div class="post-content"> <div class="post-content">
<Separator class="mt-0" />
<ContentRenderer :value="doc" /> <ContentRenderer :value="doc" />
</div> </div>
</template> </template>

View File

@ -1,5 +1,42 @@
<script setup lang="ts"> <script setup lang="ts">
import { formatDate } from 'date-fns' import { formatDate } from 'date-fns'
const config = useAppConfig()
const meta = {
title: 'The Enderchest',
description:
'A blog about software development, scientific research and Windows quirks.',
image: `${config.url}/images/chest.png`,
url: `${config.url}/blog`,
}
useSeoMeta({
title: meta.title,
description: meta.description,
ogTitle: meta.title,
ogDescription: meta.description,
ogImage: meta.image,
ogUrl: meta.url,
ogType: 'website',
twitterTitle: meta.title,
twitterDescription: meta.description,
twitterImage: meta.image,
twitterCard: 'summary',
})
useHead({
title: 'The Enderchest',
htmlAttrs: {
lang: config.locale || 'en',
},
link: [
{
rel: 'icon',
type: 'image/x-icon',
href: '/favicon.ico',
},
],
})
</script> </script>
<template> <template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
public/images/chest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB