访问不存在的缩略图

我已经创建了一个应用程序,它会向您显示计算机中的文件列表。 每当您单击列表中的任何项目时,它旁边的小PictureBox都应显示相应文件的缩略图。 我在Windows 7上使用C#。

为了获得缩略图,我再次发现了一个在不同问题中发布的方法。 首先,我引用Windows API代码包。 然后,我使用以下代码:

ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile); myPictureBox.Image = shellFile.Thumbnail.LargeBitmap; 

这并不总是有效。 有时,显示的缩略图仅仅是“默认应用程序”图标。 我发现只有在Windows之前为该文件生成缩略图并将其存储在缩略图缓存中时才显示真正的缩略图。 这意味着我必须手动打开文件夹,等待Windows为每个文件生成缩略图,然后我的应用程序将能够看到这些拇指。

我的程序如何在使用它们之前强制Windows 7生成真正的缩略图?

更新(由Li0liQ提供)

可以通过添加FormatOption强制缩略图检索:

 ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile); shellFile.Thumbnail.FormatOption = ShellThumbnailFormatOption.ThumbnailOnly; myPictureBox.Image = shellFile.Thumbnail.LargeBitmap; 

但是,我得到一个例外,如果缩略图还没有:

当前的ShellObject没有有效的缩略图处理程序,或者在提取此特定shell对象的缩略图时出现问题。 —> System.Runtime.InteropServices.COMException:未注册类(HRESULTexception:0x80040154(REGDB_E_CLASSNOTREG))

请参阅如何在Windows资源管理器中刷新文件的缩略图? 潜在线索的问题和代码片段 。

以下是一段提取缩略图位图的代码(仅使用Windows Vista或更高版本)。 它基于很酷的IShellItemImageFactory接口 :

  static void Main(string[] args) { // you can use any type of file supported by your windows installation. string path = @"c:\temp\whatever.pdf"; using (Bitmap bmp = ExtractThumbnail(path, new Size(1024, 1024), SIIGBF.SIIGBF_RESIZETOFIT)) { bmp.Save("whatever.png", ImageFormat.Png); } } public static Bitmap ExtractThumbnail(string filePath, Size size, SIIGBF flags) { if (filePath == null) throw new ArgumentNullException("filePath"); // TODO: you might want to cache the factory for different types of files // as this simple call may trigger some heavy-load underground operations IShellItemImageFactory factory; int hr = SHCreateItemFromParsingName(filePath, IntPtr.Zero, typeof(IShellItemImageFactory).GUID, out factory); if (hr != 0) throw new Win32Exception(hr); IntPtr bmp; hr = factory.GetImage(size, flags, out bmp); if (hr != 0) throw new Win32Exception(hr); return Bitmap.FromHbitmap(bmp); } [Flags] public enum SIIGBF { SIIGBF_RESIZETOFIT = 0x00000000, SIIGBF_BIGGERSIZEOK = 0x00000001, SIIGBF_MEMORYONLY = 0x00000002, SIIGBF_ICONONLY = 0x00000004, SIIGBF_THUMBNAILONLY = 0x00000008, SIIGBF_INCACHEONLY = 0x00000010, SIIGBF_CROPTOSQUARE = 0x00000020, SIIGBF_WIDETHUMBNAILS = 0x00000040, SIIGBF_ICONBACKGROUND = 0x00000080, SIIGBF_SCALEUP = 0x00000100, } [DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern int SHCreateItemFromParsingName(string path, IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItemImageFactory factory); [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")] private interface IShellItemImageFactory { [PreserveSig] int GetImage(Size size, SIIGBF flags, out IntPtr phbm); } 

补充说明:

  • SIIGBF方法有各种有趣的标志( SIIGBF )可以玩。
  • 出于性能原因,您可以缓存工厂。 例如,.PDF文件需要在后台加载整个Adobe Reader .exe。
  • 与shell(Windows资源管理器)通信时,您希望确保您的进程在与其他操作系统相同的UAC级别运行,但出于安全考虑,某些操作将失败。 因此,例如,如果您在Visual Studio中从F5或CTRL + F5运行您的进程,并且您的Visual Studio以管理员身份运行,则您的进程可能无法检索缩略图,而在运行双击.exe时它将起作用来自探险家。 REGDB_E_CLASSNOTREG是在这些情况下可能出现的典型错误。

经过一番搜索,我在Sharepoint中找到了Microsoft Office缩略图 。 它可能只适用于办公文档,但可能是您想要的。 将需要一些翻译,因为示例在C ++和VB.Net中。

我的程序如何在使用它们之前强制Windows 7生成真正的缩略图?

来自Shell接口: IThumbnailCache接口 (强调我的)

Thumbnail Cache API旨在为应用程序提供统一的方法来检索和缓存缩略图。 在Windows XP中,缩略图缓存是基于每个文件夹完成的,缓存是在每个文件夹中的Thumbs.db文件中维护的。 虽然此方法提供空间局部性,但它不支持跨文件夹的预览和查询。 Windows Vista中的缩略图缓存通过提供全局缓存来解决此缺点。

要缓存缩略图,应用程序必须首先获取表示将获取缩略图的项目的IShellItem,然后将IShellItem传递给对IThumbnailCache :: GetThumbnail的调用。 如果IThumbnailCache :: GetThumbnail的flags参数包含标志WTS_EXTRACT,并且缩略图尚未缓存,则将提取缩略图并将其放入缓存中。 如果设置了标志WTS_FORCEEXTRACTION,则忽略缓存并始终提取新的缩略图。 有关传递给IThumbnailCache :: GetThumbnail的标志的更多详细信息,请参阅IThumbnailCache :: GetThumbnail主题。

如果缩略图尚未在缓存中,则将使用在操作系统上注册的IExtractImage或IThumbnailProvider的现有实现自动从源文件中提取缩略图 。 您的应用程序不必提供缩略图提取器的实现。

因此,假设您的系统具有适用于PDF的IThumbnail提供程序的实现:

  1. 获取PDF的shell项。
  2. 获取对shell缩略图缓存的引用。 我们称之为thumbNailCache
  3. 调用thumbNailCache.GetThumbnail (shellItem, thumbNailpx, wtxFlagSet , out thumbNailBitmap); 。 文档说这会为你创建缩略图并在out参数thumbNailBitmap中返回它。

注意事项:我不知道您的Code Pack是否完全暴露了IThumbnailCache,但如果确实如此,这看起来非常简单。 如果没有,你将不得不从shell32.dll导入它。

还有一个IThumbnailProvider界面可能适合您,但请阅读社区评论。 使用它似乎很脆弱和​​棘手。

据我所知,你无法强制Windows 7生成缩略图。 但是,您可以自己使用代码创建它:

 Image image = Image.FromFile(fileName); Image thumbNail = image.GetThumbnailImage(120, 120, ()=>false, IntPtr.Zero); thumbNail.Save(Path.ChangeExtension(fileName, "thumb")); 

http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx