Description
Proposal: simple context menu entries in app manifest
Summary
Support declaring a context menu entry with a specific icon, display name and executable in app manifest instead of requiring to provide an IExplorerCommand
implementation.
Rationale
- Currently, to have an entry in the new Windows 11 context menu (instead of the legacy Windows 10 menu, which shows up under "Show more options"), one needs to implement
IExplorerCommand
- This is needlessly complicated if the context menu entry is just a simple entry which launches the app executable with a certain command line argument (which I'd wager is most context menu entries out there, people who need more already have a shell extension).
It also requires implementing it in C++, as C# and other managed languages are heavily discouraged by Microsoft for in-process shell extensions (andIExplorerCommand
indeed only supports in-process activation).This will cause the DLL to be loaded in any process with a save as/browse dialog, causing potential runtime version conflicts. So, even if one disregards the MS recommendations and goes ahead with a managed implementation, this will cause problems in the real world.- This means that, in practice, many projects might skip this altogether because of implementation complexity.
Scope
Capability | Priority |
---|---|
This proposal will allow developers to register context menu entries that launch an app when clicked | Must |
This proposal will allow developers to pass command line arguments including the selected file, if any, to the Win32 app | Must |
This proposal will allow developers to activate UWP apps in response to a context menu entry click | Should |
This proposal will allow end users to show/hide undesired context menu entries from the Settings app | Could |
This proposal will allow end users to register their own context menu entries | Won't |
Important Notes
The app manifest entry could look something like this:
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<!-- add a context menu entry on a folder, with no icon -->
<desktop5:ItemType Type="Directory">
<desktop7:SimpleVerb Id="OpenFolderWin32" Executable="myappwin32.exe" EntryPoint="Windows.FullTrustApplication" Parameters='--folder "%1"'>
<uap:DisplayName>Open folder in App</uap:DisplayName>
</desktop7:SimpleVerb>
</desktop5:ItemType>
<!-- add a context menu entry on the desktop wallpaper, activating a UWP app -->
<desktop5:ItemType Type="Directory\Background">
<desktop7:SimpleVerb Id="OpenBackgroundUWP" Executable="myappuwp.exe" EntryPoint="Contoso.App">
<uap:DisplayName>Do something</uap:DisplayName>
</desktop7:SimpleVerb>
</desktop5:ItemType>
<!-- add a context menu entry on the desktop wallpaper, opening a Win32 app without command line parameters -->
<desktop5:ItemType Type="Directory\Background">
<desktop7:SimpleVerb Id="OpenBackgroundWin32" Executable="myappwin32.exe" EntryPoint="Windows.FullTrustApplication">
<uap:DisplayName>Do something but with Win32</uap:DisplayName>
</desktop7:SimpleVerb>
</desktop5:ItemType>
<!-- add a context menu entry on the desktop wallpaper, opening a Win32 app with command line parameters -->
<desktop5:ItemType Type="Directory\Background">
<desktop7:SimpleVerb Id="OpenBackgroundWin32" Executable="myappwin32.exe" EntryPoint="Windows.FullTrustApplication" Parameters='--background'>
<uap:DisplayName>Do something but with Win32</uap:DisplayName>
</desktop7:SimpleVerb>
</desktop5:ItemType>
<!-- add a context menu entry on all files, using a package resource as display name -->
<desktop5:ItemType Type="*">
<desktop7:SimpleVerb Id="OpenFileWin32" Executable="myappwin32.exe" EntryPoint="Windows.FullTrustApplication" Parameters='--file "%1"'>
<uap:DisplayName>ms-resource:OpenFileVerbDescription</uap:DisplayName>
</desktop7:SimpleVerb>
</desktop5:ItemType>
<!-- add a context menu entry on text files, with an icon -->
<desktop5:ItemType Type=".txt">
<desktop7:SimpleVerb Id="OpenTxtWin32" Executable="myappwin32.exe" EntryPoint="Windows.FullTrustApplication" Parameters='--text-file "%1"'>
<uap:DisplayName>Edit file in App</uap:DisplayName>
<uap:Logo>Assets\EditFile.ico</uap:Logo>
</Verb>
</desktop5:ItemType>
<!-- add a context menu entry on log files, with a PNG file as icon -->
<desktop5:ItemType Type=".log">
<desktop7:SimpleVerb Id="OpenLogWin32" Executable="myappwin32.exe" EntryPoint="Windows.FullTrustApplication" Parameters='--log-file "%1"'>
<uap:DisplayName>View log file in App</uap:DisplayName>
<uap:Logo>Assets\ViewLog.png</uap:Logo>
</desktop7:SimpleVerb>
</desktop5:ItemType>
<!-- add a context menu entry on C++ files, activating a UWP app -->
<desktop5:ItemType Type=".cpp">
<desktop7:SimpleVerb Id="OpenCodeUWP" Executable="myappuwp.exe" EntryPoint="Contoso.App">
<uap:DisplayName>Edit C++ in App</uap:DisplayName>
</desktop7:SimpleVerb>
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
In command line arguments, %1
is a placeholder for the file/folder name, if any.
One could then use activation APIs to determine if the app was launched in response to a context menu entry (or for Win32 apps, they can read command line arguments). It wouldn't be unlike the File activation API:
namespace Windows.ApplicationModel.Activation
{
public enum ActivationKind
{
+ ContextMenu = 1023
}
+ public sealed class ContextMenuTargetActivatedEventArgs : IActivatedEventArgsWithUser
+ {
+ public string ItemType { get; }
+ public string Verb { get; }
+ public IStorageItem? File { get; } // null if something like Directory\Background was activated
+ }
}
namespace Windows.UI.Xaml
{
public class Application
{
+ protected virtual void OnContextMenuTargetActivated(ContextMenuTargetActivatedEventArgs args);
}
}
Command line arguments are supported to simplify the migration of an existing Win32 app to MSIX, as the app might already have command line arguments for context menu entries and adding code checking for the activation kind is not possible or too costly. It's not needed for UWP/Windows App SDK apps, which use activation from the start.
Open Questions
None that I can think of.