mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
Well this took enough time! I have almost corrected all the issues with the icon parsing functions, but I still have a couple of edge cases to fix.
602 lines
18 KiB
C#
602 lines
18 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Drawing;
|
|
using System.Windows;
|
|
|
|
namespace DisplayMagician
|
|
{
|
|
class IconFromFile
|
|
{
|
|
|
|
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
|
|
|
// Constants that we need in the function call
|
|
|
|
private const int SHGFI_ICON = 0x100;
|
|
|
|
private const int SHGFI_SMALLICON = 0x1;
|
|
|
|
private const int SHGFI_LARGEICON = 0x0;
|
|
|
|
private const int SHIL_JUMBO = 0x4;
|
|
private const int SHIL_EXTRALARGE = 0x2;
|
|
|
|
// This structure will contain information about the file
|
|
|
|
public struct SHFILEINFO
|
|
{
|
|
|
|
// Handle to the icon representing the file
|
|
|
|
public IntPtr hIcon;
|
|
|
|
// Index of the icon within the image list
|
|
|
|
public int iIcon;
|
|
|
|
// Various attributes of the file
|
|
|
|
public uint dwAttributes;
|
|
|
|
// Path to the file
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
|
|
|
public string szDisplayName;
|
|
|
|
// File type
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
|
|
|
|
public string szTypeName;
|
|
|
|
};
|
|
|
|
[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
|
|
public static extern Boolean CloseHandle(IntPtr handle);
|
|
|
|
#pragma warning disable 0649
|
|
private struct IMAGELISTDRAWPARAMS
|
|
{
|
|
public int cbSize;
|
|
public IntPtr himl;
|
|
public int i;
|
|
public IntPtr hdcDst;
|
|
public int x;
|
|
public int y;
|
|
public int cx;
|
|
public int cy;
|
|
public int xBitmap; // x offest from the upperleft of bitmap
|
|
public int yBitmap; // y offset from the upperleft of bitmap
|
|
public int rgbBk;
|
|
public int rgbFg;
|
|
public int fStyle;
|
|
public int dwRop;
|
|
public int fState;
|
|
public int Frame;
|
|
public int crEffect;
|
|
}
|
|
#pragma warning restore 0649
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct IMAGEINFO
|
|
{
|
|
public IntPtr hbmImage;
|
|
public IntPtr hbmMask;
|
|
public int Unused1;
|
|
public int Unused2;
|
|
public Rect rcImage;
|
|
}
|
|
|
|
#region Private ImageList COM Interop (XP)
|
|
[ComImportAttribute()]
|
|
[GuidAttribute("46EB5926-582E-4017-9FDF-E8998DAA0950")]
|
|
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
|
|
//helpstring("Image List"),
|
|
interface IImageList
|
|
{
|
|
[PreserveSig]
|
|
int Add(
|
|
IntPtr hbmImage,
|
|
IntPtr hbmMask,
|
|
ref int pi);
|
|
|
|
[PreserveSig]
|
|
int ReplaceIcon(
|
|
int i,
|
|
IntPtr hicon,
|
|
ref int pi);
|
|
|
|
[PreserveSig]
|
|
int SetOverlayImage(
|
|
int iImage,
|
|
int iOverlay);
|
|
|
|
[PreserveSig]
|
|
int Replace(
|
|
int i,
|
|
IntPtr hbmImage,
|
|
IntPtr hbmMask);
|
|
|
|
[PreserveSig]
|
|
int AddMasked(
|
|
IntPtr hbmImage,
|
|
int crMask,
|
|
ref int pi);
|
|
|
|
[PreserveSig]
|
|
int Draw(
|
|
ref IMAGELISTDRAWPARAMS pimldp);
|
|
|
|
[PreserveSig]
|
|
int Remove(
|
|
int i);
|
|
|
|
[PreserveSig]
|
|
int GetIcon(
|
|
int i,
|
|
int flags,
|
|
ref IntPtr picon);
|
|
|
|
[PreserveSig]
|
|
int GetImageInfo(
|
|
int i,
|
|
ref IMAGEINFO pImageInfo);
|
|
|
|
[PreserveSig]
|
|
int Copy(
|
|
int iDst,
|
|
IImageList punkSrc,
|
|
int iSrc,
|
|
int uFlags);
|
|
|
|
[PreserveSig]
|
|
int Merge(
|
|
int i1,
|
|
IImageList punk2,
|
|
int i2,
|
|
int dx,
|
|
int dy,
|
|
ref Guid riid,
|
|
ref IntPtr ppv);
|
|
|
|
[PreserveSig]
|
|
int Clone(
|
|
ref Guid riid,
|
|
ref IntPtr ppv);
|
|
|
|
[PreserveSig]
|
|
int GetImageRect(
|
|
int i,
|
|
ref Rect prc);
|
|
|
|
[PreserveSig]
|
|
int GetIconSize(
|
|
ref int cx,
|
|
ref int cy);
|
|
|
|
[PreserveSig]
|
|
int SetIconSize(
|
|
int cx,
|
|
int cy);
|
|
|
|
[PreserveSig]
|
|
int GetImageCount(
|
|
ref int pi);
|
|
|
|
[PreserveSig]
|
|
int SetImageCount(
|
|
int uNewCount);
|
|
|
|
[PreserveSig]
|
|
int SetBkColor(
|
|
int clrBk,
|
|
ref int pclr);
|
|
|
|
[PreserveSig]
|
|
int GetBkColor(
|
|
ref int pclr);
|
|
|
|
[PreserveSig]
|
|
int BeginDrag(
|
|
int iTrack,
|
|
int dxHotspot,
|
|
int dyHotspot);
|
|
|
|
[PreserveSig]
|
|
int EndDrag();
|
|
|
|
[PreserveSig]
|
|
int DragEnter(
|
|
IntPtr hwndLock,
|
|
int x,
|
|
int y);
|
|
|
|
[PreserveSig]
|
|
int DragLeave(
|
|
IntPtr hwndLock);
|
|
|
|
[PreserveSig]
|
|
int DragMove(
|
|
int x,
|
|
int y);
|
|
|
|
[PreserveSig]
|
|
int SetDragCursorImage(
|
|
ref IImageList punk,
|
|
int iDrag,
|
|
int dxHotspot,
|
|
int dyHotspot);
|
|
|
|
[PreserveSig]
|
|
int DragShowNolock(
|
|
int fShow);
|
|
|
|
/* [PreserveSig]
|
|
int GetDragImage(
|
|
ref Point ppt,
|
|
ref Point pptHotspot,
|
|
ref Guid riid,
|
|
ref IntPtr ppv);*/
|
|
|
|
[PreserveSig]
|
|
int GetItemFlags(
|
|
int i,
|
|
ref int dwFlags);
|
|
|
|
[PreserveSig]
|
|
int GetOverlayImage(
|
|
int iOverlay,
|
|
ref int piIndex);
|
|
};
|
|
#endregion
|
|
|
|
///
|
|
/// SHGetImageList is not exported correctly in XP. See KB316931
|
|
/// http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q316931
|
|
/// Apparently (and hopefully) ordinal 727 isn't going to change.
|
|
///
|
|
[DllImport("shell32.dll", EntryPoint = "#727")]
|
|
private extern static int SHGetImageList(
|
|
int iImageList,
|
|
ref Guid riid,
|
|
out IImageList ppv
|
|
);
|
|
|
|
// The signature of SHGetFileInfo (located in Shell32.dll)
|
|
[DllImport("Shell32.dll")]
|
|
public static extern int SHGetFileInfo(string pszPath, int dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);
|
|
|
|
[DllImport("Shell32.dll")]
|
|
public static extern int SHGetFileInfo(IntPtr pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);
|
|
|
|
[DllImport("shell32.dll", SetLastError = true)]
|
|
static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, Int32 nFolder,
|
|
ref IntPtr ppidl);
|
|
|
|
[DllImport("user32")]
|
|
public static extern int DestroyIcon(IntPtr hIcon);
|
|
|
|
public struct Pair
|
|
{
|
|
public System.Drawing.Icon Icon { get; set; }
|
|
public IntPtr IconHandleToDestroy { set; get; }
|
|
|
|
}
|
|
|
|
public static int DestroyIcon2(IntPtr hIcon)
|
|
{
|
|
return DestroyIcon(hIcon);
|
|
}
|
|
|
|
/*private static BitmapSource bitmap_source_of_icon(System.Drawing.Icon ic)
|
|
{
|
|
var ic2 = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(ic.Handle,
|
|
System.Windows.Int32Rect.Empty,
|
|
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
|
|
ic2.Freeze();
|
|
return ((BitmapSource)ic2);
|
|
}*/
|
|
|
|
/*public static BitmapSource SystemIcon(bool small, ShellLib.ShellApi.CSIDL csidl)
|
|
{
|
|
|
|
IntPtr pidlTrash = IntPtr.Zero;
|
|
int hr = SHGetSpecialFolderLocation(IntPtr.Zero, (int)csidl, ref pidlTrash);
|
|
Debug.Assert(hr == 0);
|
|
|
|
SHFILEINFO shinfo = new SHFILEINFO();
|
|
|
|
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
|
|
|
// Get a handle to the large icon
|
|
uint flags;
|
|
uint SHGFI_PIDL = 0x000000008;
|
|
if (!small)
|
|
{
|
|
flags = SHGFI_PIDL | SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES;
|
|
}
|
|
else
|
|
{
|
|
flags = SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES;
|
|
}
|
|
|
|
var res = SHGetFileInfo(pidlTrash, 0, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
|
Debug.Assert(res != 0);
|
|
|
|
var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
|
|
Marshal.FreeCoTaskMem(pidlTrash);
|
|
var bs = bitmap_source_of_icon(myIcon);
|
|
myIcon.Dispose();
|
|
bs.Freeze(); // importantissimo se no fa memory leak
|
|
DestroyIcon(shinfo.hIcon);
|
|
CloseHandle(shinfo.hIcon);
|
|
return bs;
|
|
|
|
}*/
|
|
|
|
/* public static BitmapSource GetSmallBitmapFromFile(string FileName, bool small, bool checkDisk, bool addOverlay)
|
|
{
|
|
SHFILEINFO shinfo = new SHFILEINFO();
|
|
|
|
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
|
uint SHGFI_LINKOVERLAY = 0x000008000;
|
|
|
|
uint flags;
|
|
if (small)
|
|
{
|
|
flags = SHGFI_ICON | SHGFI_SMALLICON;
|
|
}
|
|
else
|
|
{
|
|
flags = SHGFI_ICON | SHGFI_LARGEICON;
|
|
}
|
|
if (!checkDisk)
|
|
flags |= SHGFI_USEFILEATTRIBUTES;
|
|
if (addOverlay)
|
|
flags |= SHGFI_LINKOVERLAY;
|
|
|
|
var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
|
if (res == 0)
|
|
{
|
|
throw (new System.IO.FileNotFoundException());
|
|
}
|
|
|
|
var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
|
|
|
|
var bs = bitmap_source_of_icon(myIcon);
|
|
myIcon.Dispose();
|
|
bs.Freeze(); // importantissimo se no fa memory leak
|
|
DestroyIcon(shinfo.hIcon);
|
|
CloseHandle(shinfo.hIcon);
|
|
return bs;
|
|
|
|
}*/
|
|
|
|
public static Bitmap GetSmallBitmapFromFile(string FileName, bool small, bool checkDisk, bool addOverlay)
|
|
{
|
|
SHFILEINFO shinfo = new SHFILEINFO();
|
|
|
|
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
|
uint SHGFI_LINKOVERLAY = 0x000008000;
|
|
|
|
uint flags;
|
|
if (small)
|
|
{
|
|
flags = SHGFI_ICON | SHGFI_SMALLICON;
|
|
}
|
|
else
|
|
{
|
|
flags = SHGFI_ICON | SHGFI_LARGEICON;
|
|
}
|
|
if (!checkDisk)
|
|
flags |= SHGFI_USEFILEATTRIBUTES;
|
|
if (addOverlay)
|
|
flags |= SHGFI_LINKOVERLAY;
|
|
|
|
var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
|
if (res == 0)
|
|
{
|
|
throw (new System.IO.FileNotFoundException());
|
|
}
|
|
|
|
var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
|
|
|
|
Bitmap bm = myIcon.ToBitmap();
|
|
myIcon.Dispose();
|
|
DestroyIcon(shinfo.hIcon);
|
|
//CloseHandle(shinfo.hIcon);
|
|
return bm;
|
|
|
|
}
|
|
|
|
/*public static BitmapSource GetLargeBitmapSourceFromFile(string FileName, bool jumbo, bool checkDisk)
|
|
{
|
|
|
|
SHFILEINFO shinfo = new SHFILEINFO();
|
|
|
|
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
|
uint SHGFI_SYSICONINDEX = 0x4000;
|
|
|
|
int FILE_ATTRIBUTE_NORMAL = 0x80;
|
|
|
|
uint flags;
|
|
flags = SHGFI_SYSICONINDEX;
|
|
|
|
if (!checkDisk) // This does not seem to work. If I try it, a folder icon is always returned.
|
|
flags |= SHGFI_USEFILEATTRIBUTES;
|
|
|
|
var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
|
if (res == 0)
|
|
{
|
|
throw (new System.IO.FileNotFoundException());
|
|
}
|
|
var iconIndex = shinfo.iIcon;
|
|
|
|
// Get the System IImageList object from the Shell:
|
|
Guid iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
|
|
|
|
IImageList iml;
|
|
int size = jumbo ? SHIL_JUMBO : SHIL_EXTRALARGE;
|
|
var hres = SHGetImageList(size, ref iidImageList, out iml); // writes iml
|
|
//if (hres == 0)
|
|
//{
|
|
// throw (new System.Exception("Error SHGetImageList"));
|
|
//}
|
|
|
|
IntPtr hIcon = IntPtr.Zero;
|
|
int ILD_TRANSPARENT = 1;
|
|
hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon);
|
|
//if (hres == 0)
|
|
//{
|
|
// throw (new System.Exception("Error iml.GetIcon"));
|
|
//}
|
|
|
|
var myIcon = System.Drawing.Icon.FromHandle(hIcon);
|
|
var bs = bitmap_source_of_icon(myIcon);
|
|
myIcon.Dispose();
|
|
bs.Freeze(); // very important to avoid memory leak
|
|
DestroyIcon(hIcon);
|
|
CloseHandle(hIcon);
|
|
|
|
return bs;
|
|
|
|
}*/
|
|
|
|
public static Icon GetSmallIconFromFile(string FileName, bool small, bool checkDisk, bool addOverlay)
|
|
{
|
|
SHFILEINFO shinfo = new SHFILEINFO();
|
|
|
|
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
|
uint SHGFI_LINKOVERLAY = 0x000008000;
|
|
|
|
uint flags;
|
|
if (small)
|
|
{
|
|
flags = SHGFI_ICON | SHGFI_SMALLICON;
|
|
}
|
|
else
|
|
{
|
|
flags = SHGFI_ICON | SHGFI_LARGEICON;
|
|
}
|
|
if (!checkDisk)
|
|
flags |= SHGFI_USEFILEATTRIBUTES;
|
|
if (addOverlay)
|
|
flags |= SHGFI_LINKOVERLAY;
|
|
|
|
var res = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
|
if (res == 0)
|
|
{
|
|
throw (new System.IO.FileNotFoundException());
|
|
}
|
|
|
|
var myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
|
|
DestroyIcon(shinfo.hIcon);
|
|
//CloseHandle(shinfo.hIcon);
|
|
return myIcon;
|
|
|
|
}
|
|
|
|
public static Icon GetLargeIconFromFile(string FileName, bool jumbo, bool checkDisk)
|
|
{
|
|
|
|
SHFILEINFO shinfo = new SHFILEINFO();
|
|
|
|
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
|
uint SHGFI_SYSICONINDEX = 0x4000;
|
|
|
|
int FILE_ATTRIBUTE_NORMAL = 0x80;
|
|
|
|
uint flags;
|
|
flags = SHGFI_SYSICONINDEX;
|
|
|
|
if (!checkDisk) // This does not seem to work. If I try it, a folder icon is always returned.
|
|
flags |= SHGFI_USEFILEATTRIBUTES;
|
|
|
|
var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
|
if (res == 0)
|
|
{
|
|
throw (new System.IO.FileNotFoundException());
|
|
}
|
|
var iconIndex = shinfo.iIcon;
|
|
|
|
// Get the System IImageList object from the Shell:
|
|
Guid iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
|
|
|
|
int size = jumbo ? SHIL_JUMBO : SHIL_EXTRALARGE;
|
|
var hres = SHGetImageList(size, ref iidImageList, out IImageList iml); // writes iml
|
|
//if (hres == 0)
|
|
//{
|
|
// throw (new System.Exception("Error SHGetImageList"));
|
|
//}
|
|
|
|
IntPtr hIcon = IntPtr.Zero;
|
|
int ILD_TRANSPARENT = 1;
|
|
hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon);
|
|
//if (hres == 0)
|
|
//{
|
|
// throw (new System.Exception("Error iml.GetIcon"));
|
|
//}
|
|
|
|
var myIcon = System.Drawing.Icon.FromHandle(hIcon);
|
|
//myIcon.Dispose();
|
|
//DestroyIcon(hIcon);
|
|
//CloseHandle(hIcon);
|
|
|
|
return myIcon;
|
|
|
|
}
|
|
|
|
public static Bitmap GetLargeBitmapFromFile(string FileName, bool jumbo, bool checkDisk)
|
|
{
|
|
|
|
SHFILEINFO shinfo = new SHFILEINFO();
|
|
|
|
uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
|
uint SHGFI_SYSICONINDEX = 0x4000;
|
|
|
|
int FILE_ATTRIBUTE_NORMAL = 0x80;
|
|
|
|
uint flags;
|
|
flags = SHGFI_SYSICONINDEX;
|
|
|
|
if (!checkDisk) // This does not seem to work. If I try it, a folder icon is always returned.
|
|
flags |= SHGFI_USEFILEATTRIBUTES;
|
|
|
|
var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
|
if (res == 0)
|
|
{
|
|
throw (new System.IO.FileNotFoundException());
|
|
}
|
|
var iconIndex = shinfo.iIcon;
|
|
|
|
// Get the System IImageList object from the Shell:
|
|
Guid iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
|
|
|
|
int size = jumbo ? SHIL_JUMBO : SHIL_EXTRALARGE;
|
|
var hres = SHGetImageList(size, ref iidImageList, out IImageList iml); // writes iml
|
|
//if (hres == 0)
|
|
//{
|
|
// throw (new System.Exception("Error SHGetImageList"));
|
|
//}
|
|
|
|
IntPtr hIcon = IntPtr.Zero;
|
|
int ILD_TRANSPARENT = 1;
|
|
hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon);
|
|
/*if (hres == 0)
|
|
{
|
|
return new Bitmap(1, 1);
|
|
}*/
|
|
|
|
var myIcon = System.Drawing.Icon.FromHandle(hIcon);
|
|
Bitmap bm = myIcon.ToBitmap();
|
|
myIcon.Dispose();
|
|
DestroyIcon(hIcon);
|
|
//CloseHandle(hIcon);
|
|
|
|
return bm;
|
|
|
|
}
|
|
}
|
|
}
|