系列专题:【附源码】Windows Shell接口之VB实现(三):IThumbnailProvider接口 (缩略图)

supergreenbean 2009-03-14 06:22:15
加精
【源码下载地址】:http://econet.zjgsu.edu.cn/cy_filesxxx/vbsrc/ThumbnailProvider.rar

我们知道,在Windows XP中,系统会在每个需要产生缩略图的文件夹中创建一个名为thumb.db的缩略图数据库文件。但是,这种以文件夹为单位维护手段无法为我们提供预览或跨文件夹的查询的功能。针对这些缺点,MS在Windows Vista中对缩略图功能做了比较大的调整,将权利从地方收回中央,建立了一个全局的缩略图缓存。打开 "%SystemDrive%\Users\%UserName%\AppData\Local\Microsoft\Windows\Explorer" 文件夹,你会发现若干个名为thumbcache_*.*的文件。这些文件名后面标着数字32、96、256、1024的db文件就是保存了系统中相应尺寸缩略图(分别对应资源管理器“视图”中的“小图标”、“中等图标”、“大图标”和“特大图标”)的缓存数据库。根据新的设计,我们在Vista中可以不受限制的为每一个单独的文件提供任意大小、任意内容的缩略图,完全摆脱了以往那种只能提供几个特定尺寸的死板约束。
Windows Vista用户界面中常用的是32位256x256的缩略图。根据微软的文档的建议,当你使用自己自定义格式的文件时,最好能同时为其提供上述规格的动态缩略图,以随时反映出特定文件的内容。有鉴于此,Vista中引入了全新的接口IThumbnailProvider,以一种更加简洁方便的方式替代以前的IExtractImage帮助我们完成提供缩略图的工作。当然,为了保持兼容,IExtractImage在Vista中依旧可用,只是资源管理器中的“详细信息面板”不支持该接口。
缩略图提供器(ThumbnailProvider)主要由两个接口组成,除了实现IThumbnailProvider之外,你还必须要实现IInitializeWithStream或IInitializeWithItem接口,以获得目标文件的信息。系统在调用你的IThumbnailProvider之前会依照顺序先后尝试调用这两个接口。如果你已实现了IInitializeWithStream或已同时实现了两个接口,系统将会调用IInitializeWithStream.Initialize方法将代表目标文件内容的流对象通过第一个参数(pstream)传到你的提供器程序中。IInitializeWithItem当然也是可以使用的,通过IInitializeWithItem.Initialize传入的是代表目标文件的IShellItem对象。但是,MS强烈建议我们不要使用这个接口,如果你实在要使用它的话,请通过在HKEY_CLASSES_ROOT\CLSID\{缩略图提供器类的CLSID}下新建一个名为DisableProcessIsolation、值为1、类型为REG_DWORD的键,取消你提供器组件的进程隔离特性(process isolation feature)。另外,MS的文档中还提到了另一个接口IinitializeWithFile,但是不知道什么原因,似乎系统从来不会访问它。
介绍了有关缩略图以及缩略图提供器(ThumbnailProvider)的前世今生后,下面就让我们动手,使用Visual Basic 6创建一个我们自己的缩略图提供器(ThumbnailProvider)吧。
假设你某天早晨刷牙时,突然想到为自己的新软件设计一种文本格式的自定义文件,并给它取了一个很响亮的扩展名.myext。而现在你想为它写一个能够用于显示特定文件内容的缩略图提供器。
就像所有其他的接口编程一样,在开始之前我们得有一个类型库,一个包含了IThumbnailProvider、IInitializeWithStream以及IStream声明的类型库。这一步我已经帮你做好,示例文件中的ThumbnailProvider.tlb应该可以满足你的要求。
接着打开你的VB6 IDE,新建一个ActiveX DLL工程(比如叫MyThumbnailProvider),并添加一个"Instancing=5 - MultiUse"的公共类(比如叫CMyThumbnailProvider)。引用前面提到的类型库ThumbnailProvider.tlb。
OK,现在万事俱备,你可以开始写你的缩略图提供器了。
首先,实现两个接口:
Implements IInitializeWithStream
Implements IThumbnailProvider


根据MS文档的建议,我们选择实现最可靠的IInitializeWithStream接口,并在其Initialize方法中将传入的IStream对象保存起来:
Private Sub IInitializeWithStream_Initialize(ByVal pstream As ThumbnailProvider.IStream, ByVal grfMode As Long)
If pstream Is Nothing Then
Err.Raise E_NOTIMPL
Else
Set m_pStream = pstream
End If
End Sub

接下来是IThumbnailProvider的GetThumbnail方法,系统会调用此方法以获得相应的缩略图。
Private Sub IThumbnailProvider_GetThumbnail(ByVal cx As Long, phbmp As Long, pdwAlpha As WTS_ALPHATYPE)
Dim sFileName As String
Dim st As STATSTG

'取得IStream对象的信息
m_pStream.Stat st

'获取IStream对象的名称信息
If st.pwcsName <> 0 Then
sFileName = StrFromPtr(st.pwcsName, True)
CoTaskMemFree st.pwcsName
End If

'获得流对象中的字节数据大小
Dim lFileSize As Long
lFileSize = IntegerFromCurrency(st.cbSize)

If lFileSize <= 0 Then Exit Sub

Dim sBuffer As String
Dim abBuffer() As Byte
ReDim abBuffer(lFileSize - 1)

'读取所有数据
If m_pStream.Read(abBuffer(0), lFileSize) <= 0 Then Exit Sub

sBuffer = StrConv(abBuffer, vbUnicode)

'创建缩略图
phbmp = CreateThumbnail(sBuffer)
End Sub


从上面的例程可以看到,提供缩略图的这个过程其实并不复杂,而我这里仅仅是很简单的取出文件内容,并使用API DrawText将其写到新建的Bitmap对象中。我相信,能在刷牙时灵光乍现、聪明绝顶的你,肯定可以想出N种惊天地泣鬼神的方法来绘制各种神奇的缩略图。
以上的例程编译后就是一个个头虽小,但却五脏俱全的缩略图提供器了,要让它真正的运作起来,我们还必须将其与你响亮的扩展名.myext联系起来。具体的方法就是建立如下的注册表项:

HKEY_CLASSES_ROOT\.myext
HKEY_CLASSES_ROOT\.myext\ShellEx
HKEY_CLASSES_ROOT\.myext\ShellEx\ {E357FCCD-A995-4576-B01F-234630154E96}


其中,“{E357FCCD-A995-4576-B01F-234630154E96}”就是IThumbnailProvider 的接口ID——IID_IThumbnailProvider。建立好上面的注册表项之后,还要将HKEY_CLASSES_ROOT\.myext\ShellEx\ {E357FCCD-A995-4576-B01F-234630154E96}的默认值设为你所编写的缩略图提供器的类ID。
使用VB6的我们,在这里就要碰到一点点小麻烦了。如果我们用VC之类的工具来编写这个缩略图提供器,那么我们不仅可以自己指定类的ID,而且上面的注册表操作过程我们也完全可以在组件的DllRegisterServer函数中写入。可是,在VB6中我们在这个类被注册前,是无法在代码中得到类ID的,而且虽然通过拦截编译过程修改Dll导出函数等手段,可以达到自定义DllRegisterServer等函数的目的,但是,这个工程量就有点儿太大了。于是,我就想了一种变通的手段,通过第三者(RegProvider)读取组件中的类信息,并将相关的信息写入注册表。

以下是RegProvider的使用方法:

1. 选择提供ThumbnailProvider服务的文件

2. 选择要注册的类

3. 输入要注册的文件扩展名

4. 选择用于显示覆盖图标的图标文件或资源(任何图标或资源引用皆可) (可选操作)
5. 选择系统显示缩略图时所用的修饰效果 (可选操作)
6. 选择是否作为进程内组件运行 (可选操作)

7. 单击 注册 或 注销

在结束前,我再提下MS在文档中就缩略图所提的几点指导原则:
A、提供能在32位256x256像素大小下很好显示的缩略图。Windows Vista的预览窗格在找不到相对应的预览处理程序(preview handler)时,会使用该规格的缩略图以作替代。但是,最好的选择还是预览处理程序,所以,应该尽可能的提供之。
B、当你创建尺寸不同的多个图像时,不要通过裁剪大图像的页面、帧或图像的方式创建小图像,而应该整体缩放之。
C、不要一次显示多个页面、帧或图像,一次只使用一个。如果一个文档由多个页面组成,比如一个文本文档或多页电子表格,那么最佳的选择就是封面。但是,不管你使用哪一页,一次只使用一次。不要同时混合多个不同的页面,这样看起来很乱。
D、Windows Vista会负责缩小图像。如果系统要求你的处理程序提供的图像比你能提供的要大,那就提供大小最相近的。不要意图动态改变你图片的大小。
E、你的处理程序在任何时候都应返回一个缩略图像,而非通过某种特殊的逻辑返回传统的图标。当低于特定的尺寸时,Windows Vista会自动显示传统图标而非缩略图。更多详情可以参考Thumbnail Providers中的Thumbnail Cache and Sizing部分。
F、在任何时候都应返回与页面、帧或图像纵横比相同的缩略图。对于非正方形的图像, Windows Vista会负责正确摆正其位置,不要使用透明去补全图像。
G、不要在你的缩略图上添加修饰效果。Windows Vista会自动在适当的时候应用投影等修饰效果,也会对特定的文件类型,比如图片或视频,应用特殊的修饰效果。
H、不要在你的缩略图上覆盖文件类型或应用程序信息。Windows Vista在图像的右下角会显示一个类型覆盖图标。覆盖图标是基于文件类型的,但是也可以根据单独的文件类型进行设置。
I、为了能有更好的性能表现,如果你的缩略图是基于文件内容的——比如某个文档中的某一页——那么,在文件保存时应连同预览的图像一起保存,而不是实时对其进行计算。如果这种计算操作是内存敏感的(操作时间大于1、2秒),就应当采取这种方式。否则,在显示具有大量使用不同处理程序显示文件缩略图的文件视图时,将会花去不少时间——而这是一种很糟糕的用户体验。Windows Vista缓存缩略图,并根据最近的修改时间以决定是否更新某个缩略图。

Windows Vista中除了提供缩略图的IThumbnailProvider之外,还有一个更好玩的IPreviewHandler,它可以让我们为自己的文件提供预览功能。不过当然,这个就只能且听下回分解了,哈!
...全文
2189 47 打赏 收藏 转发到动态 举报
写回复
用AI写文章
47 条回复
切换为时间正序
请发表友善的回复…
发表回复
ah_2026 2011-06-28
  • 打赏
  • 举报
回复 1
vb区能有如此高贴,不得不佩服..........楼主威武!!!!!!!
熊孩子开学喽 2010-09-27
  • 打赏
  • 举报
回复
收藏,慢慢消化.
lanmuz 2009-12-18
  • 打赏
  • 举报
回复
收藏了!以后慢慢学习,感谢LZ
tweeger 2009-03-18
  • 打赏
  • 举报
回复
学习,再学习!
caofusheng 2009-03-17
  • 打赏
  • 举报
回复
UP
hugo513 2009-03-17
  • 打赏
  • 举报
回复
认真学习中
dt168 2009-03-17
  • 打赏
  • 举报
回复
up
laviewpbt 2009-03-17
  • 打赏
  • 举报
回复
[Quote=引用 39 楼 myjian 的回复:]
引用 34 楼 supergreenbean 的回复:
哈,那你的软件先拿来玩玩

好象都在群里吧?
[/Quote]

都在那个群里啊?
东方之珠 2009-03-16
  • 打赏
  • 举报
回复
三个专题都齐全了,收藏!
supergreenbean 2009-03-16
  • 打赏
  • 举报
回复
哈,那你的软件先拿来玩玩
嗷嗷叫的老马 2009-03-16
  • 打赏
  • 举报
回复
[Quote=引用 34 楼 supergreenbean 的回复:]
哈,那你的软件先拿来玩玩
[/Quote]
好象都在群里吧?
ezlj 2009-03-16
  • 打赏
  • 举报
回复
不错,好东西
白发程序猿 2009-03-16
  • 打赏
  • 举报
回复
学习
hujun_zero 2009-03-16
  • 打赏
  • 举报
回复
up!
hpygzhx520 2009-03-15
  • 打赏
  • 举报
回复
到一定层次的人都明白语言只是工具,无严格的高低贵贱。
但若是找工作,说VB,人家就像看待一个不会编程的一样。看到VB的日薄西山,江湖地位也江河日下,怎能不苍凉?……

绿豆和CSDN众高手帮助了我很多很多,所以感动。
Internet9XP 2009-03-15
  • 打赏
  • 举报
回复
俺是打工滴
liuysheng 2009-03-15
  • 打赏
  • 举报
回复
分享是美德,为楼主的美德,顶一顶!!!
学习!
laviewpbt 2009-03-15
  • 打赏
  • 举报
回复
感谢supergreenbean 大哥,
已经下载并且证明是可行的,我要在我的小程序致谢中加入你的大名了。呵呵
supergreenbean 2009-03-15
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 laviewpbt 的回复:]
supergreenbean 大哥,我对SHELL编程不太在行,你看有空能帮大家搞个IExtractImage接口实现缩略图不。
呵呵,我对图像编程比较了解,现在正在搞一个新版本的VB迷你PS,也很想把缩略图这个功能加上去,但一直不知道如何实现。

这个帖子真是来的及时啊,谢谢你的共享精神。
[/Quote]

我更新过源代码了,加入了简单的IExtractImage实现方式,你可以先拿去玩玩
zzyong00 2009-03-15
  • 打赏
  • 举报
回复
mark
加载更多回复(27)

742

社区成员

发帖
与我相关
我的任务
社区描述
VB 版八卦、闲侃,联络感情地盘,禁广告帖、作业帖
社区管理员
  • 非技术类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧