Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FolderDropDown thumbnail preview support
- Loading branch information
1 parent
f6f5ff4
commit c3048d0
Showing
2 changed files
with
318 additions
and
13 deletions.
There are no files selected for viewing
207 changes: 207 additions & 0 deletions
207
src/Lively/Lively.Common/Helpers/Shell/ThumbnailUtil.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Drawing.Imaging; | ||
using System.Drawing; | ||
using System.IO; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
|
||
namespace Lively.Common.Helpers.Shell | ||
{ | ||
//Ref: https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows/21752100 | ||
public static class ThumbnailUtil | ||
{ | ||
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93"; | ||
|
||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | ||
internal static extern int SHCreateItemFromParsingName( | ||
[MarshalAs(UnmanagedType.LPWStr)] string path, | ||
// The following parameter is not used - binding context. | ||
IntPtr pbc, | ||
ref Guid riid, | ||
[MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem); | ||
|
||
[DllImport("gdi32.dll")] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
internal static extern bool DeleteObject(IntPtr hObject); | ||
|
||
[ComImport] | ||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | ||
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] | ||
internal interface IShellItem | ||
{ | ||
void BindToHandler(IntPtr pbc, | ||
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid, | ||
[MarshalAs(UnmanagedType.LPStruct)] Guid riid, | ||
out IntPtr ppv); | ||
|
||
void GetParent(out IShellItem ppsi); | ||
void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName); | ||
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); | ||
void Compare(IShellItem psi, uint hint, out int piOrder); | ||
}; | ||
|
||
internal enum SIGDN : uint | ||
{ | ||
NORMALDISPLAY = 0, | ||
PARENTRELATIVEPARSING = 0x80018001, | ||
PARENTRELATIVEFORADDRESSBAR = 0x8001c001, | ||
DESKTOPABSOLUTEPARSING = 0x80028000, | ||
PARENTRELATIVEEDITING = 0x80031001, | ||
DESKTOPABSOLUTEEDITING = 0x8004c000, | ||
FILESYSPATH = 0x80058000, | ||
URL = 0x80068000 | ||
} | ||
|
||
internal enum HResult | ||
{ | ||
Ok = 0x0000, | ||
False = 0x0001, | ||
InvalidArguments = unchecked((int)0x80070057), | ||
OutOfMemory = unchecked((int)0x8007000E), | ||
NoInterface = unchecked((int)0x80004002), | ||
Fail = unchecked((int)0x80004005), | ||
ElementNotFound = unchecked((int)0x80070490), | ||
TypeElementNotFound = unchecked((int)0x8002802B), | ||
NoObject = unchecked((int)0x800401E5), | ||
Win32ErrorCanceled = 1223, | ||
Canceled = unchecked((int)0x800704C7), | ||
ResourceInUse = unchecked((int)0x800700AA), | ||
AccessDenied = unchecked((int)0x80030005) | ||
} | ||
|
||
[ComImportAttribute()] | ||
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")] | ||
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] | ||
internal interface IShellItemImageFactory | ||
{ | ||
[PreserveSig] | ||
HResult GetImage( | ||
[In, MarshalAs(UnmanagedType.Struct)] NativeSize size, | ||
[In] ThumbnailOptions flags, | ||
[Out] out IntPtr phbm); | ||
} | ||
|
||
[StructLayout(LayoutKind.Sequential)] | ||
internal struct NativeSize | ||
{ | ||
private int width; | ||
private int height; | ||
|
||
public int Width { set { width = value; } } | ||
public int Height { set { height = value; } } | ||
}; | ||
|
||
[StructLayout(LayoutKind.Sequential)] | ||
public struct RGBQUAD | ||
{ | ||
public byte rgbBlue; | ||
public byte rgbGreen; | ||
public byte rgbRed; | ||
public byte rgbReserved; | ||
} | ||
|
||
public static Bitmap GetThumbnail(string fileName, int width, int height, ThumbnailOptions options) | ||
{ | ||
IntPtr hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options); | ||
|
||
try | ||
{ | ||
// return a System.Drawing.Bitmap from the hBitmap | ||
return GetBitmapFromHBitmap(hBitmap); | ||
} | ||
finally | ||
{ | ||
// delete HBitmap to avoid memory leaks | ||
DeleteObject(hBitmap); | ||
} | ||
} | ||
|
||
public static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap) | ||
{ | ||
Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap); | ||
|
||
if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32) | ||
return bmp; | ||
|
||
return CreateAlphaBitmap(bmp, PixelFormat.Format32bppArgb); | ||
} | ||
|
||
public static Bitmap CreateAlphaBitmap(Bitmap srcBitmap, PixelFormat targetPixelFormat) | ||
{ | ||
Bitmap result = new Bitmap(srcBitmap.Width, srcBitmap.Height, targetPixelFormat); | ||
|
||
Rectangle bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height); | ||
|
||
BitmapData srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat); | ||
|
||
bool isAlplaBitmap = false; | ||
|
||
try | ||
{ | ||
for (int y = 0; y <= srcData.Height - 1; y++) | ||
{ | ||
for (int x = 0; x <= srcData.Width - 1; x++) | ||
{ | ||
Color pixelColor = Color.FromArgb( | ||
Marshal.ReadInt32(srcData.Scan0, (srcData.Stride * y) + (4 * x))); | ||
|
||
if (pixelColor.A > 0 & pixelColor.A < 255) | ||
{ | ||
isAlplaBitmap = true; | ||
} | ||
|
||
result.SetPixel(x, y, pixelColor); | ||
} | ||
} | ||
} | ||
finally | ||
{ | ||
srcBitmap.UnlockBits(srcData); | ||
} | ||
|
||
if (isAlplaBitmap) | ||
{ | ||
return result; | ||
} | ||
else | ||
{ | ||
return srcBitmap; | ||
} | ||
} | ||
|
||
private static IntPtr GetHBitmap(string fileName, int width, int height, ThumbnailOptions options) | ||
{ | ||
IShellItem nativeShellItem; | ||
Guid shellItem2Guid = new Guid(IShellItem2Guid); | ||
int retCode = SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem); | ||
|
||
if (retCode != 0) | ||
throw Marshal.GetExceptionForHR(retCode); | ||
|
||
NativeSize nativeSize = new NativeSize(); | ||
nativeSize.Width = width; | ||
nativeSize.Height = height; | ||
|
||
IntPtr hBitmap; | ||
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, options, out hBitmap); | ||
|
||
Marshal.ReleaseComObject(nativeShellItem); | ||
|
||
if (hr == HResult.Ok) return hBitmap; | ||
|
||
throw Marshal.GetExceptionForHR((int)hr); | ||
} | ||
|
||
[Flags] | ||
public enum ThumbnailOptions | ||
{ | ||
None = 0x00, | ||
BiggerSizeOk = 0x01, | ||
InMemoryOnly = 0x02, | ||
IconOnly = 0x04, | ||
ThumbnailOnly = 0x08, | ||
InCacheOnly = 0x10, | ||
} | ||
} | ||
} |
Oops, something went wrong.
c3048d0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.