Click here to Skip to main content
15,893,266 members
Articles / Desktop Programming / Windows Forms

Extracting Icons from EXE/DLL and Icon Manipulation

Rate me:
Please Sign up or sign in to vote.
4.83/5 (37 votes)
17 Jan 2009CPOL2 min read 154.8K   11K   84  
How to extract icons from EXE/DLL, split/merge icons, and get icons associated with files.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.API;
using TAFactory.Utilities;

namespace TAFactory.IconPack
{
    /// <summary>
    /// Provides information about a givin icon.
    /// This class cannot be inherited.
    /// </summary>
    [Serializable]
    public class IconInfo
    {
        #region ReadOnly
        public static int SizeOfIconDir = Marshal.SizeOf(typeof(IconDir));
        public static int SizeOfIconDirEntry = Marshal.SizeOf(typeof(IconDirEntry));
        public static int SizeOfGroupIconDir = Marshal.SizeOf(typeof(GroupIconDir));
        public static int SizeOfGroupIconDirEntry = Marshal.SizeOf(typeof(GroupIconDirEntry));
        #endregion

        #region Properties
        private Icon _sourceIcon;
        /// <summary>
        /// Gets the source System.Drawing.Icon.
        /// </summary>
        public Icon SourceIcon
        {
            get { return _sourceIcon; }
            private set { _sourceIcon = value; }
        }

        private string _fileName = null;
        /// <summary>
        /// Gets the icon's file name. 
        /// </summary>
        public string FileName
        {
            get { return _fileName; }
            private set { _fileName = value; }
        }

        private List<Icon> _images;
        /// <summary>
        /// Gets a list System.Drawing.Icon that presents the icon contained images.
        /// </summary>
        public List<Icon> Images
        {
            get { return _images; }
            private set { _images = value; }
        }

        /// <summary>
        /// Get whether the icon contain more than one image or not.
        /// </summary>
        public bool IsMultiIcon
        {
            get { return (this.Images.Count > 1); }
        }

        private int _bestFitIconIndex;
        /// <summary>
        /// Gets icon index that best fits to screen resolution.
        /// </summary>
        public int BestFitIconIndex
        {
            get { return _bestFitIconIndex; }
            private set { _bestFitIconIndex = value; }
        }

        private int _width;
        /// <summary>
        /// Gets icon width.
        /// </summary>
        public int Width
        {
            get { return _width; }
            private set { _width = value; }
        }

        private int _height;
        /// <summary>
        /// Gets icon height.
        /// </summary>
        public int Height
        {
            get { return _height; }
            private set { _height = value; }
        }

        private int _colorCount;
        /// <summary>
        /// Gets number of colors in icon (0 if >=8bpp).
        /// </summary>
        public int ColorCount
        {
            get { return _colorCount; }
            private set { _colorCount = value; }
        }

        private int _planes;
        /// <summary>
        /// Gets icon color planes.
        /// </summary>
        public int Planes
        {
            get { return _planes; }
            private set { _planes = value; }
        }

        private int _bitCount;
        /// <summary>
        /// Gets icon bits per pixel (0 if < 8bpp).
        /// </summary>
        public int BitCount
        {
            get { return _bitCount; }
            private set { _bitCount = value; }
        }

        /// <summary>
        /// Gets icon bits per pixel.
        /// </summary>
        public int ColorDepth
        {
            get
            {
                if (this.BitCount != 0)
                    return this.BitCount;
                if (this.ColorCount == 0)
                    return 0;
                return (int)Math.Log(this.ColorCount, 2);
            }
        }
        #endregion

        #region Icon Headers Properties
        private IconDir _iconDir;
        /// <summary>
        /// Gets the TAFactory.IconPack.IconDir of the icon.
        /// </summary>
        public IconDir IconDir
        {
            get { return _iconDir; }
            private set { _iconDir = value; }
        }

        private GroupIconDir _groupIconDir;
        /// <summary>
        /// Gets the TAFactory.IconPack.GroupIconDir of the icon.
        /// </summary>
        public GroupIconDir GroupIconDir
        {
            get { return _groupIconDir; }
            private set { _groupIconDir = value; }
        }

        private List<IconDirEntry> _iconDirEntries;
        /// <summary>
        /// Gets a list of TAFactory.IconPack.IconDirEntry of the icon.
        /// </summary>
        public List<IconDirEntry> IconDirEntries
        {
            get { return _iconDirEntries; }
            private set { _iconDirEntries = value; }
        }

        private List<GroupIconDirEntry> _groupIconDirEntries;
        /// <summary>
        /// Gets a list of TAFactory.IconPack.GroupIconDirEntry of the icon.
        /// </summary>
        public List<GroupIconDirEntry> GroupIconDirEntries
        {
            get { return _groupIconDirEntries; }
            private set { _groupIconDirEntries = value; }
        }

        private List<byte[]> _rawData;
        /// <summary>
        /// Gets a list of raw data for each icon image.
        /// </summary>
        public List<byte[]> RawData
        {
            get { return _rawData; }
            private set { _rawData = value; }
        }

        private byte[] _resourceRawData;
        /// <summary>
        /// Gets the icon raw data as a resource data.
        /// </summary>
        public byte[] ResourceRawData
        {
            get { return _resourceRawData; }
            set { _resourceRawData = value; }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Intializes a new instance of TAFactory.IconPack.IconInfo which contains the information about the givin icon.
        /// </summary>
        /// <param name="icon">A System.Drawing.Icon object to retrieve the information about.</param>
        public IconInfo(Icon icon)
        {
            this.FileName = null;
            LoadIconInfo(icon);
        }

        /// <summary>
        /// Intializes a new instance of TAFactory.IconPack.IconInfo which contains the information about the icon in the givin file.
        /// </summary>
        /// <param name="fileName">A fully qualified name of the icon file, it can contain environment variables.</param>
        public IconInfo(string fileName)
        {
            this.FileName = FileName;
            LoadIconInfo(new Icon(fileName));
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Gets the index of the icon that best fits the current display device.
        /// </summary>
        /// <returns>The icon index.</returns>
        public int GetBestFitIconIndex()
        {
            int iconIndex = 0;
            IntPtr resBits = Marshal.AllocHGlobal(this.ResourceRawData.Length);
            Marshal.Copy(this.ResourceRawData, 0, resBits, this.ResourceRawData.Length);
            try { iconIndex = Win32.LookupIconIdFromDirectory(resBits, true); }
            finally { Marshal.FreeHGlobal(resBits); }

            return iconIndex;
        }
        /// <summary>
        /// Gets the index of the icon that best fits the current display device.
        /// </summary>
        /// <param name="desiredSize">Specifies the desired size of the icon.</param>
        /// <returns>The icon index.</returns>
        public int GetBestFitIconIndex(Size desiredSize)
        {
            return GetBestFitIconIndex(desiredSize, false);
        }
        /// <summary>
        /// Gets the index of the icon that best fits the current display device.
        /// </summary>
        /// <param name="desiredSize">Specifies the desired size of the icon.</param>
        /// <param name="isMonochrome">Specifies whether to get the monochrome icon or the colored one.</param>
        /// <returns>The icon index.</returns>
        public int GetBestFitIconIndex(Size desiredSize, bool isMonochrome)
        {
            int iconIndex = 0;
            LookupIconIdFromDirectoryExFlags flags = LookupIconIdFromDirectoryExFlags.LR_DEFAULTCOLOR;
            if (isMonochrome)
                flags = LookupIconIdFromDirectoryExFlags.LR_MONOCHROME;
            IntPtr resBits = Marshal.AllocHGlobal(this.ResourceRawData.Length);
            Marshal.Copy(this.ResourceRawData, 0, resBits, this.ResourceRawData.Length);
            try { iconIndex = Win32.LookupIconIdFromDirectoryEx(resBits, true, desiredSize.Width, desiredSize.Height, flags); }
            finally { Marshal.FreeHGlobal(resBits); }

            return iconIndex;
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Loads the icon information from the givin icon into class members.
        /// </summary>
        /// <param name="icon">A System.Drawing.Icon object to retrieve the information about.</param>
        private void LoadIconInfo(Icon icon)
        {
            if (icon == null)
                throw new ArgumentNullException("icon");

            this.SourceIcon = icon;
            MemoryStream inputStream = new MemoryStream();
            this.SourceIcon.Save(inputStream);

            inputStream.Seek(0, SeekOrigin.Begin);
            IconDir dir = Utility.ReadStructure<IconDir>(inputStream);
            
            this.IconDir = dir;
            this.GroupIconDir = dir.ToGroupIconDir();

            this.Images = new List<Icon>(dir.Count);
            this.IconDirEntries = new List<IconDirEntry>(dir.Count);
            this.GroupIconDirEntries = new List<GroupIconDirEntry>(dir.Count);
            this.RawData = new List<byte[]>(dir.Count);

            IconDir newDir = dir;
            newDir.Count = 1;
            for (int i = 0; i < dir.Count; i++)
            {
                inputStream.Seek(SizeOfIconDir + i * SizeOfIconDirEntry, SeekOrigin.Begin);

                IconDirEntry entry = Utility.ReadStructure<IconDirEntry>(inputStream);
                
                this.IconDirEntries.Add(entry);
                this.GroupIconDirEntries.Add(entry.ToGroupIconDirEntry(i));

                byte[] content = new byte[entry.BytesInRes];
                inputStream.Seek(entry.ImageOffset, SeekOrigin.Begin);
                inputStream.Read(content, 0, content.Length);
                this.RawData.Add(content);

                IconDirEntry newEntry = entry;
                newEntry.ImageOffset = SizeOfIconDir + SizeOfIconDirEntry;

                MemoryStream outputStream = new MemoryStream();
                Utility.WriteStructure<IconDir>(outputStream, newDir);
                Utility.WriteStructure<IconDirEntry>(outputStream, newEntry);
                outputStream.Write(content, 0, content.Length);

                outputStream.Seek(0, SeekOrigin.Begin);
                Icon newIcon = new Icon(outputStream);
                outputStream.Close();

                this.Images.Add(newIcon);
                if (dir.Count == 1)
                {
                    this.BestFitIconIndex = 0;

                    this.Width = entry.Width;
                    this.Height = entry.Height;
                    this.ColorCount = entry.ColorCount;
                    this.Planes = entry.Planes;
                    this.BitCount = entry.BitCount;
                }
            }
            inputStream.Close();
            this.ResourceRawData = GetIconResourceData();

            if (dir.Count > 1)
            {
                this.BestFitIconIndex = GetBestFitIconIndex();

                this.Width = this.IconDirEntries[this.BestFitIconIndex].Width;
                this.Height = this.IconDirEntries[this.BestFitIconIndex].Height;
                this.ColorCount = this.IconDirEntries[this.BestFitIconIndex].ColorCount;
                this.Planes = this.IconDirEntries[this.BestFitIconIndex].Planes;
                this.BitCount = this.IconDirEntries[this.BestFitIconIndex].BitCount;
            }

        }
        /// <summary>
        /// Returns the icon's raw data as a resource data.
        /// </summary>
        /// <returns>The icon's raw as a resource data.</returns>
        private byte[] GetIconResourceData()
        {
            MemoryStream outputStream = new MemoryStream();
            Utility.WriteStructure<GroupIconDir>(outputStream, this.GroupIconDir);
            foreach (GroupIconDirEntry entry in this.GroupIconDirEntries)
            {
                Utility.WriteStructure<GroupIconDirEntry>(outputStream, entry);
            }

            return outputStream.ToArray();
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect RoboteQ
Egypt Egypt
Abdallah Gomah
Master in Computer Science, 2013, Faculty of Computers & Information, Cairo University (Egypt)

- Working as a developer since I graduated from the faculty.
- Like coding in C++ aloso like to code in assembly.
- Have a great experience in coding with .NET (C#/VB), but I prefer the C# notation.
- Had written a lot of applications Desktop and Web.

I love playing football as much as I love the programming.

Comments and Discussions