我制作了一个应用程序,可以向您显示计算机中的文件列表。每当您单击列表中的任何项目时,它旁边的一个小PictureBox都会显示相应文件的缩略图。我在Windows7上使用C#。
为了获得缩略图,我重复使用了另一个问题中发布的方法。首先,我参考了Windows API代码包。然后,我使用以下代码:
ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile);
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap;
这并不总是有效的。有时,显示的缩略图只是"默认应用程序"图标。我发现,只有当Windows之前为该文件生成缩略图并将其存储在缩略图缓存中时,才会显示真正的缩略图。这意味着我必须手动打开一个文件夹,等待Windows为每个文件生成缩略图,然后我的应用程序才能看到这些缩略图。
我的程序如何在使用之前强制Windows7生成真正的缩略图?
更新(按Li0liQ)
可以通过添加FormatOption:来强制缩略图检索
ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile);
shellFile.Thumbnail.FormatOption = ShellThumbnailFormatOption.ThumbnailOnly;
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap;
然而,我得到了一个例外,以防缩略图还没有出现:
当前ShellObject没有有效的缩略图处理程序或提取此特定的缩略图时出现问题shell对象。--->System.Runtime.InteropServices.COMException:类未注册(HRESULT中的异常: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:tempwhatever.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
是一种典型的错误
经过一番搜索,我在Sharepoint中找到了Microsoft Office缩略图。它可能只适用于办公室文档,但可能是您想要的。将需要一些翻译,因为示例在C++和VB.Net.中
我的程序如何在使用Windows 7之前强制生成真正的缩略图
来自Shell接口:IThumbnailCache接口(emphasis mine)
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提供商的实现
- 为您的PDF获取一个shell项目
- 获取对外壳缩略图缓存的引用。让我们称之为
thumbNailCache
- 呼叫
thumbNailCache.GetThumbnail
(shellItem, thumbNailpx,
wtxFlagSet
, out thumbNailBitmap);
。文档中说,这将为您创建缩略图,并将其返回到out参数thumbNailBitmap中
注意事项:我不知道你的代码包是否完全暴露了IThumbnailCache,但如果真的暴露了,这看起来很直接。如果没有,你将不得不从shell32.dll导入。
还有一个IThumbnailProvider接口可能对你有用,但请阅读社区评论。它似乎很脆弱,使用起来很棘手。
据我所知,你不能强迫Windows7生成缩略图。然而,您可以自己用代码创建它:
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