如何获取文件扩展名的 IPreviewHandler? [英] How to get the IPreviewHandler for a file extension?

查看:30
本文介绍了如何获取文件扩展名的 IPreviewHandler?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何获得 shell !

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

HKEY_CLASSES_ROOT.jpg(默认)= ACDC_JPGHKEY_CLASSES_ROOTACDC_JPG壳牌{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}ContextMenuHandlers

等等,预览处理程序没有 {8895b1c6-b41f-4c1c-a562-0d564250836f} 子键.那一定意味着我们无法获得 .jpg 文件的缩略图.

归结为荒谬

真正的问题

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

<块引用>

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

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

所以请随意回答;或两者兼而有之!

红利阅读

解决方案

@hvd 给出了正确答案.

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

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

  • {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1} IExtractImage
  • {953BB1EE-93B4-11d1-98A3-00C04FB687DA} IExtractImage2
  • {e357fccd-a995-4576-b01f-234630154e96} IThumbnailProvider
  • {8895b1c6-b41f-4c1c-a562-0d564250836f} IPreviewHandler

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

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

HKEY_CLASSES_ROOT/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}(默认)= [clsid]

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

HKEY_CLASSES_ROOT/.jpg(默认)= jpg文件HKEY_CLASSES_ROOT/jpgfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}(默认)= [clsid]

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

HKEY_CLASSES_ROOT/SystemFileAssociations/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}(默认)= [clsid]

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

HKEY_CLASSES_ROOT/SystemFileAssociations/jpegfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}(默认)= [clsid]

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

HKEY_CLASSES_ROOT/SystemFileAssociations/image/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}(默认)= [clsid]

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

不要使用无证拼写

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

Guid GetShellClsidForFileType(String fileExtension, Guid interfaceID){//例如.://字符串文件扩展名 = ".jpg"//Guid interfaceID = "{8895b1c6-b41f-4c1c-a562-0d564250836f}";//IExtractImage//我们所追求的接口 - 以字符串形式字符串 szInterfaceID := GuidToString(interfaceID);//缓冲区接收clsid字符串双字缓冲区大小:= 1024;//足以容纳 38 个字符的 clsid字符串缓冲区;设置长度(缓冲区,缓冲区大小);HRESULT hr := AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR,ASSOCSTR_SHELLEXTENSION,//用于查找外壳扩展文件扩展名,//例如.文本"szInterfaceID,//例如{8895b1c6-b41f-4c1c-a562-0d564250836f}"buffer,//将接收 clsid 字符串@缓冲区大小);如果 (hr <> S_OK)返回 Guid.Empty;Guid clsid;HRESULT hr = CLSIDFromString(buffer, out clsid);if (hr <> NOERROR)返回 Guid.Empty;返回 clsid;}

为了获得.xps文件的IPreviewHandlerclsid:

Guid clsid = GetShellClsidForFileType(".xps", IPreviewHandler);

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

有了以上所有内容,我们现在可以回答问题了:

IPreviewHandler GetPreviewHandlerForFileType(String extension){//扩展名:要为其返回IPreviewHandler的文件类型(例如.xps")Guid previewHandlerClassID = GetShellClsidForFileType(extension, IPreviewHandler);//创建COM对象IUnknown unk = CreateComObject(previewHandlerClassID);//返回实际的IPreviewHanler接口(不是IUnknown)返回(IPreviewhandler)unk;}

How do i get the shell IPreviewHandler for a particular file extension?

Background

Windows allows developers to create a preview handler for their custom file types:

Preview handlers are called when an item is selected to show a lightweight, rich, read-only preview of the file's contents in the view's reading pane. This is done without launching the file's associated application.

A preview handler is a hosted application. Hosts include the Windows Explorer in Windows Vista or Microsoft Outlook 2007.

I want to leverage the existing IPreviewHandler infrasturcture to get a thumbnail for a file.

In A Stream

The problem is that my files are not housed in the shell namespace (i.e. they are not sitting on the hard drive). They are sitting in memory, accessable through an IStream. This means i cannot use the legacy IExtractImage interface; as it does not support loading a file from a Stream.

Fortunately, this is why the modern IPreviewHandler supports (recommends, and prefers) loading data from a Stream, and recommends against loading previews from a file:

This method is preferred to Initialize due to its ability to use streams that are not accessible through a Win32 path, such as the contents of a compressed file with a .zip file name extension.

So how do i get it?

There is no documentation on the correct way to get ahold of the IPreviewHandler associated with a particular extension. But if i take the directions of how to register an IPreviewHandler, and read the contract from the other side:

HKEY_CLASSES_ROOT
  .xyz
     (Default) = xyzfile

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

I should be able to follow the same route, given that i know the extension. Lets follow that with a real world example, a .jpg file:

Notice that the file has a preview. Notice i included the second screenshot only to reinforce the idea that the preview doesn't come from a file sitting on the hard drive.

Lets get spellunking!

First is the fact that it's a .jpg file:

HKEY_CLASSES_ROOT
   .jpg
      (Default) = ACDC_JPG

HKEY_CLASSES_ROOT
   ACDC_JPG
      ShellEx
         {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
         ContextMenuHandlers

Wait, there is no {8895b1c6-b41f-4c1c-a562-0d564250836f} subkey for a previewhandler. That must mean that we cannot get a thumbnail for .jpg files.

reducto an absurdum

The Real Question

The careful reader will realize that the actual question i'm asking is:

How do i get the preview of an image contained only in a stream?

And while that is a useful question, and the real issue i'm having, having an answer on how to use IPreviewHandler is also a useful question.

So feel free to answer either; or both!

Bonus Reading

解决方案

@hvd had the right answer.

File types have a ShellEx key, with {guid} subkeys. Each {guid} key represents a particular InterfaceID.

There are a number of standard shell interfaces that can be associated with a file type:

  • {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1} IExtractImage
  • {953BB1EE-93B4-11d1-98A3-00C04FB687DA} IExtractImage2
  • {e357fccd-a995-4576-b01f-234630154e96} IThumbnailProvider
  • {8895b1c6-b41f-4c1c-a562-0d564250836f} IPreviewHandler

Unsupported spelunking of undocumented registry keys

If i want to find, for example, the clsid of the IPreviewHandler associated with a .jpg file, i would look in:

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

But that's not the only place i could look. I can also look in:

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

But that's not the only place i could look. I can also look in:

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

But that's not the only place i could look. I can also look in:

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

But that's not the only place i could look. If i think the file is an image, i can also look in:

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

How did i find these locations? Did i only follow documented and supported locations? No, i spied on Explorer using Process Monitor as it went hunting for an IThumbnailProvider.

Don't use undocumented spellunking

So now i want to use a standard shell interface for a file-type myself. This means that i have to crawl the locations. But why crawl these locations in an undocumented, unsupported way. Why incur the wrath from the guy from high atop the thing? Use AssocQueryString:

Guid GetShellClsidForFileType(String fileExtension, Guid interfaceID)
{
    //E.g.:
    //   String fileExtension = ".jpg"
    //   Guid   interfaceID   = "{8895b1c6-b41f-4c1c-a562-0d564250836f}"; //IExtractImage

    //The interface we're after - in string form
    String szInterfaceID := GuidToString(interfaceID);

    //Buffer to receive the clsid string
    DWORD bufferSize := 1024; //more than enough to hold a 38-character clsid
    String buffer;
    SetLength(buffer, bufferSize);

    HRESULT hr := AssocQueryString(
          ASSOCF_INIT_DEFAULTTOSTAR, 
          ASSOCSTR_SHELLEXTENSION, //for finding shell extensions
          fileExtension, //e.g. ".txt"
          szInterfaceID, //e.g. "{8895b1c6-b41f-4c1c-a562-0d564250836f}"
          buffer,        //will receive the clsid string
          @bufferSize);
   if (hr <> S_OK) 
      return Guid.Empty;

   Guid clsid;
   HRESULT hr = CLSIDFromString(buffer, out clsid);
   if (hr <> NOERROR) 
      return Guid.Empty;

   return clsid;
}

And so to get the clsid of IPreviewHandler for .xps files:

Guid clsid = GetShellClsidForFileType(".xps", IPreviewHandler);

How to get IPreviewHandler for a file extension?

With all the above, we can now answer the question:

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;
}

这篇关于如何获取文件扩展名的 IPreviewHandler?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆