# 第 ④ 章 · 缩略图处理器（IThumbnailProvider）

> 用 IThumbnailProvider 为文件生成自定义缩略图，取代已过时的 IExtractImage；讲 IInitializeWithStream 拿内容、GDI 画 32bpp 位图、WTS_ALPHATYPE 与注册。

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

从本章起进入“文件视觉”部分。**缩略图**就是资源管理器在大图标视图里给文件画的那张预览图。老教程用的 `IExtractImage` 早已被 **`IThumbnailProvider`**（Vista 起推荐）取代——后者更简单、更安全（默认在隔离进程里跑）。

本章给 `.txt` 文件生成缩略图：底色由文件大小推导、中间画出字节数。配套代码：[`04-thumbnail`](https://github.com/davidapp/shell-extension-demos/tree/main/04-thumbnail)。

## 两个接口

- **`IInitializeWithStream`** —— Shell 不再给你文件路径，而是给一个 **`IStream`**。这样即使文件在网络上、或在受限沙箱里也能取到内容，且缩略图默认跑在隔离宿主 `dllhost.exe` 里，崩了不连累资源管理器。
- **`IThumbnailProvider::GetThumbnail(cx, phbmp, pdwAlpha)`** —— 给定边长 `cx`，返回一张 `HBITMAP`。

```cpp title="ThumbnailProvider.cpp（节选）"
IFACEMETHODIMP ThumbnailProvider::Initialize(IStream* pStream, DWORD) {
    if (m_pStream) return E_UNEXPECTED;          // Shell 保证只调一次
    return pStream->QueryInterface(IID_PPV_ARGS(&m_pStream));
}
```

## 画一张 32bpp 位图

Shell 缩略图要求 **32 位位图**。用 `CreateDIBSection` 建一张自顶向下（高度取负）的 DIB，然后用普通 GDI 往里画：

```cpp
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth  =  (LONG)cx;
bmi.bmiHeader.biHeight = -(LONG)cx;   // 负 = 自顶向下
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
void* bits = nullptr;
HBITMAP hbmp = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0);
// 选进内存 DC，FillRect 底色 + DrawText 画字节数…
*phbmp = hbmp;
*pdwAlpha = WTSAT_RGB;   // 不用 alpha 通道就声明 RGB
```

<Callout type="info">
  `pdwAlpha`（`WTS_ALPHATYPE`）告诉 Shell 位图有没有 alpha：`WTSAT_RGB` 忽略 alpha 通道；`WTSAT_ARGB` 表示**预乘 alpha**（做圆角/透明缩略图时用，且像素必须是预乘的）。用普通 GDI 画完不去管 alpha，就老实声明 `WTSAT_RGB`。
</Callout>

<Callout type="warn">
  `GetThumbnail` 里**别读整个大文件、别做网络请求**。虽然它在独立宿主进程里跑、不会直接卡住资源管理器，但仍要尽快返回——否则缩略图迟迟不出来。
</Callout>

## 注册

缩略图处理器注册在文件类型的 `shellex\{E357FCCD-A995-4576-B01F-234630154E96}` 下（这个固定 GUID 是系统定义的“缩略图处理器”类别），默认值为你的 CLSID：

```cpp
RegisterInprocServer(CLSID_DemoThumbnailProvider, dll, L"Demo Thumbnail Provider");
RegWriteString(HKEY_CLASSES_ROOT,
    L".txt\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}", nullptr, clsidStr);
```

<Callout type="warn">
  缩略图有**缓存**。装好后看不到效果，把 `.txt` 文件夹切到「大图标」视图；仍不行就用「磁盘清理」清缩略图缓存、或删 `%LocalAppData%\Microsoft\Windows\Explorer\thumbcache_*.db` 后重启资源管理器。
</Callout>

## 参考

- [IThumbnailProvider](https://learn.microsoft.com/zh-cn/windows/win32/api/thumbcache/nn-thumbcache-ithumbnailprovider) · [IInitializeWithStream](https://learn.microsoft.com/zh-cn/windows/win32/api/propsys/nn-propsys-iinitializewithstream)
- [RecipeThumbnailProvider 官方示例](https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/Win7Samples/winui/shell/appshellintegration/RecipeThumbnailProvider)
