vbAccelerator - Contents of code file: SysImageList.cs

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace vbAccelerator.Components.ImageList
{

   #region Public Enumerations
   public enum SysImageListSize : int
   {
      /// <summary>
      /// System Large Icon Size (typically 32x32)
      /// </summary>
      largeIcons = 0x0,
      /// <summary>
      /// System Small Icon Size (typically 16x16)
      /// </summary>
      smallIcons = 0x1,
      /// <summary>
      /// System Extra Large Icon Size (typically 48x48).
      /// Only available under XP; other OS return the
      /// Large Icon ImageList.
      /// </summary>
      extraLargeIcons = 0x2
   }

   [Flags]
   public enum ImageListDrawItemConstants : int
   {
      /// <summary>
      /// Draw item normally.
      /// </summary>
      ILD_NORMAL = 0x0,
      /// <summary>
      /// Draw item transparently.
      /// </summary>
      ILD_TRANSPARENT = 0x1,
      /// <summary>
      /// Draw item blended with 25% of the specified foreground colour
      /// or the Highlight colour if no foreground colour specified.
      /// </summary>
      ILD_BLEND25 = 0x2,
      /// <summary>
      /// Draw item blended with 50% of the specified foreground colour
      /// or the Highlight colour if no foreground colour specified.
      /// </summary>
      ILD_SELECTED = 0x4,
      /// <summary>
      /// Draw the icon's mask
      /// </summary>
      ILD_MASK = 0x10,
      /// <summary>
      /// Draw the icon image without using the mask
      /// </summary>
      ILD_IMAGE = 0x20,
      /// <summary>
      /// Draw the icon using the ROP specified.
      /// </summary>
      ILD_ROP = 0x40,
      /// <summary>
      /// ?
      /// </summary>
      ILD_OVERLAYMASK = 0xF00,
      /// <summary>
      /// Preserves the alpha channel in dest. XP only.
      /// </summary>
      ILD_PRESERVEALPHA = 0x1000, // 
      /// <summary>
      /// Scale the image to cx, cy instead of clipping it.  XP only.
      /// </summary>
      ILD_SCALE = 0x2000,
      /// <summary>
      /// Scale the image to the current DPI of the display. XP only.
      /// </summary>
      ILD_DPISCALE = 0x4000
   }
   #endregion

   #region SysImageList
   /// <summary>
   /// Summary description for SysImageList.
   /// </summary>
   public class SysImageList : IDisposable
   {
      #region UnmanagedCode
      private const int MAX_PATH = 260;
      
      [DllImport("shell32")]
      private static extern IntPtr SHGetFileInfo (
         string pszPath, 
         int dwFileAttributes,
         ref SHFILEINFO psfi, 
         uint cbFileInfo, 
         uint uFlags);

      [DllImport("user32.dll")]
      private static extern int DestroyIcon(IntPtr hIcon);

      private const int FILE_ATTRIBUTE_NORMAL = 0x80;
      private const int FILE_ATTRIBUTE_DIRECTORY = 0x10;

      private const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100; 
      private const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x2000;
      private const int FORMAT_MESSAGE_FROM_HMODULE = 0x800;
      private const int FORMAT_MESSAGE_FROM_STRING = 0x400;
      private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000;
      private const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x200;
      private const int FORMAT_MESSAGE_MAX_WIDTH_MASK = 0xFF;
      [DllImport("kernel32")]
      private extern static int FormatMessage (
         int dwFlags, 
         IntPtr lpSource, 
         int dwMessageId, 
         int dwLanguageId, 
         string lpBuffer,
         uint nSize, 
         int argumentsLong);

      [DllImport("kernel32")]
      private extern static int GetLastError();

      [DllImport("comctl32")]
      private extern static int ImageList_Draw(
         IntPtr hIml,
         int i,
         IntPtr hdcDst,
         int x,
         int y,
         int fStyle);

      [DllImport("comctl32")]
      private extern static int ImageList_DrawIndirect(
         ref IMAGELISTDRAWPARAMS pimldp);

      [DllImport("comctl32")]
      private extern static int ImageList_GetIconSize(
         IntPtr himl, 
         ref int cx, 
         ref int cy);

      [DllImport("comctl32")]
      private extern static IntPtr ImageList_GetIcon(
         IntPtr himl, 
         int i, 
         int flags);

      /// <summary>
      /// 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.
      /// </summary>
      [DllImport("shell32.dll", EntryPoint = "#727")]
      private extern static int SHGetImageList(
         int iImageList,
         ref Guid riid,
         ref IImageList ppv
         );


      #endregion
      
      #region Private Enumerations
      [Flags]      
         private enum SHGetFileInfoConstants : int
      {
         SHGFI_ICON = 0x100,                // get icon 
         SHGFI_DISPLAYNAME = 0x200,         // get display name 
         SHGFI_TYPENAME = 0x400,            // get type name 
         SHGFI_ATTRIBUTES = 0x800,          // get attributes 
         SHGFI_ICONLOCATION = 0x1000,       // get icon location 
         SHGFI_EXETYPE = 0x2000,            // return exe type 
         SHGFI_SYSICONINDEX = 0x4000,       // get system icon index 
         SHGFI_LINKOVERLAY = 0x8000,        // put a link overlay on icon 
         SHGFI_SELECTED = 0x10000,          // show icon in selected state 
         SHGFI_ATTR_SPECIFIED = 0x20000,    // get only specified attributes 
         SHGFI_LARGEICON = 0x0,             // get large icon 
         SHGFI_SMALLICON = 0x1,             // get small icon 
         SHGFI_OPENICON = 0x2,              // get open icon 
         SHGFI_SHELLICONSIZE = 0x4,         // get shell size icon 
         //SHGFI_PIDL = 0x8,                  // pszPath is a pidl 
         SHGFI_USEFILEATTRIBUTES = 0x10,     // use passed dwFileAttribute 
         SHGFI_ADDOVERLAYS = 0x000000020,     // apply the appropriate overlays
         SHGFI_OVERLAYINDEX = 0x000000040     // Get the index of the overlay
      }
      #endregion

      #region Private ImageList structures
      [StructLayout(LayoutKind.Sequential)]
         private struct RECT
      {
         int left;
         int top;
         int right;
         int bottom;
      }

      [StructLayout(LayoutKind.Sequential)]
         private struct POINT
      {
         int x;
         int y;
      }

      [StructLayout(LayoutKind.Sequential)]
         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;
      }

      [StructLayout(LayoutKind.Sequential)]
         private struct IMAGEINFO
      {
         public IntPtr hbmImage;
         public IntPtr hbmMask;
         public int Unused1;
         public int Unused2;
         public RECT rcImage;
      }
      [StructLayout(LayoutKind.Sequential)]
         private struct SHFILEINFO
      {
         public IntPtr hIcon;
         public int iIcon;
         public int dwAttributes;
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)]
         public string szDisplayName;
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst=80)]
         public string szTypeName;
      }
      #endregion

      #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

      #region Member Variables
      private IntPtr hIml = IntPtr.Zero;
      private IImageList iImageList = null;
      private SysImageListSize size = SysImageListSize.smallIcons;
      private bool disposed = false;
      #endregion

      #region Implementation

      #region Properties
      /// <summary>
      /// Gets/sets the size of System Image List to retrieve.
      /// </summary>
      public SysImageListSize ImageListSize
      {
         get
         {
            return size;
         }
         set
         {
            size = value;
            create();
         }

      }

      /// <summary>
      /// Returns the size of the Image List Icons.
      /// </summary>
      public System.Drawing.Size Size
      {
         get
         {
            int cx = 0; 
            int cy = 0;
            if (iImageList == null)
            {
               ImageList_GetIconSize(
                  hIml,
                  ref cx, 
                  ref cy);
            }
            else
            {
               iImageList.GetIconSize(ref cx, ref cy);
            }
            System.Drawing.Size sz = new System.Drawing.Size(
               cx, cy);
            return sz;
         }      
      }
      #endregion

      #region Methods
      /// <summary>
      /// Returns a GDI+ copy of the icon from the ImageList
      /// at the specified index.
      /// </summary>
      /// <param name="index"></param>
      /// <returns></returns>
      public Icon Icon(int index)
      {
         Icon icon = null;

         IntPtr hIcon = IntPtr.Zero;
         if (iImageList == null)
         {
            hIcon = ImageList_GetIcon(
               hIml,
               index,
               (int)ImageListDrawItemConstants.ILD_TRANSPARENT);

         }
         else
         {
            iImageList.GetIcon(
               index,
               (int)ImageListDrawItemConstants.ILD_TRANSPARENT,
               ref hIcon);
         }

         if (hIcon != IntPtr.Zero)
         {
            icon = System.Drawing.Icon.FromHandle(hIcon);
         }            
         return icon;
      }

      /// <summary>
      /// Return the index of the icon for the specified file, always using 
      /// the cached version where possible.
      /// </summary>
      /// <param name="fileName">Filename to get icon for</param>
      /// <returns></returns>
      public int IconIndex(string fileName)
      {
         return IconIndex(fileName, false);
      }

      /// <summary>
      /// Returns the index of the icon for the specified file
      /// </summary>
      /// <param name="fileName">Filename to get icon for</param>
      /// <param name="forceLoadFromDisk">If True, then hit the disk to get the
       icon,
      /// otherwise only hit the disk if no cached icon is available.</param>
      /// <returns></returns>
      public int IconIndex(string fileName, bool forceLoadFromDisk)
      {
         SHGetFileInfoConstants dwFlags =
          SHGetFileInfoConstants.SHGFI_SYSICONINDEX;
         int dwAttr = 0;
         if (size == SysImageListSize.smallIcons)
         {
            dwFlags |= SHGetFileInfoConstants.SHGFI_SMALLICON;
         }

         // We can choose whether to access the disk or not. If you don't
         // hit the disk, you may get the wrong icon if the icon is
         // not cached. But the speed is very good!
         if (!forceLoadFromDisk)
         {
            dwFlags |= SHGetFileInfoConstants.SHGFI_USEFILEATTRIBUTES;
            dwAttr = FILE_ATTRIBUTE_NORMAL;
         }
         else
         {            
            dwAttr = 0;
         }

         // sFileSpec can be any file. You can specify a
         // file that does not exist and still get the
         // icon, for example sFileSpec = "C:\PANTS.DOC"
         SHFILEINFO shfi = new SHFILEINFO();
         uint shfiSize = (uint)Marshal.SizeOf(shfi.GetType());
         IntPtr retVal = SHGetFileInfo( 
            fileName, dwAttr, ref shfi, shfiSize, 
            (uint)dwFlags);           

         if (retVal.Equals(IntPtr.Zero))
         {
            System.Diagnostics.Debug.Assert((!retVal.Equals(IntPtr.Zero)),"Faile
            d to get icon index");
            return 0;
         }
         else
         {
            return shfi.iIcon;
         }
      }

      /// <summary>
      /// Draws an image
      /// </summary>
      /// <param name="hdc">Device context to draw to</param>
      /// <param name="index">Index of image to draw</param>
      /// <param name="x">X Position to draw at</param>
      /// <param name="y">Y Position to draw at</param>
      public void DrawImage( 
         IntPtr hdc,
         int index, 
         int x,
         int y
         )
      {
         DrawImage(hdc, index, x, y,
          ImageListDrawItemConstants.ILD_TRANSPARENT);
      }

      /// <summary>
      /// Draws an image using the specified flags
      /// </summary>
      /// <param name="hdc">Device context to draw to</param>
      /// <param name="index">Index of image to draw</param>
      /// <param name="x">X Position to draw at</param>
      /// <param name="y">Y Position to draw at</param>
      /// <param name="flags">Drawing flags</param>
      public void DrawImage(
         IntPtr hdc,
         int index,
         int x,
         int y,
         ImageListDrawItemConstants flags
         )
      {
         if (iImageList == null)
         {
            int ret = ImageList_Draw(
               hIml, 
               index, 
               hdc, 
               x, 
               y, 
               (int)flags);
         }
         else
         {
            IMAGELISTDRAWPARAMS pimldp = new IMAGELISTDRAWPARAMS();
            pimldp.hdcDst = hdc;
            pimldp.cbSize = Marshal.SizeOf(pimldp.GetType());
            pimldp.i = index;
            pimldp.x = x;
            pimldp.y = y;
            pimldp.fStyle = (int)flags;
            iImageList.Draw(ref pimldp);
         }
         
      }

      /// <summary>
      /// Draws an image using the specified flags
      /// </summary>
      /// <param name="hdc">Device context to draw to</param>
      /// <param name="index">Index of image to draw</param>
      /// <param name="x">X Position to draw at</param>
      /// <param name="y">Y Position to draw at</param>
      /// <param name="flags">Drawing flags</param>
      /// <param name="cx">Width to draw</param>
      /// <param name="cy">Height to draw</param>
      public void DrawImage(
         IntPtr hdc,
         int index,
         int x,
         int y,
         ImageListDrawItemConstants flags,
         int cx,
         int cy
         )
      {
         IMAGELISTDRAWPARAMS pimldp = new IMAGELISTDRAWPARAMS();
         pimldp.hdcDst = hdc;
         pimldp.cbSize = Marshal.SizeOf(pimldp.GetType());
         pimldp.i = index;
         pimldp.x = x;
         pimldp.y = y;
         pimldp.cx = cx;
         pimldp.cy = cy;
         pimldp.fStyle = (int)flags;
         if (iImageList == null)
         {
            int ret = ImageList_DrawIndirect(ref pimldp);
         }
         else
         {

            iImageList.Draw(ref pimldp);
         }
      }

      /// <summary>
      /// Determines if the system is running Windows XP
      /// or above
      /// </summary>
      /// <returns>True if system is running XP or above, False
       otherwise</returns>
      private bool isXpOrAbove()
      {
         bool ret = false;
         if (Environment.OSVersion.Version.Major > 5)
         {
            ret = true;
         }
         else if ((Environment.OSVersion.Version.Major == 5) &&
            (Environment.OSVersion.Version.Minor >= 1))
         {
            ret = true;
         }
         return ret;
      }

      /// <summary>
      /// Creates the SystemImageList
      /// </summary>
      private void create()
      {
         // forget last image list if any:
         hIml = IntPtr.Zero;

         if (isXpOrAbove())
         {
            Guid iidImageList = new
             Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
            int ret = SHGetImageList(
               (int)size,
               ref iidImageList,
               ref iImageList
               );
         }
         else
         {
            // Prepare flags:
            SHGetFileInfoConstants dwFlags =
             SHGetFileInfoConstants.SHGFI_USEFILEATTRIBUTES |
             SHGetFileInfoConstants.SHGFI_SYSICONINDEX ;
            if (size == SysImageListSize.smallIcons)
            {
               dwFlags |= SHGetFileInfoConstants.SHGFI_SMALLICON;
            }
            // Get image list
            SHFILEINFO shfi = new SHFILEINFO();
            uint shfiSize = (uint)Marshal.SizeOf(shfi.GetType());

            hIml = SHGetFileInfo(".txt", FILE_ATTRIBUTE_NORMAL, ref shfi,
             shfiSize, (uint)dwFlags);
            System.Diagnostics.Debug.Assert ((hIml != IntPtr.Zero),"Failed to
             create Image List");
         }
      }

      /// <summary>
      /// Gets the hImageList handle
      /// </summary>
      public IntPtr Handle
      {
         get
         {
            if (iImageList == null)
            {
               return this.hIml;
            }
            else
            {
               return Marshal.GetIUnknownForObject(
                  iImageList);                  
            }
         }
      }
      #endregion

      #region Constructor, Dispose, Destructor
      /// <summary>
      /// Creates a Small Icons SystemImageList 
      /// </summary>
      public SysImageList()
      {
         create();
      }
      /// <summary>
      /// Creates a SystemImageList with the specified size
      /// </summary>
      /// <param name="size">Size of System ImageList</param>
      public SysImageList(SysImageListSize size)
      {
         this.size = size;
         create();
      }
      public void Dispose()
      {
         Dispose(true);
         GC.SuppressFinalize(this);
      }
      public virtual void Dispose(bool disposing)
      {
         if (!disposed)
         {
            if (disposing) 
            {
               if (iImageList != null)
               {
                  Marshal.ReleaseComObject(iImageList);
               }
               iImageList = null;
            }
         }
         disposed = true;
      }
      ~SysImageList()
      {
         Dispose(false);
      }

   }
   #endregion

      #endregion

   #endregion
}