13

我制作了一个应用程序,向您显示计算机中的文件列表。每当您单击列表中的任何项目时,它旁边的一个小图片框应显示相应文件的缩略图。我在 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 没有有效的缩略图处理程序,或者在提取此特定外壳对象的缩略图时出现问题。---> System.Runtime.InteropServices.COMException:类未注册(来自 HRESULT 的异常:0x80040154 (REGDB_E_CLASSNOTREG))

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

4

4 回答 4

5

这是一段提取缩略图位图的代码(仅使用 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);
    }

补充说明:

  • GetImage方法有各种有趣的标志 ( SIIGBF) 你可以玩。
  • 出于性能原因,您可以缓存工厂。例如,.PDF 文件需要在后台加载整个 Adob​​e Reader .exe。
  • 与 shell(Windows 资源管理器)对话时,您要确保您的进程在与 shell 相同的UAC 级别上运行,否则出于安全原因,某些操作将失败。例如,如果您在 Visual Studio 中从 F5 或 CTRL+F5 运行您的进程,并且您的 Visual Studio 以管理员身份运行,您的进程可能无法检索缩略图,但在双击 .exe 运行时它将起作用来自探险家。这REGDB_E_CLASSNOTREG是您在这些情况下可能遇到的典型错误。
于 2013-12-20T07:44:24.000 回答
0

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

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

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

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

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

因此,假设您的系统具有与 PDF 一起使用的 IThumbnail 提供程序的实现:

  1. 为您的 PDF 获取一个外壳项目。
  2. 获取对 shell 的缩略图缓存的引用。让我们称之为thumbNailCache
  3. 打电话。文档说这将为您创建缩略图并在 out 参数 thumbNailBitmap 中返回它。thumbNailCache.GetThumbnail(shellItem, thumbNailpx, wtxFlagSet, out thumbNailBitmap);

警告:我不知道您的代码包是否完全公开了 IThumbnailCache,但如果确实如此,这看起来很简单。如果不是,则必须从 shell32.dll 导入它。

还有一个IThumbnailProvider接口可能对您有用,但请阅读社区评论。它似乎脆弱且难以使用。

于 2013-12-19T17:13:22.993 回答
0

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

于 2013-12-19T16:05:25.007 回答
-1

据我所知,您不能强制 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

于 2013-12-19T15:57:51.240 回答