IconEx.cs :  » Build-Systems » NETZ » vbAccelerator » Components » Win32 » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Build Systems » NETZ 
NETZ » vbAccelerator » Components » Win32 » IconEx.cs
/*

The IconEx is taken from:
.NET Icon Explorer
by Steve McMahon steve@vbaccelerator.com
http://vbaccelerator.com/home/NET/Utilities/Icon_Extractor/article.asp
http://vbaccelerator.com/home/NET/Utilities/Icon_Extractor/IconExplorer.asp
http://vbaccelerator.com/home/NET/Utilities/Icon_Extractor/IconExplorer_zip_IconEx%5CIconEx_cs.asp

*/

using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace vbAccelerator.Components.Win32{
   #region IconExException
   /// <summary>
   /// Exception thrown for unreadable icons
   /// </summary>
   public class IconExException : Exception
   {
      public IconExException() : base()
      {
      }
      public IconExException(string message) : base(message)
      {
      }
      public IconExException(string message, Exception innerException) :
       base(message, innerException)
      {
      }
   }
   #endregion

   #region IconEx
   /// <summary>
   /// Manages a true Windows Icon with multiple images
   /// (colour depths and sizes)
   /// </summary>
   public class IconEx : IDisposable
   {
      #region Unmanaged Code
      [DllImport("kernel32", CharSet = CharSet.Auto)]
      private extern static IntPtr LoadLibraryEx(
         [MarshalAs(UnmanagedType.LPTStr)]
         string lpLibFileName, 
         IntPtr hFile, 
         int dwFlags);                     
      [DllImport("kernel32")] 
      private extern static int FreeLibrary (
         IntPtr hLibModule);
      [DllImport("kernel32")] 
      private extern static IntPtr LoadResource (
         IntPtr hInstance, 
         IntPtr hResInfo);
      [DllImport("kernel32")] 
      private extern static IntPtr LockResource(
         IntPtr hResData);
      [DllImport("kernel32", CharSet = CharSet.Auto)] 
      private extern static IntPtr FindResource(
         IntPtr hInstance, 
         [MarshalAs(UnmanagedType.LPTStr)]
         string lpName, 
         IntPtr lpType);
      [DllImport("kernel32")] 
      private extern static int SizeofResource(
         IntPtr hInstance, 
         IntPtr hResInfo);
      [DllImport("kernel32")] 
      private extern static int FreeResource (
         IntPtr hResData);
      #endregion

      #region Constants
      private const Int16 IMAGE_ICON = 1;
      private const int LOAD_LIBRARY_AS_DATAFILE = 0x2;
      private const int RT_CURSOR = 1;
      private const int RT_BITMAP = 2;
      private const int RT_ICON = 3;
      private const int DIFFERENCE = 11;
      private const int RT_GROUP_CURSOR = RT_CURSOR + DIFFERENCE;
      private const int RT_GROUP_ICON = RT_ICON + DIFFERENCE;
      #endregion

      #region Structures
      private struct ICONDIRENTRY
      {
         public byte width; // Width of the image
         public byte height; // Height of the image (times 2)
         public byte colorCount; // Number of colors in image (0 if more than 8bpp)
         public byte reserved; // Reserved
         public Int16 wPlanes; // Color Planes
         public Int16 wBitCount; // Bits per pixel
         public int dwBytesInRes; // how many bytes in this resource?
         public int dwImageOffset;// where in the file is this image         

         public ICONDIRENTRY(
            BinaryReader br)
         {
            this.width = br.ReadByte();
            this.height = br.ReadByte();
            this.colorCount = br.ReadByte();
            this.reserved = br.ReadByte();
            this.wPlanes = br.ReadInt16();
            this.wBitCount = br.ReadInt16();
            this.dwBytesInRes = br.ReadInt32();
            this.dwImageOffset = br.ReadInt32();
         }

         public void Write(
            BinaryWriter br)
         {
            br.Write(this.width);
      br.Write(this.height);
            br.Write(this.colorCount);
            br.Write(this.reserved);
      br.Write(this.wPlanes);
            br.Write(this.wBitCount);
            br.Write(this.dwBytesInRes);
            br.Write(this.dwImageOffset);
         }

         public override string ToString()
         {
            return string.Format("Size: ({0},{1}), ColorCount: {2}, Reserved : {3}, Planes: {4}, BitCount {5}, BytesInRes: {6}, ImageOffset {7}",
              this.width, this.height, this.colorCount, this.reserved,
               this.wPlanes, this.wBitCount,
               this.dwBytesInRes, this.dwImageOffset);
         }
      }

      private struct MEMICONDIRENTRY
      {
         public byte width; // Width of the image
         public byte height; // Height of the image (times 2)
         public byte colorCount; // Number of colors in image (0 if more than 8bpp)
         public byte reserved; // Reserved
         public Int16 wPlanes; // Color Planes
         public Int16 wBitCount; // Bits per pixel
         public int dwBytesInRes; // how many bytes in this resource?
         public Int16 nID;// resource id of the image

         public MEMICONDIRENTRY(
            IntPtr lPtr, 
            int ofs)
         {
            this.width = Marshal.ReadByte(lPtr, ofs);
            this.height = Marshal.ReadByte(lPtr, ofs + 1);
            this.colorCount = Marshal.ReadByte(lPtr, ofs + 2);
            this.reserved = Marshal.ReadByte(lPtr, ofs + 3);
            this.wPlanes = Marshal.ReadInt16(lPtr, ofs + 4);
            this.wBitCount = Marshal.ReadInt16(lPtr, ofs + 6);
            this.dwBytesInRes = Marshal.ReadInt32(lPtr, ofs + 8);
            this.nID = Marshal.ReadInt16(lPtr, ofs + 12);
         }

         public override string ToString()
         {
            return string.Format(
               "Size: ({0},{1}), ColorCount: {2}, Planes: {3}, BitCount {4}, BytesInRes: {5}, IconResourceID {6}",
               this.width, this.height, this.colorCount, 
               this.wPlanes , this.wBitCount,
               this.dwBytesInRes, this.nID );
         }
      }

      #endregion

      #region Member Variables
      private IconDeviceImageCollection iconCollection = null;
      private string iconFile = null;
      private string libraryFile = null;
      private int resourceId = -1;
      private string resourceName = null;
      #endregion

      #region Properties
      /// <summary>
      /// Returns the collection of device images
      /// within this icon 
      /// </summary>
      public IconDeviceImageCollection Items
      {
         get
         {
            return this.iconCollection;
         }
         set
         {

         }
      }
      
      /// <summary>
      /// Gets the file the icon was loaded from
      /// </summary>
      public string IconFile
      {
         get
         {
            return this.iconFile;
         }
      }
      
      /// <summary>
      /// Gets the library this icon was loaded from
      /// or a blank string if the icon was not sourced
      /// from a library.
      /// </summary>
      public string LibraryFile
      {
         get
         {
            return this.libraryFile;
         }         
      }
      
      /// <summary>
      /// Gets the integer resource id of this icon if it
      /// was loaded from a library
      /// </summary>
      public int ResourceId
      {
         get
         {
            return this.resourceId;
         }
      }
      
      /// <summary>
      /// Gets the string resource id of this icon if it
      /// was loaded from a library
      /// </summary>
      public string ResourceName
      {
         get
         {
            return this.resourceName;
         }
      }
      #endregion

      #region Methods
      /// <summary>
      /// Loads an icon from the specified file
      /// </summary>
      /// <param name="iconFile">File containing icon</param>
      public void FromFile(
         string iconFile)
      {
         loadFromFile(iconFile);
      }
      
      /// <summary>
      /// Loads an icon from an executable or library
      /// with the specified integer resource id
      /// </summary>
      /// <param name="libraryFile">Executable or DLL 
      /// containing icon</param>
      /// <param name="resourceId">Integer resource identifier</param>
      public void FromLibrary(
         string libraryFile,
         int resourceId)
      {
         loadInitialise();
         string resourceName = "#" + resourceId.ToString(); //uses "G" String.Format("#{0:N0}", resourceId);
         loadFromLibrary(libraryFile, resourceName);
      }
      
      /// <summary>
      /// Loads an icon from an executable or library
      /// with the specified string resource id
      /// </summary>
      /// <param name="libraryFile">Executable or DLL 
      /// containing icon</param>
      /// <param name="resourceName">String resource identifier</param>
      public void FromLibrary(
         string libraryFile,
         string resourceName
         )
      {
         loadInitialise();
         loadFromLibrary(libraryFile, resourceName);
      }
      
      /// <summary>
      /// Saves the icon to the specified file
      /// </summary>
      /// <param name="iconFile">File to save to</param>
      public void Save(
         string iconFile
         )
      {
         // open the file for writing, truncate if exists
         FileStream fs = new FileStream(
            iconFile, 
            FileMode.Create,
            FileAccess.Write,
            FileShare.Read);
         BinaryWriter bw = null;
         try
         {
            bw = new BinaryWriter(fs);

            // write out the icon header:
            writeIconFileHeader(bw);
            // write out the icon directory entries:
            int iconOffset = 6 + 16 * this.iconCollection.Count;
            foreach (IconDeviceImage idi in this.iconCollection)
            {
               int bytesInRes = idi.IconImageDataBytes();

               ICONDIRENTRY ide = new ICONDIRENTRY();
               ide.width = (byte)idi.IconSize.Width;
               ide.height = (byte)idi.IconSize.Height;
               switch (idi.ColorDepth)
               {
                  case ColorDepth.Depth4Bit:
                     ide.colorCount = 16;
                     ide.wBitCount = 4;
                     break;
                  case ColorDepth.Depth8Bit:
                     ide.colorCount = 0; //BUG CORRECTED, vasian, old was 255, based on http://www.daubnet.com/formats/ICO.html
                     ide.wBitCount = 8;
                     break;
                  case ColorDepth.Depth16Bit:
                     ide.colorCount = 0;
                     ide.wBitCount = 16;
                     break;
                  case ColorDepth.Depth24Bit:
                     ide.colorCount = 0;
                     ide.wBitCount = 24;
                     break;
                  case ColorDepth.Depth32Bit:
                     ide.colorCount = 0;
                     ide.wBitCount = 32;
                     break;
               }
               ide.wPlanes = 1;
               ide.dwBytesInRes = bytesInRes;
               ide.dwImageOffset = iconOffset;
               ide.Write(bw);
               iconOffset += bytesInRes;
            }

            // write out the icon data:
            foreach (IconDeviceImage idi in this.iconCollection)
            {
               idi.SaveIconBitmapData(bw);
            }
         }
         catch (Exception ex)
         {
            if (ex is SystemException)
            {
               throw ex;
            }
            else
            {
               throw new IconExException(ex.Message, ex);
            }
         }
         finally
         {
            if (bw != null)
            {
               bw.Close();
            }
         }

      }
      #endregion

      #region Private Implementation
      private void loadInitialise()
      {
         this.iconFile = "";
         this.resourceId = -1;
         this.libraryFile = "";
         this.iconCollection = new IconDeviceImageCollection();
      }

      // this method is too long, I'm sorry...
      private void loadFromLibrary(
         string libraryFile,
         string resourceName
         )
      {
         string msg = "";
         bool failed = false;
         IntPtr hGlobal = IntPtr.Zero;
         IntPtr hRsrc = IntPtr.Zero;
         IntPtr hLibrary = IntPtr.Zero;
         IntPtr lPtr = IntPtr.Zero;

         try
         {
            hLibrary = LoadLibraryEx(               
               libraryFile,
               IntPtr.Zero,
               LOAD_LIBRARY_AS_DATAFILE);
            if (hLibrary != IntPtr.Zero)
            {
               hRsrc = FindResource(
                  hLibrary,
                  resourceName,
                  (IntPtr)RT_GROUP_ICON);
               if (hRsrc != IntPtr.Zero)
               {
                  hGlobal = LoadResource(hLibrary, hRsrc);
                  if (hGlobal != IntPtr.Zero)
                  {
                     lPtr = LockResource(hGlobal);
                     if (lPtr != IntPtr.Zero)
                     {
                        // now we can read the header:
                        int iconCount = readResourceIconFileHeader(lPtr);
                        // read the directory:
                        MEMICONDIRENTRY[] ide = new MEMICONDIRENTRY[iconCount];
                        int ofs = 6;
                        for (int iconEntry = 0; iconEntry < iconCount;
                         iconEntry++)
                        {
                           ide[iconEntry] = new MEMICONDIRENTRY(lPtr, ofs);
                           //Console.WriteLine(ide[iconEntry].ToString());
                           ofs += 14;                           
                        }                        
                        FreeResource(hGlobal);
                        hGlobal = IntPtr.Zero;

                        // we have the directory, so now can load the icons:
                        //IconDeviceImage[] icons = new
                        // IconDeviceImage[iconCount];
             ArrayList icons = new ArrayList();
                        // read the icons:
                        for (int iconEntry = 0; iconEntry < iconCount;
                         iconEntry++)
                        {
                           // find the specified icon:
                           string resName = String.Format("#{0:G}", //N0
                            ide[iconEntry].nID);
                           hRsrc = FindResource(
                              hLibrary,
                              resName,
                              (IntPtr)RT_ICON);
                           if (hRsrc == IntPtr.Zero)
                           {
                              msg = String.Format(
                                 "Could not find the component icon resource with id {0}", 
                                 ide[iconEntry].nID);
                              failed = true;
                              break;
                           }
                           else
                           {
                              // load the resource:
                              hGlobal = LoadResource(
                                 hLibrary,
                                 hRsrc);
                              if (hGlobal == IntPtr.Zero)
                              {
                                 msg = String.Format(
                                    "Could not load the component icon resource with id {0}", 
                                    ide[iconEntry].nID);
                                 failed = true;
                                 break;
                              }
                              else
                              {
                                 // check the size:
                                 int resSize = SizeofResource(hLibrary, hRsrc);
                                 if ((resSize > 0) && (resSize ==
                                  ide[iconEntry].dwBytesInRes))
                                 {
                                    // ok
                                    lPtr = LockResource(hGlobal);
                                    byte[] b = new byte[resSize];
                                    Marshal.Copy(lPtr, b, 0, resSize);
                   try
                   {
                     //icons[iconEntry] = new IconDeviceImage(b);
                     icons.Add(new IconDeviceImage(b));
                   }
                   catch{}
                                 }
                                 else
                                 {
                                    msg = String.Format(
                                       "Component icon resource with id {0} is corrupt", 
                                       ide[iconEntry].nID);
                                    failed = true;
                                 }
                              }
                           }
                        }
                        if (!failed)
                        {
                           // Add the icons to the collection:
              IconDeviceImage[] temp = new IconDeviceImage[icons.Count];
              icons.CopyTo(temp);
                           this.iconCollection = new
                            IconDeviceImageCollection(temp);
                        }
                     }
                     else
                     {
                        msg = "Can't lock resource for reading.";
                        failed = true;
                     }
                  }
                  else
                  {
                     msg = "Can't load resource for reading.";
                     failed  = true;
                  }
               }
               else
               {
                  msg = "Can't find resource.";
                  failed  = true;
               }
            }
            else
            {
               msg = "Can't load library.";
               failed  = true;
            }
         }
         catch (Exception ex)
         {
            failed = true;
            msg = ex.Message;
         }
         finally
         {
            // clear up handles:
            if (hGlobal != IntPtr.Zero)
            {
               FreeResource(hGlobal);
            }
            if (hLibrary != IntPtr.Zero)
            {
               FreeLibrary(hLibrary);
            }
            if (failed)
            {
               throw new IconExException(msg);
            }
         }

      }

      private void loadFromFile(
         string iconFile)
      {
         loadInitialise();

         // Open the file
         FileStream fs = new FileStream(
            iconFile,
            FileMode.Open,
            FileAccess.Read,
            FileShare.Read);
         BinaryReader br = new BinaryReader(fs);

         try
         {
            // read the header:
            int iconCount = readIconFileHeader(br);
            // read the directory:
            ICONDIRENTRY[] ide = new ICONDIRENTRY[iconCount];
            for (int iconEntry = 0; iconEntry < iconCount; iconEntry++)
            {
               ide[iconEntry] = new ICONDIRENTRY(br);
            }
            IconDeviceImage[] icons = new IconDeviceImage[iconCount];
            // read the actual icons:
            for (int iconEntry = 0; iconEntry < iconCount; iconEntry++)
            {
               fs.Seek(ide[iconEntry].dwImageOffset, SeekOrigin.Begin);
               byte[] b = new byte[ide[iconEntry].dwBytesInRes];
               br.Read(b, 0, ide[iconEntry].dwBytesInRes);
               icons[iconEntry] = new IconDeviceImage(b);
            }
            // Add the icons to the collection:
            this.iconCollection = new IconDeviceImageCollection(icons);
         }
         catch (Exception ex)
         {
            if (ex is SystemException)
            {
               throw ex;
            }
            else
            {
               throw new IconExException("Failed to read icon file.", ex);   
            }
         }
         finally
         {
            br.Close();            
         }

         this.iconFile = iconFile;
      }

      private int readResourceIconFileHeader(
         IntPtr lPtr)
      {
         int idReserved = Marshal.ReadInt16(lPtr);
         int idType = Marshal.ReadInt16(lPtr, 2);
         int idCount = Marshal.ReadInt16(lPtr, 4);
         if ((idReserved == 0) &&
            (idType == IMAGE_ICON) &&
            (idCount > 0) &&
            (idCount < 1024))
         {
            return idCount;
         }
         else
         {
            throw new IconExException("Invalid Icon File Header");
         }
      }

      private int readIconFileHeader(
         BinaryReader br)
      {
         int idReserved = br.ReadInt16();
         int idType = br.ReadInt16();
         int idCount = br.ReadInt16();
         if ((idReserved == 0) &&
            (idType == IMAGE_ICON) &&
            (idCount > 0) &&
            (idCount < 1024))
         {
            return idCount;
         }
         else
         {
            throw new IconExException("Invalid Icon File Header");
         }
      }

      private void writeIconFileHeader(
         BinaryWriter bw)
      {
         Int16 idReserved = 0;
         bw.Write(idReserved);
         Int16 idType = IMAGE_ICON;
         bw.Write(idType);
         Int16 idCount = (Int16)this.Items.Count;
         bw.Write(idCount);
      }
         
      #endregion

      #region Constructor, Dispose
      /// <summary>
      /// Constructs a new, empty instance of the IconEx
      /// object
      /// </summary>
      public IconEx()
      {
      }

      /// <summary>
      /// Constructs an IconEx instance and opens the icon
      /// file specified.
      /// </summary>
      /// <param name="iconFile">Icon file to read</param>
      public IconEx(string iconFile)
      {
         loadFromFile(iconFile);
      }

      /// <summary>
      /// Constructs an IconEx instance and opens the icon
      /// from the specified library (Executable or DLL)
      /// with the specified integer resource identifier
      /// </summary>
      /// <param name="libraryFile">Executable or DLL to extract
      /// icon from</param>
      /// <param name="resourceId">Integer resource Id</param>
      public IconEx(
         string libraryFile,
         int resourceId
         )
      {
         FromLibrary(libraryFile, resourceId);
      }

      /// <summary>
      /// Constructs an IconEx instance and opens the icon
      /// from the specified library (Executable or DLL)
      /// with the specified string resource identifier
      /// </summary>
      /// <param name="libraryFile">Executable or DLL to extract
      /// icon from</param>
      /// <param name="resourceName">String resource Id</param>
      public IconEx(
         string libraryFile,
         string resourceName
         )
      {
         FromLibrary(libraryFile, resourceName);
      }
      public void Dispose()
      {
         if (this.iconCollection != null)
         {
            iconCollection.Dispose();
            iconCollection = null;            
         }
      }
      #endregion
   }
   #endregion

   #region IconDeviceImageCollection
   /// <summary>
   /// Manages a read/write collection of icon resources
   /// within an Icon file
   /// </summary>
   public class IconDeviceImageCollection : CollectionBase, IDisposable
   {
      #region Member Variables
      #endregion      

      #region Methods
      /// <summary>
      /// Add a new icon device image
      /// </summary>
      /// <param name="icon">Icon to add</param>
      public void Add(IconDeviceImage icon)
      {
         foreach (IconDeviceImage iconExisting in this.InnerList)
         {
            if (icon.IconSize.Equals(iconExisting.IconSize) &&
               icon.ColorDepth.Equals(iconExisting.ColorDepth))
            {
               throw new IconExException("An Icon Device Image with the same size and colour depth already exists in this icon");
            }
         }
         this.InnerList.Add(icon);
      }
      /// <summary>
      /// Gets the IconDevice Image at the specified
      /// index
      /// </summary>
      public IconDeviceImage this[int index]
      {
         get
         {
            return (IconDeviceImage)this.InnerList[index];
         }
      }
      #endregion

      #region Constructor, Dispose
      /// <summary>
      ///  Constructs a new, empty collection of device
      ///  images.
      /// </summary>
      public IconDeviceImageCollection()
      {
      }
      /// <summary>
      /// Constructs a new collection of device images
      /// </summary>
      /// <param name="icons">Icons to add</param>
      public IconDeviceImageCollection(
         IconDeviceImage[] icons
         )
      {
         foreach (IconDeviceImage icon in icons)
         {
            this.InnerList.Add(icon);
         }
      }
      public void Dispose()
      {
         if (this.InnerList != null)
         {
            foreach (IconDeviceImage icon in this.InnerList)
            {
        if(icon != null)
        {
          icon.Dispose();
        }
            }
            this.InnerList.Clear();
         }
      }
      #endregion
   }
   #endregion

   #region IconDeviceImage
   /// <summary>
   /// Manages a single icon device image within an
   /// Icon file
   /// </summary>
   public class IconDeviceImage : IDisposable
   {
      #region Member Variables
      private Size size;
      private System.Windows.Forms.ColorDepth colorDepth = ColorDepth.Depth4Bit;
      private byte[] data;
      private IntPtr hIcon = IntPtr.Zero;
      #endregion

      #region Unmanaged Code
      [DllImport("gdi32")]
      private static extern int SetDIBitsToDevice(
         IntPtr hdc, 
         int X, int Y, int dx, int dy, 
         int SrcX, int SrcY, int Scan, int NumScans, 
         IntPtr Bits, 
         IntPtr BitsInfo, 
         int wUsage);
      [DllImport("gdi32")]
      public static extern int GetDIBits (
         IntPtr hdc, 
         IntPtr hBitmap, 
         int nStartScan, 
         int nNumScans, 
         IntPtr Bits, 
         IntPtr BitsInfo, 
         int wUsage);

      private const int DIB_RGB_COLORS = 0; //  color table in RGBs
      private const int DIB_PAL_COLORS = 1; //  color table in palette indices
      private const int DIB_PAL_INDICES = 2; //  No color table indices into surf palette
      private const int DIB_PAL_PHYSINDICES = 2; //  No color table indices into surf palette
      private const int DIB_PAL_LOGINDICES = 4; //  No color table indices into DC palette

      // Bitmap compression types:
      private const int BI_RGB = 0x0;
      private const int BI_RLE4 = 0x2;
      private const int BI_RLE8 = 0x1;

      [DllImport("gdi32")]
      private static extern IntPtr CreateCompatibleDC(
         IntPtr hdc);
      
      [DllImport("gdi32", CharSet=CharSet.Auto)]
      private static extern IntPtr CreateDC (
         [MarshalAs(UnmanagedType.LPTStr)]
         string lpDriverName, 
         IntPtr lpDeviceName, 
         IntPtr lpOutput, 
         IntPtr lpInitData);

      [DllImport("gdi32")]
      private static extern IntPtr CreateCompatibleBitmap(
         IntPtr hdc, 
         int width,
         int height);

      [DllImport("gdi32")]
      private static extern IntPtr SelectObject(
         IntPtr hdc, IntPtr hObject);

      [DllImport("gdi32")]
      private static extern int DeleteObject(
         IntPtr hObject);
      
      [DllImport("gdi32")]
      private static extern int DeleteDC(
         IntPtr hdc);
      
      [DllImport("user32")]
      private static extern int DestroyIcon(
         IntPtr hIcon);

      [DllImport("user32")]
      private static extern IntPtr CreateIconIndirect(
         ref ICONINFO piconInfo);

      private const Int16 IMAGE_ICON = 1;

      #endregion

      #region Structures

      #region ICONINFO.  Used by the CreateIconIndirect API function
      private struct ICONINFO
      {
         public int fIcon;
         public int xHotspot;
         public int yHotspot;
         public IntPtr hBmMask;
         public IntPtr hBmColor;
      }
      #endregion

      #region BITMAPINFOHEADER.  This is stored at the start of an icon's data
      private struct BITMAPINFOHEADER
      {
         public int biSize;
         public int biWidth;
         public int biHeight;
         public Int16 biPlanes;
         public Int16 biBitCount;
         public int biCompression;
         public int biSizeImage;
         public int biXPelsPerMeter;
         public int biYPelsPerMeter;
         public int biClrUsed;
         public int biClrImportant;

         public BITMAPINFOHEADER(
            Size size,
            ColorDepth colorDepth
            )
         {
            this.biSize = 0;
            this.biWidth = size.Width;
            this.biHeight = size.Height * 2;
            this.biPlanes = 1;
            this.biCompression = BI_RGB;
            this.biSizeImage = 0;
            this.biXPelsPerMeter = 0;
            this.biYPelsPerMeter = 0;
            this.biClrUsed = 0;
            this.biClrImportant = 0;
            switch (colorDepth)
            {
               case ColorDepth.Depth4Bit:
                  this.biBitCount = 4;
                  break;
               case ColorDepth.Depth8Bit:
                  this.biBitCount = 8;
                  break;
               case ColorDepth.Depth16Bit:
                  this.biBitCount = 16;
                  break;
               case ColorDepth.Depth24Bit:
                  this.biBitCount = 24;
                  break;
               case ColorDepth.Depth32Bit:
                  this.biBitCount = 32;
                  break;
               default:
                  this.biBitCount = 4;
                  break;
            }
            this.biSize = Marshal.SizeOf(this.GetType());
         }
         
         public void Write(
            BinaryWriter bw)
         {
            bw.Write(this.biSize);
            bw.Write(this.biWidth);
            bw.Write(this.biHeight);
            bw.Write(this.biPlanes);
            bw.Write(this.biBitCount);
            bw.Write(this.biCompression);
            bw.Write(this.biSizeImage);
            bw.Write(this.biXPelsPerMeter);
            bw.Write(this.biYPelsPerMeter);
            bw.Write(this.biClrUsed);
            bw.Write(this.biClrImportant);
         }

         public BITMAPINFOHEADER(byte[] data)
         {
            MemoryStream ms = new MemoryStream(data, false);
            BinaryReader br = new BinaryReader(ms);
            biSize = br.ReadInt32();
            biWidth = br.ReadInt32();
            biHeight = br.ReadInt32();
            biPlanes = br.ReadInt16();
            biBitCount = br.ReadInt16();
            biCompression = br.ReadInt32();
            biSizeImage = br.ReadInt32();
            biXPelsPerMeter = br.ReadInt32();
            biYPelsPerMeter = br.ReadInt32();
            biClrUsed = br.ReadInt32();
            biClrImportant = br.ReadInt32();
            br.Close();            
         }

         public override string ToString()
         {
            return string.Format(
               "biSize: {0}, biWidth: {1}, biHeight: {2}, biPlanes: {3}, biBitCount: {4},"
                + "biCompression: {5}, biSizeImage: {6}, biXPelsPerMeter: {7}, biYPelsPerMeter {8}, biClrUsed {9},"
                + "biClrImportant {10}",
               biSize, biWidth, biHeight, biPlanes, biBitCount,
               biCompression, biSizeImage, biXPelsPerMeter, biYPelsPerMeter,
               biClrUsed, biClrImportant);
         }
      }
      #endregion

      #region RQBQUAD. Used to store colours in a paletised icon (2, 4 or 8 bit)
      private struct RGBQUAD
      {
         public byte rgbBlue;
         public byte rgbGreen;
         public byte rgbRed;
         public byte rgbReserved;

         public RGBQUAD(
            byte r, byte g, byte b, byte alpha
            )
         {
            rgbBlue = b;
            rgbGreen = g;
            rgbRed = r;
            rgbReserved = 0; //alpha;
         }
         public RGBQUAD(
            Color c
            )
         {
            rgbBlue = c.B;
            rgbGreen = c.G;
            rgbRed = c.R;
            rgbReserved = 0; //c.A;
         }
         public void Write(
            BinaryWriter bw)
         {
            bw.Write(this.rgbBlue);
            bw.Write(this.rgbGreen);
            bw.Write(this.rgbRed);
            bw.Write(this.rgbReserved);
         }
         public override string ToString()
         {
            return string.Format(
               "rgbBlue: {0}, rgbGreen: {1}, rgbRed: {2}", rgbBlue, rgbGreen, rgbRed);
         }
      }
      #endregion

      #endregion

      #region Properties
      /// <summary>
      /// Gets the Icon handle for this device image
      /// </summary>
      public IntPtr Handle
      {
         get
         {
            return this.hIcon;
         }
      }
      /// <summary>
      /// Gets the size of this device image
      /// </summary>
      public Size IconSize
      {
         get
         {
            return this.size;
         }
      }
      /// <summary>
      /// Gets the colour depth of this device image
      /// </summary>
      public System.Windows.Forms.ColorDepth ColorDepth
      {
         get
         {
            return this.colorDepth;
         }
      }

      /// <summary>
      /// Gets/sets the Mask Image of the icon as a bitmap
      /// </summary>
      public System.Drawing.Bitmap MaskImage
      {
         get
         {
            IntPtr junk = IntPtr.Zero;
            Bitmap bm = getIconBitmap(true, false, ref junk);
            return bm;
         }
         set
         {
            setMaskBitsFromBitmap(value);
         }
      }
      /// <summary>
      /// Gets/sets the image portion of the icon as a bitmap
      /// </summary>
      public System.Drawing.Bitmap IconImage
      {
         get
         {
            IntPtr junk = IntPtr.Zero;
            Bitmap bm = getIconBitmap(false, false, ref junk);
            return bm;
         }
         set
         {
            setImageBitsFromBitmap(value);
         }
      }
      /// <summary>
      /// Gets the device image as a managed icon
      /// Note that you should clone the icon if you want to keep it
      /// after this class has been disposed.      
      /// </summary>
      public System.Drawing.Icon Icon
      {
         get
         {
            System.Drawing.Icon icon =
             System.Drawing.Icon.FromHandle(this.hIcon);
            return icon;
         }
      }
      #endregion

      #region Private Implementation
      private void setMaskBitsFromBitmap(
         Bitmap bm
         )
      {
         IntPtr hdcc = CreateDC("DISPLAY", IntPtr.Zero, IntPtr.Zero,
          IntPtr.Zero);
         IntPtr hdc = CreateCompatibleDC(hdcc);
         DeleteDC(hdcc);
         IntPtr hBmp = bm.GetHbitmap();

         BITMAPINFOHEADER bmInfoHdr = new BITMAPINFOHEADER(
            this.size, this.colorDepth);

         // Now prepare the for GetDIBits call:
         RGBQUAD rgbQuad = new RGBQUAD();
         int monoBmHdrSize = bmInfoHdr.biSize + Marshal.SizeOf(rgbQuad)* 2;

         IntPtr bitsInfo = Marshal.AllocCoTaskMem(
            monoBmHdrSize);
         Marshal.WriteInt32(bitsInfo, Marshal.SizeOf(bmInfoHdr));
         Marshal.WriteInt32(bitsInfo, 4, this.size.Width);
         Marshal.WriteInt32(bitsInfo, 8, this.size.Height);
         Marshal.WriteInt16(bitsInfo, 12, 1);
         Marshal.WriteInt16(bitsInfo, 14, 1);
         Marshal.WriteInt32(bitsInfo, 16, BI_RGB);
         Marshal.WriteInt32(bitsInfo, 20, 0);
         Marshal.WriteInt32(bitsInfo, 24, 0);
         Marshal.WriteInt32(bitsInfo, 28, 0);
         Marshal.WriteInt32(bitsInfo, 32, 0);
         Marshal.WriteInt32(bitsInfo, 36, 0);
         // Write the black and white colour indices:
         Marshal.WriteInt32(bitsInfo, 40, 0);
         Marshal.WriteByte(bitsInfo, 44, 255);
         Marshal.WriteByte(bitsInfo, 45, 255);
         Marshal.WriteByte(bitsInfo, 46, 255);
         Marshal.WriteByte(bitsInfo, 47, 0);

         int maskImageBytes = MaskImageSize(bmInfoHdr);
         IntPtr bits = Marshal.AllocCoTaskMem(maskImageBytes);

         int success = GetDIBits(hdc, hBmp, 0, this.size.Height, bits,
          bitsInfo, DIB_RGB_COLORS);

         Marshal.Copy(bits, data, MaskImageIndex(bmInfoHdr), maskImageBytes);

         // Free memory:
         Marshal.FreeCoTaskMem(bits);
         Marshal.FreeCoTaskMem(bitsInfo);

         DeleteObject(hBmp);
         DeleteDC(hdc);

         createIcon();

      }
      private void setImageBitsFromBitmap(
         Bitmap bm
         )
      {
         IntPtr hdcc = CreateDC("DISPLAY", IntPtr.Zero, IntPtr.Zero,
          IntPtr.Zero);
         IntPtr hdc = CreateCompatibleDC(hdcc);
         DeleteDC(hdcc);
         IntPtr hBmp = bm.GetHbitmap();

         BITMAPINFOHEADER bmInfoHdr = new BITMAPINFOHEADER(
            this.size, this.colorDepth);

         // Now prepare for GetDIBits call:
         int xorIndex = XorImageIndex(bmInfoHdr);
         int xorImageBytes = XorImageSize(bmInfoHdr);

         // Get the BITMAPINFO header into the pointer:
         IntPtr bitsInfo = Marshal.AllocCoTaskMem(
            xorIndex);
         Marshal.Copy(data, 0, bitsInfo, xorIndex);
         // fix the height:
         Marshal.WriteInt32(bitsInfo, 8, bmInfoHdr.biHeight / 2);

         IntPtr bits = Marshal.AllocCoTaskMem(xorImageBytes);

         int success = GetDIBits(hdc, hBmp, 0, this.size.Height, bits,
          bitsInfo, DIB_RGB_COLORS);

         Marshal.Copy(bits, data, xorIndex, xorImageBytes);

         // Free memory:
         Marshal.FreeCoTaskMem(bits);
         Marshal.FreeCoTaskMem(bitsInfo);

         DeleteObject(hBmp);
         DeleteDC(hdc);

         createIcon();
      }

      private void setDeviceImage(
         Size size,
         System.Windows.Forms.ColorDepth colorDepth
         )
      {
         this.size = size;
         this.colorDepth = colorDepth;         
         // Initialise the data:
         BITMAPINFOHEADER bmInfoHdr = new BITMAPINFOHEADER(
            size, colorDepth);
         this.data = new byte[
            this.MaskImageIndex(bmInfoHdr) + this.MaskImageSize(bmInfoHdr)];
         
         MemoryStream mw = new MemoryStream(this.data, 0, this.data.Length,
          true);
         BinaryWriter bw = new BinaryWriter(mw);
         bmInfoHdr.Write(bw);
         // Write the colour indexes if required:
         switch (this.colorDepth)
         {
            case ColorDepth.Depth4Bit:
               write16ColorPalette(bw);
               break;
            case ColorDepth.Depth8Bit:
               write256ColorPalette(bw);
               break;
         }
         bw.Close();

      }

      private void write16ColorPalette(
         BinaryWriter bw)
      {
         // Write out 16 entries containing the
         // standard colour palette:
         writeColor(bw, Color.Black);
         writeColor(bw, Color.White);
         writeColor(bw, Color.Red);
         writeColor(bw, Color.Green);
         writeColor(bw, Color.Blue);         
         writeColor(bw, Color.Yellow);
         writeColor(bw, Color.Magenta);
         writeColor(bw, Color.Cyan);
         writeColor(bw, Color.Gray);
         writeColor(bw, Color.DarkRed);
         writeColor(bw, Color.DarkGreen);
         writeColor(bw, Color.DarkBlue);
         writeColor(bw, Color.Olive);
         writeColor(bw, Color.Purple);
         writeColor(bw, Color.Teal);
         writeColor(bw, Color.DarkGray);
      }
      private void write256ColorPalette(
         BinaryWriter bw)
      {
         KnownColor kc = KnownColor.ActiveBorder;
         Array colors = Enum.GetValues(kc.GetType());         
         int i = 0;
         foreach (KnownColor color in colors)
         {
            writeColor(bw, Color.FromKnownColor(color));
            i++;
            if (i > 255)
            {
               break;
            }
         }
      }

      private void writeColor(
         BinaryWriter bw,
         Color color
         )
      {
         RGBQUAD r = new RGBQUAD(color);
         r.Write(bw);
      }

      private Bitmap getIconBitmap(
         bool mask,
         bool returnHandle,
         ref IntPtr hBmp
         )
      {
         // Bitmap to return
         Bitmap bm = null;

         // Get bitmap info:         
         BITMAPINFOHEADER bmInfoHdr = new BITMAPINFOHEADER(data);

         if (mask)
         {
            // extract monochrome mask
            IntPtr hdc = CreateCompatibleDC(IntPtr.Zero);
            hBmp = CreateCompatibleBitmap(hdc, bmInfoHdr.biWidth,
             bmInfoHdr.biHeight / 2);
            IntPtr hBmpOld = SelectObject(hdc, hBmp);

            // Prepare BitmapInfoHeader for mono bitmap:
            RGBQUAD rgbQuad = new RGBQUAD();
            int monoBmHdrSize = bmInfoHdr.biSize + Marshal.SizeOf(rgbQuad)* 2;

            IntPtr bitsInfo = Marshal.AllocCoTaskMem(
               monoBmHdrSize);
            Marshal.WriteInt32(bitsInfo, Marshal.SizeOf(bmInfoHdr));
            Marshal.WriteInt32(bitsInfo, 4, bmInfoHdr.biWidth);
            Marshal.WriteInt32(bitsInfo, 8, bmInfoHdr.biHeight / 2);
            Marshal.WriteInt16(bitsInfo, 12, 1);
            Marshal.WriteInt16(bitsInfo, 14, 1);
            Marshal.WriteInt32(bitsInfo, 16, BI_RGB);
            Marshal.WriteInt32(bitsInfo, 20, 0);
            Marshal.WriteInt32(bitsInfo, 24, 0);
            Marshal.WriteInt32(bitsInfo, 28, 0);
            Marshal.WriteInt32(bitsInfo, 32, 0);
            Marshal.WriteInt32(bitsInfo, 36, 0);
            // Write the black and white colour indices:
            Marshal.WriteInt32(bitsInfo, 40, 0);
            Marshal.WriteByte(bitsInfo, 44, 255);
            Marshal.WriteByte(bitsInfo, 45, 255);
            Marshal.WriteByte(bitsInfo, 46, 255);
            Marshal.WriteByte(bitsInfo, 47, 0);

            // Prepare Mask bits:
            int maskImageBytes = MaskImageSize(bmInfoHdr);
            IntPtr bits = Marshal.AllocCoTaskMem(maskImageBytes);
            Marshal.Copy(data, MaskImageIndex(bmInfoHdr), bits, maskImageBytes);

            int success = SetDIBitsToDevice(
               hdc, 
               0, 0, bmInfoHdr.biWidth, bmInfoHdr.biHeight / 2, 
               0, 0, 0, bmInfoHdr.biHeight / 2, 
               bits, 
               bitsInfo, 
               DIB_RGB_COLORS);

            Marshal.FreeCoTaskMem(bits);
            Marshal.FreeCoTaskMem(bitsInfo);

            SelectObject(hdc, hBmpOld);
            DeleteObject(hdc);

         }
         else
         {
            // extract colour (XOR) part of image:
            
            // Create bitmap:
            IntPtr hdcDesktop = CreateDC("DISPLAY", IntPtr.Zero, IntPtr.Zero,
             IntPtr.Zero);
            IntPtr hdc = CreateCompatibleDC(hdcDesktop);
            hBmp = CreateCompatibleBitmap(hdcDesktop, bmInfoHdr.biWidth,
             bmInfoHdr.biHeight / 2);
            DeleteDC(hdcDesktop);
            IntPtr hBmpOld = SelectObject(hdc, hBmp);
            
            // Find the index of the XOR bytes:
            int xorIndex = XorImageIndex(bmInfoHdr);
            int xorImageSize = XorImageSize(bmInfoHdr);

            // Get Bitmap info header to a pointer:                        
            IntPtr bitsInfo = Marshal.AllocCoTaskMem(xorIndex);
            Marshal.Copy(data, 0, bitsInfo, xorIndex);
            // fix the height:
            Marshal.WriteInt32(bitsInfo, 8, bmInfoHdr.biHeight / 2);

            // Get the XOR bits:            
            IntPtr bits = Marshal.AllocCoTaskMem(xorImageSize);
            Marshal.Copy(data, xorIndex, bits, xorImageSize);

            int success = SetDIBitsToDevice(
               hdc, 
               0, 0, bmInfoHdr.biWidth, bmInfoHdr.biHeight/2, 
               0, 0, 0, bmInfoHdr.biHeight/2, 
               bits, 
               bitsInfo, 
               DIB_RGB_COLORS);

            Marshal.FreeCoTaskMem(bits);
            Marshal.FreeCoTaskMem(bitsInfo);

            SelectObject(hdc, hBmpOld);
            DeleteObject(hdc);
         }

         if (!returnHandle)
         {
            // the bitmap will own the handle and clear
            // it up when it is disposed.  Otherwise
            // need to call DeleteObject on hBmp
            // returned.
            bm = Bitmap.FromHbitmap(hBmp);
         }
         return bm;
      }

      private int MaskImageIndex(
         BITMAPINFOHEADER bmInfoHeader
         )
      {
         int maskImageIndex = XorImageIndex(bmInfoHeader);
         maskImageIndex += XorImageSize(bmInfoHeader);
         return maskImageIndex;
      }
      
      private int XorImageSize(
         BITMAPINFOHEADER bmInfoHeader
         )
      {
         int imageBytes = (bmInfoHeader.biHeight/ 2 * 
            WidthBytes(bmInfoHeader.biWidth * bmInfoHeader.biBitCount *
             bmInfoHeader.biPlanes));
         return imageBytes;
      }

      private int MaskImageSize(
         BITMAPINFOHEADER bmInfoHeader
         )
      {
         int imageBytes = bmInfoHeader.biHeight / 2 * 
            WidthBytes(bmInfoHeader.biWidth);
         return imageBytes;
      }
      
      private int WidthBytes(int width)
      {   
         // Returns the width of a row in a DIB Bitmap given the
         // number of bits.  DIB Bitmap rows always align on a 
         // DWORD boundary.
         int widthBytes = ((width + 31) / 32) * 4;
         return widthBytes;
      }

      private int XorImageIndex(
         BITMAPINFOHEADER bmInfoHeader)
      {
         // Returns the position of the DIB bitmap bits within a
         // DIB bitmap array:
         RGBQUAD rgbq = new RGBQUAD();
         return Marshal.SizeOf(bmInfoHeader) + 
            dibNumColors(bmInfoHeader) * Marshal.SizeOf(rgbq);
      }                                            
      private int dibNumColors(
         BITMAPINFOHEADER bmInfoHeader)
      {
         int colorCount = 0;
         if (bmInfoHeader.biClrUsed != 0)
         {
            colorCount = bmInfoHeader.biClrUsed;
         }
         else
         {
            switch (bmInfoHeader.biBitCount)
            {
               case 1:
                  colorCount = 2;
                  break;
               case 4:
                  colorCount = 16;
                  break;
               case 8:
                  colorCount = 256;
                  break;
            }
         }
         return colorCount;      
      }
      /// <summary>
      /// Internal method.  Returns the number of bytes in the
      /// icon data.  Not intended for public use.
      /// </summary>
      /// <returns>Number of bytes of icon data</returns>
      internal int IconImageDataBytes()
      {
         return this.data.Length;
      }
      /// <summary>
      /// Internal method.  Writes the icon bitmap data to
      /// the specified BinaryWriter.  Not intended for 
      /// public use.
      /// </summary>
      /// <param name="bw">BinaryWriter to write to</param>
      internal void SaveIconBitmapData(
         BinaryWriter bw)
      {
         bw.Write(this.data, 0, this.data.Length);
      }
      private void createIcon()
      {
         if (this.hIcon != IntPtr.Zero)
         {
            DestroyIcon(this.hIcon);
            this.hIcon = IntPtr.Zero;
         }

         ICONINFO ii = new ICONINFO();
         ii.fIcon = IMAGE_ICON;
         getIconBitmap(false, true, ref ii.hBmColor);
         getIconBitmap(true, true, ref ii.hBmMask);
                        
         this.hIcon = CreateIconIndirect(ref ii);
            
         DeleteObject(ii.hBmColor);
         DeleteObject(ii.hBmMask);
      }
      #endregion

      #region Constructor, Dispose
      /// <summary>
      /// Constructs a new IconDeviceImage with the specified
      /// size and colour depth.
      /// </summary>
      /// <param name="size">Size of device image</param>
      /// <param name="colorDepth">Colour depth of device image</param>
      public IconDeviceImage(
         Size size,
         System.Windows.Forms.ColorDepth colorDepth
         )
      {         
         setDeviceImage(size, colorDepth);
         createIcon();
      }

      /// <summary>
      /// Constructs a new IconDeviceImage from a Managed Icon
      /// </summary>
      /// <param name="icon">Icon to construct from</param>      
      public IconDeviceImage(
         System.Drawing.Icon icon
         )
      {
         // use DrawIconEx to create bitmaps for the 
         // colour and mask images, then use GetDIBits
         // to populate data
      }

      /// <summary>
      /// Constructs a new icon device image from an array of
      /// bytes in the Icon file format
      /// </summary>
      /// <param name="b">Array of bytes</param>
      internal IconDeviceImage(
         byte[] b
         )
      {
         // store the bytes:
         data = new Byte[b.Length];
         for (int i = 0; i < b.Length; i++)
         {
            data[i] = b[i];
         }
         
         // Read the BitmapInfoHeader structure to get the 
         // size and number of bytes:
         BITMAPINFOHEADER bmInfoHeader = new BITMAPINFOHEADER(data);
         //Console.WriteLine(bmInfoHeader.ToString());
         
         this.size.Width = bmInfoHeader.biWidth;
         this.size.Height = bmInfoHeader.biHeight/2;
         switch (bmInfoHeader.biBitCount)
         {
            case 1:
            case 4:
               this.colorDepth = ColorDepth.Depth4Bit;            
               break;
            case 8:
               this.colorDepth = ColorDepth.Depth8Bit;
               break;
            case 16:
               this.colorDepth = ColorDepth.Depth16Bit;
               break;
            case 24:
               this.colorDepth = ColorDepth.Depth24Bit;
               break;
            case 32:
               this.colorDepth = ColorDepth.Depth32Bit;
               break;
         }
         createIcon();
      }
      /// <summary>
      /// Clears up any resources associated with this
      /// Icon Device Image.
      /// </summary>
      public void Dispose()
      {
         if (this.hIcon != IntPtr.Zero)
         {
            DestroyIcon(this.hIcon);
            this.hIcon = IntPtr.Zero;
         }
      }
      #endregion
   }
   #endregion

}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.