How to get IPreviewHandler for file extension?

How to get IPreviewHandler shell for a specific file extension?

Background

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

Preview handlers are invoked when an item is selected to show a light, rich, read-only preview of the contents of the file in the reading area. This is done without starting the application associated with the file.

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

I want to use the existing IPreviewHandler infrastructure to get a thumbnail for a file.

In stream A

The problem is that my files are not located in the shell namespace (i.e. they are not sitting on the hard drive). They sit in memory, accessible through IStream . This means that I cannot use the legacy IExtractImage interface; since it does not support downloading a file from Stream .

Fortunately, this is why modern IPreviewHandler supports (recommends and prefers) to download data from Stream and recommends not to download previews from a file:

This method is preferable to Initialize because of its ability to use streams that are not accessible through the Win32 path, for example, the contents of a compressed file with the extension of the .zip file.

So how do I get this?

There is no documentation on the correct way to obtain IPreviewHandler associated with a particular extension. But if I take directions on how to register IPreviewHandler , and read the contract on the other hand

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

I must be able to follow the same route, given that I know the extension. The following is an example of a real world: .jpg file:

enter image description here

enter image description here

Please note that the file has a preview. Note that I included the second screen shot only to reinforce the idea that the preview does not come from a file sitting on the hard drive.

Lets get spellunking !

The first is the .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} for the preview handler. This should mean that we cannot get a thumbnail for the .jpg files.

reducto absurdum

Real question

A careful reader will understand that the actual question I am asking is:

How to get a preview of the image contained only in the stream?

And although this is a useful question, and the real problem I came across with the answer on how to use IPreviewHandler is also a useful question.

So feel free to answer; or both!

Reading bonuses

+8
windows windows-shell
source share
1 answer

@Hvd had the correct answer.

File types have a ShellEx key with sub-sections {guid} . Each {guid} key represents a specific 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 spelling of undocumented registry keys

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

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

But this is not the only place I could see. I can also look in:

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

But this is not the only place I could see. I can also look in:

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

But this is not the only place I could see. I can also look in:

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

But this is not the only place I could see. If I think the file is an image, I can also see:

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

How did I find these places? Did I just follow registered and maintained locations? No, I watched the explorer using Process Monitor, since it was hunting for IThumbnailProvider .

Do not use undocumented spells.

So now I want to use the standard shell interface for the file type myself. That means I have to scan places. But why scan these locations without documents, without support. Why incur the wrath of a guy from above things ? Use AssocQueryString :

 Guid GetShellClsidForFileType(String fileExtension, Guid interfaceID) { //Eg: // 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, //eg ".txt" szInterfaceID, //eg "{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 clsid from IPreviewHandler for .xps files:

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

How to get IPreviewHandler for file extension?

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

 IPreviewHandler GetPreviewHandlerForFileType(String extension) { //Extension: the file type to return IPreviewHandler for (eg ".xps") Guid previewHandlerClassID = GetShellClsidForFileType(extension, IPreviewHandler); //Create the COM object IUnknown unk = CreateComObject(previewHandlerClassID); //Return the actual IPreviewHanler interface (not IUnknown) return (IPreviewhandler)unk; } 
+4
source share

All Articles