How to get the IPreviewHandler for a file extension?

半城伤御伤魂 提交于 2019-12-01 03:57:31

@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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!