第 ④ 章 · 缩略图处理器(IThumbnailProvider)
用 IThumbnailProvider 为文件生成自定义缩略图,取代已过时的 IExtractImage;讲 IInitializeWithStream 拿内容、GDI 画 32bpp 位图、WTS_ALPHATYPE 与注册。
从本章起进入“文件视觉”部分。缩略图就是资源管理器在大图标视图里给文件画的那张预览图。老教程用的 IExtractImage 早已被 IThumbnailProvider(Vista 起推荐)取代——后者更简单、更安全(默认在隔离进程里跑)。
本章给 .txt 文件生成缩略图:底色由文件大小推导、中间画出字节数。配套代码:04-thumbnail。
两个接口
IInitializeWithStream—— Shell 不再给你文件路径,而是给一个IStream。这样即使文件在网络上、或在受限沙箱里也能取到内容,且缩略图默认跑在隔离宿主dllhost.exe里,崩了不连累资源管理器。IThumbnailProvider::GetThumbnail(cx, phbmp, pdwAlpha)—— 给定边长cx,返回一张HBITMAP。
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 往里画:
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 通道就声明 RGBpdwAlpha(WTS_ALPHATYPE)告诉 Shell 位图有没有 alpha:WTSAT_RGB 忽略 alpha 通道;WTSAT_ARGB 表示预乘 alpha(做圆角/透明缩略图时用,且像素必须是预乘的)。用普通 GDI 画完不去管 alpha,就老实声明 WTSAT_RGB。
GetThumbnail 里别读整个大文件、别做网络请求。虽然它在独立宿主进程里跑、不会直接卡住资源管理器,但仍要尽快返回——否则缩略图迟迟不出来。
注册
缩略图处理器注册在文件类型的 shellex\{E357FCCD-A995-4576-B01F-234630154E96} 下(这个固定 GUID 是系统定义的“缩略图处理器”类别),默认值为你的 CLSID:
RegisterInprocServer(CLSID_DemoThumbnailProvider, dll, L"Demo Thumbnail Provider");
RegWriteString(HKEY_CLASSES_ROOT,
L".txt\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}", nullptr, clsidStr);缩略图有缓存。装好后看不到效果,把 .txt 文件夹切到「大图标」视图;仍不行就用「磁盘清理」清缩略图缓存、或删 %LocalAppData%\Microsoft\Windows\Explorer\thumbcache_*.db 后重启资源管理器。