如何获取IPreviewHandler文件扩展名?

Ian*_*oyd 8 windows windows-shell ipreviewhandler

如何获取IPreviewHandler特定文件扩展名的shell ?

背景

Windows允许开发人员为其自定义文件类型创建预览处理程序:

选择项目时,将调用预览处理程序,以在视图的阅读窗格中显示文件内容的轻量级,丰富的只读预览.这是在不启动文件的关联应用程序的情况下完成的.

预览处理程序是托管应用程序.主机包括Windows Vista或Microsoft Outlook 2007中的Windows资源管理器.

我想利用现有的基础IPreviewHandler设施来获取文件的缩略图.

在流中

问题是我的文件没有放在shell命名空间中(即它们不在硬盘上).他们坐在记忆中,通过一个可以访问IStream.这意味着我无法使用传统IExtractImage接口; 因为它不支持从Stream加载文件.

幸运的是,这就是现代IPreviewHandler支持(推荐并且更喜欢)从a加载数据的原因Stream,并建议不要从文件加载预览:

此方法优先于Initialize,因为它能够使用无法通过Win32路径访问的流,例如具有.zip文件扩展名的压缩文件的内容.

那我怎么得到它?

没有关于获得与特定扩展相关联的正确方法的文档IPreviewHandler.但是,如果我采取怎样的方向注册一个IPreviewHandler,并读取对方的合同:

HKEY_CLASSES_ROOT
  .xyz
     (Default) = xyzfile

HKEY_CLASSES_ROOT
   xyzfile
      shellex
         {8895b1c6-b41f-4c1c-a562-0d564250836f} //IPreviewHandler subkey
             (Default) = [clsid of the IPreviewHandler]
Run Code Online (Sandbox Code Playgroud)

鉴于我知道扩展,我应该能够遵循相同的路线.让我们用一个真实世界的例子,一个.jpg文件:

在此输入图像描述

在此输入图像描述

请注意,该文件有预览.请注意,我添加了第二个屏幕截图,以强调预览不是来自硬盘上的文件.

让我们得到拼写!

首先是它是一个.jpg文件:

HKEY_CLASSES_ROOT
   .jpg
      (Default) = ACDC_JPG

HKEY_CLASSES_ROOT
   ACDC_JPG
      ShellEx
         {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
         ContextMenuHandlers
Run Code Online (Sandbox Code Playgroud)

等等,{8895b1c6-b41f-4c1c-a562-0d564250836f}预览处理程序没有子项.这必然意味着我们无法获取.jpg文件的缩略图.

还原荒谬

真正的问题

细心的读者会意识到我要问的实际问题是:

如何获取仅包含在流中的图像的预览?

虽然这是一个有用的问题,但我遇到的真正问题是,如何使用答案IPreviewHandler也是一个有用的问题.

所以随时回答; 或两者!

奖金阅读

Ian*_*oyd 5

@hvd 有正确的答案。

文件类型有一个ShellEx键和{guid}子键。每个{guid}键代表一个特定的InterfaceID

有许多标准 shell 接口可以与文件类型相关联:

  • {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1} 提取图像
  • {953BB1EE-93B4-11d1-98A3-00C04FB687DA} IExtractImage2
  • {e357fccd-a995-4576-b01f-234630154e96} IT缩略图提供者
  • {8895b1c6-b41f-4c1c-a562-0d564250836f} IPreviewHandler

不支持探查未记录的注册表项

例如,如果我想查找与文件关联的IPreviewHandlerclsid,我会查看:.jpg

HKEY_CLASSES_ROOT/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
   (default) = [clsid]
Run Code Online (Sandbox Code Playgroud)

但这不是我能看的唯一地方。我也可以看看:

HKEY_CLASSES_ROOT/.jpg
   (default) = jpgfile
HKEY_CLASSES_ROOT/jpgfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
   (default) = [clsid]
Run Code Online (Sandbox Code Playgroud)

但这不是我能看的唯一地方。我也可以看看:

HKEY_CLASSES_ROOT/SystemFileAssociations/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
   (default) = [clsid] 
Run Code Online (Sandbox Code Playgroud)

但这不是我能看的唯一地方。我也可以看看:

HKEY_CLASSES_ROOT/SystemFileAssociations/jpegfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
   (default) = [clsid]
Run Code Online (Sandbox Code Playgroud)

但这不是我能看的唯一地方。如果我认为该文件是一个图像,我还可以查看:

HKEY_CLASSES_ROOT/SystemFileAssociations/image/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
   (default) = [clsid]
Run Code Online (Sandbox Code Playgroud)

我是如何找到这些地点的?我是否只遵循记录和支持的位置?不,我使用 Process Monitor 监视 Explorer,因为它正在寻找IThumbnailProvider

不要使用无证拼写

所以现在我想自己为文件类型使用标准的 shell 接口。这意味着我必须抓取这些位置。但是为什么要以未记录、不受支持的方式抓取这些位置。为什么要招致那个东西高高在上的家伙的愤怒?使用AssocQueryString

HKEY_CLASSES_ROOT/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
   (default) = [clsid]
Run Code Online (Sandbox Code Playgroud)

因此获得clsidIPreviewHandler.xps文件:

Guid clsid = GetShellClsidForFileType(".xps", IPreviewHandler);
Run Code Online (Sandbox Code Playgroud)

如何获取文件扩展名的 IPreviewHandler?

综上所述,我们现在可以回答这个问题了:

IPreviewHandler GetPreviewHandlerForFileType(String extension)
{
    //Extension: the file type to return IPreviewHandler for (e.g. ".xps")
    Guid previewHandlerClassID = GetShellClsidForFileType(extension, IPreviewHandler);

    //Create the COM object
    IUnknown unk = CreateComObject(previewHandlerClassID);

    //Return the actual IPreviewHanler interface (not IUnknown)
    return (IPreviewhandler)unk;
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,AssocQueryString 无法查找使用“metro”API(或本周调用的任何名称)实现的预览处理程序。一个例子是 Microsoft 的混合现实查看器(Windows 附带),它为 FBX 3D 对象提供预览处理程序(一旦您通过“打开方式”>“选择默认值”将它们分配给它)。它们似乎以某种新奇的方式注册(似乎并非所有必需的信息/映射都在注册表中),并且文件资源管理器似乎使用自己的代码,而不是 shell 提供给其他人使用的 API。相当令人沮丧。 (2认同)