IMHO microsoft went too far with their restriction policy. Requiring digital signing to close the door to the masses is one thing, but obfuscating the registration procedure for modern context menu handlers is not good sportsmanship. Especially so for "old school" unpackaged desktop programs — you know the actual programs you use that aren't just for social media messaging.
For quite a while my own programs were "poor relatives" relegated to the classic context menu (e.g. "Scan with i-DeClone"). After a week or so battling with "AI" contradictory suggestions I decided to do it the traditional non-AI way (RTFM) and lo and behold: i-DeClone is now in the modern windows 11 context menu! This post is the abbreviated version of my week-long ordeal.
A good starting point is the documentation for external location packaging. The basic steps are:
You can download the important manifests I used for declone and replace the key fields with your own information
STEP 1. Build your IExplorerCommand shell extension
There are plenty of samples of this skeleton interface implementation. You can use ATL to write a regular COM inproc server DLL or work your head round the WRL/WinRT samples. There's minimal code to write, focusing on these IExplorerCommand methods:
Although this looks like a regular shell extension, it is not registered as a COM object (it will end up under HKCR\PackagedCom). However I advise you during testing to do a regular REGSVR32-type registration, to make sure it works as a basic explorer command (see the test11.REG file in the downloadable above). If all is well your command will appear in the legacy context menu and launch the program; then you can proceed with the mumbo-jumbo packaging.
I have also signed the DLL without establishing the necessity of the step
It is paramount that your DLL also includes a manifest resource with the following MSIX identity:
add inside <assembly> <msix xmlns="urn:schemas-microsoft-com:msix.v1" publisher="CN=Contoso" packageName="ContextMenu11" applicationId="ContextMenu11" />where the publisher and package names are identical to those in the MSIX package (STEP 2 below). I have lost 4-5 days banging my head and following chatGPT ludicrous dead-end suggestions until I hit upon this important ingredient. If this is missing, windows explorer won't load the extension!
STEP 2. Create an empty package with identity
The bread and butter of WinUI applications is a folder structure that contains the executable, manifests and various resources. These are automatically created for you by Developer Studio, but in our case we must create the files manually. Our sparse package is declarative and lacks any real content except:
|
sparsePack\ ├─ AppxManifest.xml ├─ Assets\ │ └─ Square44x44Logo.png |
That is all for files, the COM object DLL isn't kept in the package. All the magic is in the MSIX manifest. I recommend you start with the template in the documentation, and add your own information. These manifest files aren't meant for human consumption, so just follow the instructions for the various XML fields. In particular:
add inside <Application>
<Extensions>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type="Directory">
<desktop5:Verb Id="declone11" Clsid="EF7E6726-B4FB-43E2-8F2E-540FFFD904E4" />
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="Context menu verb handler">
<com:Class Id="EF7E6726-B4FB-43E2-8F2E-540FFFD904E4" Path="w11_menu.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
</Extensions>
The important variable fields are highlighted in red:
I didn't touch the threading model STA, trying to avoid any jinx <g>
STEP 3. Build and sign the MSIX sparse package
Now we must build the package "installer" using MAKEAPPX. This and the signtool below are part of windows 11 SDK. Just open a command processor in the folder that contains the root package folder and execute:
makeappx.exe pack /o /d sparsePack /nv /p YOUR.msix
Use 7-zip or xplorer² Enter archive command to browse into MSIX package contents
The package won't show in the context menu without a digital signature. Local developer self-sign certificates aren't of any use if you want to deploy to end users, so you need a proper CA-trusted certificate. The command you need to sign the package is:
signtool.exe sign /fd SHA256 /a /n "YOUR PFX NAME" /tr http://timestamp.digicert.com /td SHA256 YOUR.msix
where you must replace your own certificate's subject (CN) and your MSIX package name. A timestamp server ensures that the signature will be valid even after your certificate expiers.
I still have a "soft" PFX certificate but down the road everybody will need FIPS or cloud based code signing pipeline.
STEP 4. Install program + MSIX identity
The MSIX identity package must be added in your win32 installer (I use NSIS), and installed with powershell. The explorer command DLL will be installed next to your desktop executable, say in C:\program files\my32tool. The trick that bridges the "legacy" and packaged portions is associating the package with the "legacy" installation path. The powershell command is:
PS> Add-AppxPackage -Path YOUR.msix -ExternalLocation "C:\Program Files\my32tool"
The identity package is placed somewhere under C:\Program Files\WindowsApps and the real files in the regular win32 installation folder. The COM object is registered in a special PackagedCom key — you don't need to regsvr32 it.
The documentation shows how to install the package for all users as well
So your existing installation procedure remains the same, only adding a final step for installing the package (only for windows 11 & x64 systems). You just need to figure out how to call powershell from your installer (for NSIS it's nsExec::ExecToLog). Don't forget to add the regular context menu registry snippet under HKCR\Directory\shell so that your old (COM-free) command appears in the legacy context menu. I can't imagine why some programs completely ignore 3rd party file managers that cannot show the modern context menu — it's so easy to maintain backward compatibility!
Regarding future updates, usually your identity doesn't change even if the actual DLL does, so there's no need to reinstall the package. If you do make changes to the identity manifest, make sure you increase the <Identity Version="1.0.0.x"> number and go back to STEP3. Powershell will recognize and install the update — somehow without restarting windows explorer even! To check the installed version use the package with its defined <Identity Name="xxx">:
PS> Get-AppxPackage xxx
For uninstalling the package, use the full powershell command:
powershell.exe -ExecutionPolicy Bypass -Command "Get-AppxPackage PackageName | Remove-AppxPackage"
Post a comment on this topic »