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