# 第 ⑪ 章 · 图标叠加处理器（IShellIconOverlayIdentifier）

> 给文件图标左下角叠一个小角标——OneDrive/Dropbox/TortoiseGit 的同步状态标就是它；讲 IsMemberOf 判定、15 个槽位的硬上限与抢位技巧、以及“必须快”的铁律。

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

你一定见过 OneDrive/Dropbox 文件图标左下角那个“同步中/已同步”的小角标，或者 TortoiseGit 里绿勾红叹号——它们全是**图标叠加处理器**。这是最能出效果、也最容易把资源管理器拖卡的一种扩展。配套代码：[`11-icon-overlay`](https://github.com/davidapp/shell-extension-demos/tree/main/11-icon-overlay)。

## 只有一个接口，三个方法

`IShellIconOverlayIdentifier`——不需要任何初始化接口，因为判定方法直接把路径给你：

| 方法 | 作用 |
| --- | --- |
| `GetOverlayInfo` | 叠加图标从哪个文件、第几个图标取（返回 `.ico`/DLL 路径 + 索引） |
| `GetPriority` | 多个叠加同时命中一个文件时的排序，`0` 最高 |
| `IsMemberOf(path, attrib)` | **核心判定**：这个文件要不要叠？`S_OK` 叠，`S_FALSE` 不叠 |

```cpp title="OverlayHandler.cpp（节选）——判定与取图标"
// 演示规则：文件名含 “demo” 就叠标记
IFACEMETHODIMP OverlayHandler::IsMemberOf(LPCWSTR pwszPath, DWORD) {
    return (StrStrIW(pwszPath, L"demo") != nullptr) ? S_OK : S_FALSE;
}
// 叠加图标：演示用 shell32.dll 占位，真实项目换成自带 .ico
IFACEMETHODIMP OverlayHandler::GetOverlayInfo(LPWSTR file, int cch, int* pIndex, DWORD* pdwFlags) {
    GetSystemDirectoryW(file, cch);
    StringCchCatW(file, cch, L"\\shell32.dll");
    *pIndex = 0;
    *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
    return S_OK;
}
```

## 两条硬约束（决定成败）

<Callout type="warn">
  **① 只有前 15 个生效。** 系统对叠加处理器有全局硬上限：注册在 `ShellIconOverlayIdentifiers` 下的项**按名字排序，只取前 15 个**，多的直接忽略。这就是为什么 TortoiseGit、Dropbox 的注册名前面**加空格甚至多个空格**——空格排在字母前，用来抢靠前的槽位。本示例也用了 ` DaiwDemoOverlay`（前置空格）这一招。

  **② `IsMemberOf` 必须快。** 它会对资源管理器里**每一个显示的文件**被调用。任何阻塞操作（读文件内容、查数据库、访问网络）都会让整个窗口卡死。真实扩展的做法是：后台线程维护一份内存缓存，`IsMemberOf` 只查缓存、立刻返回。
</Callout>

## 注册与生效

叠加处理器登记在 **HKLM**（机器级，需管理员）：

```
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\
    ⟨ 名字（前置空格抢槽位）⟩\  (默认) = {你的CLSID}
```

<Callout type="info">
  改完注册**必须重启资源管理器**（`Stop-Process -Name explorer -Force`）才会重新扫描叠加列表——这点和右键菜单不同，光刷新是不够的。
</Callout>

## 参考

- [IShellIconOverlayIdentifier](https://learn.microsoft.com/zh-cn/windows/win32/api/shobjidl_core/nn-shobjidl_core-ishelliconoverlayidentifier) · [How to Implement Icon Overlay Handlers](https://learn.microsoft.com/zh-cn/windows/win32/shell/how-to-implement-icon-overlay-handlers)
- 云存储的现代替代方案：[云文件 API（Cloud Filter）](https://learn.microsoft.com/zh-cn/windows/win32/cfapi/build-a-cloud-file-sync-engine)，它有自己的一套状态角标机制。
