访问不存在的缩略图

时间:2012-09-29 17:30:02

标签: c# thumbnails windows-shell windows-api-code-pack

我制作了一个应用程序,它会显示计算机中的文件列表。每当您单击列表中的任何项目时,它旁边的小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:Class   未注册(HRESULT异常:0x80040154   (REGDB_E_CLASSNOTREG))

有关潜在线索,请参阅How do I refresh a file's thumbnail in Windows Explorer?问题和代码snippet

4 个答案:

答案 0 :(得分:3)

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

    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文件需要在后台加载整个Adobe Reader .exe。
  • 与shell(Windows资源管理器)交谈时,您希望确保您的进程以与shell相同的 UAC级别运行,否则,出于安全考虑,某些操作将失败。因此,例如,如果您在Visual Studio中从F5或CTRL + F5运行您的进程,并且您的Visual Studio以管理员身份运行,则您的进程可能无法检索缩略图,而在运行双击.exe时它将起作用来自探险家。 REGDB_E_CLASSNOTREG是您在这些情况下可能遇到的典型错误。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

来自Shell界面:IThumbnailCache interface(强调我的)

  

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

     

要缓存缩略图,请执行   应用程序必须首先获取表示该项目的IShellItem   将获取缩略图,然后传递IShellItem   调用IThumbnailCache :: GetThumbnail。 如果flags参数为   IThumbnailCache :: GetThumbnail包含标志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。
  4. 注意事项: 我不知道您的Code Pack是否完全暴露了IThumbnailCache,但如果确实如此,那么这看起来非常简单。如果没有,你必须从shell32.dll导入它。

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

答案 3 :(得分:-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