如何获取特定文件扩展名的shell IPreviewHandler
?
Windows允许开发人员为其自定义文件类型创建预览处理程序:
当选择某个项目以在视图的阅读窗格中显示文件内容的轻量级,丰富的只读预览时,将调用预览处理程序。这是在不启动文件的相关应用程序的情况下完成的。
预览处理程序是托管应用程序。主机包括Windows Vista或Microsoft Outlook 2007中的Windows资源管理器。
我想利用现有的IPreviewHandler
基础设施来获取文件的缩略图。
问题是我的文件没有放在shell命名空间中(即它们不在硬盘上)。它们位于记忆中,可通过IStream
访问。这意味着我无法使用旧版IExtractImage
接口;因为它不支持从 Stream 加载文件。
幸运的是,这就是为什么现代IPreviewHandler
支持(推荐并且更喜欢)从Stream
加载数据,并建议反对从文件中加载预览:
此方法优先于Initialize,因为它能够使用无法通过Win32路径访问的流,例如带有.zip文件扩展名的压缩文件的内容。
没有关于正确方式的文档来获取与特定扩展名相关联的IPreviewHandler
。但如果我采取如何注册的方向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]
我应该能够遵循相同的路线,因为我知道扩展名。让我们用一个真实世界的例子,.jpg
文件:
请注意,该文件有预览。请注意,我添加了第二个屏幕截图,以强化预览不会来自硬盘上的文件。
首先,它是.jpg
文件:
HKEY_CLASSES_ROOT
.jpg
(Default) = ACDC_JPG
HKEY_CLASSES_ROOT
ACDC_JPG
ShellEx
{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
ContextMenuHandlers
等等,预览处理程序没有{8895b1c6-b41f-4c1c-a562-0d564250836f}
子项。这必然意味着我们无法获取.jpg
个文件的缩略图。
reducto a absurdum
细心的读者会发现我提出的实际问题是:
如何预览仅包含在流中的图像?
虽然这是一个有用的问题,但我遇到的真正问题是,如何使用IPreviewHandler
得到答案也是一个有用的问题。
所以随意回答;或两者兼而有之!
答案 0 :(得分:4)
@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
文件相关联的 IPreviewHandler 的 clsid ,我会查看:
HKEY_CLASSES_ROOT/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
但那不是我唯一能看的地方。我也可以看看:
HKEY_CLASSES_ROOT/.jpg
(default) = jpgfile
HKEY_CLASSES_ROOT/jpgfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
但那不是我唯一能看的地方。我也可以看看:
HKEY_CLASSES_ROOT/SystemFileAssociations/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
但那不是我唯一能看的地方。我也可以看看:
HKEY_CLASSES_ROOT/SystemFileAssociations/jpegfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
但那不是我唯一能看的地方。如果我认为该文件是图像,我也可以查看:
HKEY_CLASSES_ROOT/SystemFileAssociations/image/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
我是如何找到这些地点的?我是否只关注记录和支持的位置?不,我在探索资源管理器时使用了Process Monitor,因为它正在寻找 IThumbnailProvider 。
所以现在我想自己使用标准shell接口作为文件类型。这意味着我必须抓取位置。但是,为什么要以无证件,不受支持的方式抓取这些位置。为什么会在the guy之上从the thing引发愤怒?使用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;
}
为了获得clsid
IPreviewHandler
个文件.xps
,我需要Guid clsid = GetShellClsidForFileType(".xps", 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;
}
综上所述,我们现在可以回答这个问题:
www.mysite.com/store