C#通过windows api从文件中获取缩略图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1439719/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# get thumbnail from file via windows api
提问by Brian Gillespie
Windows explorer has the ability to show thumbnails of files. These thumbnails are provided by core and third-party shell extensions.
Windows 资源管理器能够显示文件的缩略图。这些缩略图由核心和第三方 shell 扩展提供。
I know how to extend the shell to provide thumbnails to Windows.
我知道如何扩展外壳以向 Windows 提供缩略图。
What I want to do is retrieve the thumbnail image from any file on the system via the shell using C#. Is this possible?
我想要做的是使用 C# 通过 shell 从系统上的任何文件中检索缩略图。这可能吗?
Essentially, I'm writing a custom file browser and I want to show thumbnails, and can't possibly parse every file on the planet to make my own thumbnails.
本质上,我正在编写一个自定义文件浏览器,我想显示缩略图,并且不可能解析地球上的每个文件来制作我自己的缩略图。
Clarification: Many answers seem to be centered around web page thumbnails, or scaling an image. But that's not at all what I'm looking for. What I want is to ask Windows for the thumbnail representation of these file types: .DOC, .PDF, .3DM, .DWG... and mabye about a dozen more. I don't want to parse, render, and make thumbnails myself, because Windows already knows how.
澄清:许多答案似乎以网页缩略图或缩放图像为中心。但这根本不是我要找的。我想要的是向 Windows 询问这些文件类型的缩略图表示形式:.DOC、.PDF、.3DM、.DWG...以及 mabye 大约十几种。我不想自己解析、渲染和制作缩略图,因为 Windows 已经知道如何做。
The code I posted as an answer actually works... maybe it can be simplified and cleaned up a bit.
我作为答案发布的代码实际上有效......也许可以简化和清理一下。
采纳答案by Christian Nunciato
Ran across this today -- it's a few months old, but it got the job done for me (on Win7, extracting thumbnails on MPEG-4 files):
今天遇到了这个问题——它已经有几个月的历史了,但它为我完成了工作(在 Win7 上,提取 MPEG-4 文件的缩略图):
- Source : https://github.com/dbarros/WindowsAPICodePack
- Nuget : https://www.nuget.org/packages/WindowsAPICodePack-Shell
- 来源:https: //github.com/dbarros/WindowsAPICodePack
- Nuget:https://www.nuget.org/packages/WindowsAPICodePack-Shell
Code:
代码:
ShellFile shellFile = ShellFile.FromFilePath(pathToYourFile);
Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap;
Hope it helps!
希望能帮助到你!
回答by hemisphire
Not exactly what you asked, but here's a project to open a Thumbs.db file.
The Wikipedia article has more informationon where to find thumbnails in Vista & 7.
不完全是你问的,但这里有一个打开 Thumbs.db 文件的项目。
维基百科文章提供了有关在 Vista 和 7 中哪里可以找到缩略图的更多信息。
Here's the code to get the image:
这是获取图像的代码:
public byte[] GetThumbData(string filename)
{
IStorageWrapper wrapper = new IStorageWrapper(_thumbDBFile, false);
foreach(CatalogItem catItem in _catalogItems)
{
if (catItem.filename == filename)
{
string streamName = BuildReverseString(catItem.itemID);
FileObject fileObject = wrapper.OpenUCOMStream(null, streamName);
byte[] rawJPGData = new byte [fileObject.Length];
fileObject.Read(rawJPGData, 0, (int)fileObject.Length);
fileObject.Close();
// 3 ints of header data need to be removed
// Don't know what first int is.
// 2nd int is thumb index
// 3rd is size of thumbnail data.
byte[] jpgData = new byte[rawJPGData.Length - 12];
for (int index = 12; index < jpgData.Length; index++)
{
jpgData[index - 12] = rawJPGData[index];
}
return jpgData;
}
}
return null;
}
public Image GetThumbnailImage(string filename)
{
byte[] thumbData = GetThumbData(filename);
if (null == thumbData)
{
return null;
}
MemoryStream ms = new MemoryStream(thumbData);
Image img = Image.FromStream(ms);
return img;
}
回答by Brian Gillespie
Here's a class that I found searching around the internet. It looks like the original code came from http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21789724.html, but I can't see it to give proper attribution. I found the source here: http://www.vbforums.com/showthread.php?t=527704
这是我在互联网上搜索的一门课。看起来原始代码来自http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21789724.html,但我看不到它给出适当的归属。我在这里找到了来源:http: //www.vbforums.com/showthread.php?t=527704
Here's a class with the proper COM calls, reproduced here for posterity:
这是一个具有正确 COM 调用的类,在此复制以供后代使用:
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace RMA.Shell
{
public class ShellThumbnail : IDisposable
{
[Flags]
private enum ESTRRET
{
STRRET_WSTR = 0,
STRRET_OFFSET = 1,
STRRET_CSTR = 2
}
[Flags]
private enum ESHCONTF
{
SHCONTF_FOLDERS = 32,
SHCONTF_NONFOLDERS = 64,
SHCONTF_INCLUDEHIDDEN = 128,
}
[Flags]
private enum ESHGDN
{
SHGDN_NORMAL = 0,
SHGDN_INFOLDER = 1,
SHGDN_FORADDRESSBAR = 16384,
SHGDN_FORPARSING = 32768
}
[Flags]
private enum ESFGAO
{
SFGAO_CANCOPY = 1,
SFGAO_CANMOVE = 2,
SFGAO_CANLINK = 4,
SFGAO_CANRENAME = 16,
SFGAO_CANDELETE = 32,
SFGAO_HASPROPSHEET = 64,
SFGAO_DROPTARGET = 256,
SFGAO_CAPABILITYMASK = 375,
SFGAO_LINK = 65536,
SFGAO_SHARE = 131072,
SFGAO_READONLY = 262144,
SFGAO_GHOSTED = 524288,
SFGAO_DISPLAYATTRMASK = 983040,
SFGAO_FILESYSANCESTOR = 268435456,
SFGAO_FOLDER = 536870912,
SFGAO_FILESYSTEM = 1073741824,
SFGAO_HASSUBFOLDER = -2147483648,
SFGAO_CONTENTSMASK = -2147483648,
SFGAO_VALIDATE = 16777216,
SFGAO_REMOVABLE = 33554432,
SFGAO_COMPRESSED = 67108864,
}
private enum EIEIFLAG
{
IEIFLAG_ASYNC = 1,
IEIFLAG_CACHE = 2,
IEIFLAG_ASPECT = 4,
IEIFLAG_OFFLINE = 8,
IEIFLAG_GLEAM = 16,
IEIFLAG_SCREEN = 32,
IEIFLAG_ORIGSIZE = 64,
IEIFLAG_NOSTAMP = 128,
IEIFLAG_NOBORDER = 256,
IEIFLAG_QUALITY = 512
}
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0, CharSet = CharSet.Auto)]
private struct STRRET_CSTR
{
public ESTRRET uType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 520)]
public byte[] cStr;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
private struct STRRET_ANY
{
[FieldOffset(0)]
public ESTRRET uType;
[FieldOffset(4)]
public IntPtr pOLEString;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct SIZE
{
public int cx;
public int cy;
}
[ComImport(), Guid("00000000-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IUnknown
{
[PreserveSig()]
IntPtr QueryInterface(ref Guid riid, ref IntPtr pVoid);
[PreserveSig()]
IntPtr AddRef();
[PreserveSig()]
IntPtr Release();
}
[ComImportAttribute()]
[GuidAttribute("00000002-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMalloc
{
[PreserveSig()]
IntPtr Alloc(int cb);
[PreserveSig()]
IntPtr Realloc(IntPtr pv, int cb);
[PreserveSig()]
void Free(IntPtr pv);
[PreserveSig()]
int GetSize(IntPtr pv);
[PreserveSig()]
int DidAlloc(IntPtr pv);
[PreserveSig()]
void HeapMinimize();
}
[ComImportAttribute()]
[GuidAttribute("000214F2-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
private interface IEnumIDList
{
[PreserveSig()]
int Next(int celt, ref IntPtr rgelt, ref int pceltFetched);
void Skip(int celt);
void Reset();
void Clone(ref IEnumIDList ppenum);
}
[ComImportAttribute()]
[GuidAttribute("000214E6-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
private interface IShellFolder
{
void ParseDisplayName(IntPtr hwndOwner, IntPtr pbcReserved,
[MarshalAs(UnmanagedType.LPWStr)]string lpszDisplayName,
ref int pchEaten, ref IntPtr ppidl, ref int pdwAttributes);
void EnumObjects(IntPtr hwndOwner,
[MarshalAs(UnmanagedType.U4)]ESHCONTF grfFlags,
ref IEnumIDList ppenumIDList);
void BindToObject(IntPtr pidl, IntPtr pbcReserved, ref Guid riid,
ref IShellFolder ppvOut);
void BindToStorage(IntPtr pidl, IntPtr pbcReserved, ref Guid riid, IntPtr ppvObj);
[PreserveSig()]
int CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);
void CreateViewObject(IntPtr hwndOwner, ref Guid riid,
IntPtr ppvOut);
void GetAttributesOf(int cidl, IntPtr apidl,
[MarshalAs(UnmanagedType.U4)]ref ESFGAO rgfInOut);
void GetUIObjectOf(IntPtr hwndOwner, int cidl, ref IntPtr apidl, ref Guid riid, ref int prgfInOut, ref IUnknown ppvOut);
void GetDisplayNameOf(IntPtr pidl,
[MarshalAs(UnmanagedType.U4)]ESHGDN uFlags,
ref STRRET_CSTR lpName);
void SetNameOf(IntPtr hwndOwner, IntPtr pidl,
[MarshalAs(UnmanagedType.LPWStr)]string lpszName,
[MarshalAs(UnmanagedType.U4)] ESHCONTF uFlags,
ref IntPtr ppidlOut);
}
[ComImportAttribute(), GuidAttribute("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
private interface IExtractImage
{
void GetLocation([Out(), MarshalAs(UnmanagedType.LPWStr)]
StringBuilder pszPathBuffer, int cch, ref int pdwPriority, ref SIZE prgSize, int dwRecClrDepth, ref int pdwFlags);
void Extract(ref IntPtr phBmpThumbnail);
}
private class UnmanagedMethods
{
[DllImport("shell32", CharSet = CharSet.Auto)]
internal extern static int SHGetMalloc(ref IMalloc ppMalloc);
[DllImport("shell32", CharSet = CharSet.Auto)]
internal extern static int SHGetDesktopFolder(ref IShellFolder ppshf);
[DllImport("shell32", CharSet = CharSet.Auto)]
internal extern static int SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath);
[DllImport("gdi32", CharSet = CharSet.Auto)]
internal extern static int DeleteObject(IntPtr hObject);
}
~ShellThumbnail()
{
Dispose();
}
private IMalloc alloc = null;
private bool disposed = false;
private Size _desiredSize = new Size(100, 100);
private Bitmap _thumbNail;
public Bitmap ThumbNail
{
get
{
return _thumbNail;
}
}
public Size DesiredSize
{
get { return _desiredSize; }
set { _desiredSize = value; }
}
private IMalloc Allocator
{
get
{
if (!disposed)
{
if (alloc == null)
{
UnmanagedMethods.SHGetMalloc(ref alloc);
}
}
else
{
Debug.Assert(false, "Object has been disposed.");
}
return alloc;
}
}
public Bitmap GetThumbnail(string fileName)
{
if (string.IsNullOrEmpty(fileName))
return null;
if (!File.Exists(fileName) && !Directory.Exists(fileName))
{
throw new FileNotFoundException(string.Format("The file '{0}' does not exist", fileName), fileName);
}
if (_thumbNail != null)
{
_thumbNail.Dispose();
_thumbNail = null;
}
IShellFolder folder = null;
try
{
folder = getDesktopFolder;
}
catch (Exception ex)
{
throw ex;
}
if (folder != null)
{
IntPtr pidlMain = IntPtr.Zero;
try
{
int cParsed = 0;
int pdwAttrib = 0;
string filePath = Path.GetDirectoryName(fileName);
folder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, filePath, ref cParsed, ref pidlMain, ref pdwAttrib);
}
catch (Exception ex)
{
Marshal.ReleaseComObject(folder);
throw ex;
}
if (pidlMain != IntPtr.Zero)
{
Guid iidShellFolder = new Guid("000214E6-0000-0000-C000-000000000046");
IShellFolder item = null;
try
{
folder.BindToObject(pidlMain, IntPtr.Zero, ref iidShellFolder, ref item);
}
catch (Exception ex)
{
Marshal.ReleaseComObject(folder);
Allocator.Free(pidlMain);
throw ex;
}
if (item != null)
{
IEnumIDList idEnum = null;
try
{
item.EnumObjects(IntPtr.Zero, (ESHCONTF.SHCONTF_FOLDERS | ESHCONTF.SHCONTF_NONFOLDERS), ref idEnum);
}
catch (Exception ex)
{
Marshal.ReleaseComObject(folder);
Allocator.Free(pidlMain);
throw ex;
}
if (idEnum != null)
{
int hRes = 0;
IntPtr pidl = IntPtr.Zero;
int fetched = 0;
bool complete = false;
while (!complete)
{
hRes = idEnum.Next(1, ref pidl, ref fetched);
if (hRes != 0)
{
pidl = IntPtr.Zero;
complete = true;
}
else
{
if (_getThumbNail(fileName, pidl, item))
{
complete = true;
}
}
if (pidl != IntPtr.Zero)
{
Allocator.Free(pidl);
}
}
Marshal.ReleaseComObject(idEnum);
}
Marshal.ReleaseComObject(item);
}
Allocator.Free(pidlMain);
}
Marshal.ReleaseComObject(folder);
}
return ThumbNail;
}
private bool _getThumbNail(string file, IntPtr pidl, IShellFolder item)
{
IntPtr hBmp = IntPtr.Zero;
IExtractImage extractImage = null;
try
{
string pidlPath = PathFromPidl(pidl);
if (Path.GetFileName(pidlPath).ToUpper().Equals(Path.GetFileName(file).ToUpper()))
{
IUnknown iunk = null;
int prgf = 0;
Guid iidExtractImage = new Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1");
item.GetUIObjectOf(IntPtr.Zero, 1, ref pidl, ref iidExtractImage, ref prgf, ref iunk);
extractImage = (IExtractImage)iunk;
if (extractImage != null)
{
Console.WriteLine("Got an IExtractImage object!");
SIZE sz = new SIZE();
sz.cx = DesiredSize.Width;
sz.cy = DesiredSize.Height;
StringBuilder location = new StringBuilder(260, 260);
int priority = 0;
int requestedColourDepth = 32;
EIEIFLAG flags = EIEIFLAG.IEIFLAG_ASPECT | EIEIFLAG.IEIFLAG_SCREEN;
int uFlags = (int)flags;
try
{
extractImage.GetLocation(location, location.Capacity, ref priority, ref sz, requestedColourDepth, ref uFlags);
extractImage.Extract(ref hBmp);
}
catch (System.Runtime.InteropServices.COMException ex)
{
}
if (hBmp != IntPtr.Zero)
{
_thumbNail = Bitmap.FromHbitmap(hBmp);
}
Marshal.ReleaseComObject(extractImage);
extractImage = null;
}
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
if (hBmp != IntPtr.Zero)
{
UnmanagedMethods.DeleteObject(hBmp);
}
if (extractImage != null)
{
Marshal.ReleaseComObject(extractImage);
}
throw ex;
}
}
private string PathFromPidl(IntPtr pidl)
{
StringBuilder path = new StringBuilder(260, 260);
int result = UnmanagedMethods.SHGetPathFromIDList(pidl, path);
if (result == 0)
{
return string.Empty;
}
else
{
return path.ToString();
}
}
private IShellFolder getDesktopFolder
{
get
{
IShellFolder ppshf = null;
int r = UnmanagedMethods.SHGetDesktopFolder(ref ppshf);
return ppshf;
}
}
public void Dispose()
{
if (!disposed)
{
if (alloc != null)
{
Marshal.ReleaseComObject(alloc);
}
alloc = null;
if (_thumbNail != null)
{
_thumbNail.Dispose();
}
disposed = true;
}
}
}
}
回答by John Gietzen
This may help:
这可能有帮助:
This includes the Shell API, and allows you to do almost everything that the shell can (including rendering thumbnails).
这包括 Shell API,并允许您执行 Shell 可以执行的几乎所有操作(包括渲染缩略图)。
回答by Eran Betzalel
回答by AMissico
Microsoft Office Thumbnails in SharePointat http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx.is exactly what you want. (I had no trouble converting the VB.NET code into C# using http://www.developerfusion.com/tools/convert/vb-to-csharp/.)
SharePoint中的Microsoft Office 缩略图,网址为http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx。正是你想要的。(我使用http://www.developerfusion.com/tools/convert/vb-to-csharp/将 VB.NET 代码转换为 C# 没有问题。)
Regarding the code you posted in your answer, Thumbnail Extraction Using the Shellat http://www.vbaccelerator.com/home/net/code/libraries/Shell_Projects/Thumbnail_Extraction/article.aspis the original article the code is from. I believe nearly all IExtractImage
samples (you find searching) are based on this article's code, due to naming convention, comments, and so on, that are carried from the original. Since this article dates from April 2003, it carries some non-standard (non-.NET) coding conventions. I did some basic testing, and there are garbage collection issues, freeing unmanaged resource issues, and other clean-up issues. Therefore, I make a strong recommendation to avoid the code in that article. Moreover, the code is structured is such a way to make maintenance difficult.
关于您在答案中发布的代码,http: //www.vbaccelerator.com/home/net/code/libraries/Shell_Projects/Thumbnail_Extraction/article.asp 上的 Thumbnail Extraction Using the Shell是该代码的原始文章。我相信几乎所有IExtractImage
由于命名约定、注释等原因,示例(您发现搜索)基于本文的代码,这些代码是从原始文件中提取的。由于本文的日期是 2003 年 4 月,因此它带有一些非标准(非 .NET)编码约定。我做了一些基本的测试,有垃圾收集问题、释放非托管资源问题和其他清理问题。因此,我强烈建议避免使用该文章中的代码。而且,这种代码结构化方式使得维护变得困难。
There is a clean simplier version on MSDN, dated July 2005, called Microsoft Office Thumbnails in SharePointat http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx.This code and the article's code share similarities, which leads me to believe the Thumbnail Extraction Using the Shellarticle is the basis for the SharePointarticle. The VB.NET version of GetThumbnailImage
ignores the longestEdge
parameter, but the C++ version uses it and documents the use of the ORIGSIZE
and QUALITY
flags. In addition, the code illustrates how to use .NET's FreeCoTaskMem
instead of the Shell's IMalloc
and SHGetMalloc
.
MSDN 上有一个更简洁的版本,日期为 2005 年 7 月,在http://msdn.microsoft.com/en-us/library/aa289172(VS.71).aspx 上称为SharePoint中的Microsoft Office Thumbnails。此代码和文章的代码有相似之处,这让我相信使用 Shell 提取缩略图一文是SharePoint文章的基础。VB.NET 版本GetThumbnailImage
忽略该longestEdge
参数,但 C++ 版本使用它并记录ORIGSIZE
和QUALITY
标志的使用。此外,代码还说明了如何使用 .NETFreeCoTaskMem
而不是 Shell 的IMalloc
和SHGetMalloc
.
IExtractImage
works with files, folders, and other namespace objects. The MSDN code works with hidden files, whereas, the vbAccelerator code needs then SHCONTF_INCLUDEHIDDEN
added to the EnumObjects
call. In addition, the vbAccelerator enumerates over the shell folder's objects looking for the specified file, which seems a waste of time. This may have been needed to find the correct "relative" PIDL that is used for the GetUIObjectOf
call.
IExtractImage
处理文件、文件夹和其他命名空间对象。MSDN 代码处理隐藏文件,而 vbAccelerator 代码需要SHCONTF_INCLUDEHIDDEN
添加到EnumObjects
调用中。另外,vbAccelerator 会枚举shell 文件夹的对象来寻找指定的文件,这似乎是在浪费时间。这可能需要找到用于GetUIObjectOf
调用的正确“相对”PIDL 。
ShellThumbnail (Work-In-Progress)
ShellThumbnail(进行中的工作)
Complete sample project at http://cid-7178d2c79ba0a7e3.office.live.com/self.aspx/.Public/ShellThumbnail.zip.
在http://cid-7178d2c79ba0a7e3.office.live.com/self.aspx/.Public/ShellThumbnail.zip完成示例项目。
Imports System.Runtime.InteropServices
Namespace Shell
''' <summary>
''' Generates a thumbnail of a folder's picture or a file's image.
''' </summary>
''' <remarks>This is the "Folder's Picture" and not the "Folder's Icon"! Use SHGetFileInfo to generate the thumbnail for a folder's icon or for a file that does not have a thumbnail handler.</remarks>
''' <reference>Microsoft Office Thumbnails in SharePoint at http://msdn.microsoft.com/en-us/library/aa289172%28VS.71%29.aspx.</reference>
Public Class ShellThumbnail
'TODO - Work out the details for image size and IEIFLAG handling.
#Region " Determining Thumbnail Size and Quality [documentation] "
'http://support.microsoft.com/kb/835823
'Determining Thumbnail Size and Quality
'Browse to HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer. Create or modify two DWORDs called ThumbnailSize and ThumbnailQuality. For ThumbnailSize set the value in pixels, with the default being 96. For ThumbnailQuality set the value as a number that represents the percentage quality between 50 and 100.
'http://www.pctools.com/guides/registry/detail/1066/ (modified)
' User Key: [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
'System Key: [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer]
'Value Name: ThumbnailSize, ThumbnailQuality
' Data Type: REG_DWORD (DWORD Value)
'Value Data: Size in pixels (32-255), Quality Percentage (50-100)
'Microsoft? Windows? XP Registry Guide
'Jerry Honeycutt
'09/11/2002
'Microsoft Press
'http://www.microsoft.com/mspress/books/sampchap/6232.aspx#118
'<H3><I><A name=118></A>Thumbnails</I></H3>The Thumbnails category controls the
'quality of thumbnails in Windows Explorer. Table 5-10 describes the values for
'Image Quality and Size. Create values that you don't see in the registry. The
'default value for <CODE>ThumbnailQuality</CODE> is <CODE>0x5A</CODE>. The
'default value for <CODE>ThumbnailSize</CODE> is <CODE>0x60</CODE>. Keep in mind
'that higher quality and larger thumbnails require more disk space, which is not
'usually a problem, but they also take longer to display. Changing the quality
'does not affect thumbnails that already exist on the file system.
'<P><B>Table 5-10 </B><I>Values in Thumbnails</I>
'<P>
'<TABLE border=0 cellSpacing=1 cellPadding=4 width="100%">
'<TBODY>
'<TR>
'<TD bgColor=#999999 vAlign=top><B>Setting</B></TD>
'<TD bgColor=#999999 vAlign=top><B>Name</B></TD>
'<TD bgColor=#999999 vAlign=top><B>Type</B></TD>
'<TD bgColor=#999999 vAlign=top><B>Data</B></TD></TR>
'<TR>
'<TD bgColor=#cccccc
'vAlign=top><CODE><B>HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer</B></CODE></TD>
'<TD bgColor=#cccccc vAlign=top> </TD>
'<TD bgColor=#cccccc vAlign=top> </TD>
'<TD bgColor=#cccccc vAlign=top> </TD></TR>
'<TR>
'<TD bgColor=#cccccc vAlign=top><CODE>Image Quality</CODE></TD>
'<TD bgColor=#cccccc vAlign=top><CODE>ThumbnailQuality</CODE></TD>
'<TD bgColor=#cccccc vAlign=top><CODE>REG_DWORD</CODE></TD>
'<TD bgColor=#cccccc vAlign=top><CODE>0x32 - 0x64</CODE></TD></TR>
'<TR>
'<TD bgColor=#cccccc vAlign=top><CODE>Size (pixels)</CODE></TD>
'<TD bgColor=#cccccc vAlign=top><CODE>ThumbnailSize</CODE></TD>
'<TD bgColor=#cccccc vAlign=top><CODE>REG_DWORD</CODE></TD>
'<TD bgColor=#cccccc vAlign=top><CODE>0x20 - 0xFF</CODE></TD></TR></TBODY></TABLE></P>
#End Region
Public Shared ReadOnly DefaultThumbnailSize As New System.Drawing.Size(96, 96)
Public Const DefaultColorDepth As Integer = 32
''' <summary>
''' Used to request an image from an object, such as an item in a Shell folder.
''' </summary>
''' <param name="path">An absolute path to a file or folder.</param>
Public Shared Function ExtractImage(ByVal path As String) As Bitmap
Return ExtractImage(path, System.Drawing.Size.Empty, DefaultColorDepth, 0)
End Function
''' <summary>
''' Used to request an image from an object, such as an item in a Shell folder.
''' </summary>
''' <param name="path">An absolute path to a file or folder.</param>
''' <param name="size"></param>
Public Shared Function ExtractImage(ByVal path As String, ByVal size As System.Drawing.Size) As Bitmap
Return ExtractImage(path, size, DefaultColorDepth, 0)
End Function
''' <summary>
''' Used to request an image from an object, such as an item in a Shell folder.
''' </summary>
''' <param name="path">An absolute path to a file or folder.</param>
''' <param name="size"></param>
''' <param name="recommendedColorDepth">The recommended color depth in units of bits per pixel. The default is 32.</param>
Public Shared Function ExtractImage(ByVal path As String, ByVal size As System.Drawing.Size, ByVal recommendedColorDepth As Integer) As Bitmap
Return ExtractImage(path, size, recommendedColorDepth, 0)
End Function
''' <summary>
''' Used to request an image from an object, such as an item in a Shell folder.
''' </summary>
''' <param name="path">An absolute path to a file or folder.</param>
''' <param name="size"></param>
''' <param name="recommendedColorDepth">The recommended color depth in units of bits per pixel. The default is 32.</param>
Private Shared Function ExtractImage(ByVal path As String, ByVal size As System.Drawing.Size, ByVal recommendedColorDepth As Integer, ByVal flags As IEIFLAG) As Bitmap
Dim oResult As Bitmap = Nothing
Dim oDesktopFolder As IShellFolder = Nothing
Dim hParentIDL As IntPtr
Dim hIDL As IntPtr
Dim oParentFolder As IShellFolder
Dim hParentFolder As IntPtr
Dim oExtractImage As IExtractImage
Dim hExtractImage As IntPtr
'Divide the file name into a path and file/folder name.
Dim sFolderName As String = System.IO.Path.GetDirectoryName(path)
Dim sBaseName As String = System.IO.Path.GetFileName(path)
'Get the desktop IShellFolder.
If SHGetDesktopFolder(oDesktopFolder) <> Missico.Win32.S_OK Then
Throw New System.Runtime.InteropServices.COMException
End If
'Get the parent folder for the specified path.
oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, sFolderName, 0, hParentIDL, 0)
oDesktopFolder.BindToObject(hParentIDL, IntPtr.Zero, ShellGUIDs.IID_IShellFolder, hParentFolder)
oParentFolder = CType(Marshal.GetTypedObjectForIUnknown(hParentFolder, GetType(IShellFolder)), IShellFolder)
'Get the file/folder's IExtractImage
oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, sBaseName, 0, hIDL, 0)
oParentFolder.GetUIObjectOf(IntPtr.Zero, 1, New IntPtr() {hIDL}, ShellGUIDs.IID_IExtractImage, IntPtr.Zero, hExtractImage)
'Free the pidls. The Runtime Callable Wrappers (RCW) should automatically release the COM objects.
Marshal.FreeCoTaskMem(hParentIDL)
Marshal.FreeCoTaskMem(hIDL)
Marshal.FinalReleaseComObject(oParentFolder)
Marshal.FinalReleaseComObject(oDesktopFolder)
If hExtractImage = IntPtr.Zero Then
'There is no handler for this file, which is odd. I believe we should default the file's type icon.
Debug.WriteLine(String.Format("There is no thumbnail for the specified file '{0}'.", path), "ShellThumbnail.ExtractImage")
Else
oExtractImage = CType(Marshal.GetTypedObjectForIUnknown(hExtractImage, GetType(IExtractImage)), IExtractImage)
'Set the size and flags
Dim oSize As Missico.Win32.SIZE 'must specify a size
Dim iFlags As IEIFLAG = flags Or IEIFLAG.IEIFLAG_ORIGSIZE Or IEIFLAG.IEIFLAG_QUALITY Or IEIFLAG.IEIFLAG_ASPECT
If size.IsEmpty Then
oSize.cx = DefaultThumbnailSize.Width
oSize.cy = DefaultThumbnailSize.Height
Else
oSize.cx = size.Width
oSize.cy = size.Height
End If
Dim hBitmap As IntPtr
Dim sPath As New System.Text.StringBuilder(Missico.Win32.MAX_PATH, Missico.Win32.MAX_PATH)
oExtractImage.GetLocation(sPath, sPath.Capacity, 0, oSize, recommendedColorDepth, iFlags)
'if the specified path is to a folder then IExtractImage.Extract fails.
Try
oExtractImage.Extract(hBitmap)
Catch ex As System.Runtime.InteropServices.COMException
'clear the handle since extract failed
hBitmap = IntPtr.Zero
Debug.WriteLine(String.Format("There is no thumbnail for the specified folder '{0}'.", path), "ShellThumbnail.ExtractImage")
Finally
Marshal.FinalReleaseComObject(oExtractImage)
End Try
If Not hBitmap.Equals(IntPtr.Zero) Then
'create the image from the handle
oResult = System.Drawing.Bitmap.FromHbitmap(hBitmap)
'dump the properties to determine what kind of bitmap is returned
'Missico.Diagnostics.ObjectDumper.Write(oResult)
'Tag={ }
'PhysicalDimension={Width=96, Height=96}
'Size={Width=96, Height=96}
'Width=96
'Height=96
'HorizontalResolution=96
'VerticalResolution=96
'Flags=335888
'RawFormat={ }
'PixelFormat=Format32bppRgb
'Palette={ }
'FrameDimensionsList=...
'PropertyIdList=...
'PropertyItems=...
Missico.Win32.DeleteObject(hBitmap) 'release the handle
End If
End If
Return oResult
End Function
End Class
End Namespace
回答by Andrew Gale
The windows API code pack thumbnail calls are not supported by XP/2003 unfortunately.
不幸的是,XP/2003 不支持 Windows API 代码包缩略图调用。