# 第 ③ 章 · 进入 Windows 11 主右键菜单（MSIX / 稀疏包）

> 不改一行处理器代码，用稀疏包（sparse package）给第②章的 IExplorerCommand 赋予“包标识”，把命令送进 Win11 的新版主右键菜单；含 AppxManifest、嵌入标识清单、自签名与注册的完整流程。

- 作者：David（道雾轩）
- 专栏：Windows Shell 扩展指南（https://daiw.org/manual/windows-shell-ext.md）
- 最后更新：2026-07-12
- 原文：https://daiw.org/manual/windows-shell-ext/win11-menu
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

前两章的命令，在 Windows 11 上都只能在「**显示更多选项**」的旧菜单里找到。因为 Win11 的**新版主菜单有个硬门槛**：命令必须来自一个**有“包标识”（package identity）的应用**，并用 `IExplorerCommand` + 包清单声明。

好消息是：**不用重写处理器**。本章把第 ② 章那个 `IExplorerCommand` 原样拿来，套一层**稀疏包（sparse package）**，就能进主菜单。

配套代码：[`03-win11-packaging`](https://github.com/davidapp/shell-extension-demos/tree/main/03-win11-packaging)。

## 什么是稀疏包

传统 MSIX 会把你的**所有文件**打进一个包里安装。**稀疏包**只打一个**清单**（`AppxManifest.xml`），文件仍留在你原来的安装目录——注册时用 `-ExternalLocation` 指向那个目录即可。这样非打包的 Win32 应用能“低成本”获得包标识，解锁 Win11 主菜单、Share、通知等能力。见[官方文档](https://learn.microsoft.com/zh-cn/windows/apps/desktop/modernize/grant-identity-to-nonpackaged-apps)。

## 三个清单，各司其职

打包扩展有点绕的地方在于：**有三处身份信息必须完全对上**。

**① `package/AppxManifest.xml`** —— 稀疏包清单。两段扩展是关键：

```xml
<!-- 声明进程内 COM 服务器：Clsid=第②章的命令，Path=外部目录里的 DLL -->
<com:Extension Category="windows.comServer">
  <com:ComServer>
    <com:SurrogateServer DisplayName="FileInfo ExplorerCommand">
      <com:Class Id="A3F1C2D4-5E6B-4789-9012-3456789ABCDE"
                 Path="w11menu.dll" ThreadingModel="STA" />
    </com:SurrogateServer>
  </com:ComServer>
</com:Extension>

<!-- 把该 CLSID 注册成文件资源管理器右键命令（这就是进主菜单的开关） -->
<desktop4:Extension Category="windows.fileExplorerContextMenus">
  <desktop4:FileExplorerContextMenus>
    <desktop5:ItemType Type="*">
      <desktop5:Verb Id="FileInfoCmd" Clsid="A3F1C2D4-5E6B-4789-9012-3456789ABCDE" />
    </desktop5:ItemType>
  </desktop4:FileExplorerContextMenus>
</desktop4:Extension>
```

还需 `<uap10:AllowExternalContent>true</uap10:AllowExternalContent>`、`runFullTrust` + `unvirtualizedResources` 能力、以及一个 `TrustLevel=mediumIL`、`RuntimeBehavior=win32App` 的 `Application`（DLL 项目没有真 exe，用个**幽灵 exe** 占位，右键命令不会去启动它）。

**② `app.manifest`** —— **嵌入 DLL** 的并排清单，用 `msix` 元素把这个二进制绑到包标识：

```xml
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="DavidApp.ShellExtDemos.Win11Menu" type="win32" />
  <msix xmlns="urn:schemas-microsoft-com:msix.v1"
        publisher="CN=DavidApp Shell Ext Demos"
        packageName="DavidApp.ShellExtDemos.Win11Menu"
        applicationId="App" />
</assembly>
```

CMake 用 `/MANIFEST:EMBED /MANIFESTINPUT` 把它嵌进 `w11menu.dll`。

<Callout type="warn">
  **这是最容易漏、也最坑的一步**：DLL 里不嵌这个 `msix` 标识清单，资源管理器就不会把它当作已打包组件加载——命令死活不出现，且没有任何报错。
</Callout>

**③ 证书** —— 签名证书的 `Subject` 必须等于清单里的 `Publisher`。

> 一句话记忆：**证书 Subject = AppxManifest 的 `Identity/Publisher` = app.manifest 的 `msix/@publisher`**，三处一字不差。

## 复用第②章的处理器

`dllmain.cpp` 只剩最精简的 `DllGetClassObject` / `DllCanUnloadNow`，处理器直接编译第②章的 `ExplorerCommand.cpp`：

```cmake title="CMakeLists.txt（节选）"
add_library(w11menu SHARED
    dllmain.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/../02-explorer-command/ExplorerCommand.cpp  # 复用！
    w11menu.def)
set_target_properties(w11menu PROPERTIES
    LINK_FLAGS "/MANIFEST:EMBED /MANIFESTINPUT:\"${CMAKE_CURRENT_SOURCE_DIR}/app.manifest\"")
```

打包后不再需要 `DllRegisterServer`——注册完全由稀疏包完成。

## 一键构建 + 注册

示例的 `build-package.ps1` 把六步串起来：

```powershell
.\build-package.ps1     # 管理员 + Win11 开发者模式
```

1. `cmake` 构建带嵌入清单的 DLL；
2. 组装“外部位置”目录（DLL + 占位资源）；
3. `makeappx pack /nv` 打稀疏包；
4. `New-SelfSignedCertificate` 自签；
5. `signtool` 签名，并把公钥证书导入 **受信任人**（否则报 `0x800B0109 CERT_E_UNTRUSTEDROOT`）；
6. `Add-AppxPackage -ExternalLocation` 注册。

成功后右键任意文件，「显示文件信息」就直接出现在 **Win11 主菜单**里了。

<Callout type="info">
  自签名 + 侧载仅用于**开发测试**。要分发给别人，需用受信任 CA 的证书（或 [Azure Trusted Signing](https://azure.microsoft.com/products/trusted-signing)）；上架微软商店则用完整 MSIX。
</Callout>

## 参考

- [用外部位置为非打包应用授予包标识](https://learn.microsoft.com/zh-cn/windows/apps/desktop/modernize/grant-identity-to-nonpackaged-apps)
- [windows.fileExplorerContextMenus 扩展](https://learn.microsoft.com/zh-cn/windows/win32/shell/context-menu-handlers) · [MakeAppx](https://learn.microsoft.com/zh-cn/windows/msix/package/create-app-package-with-makeappx-tool)
- [PackageWithExternalLocation 官方示例](https://aka.ms/sparsepkgsample)
