Download Cyotek.ArcadeExplosionMaker.zip version 1.0.0.1, last updated 05/06/2012 (123.69 KB)

Download
  • md5: bd412009442f7923a555ba5b0f508fe0
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

// http://www.codeproject.com/Articles/26824/Extract-icons-from-EXE-or-DLL-files

namespace TKageyu.Utils
{
  internal class IconExtractor : IDisposable
  {
    #region  Nested Classes


    private class IconResInfo
    {
      #region  Public Member Declarations

      public List<ResourceName> IconNames = new List<ResourceName>();

      #endregion  Public Member Declarations
    }
    private class ResourceName
    {
      #region  Private Member Declarations

      private IntPtr _bufPtr = IntPtr.Zero;

      #endregion  Private Member Declarations

      #region  Public Constructors

      public ResourceName(IntPtr lpName)
      {
        if (((uint)lpName >> 16) == 0) // #define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16) == 0)
        {
          this.Id = lpName;
          this.Name = null;
        }
        else
        {
          this.Id = IntPtr.Zero;
          this.Name = Marshal.PtrToStringAuto(lpName);
        }
      }

      #endregion  Public Constructors

      #region  Public Methods

      public void Free()
      {
        if (this._bufPtr != IntPtr.Zero)
        {
          try { Marshal.FreeHGlobal(this._bufPtr); }
          catch { }

          this._bufPtr = IntPtr.Zero;
        }
      }

      public IntPtr GetValue()
      {
        if (this.Name == null)
        {
          return this.Id;
        }
        else
        {
          this._bufPtr = Marshal.StringToHGlobalAuto(this.Name);
          return this._bufPtr;
        }
      }

      #endregion  Public Methods

      #region  Public Properties

      public IntPtr Id { get; private set; }

      public string Name { get; private set; }

      #endregion  Public Properties
    }
    #endregion  Nested Classes

    #region  Private Member Declarations

    private string _filename = null;
    private IntPtr _hModule = IntPtr.Zero;
    private Icon[] _iconCache = null;
    private IconResInfo _resInfo = null;
    private const int ERROR_BAD_EXE_FORMAT = 193;
    private const int ERROR_FILE_NOT_FOUND = 2;
    private const int ERROR_RESOURCE_TYPE_NOT_FOUND = 1813;
    private const int ERROR_SUCCESS = 0;
    private const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
    private const int MAX_PATH = 260;
    private const int RT_GROUP_ICON = 14;
    private const int RT_ICON = 3;
    // sizeof(ICONDIRENTRY)
    private const int sGRPICONDIRENTRY = 14;
    private const int sICONDIR = 6;
    // sizeof(ICONDIR) 
    private const int sICONDIRENTRY = 16;

    #endregion  Private Member Declarations

    #region  Public Constructors

    /// <summary>
    /// Load the specified executable file or DLL, and get ready to extract the icons.
    /// </summary>
    /// <param name="filename">The name of a file from which icons will be extracted.</param>
    public IconExtractor(string filename)
    {
      if (filename == null)
      {
        throw new ArgumentNullException("filename");
      }

      this._hModule = LoadLibrary(filename);
      if (this._hModule == IntPtr.Zero)
      {
        this._hModule = LoadLibraryEx(filename, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
        if (this._hModule == IntPtr.Zero)
        {
          switch (Marshal.GetLastWin32Error())
          {
            case ERROR_FILE_NOT_FOUND:
              throw new FileNotFoundException("Specified file '" + filename + "' not found.");

            case ERROR_BAD_EXE_FORMAT:
              throw new ArgumentException("Specified file '" + filename + "' is not an executable file or DLL.");

            default:
              throw new Win32Exception();
          }
        }
      }

      StringBuilder buf = new StringBuilder(MAX_PATH);
      int len = GetModuleFileName(this._hModule, buf, buf.Capacity + 1);
      if (len != 0)
      {
        this._filename = buf.ToString();
      }
      else
      {
        switch (Marshal.GetLastWin32Error())
        {
          case ERROR_SUCCESS:
            this._filename = filename;
            break;

          default:
            throw new Win32Exception();
        }
      }

      this._resInfo = new IconResInfo();
      bool success = EnumResourceNames(this._hModule, RT_GROUP_ICON, EnumResNameCallBack, this._resInfo);
      if (!success)
      {
        throw new Win32Exception();
      }

      this._iconCache = new Icon[this.IconCount];
    }

    #endregion  Public Constructors

    #region  Private Constructors

    ~IconExtractor()
    {
      Dispose();
    }

    #endregion  Private Constructors

    #region  Delegates

    [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Auto)]
    private delegate bool EnumResNameProc(IntPtr hModule, int lpszType, IntPtr lpszName, IconResInfo lParam);

    #endregion  Delegates

    #region  Public Class Methods

    /// <summary>
    /// Split an Icon consists of multiple icons into an array of Icon each consist of single icons.
    /// </summary>
    /// <param name="icon">The System.Drawing.Icon to be split.</param>
    /// <returns>An array of System.Drawing.Icon each consist of single icons.</returns>
    public static Icon[] SplitIcon(Icon icon)
    {
      if (icon == null)
      {
        throw new ArgumentNullException("icon");
      }

      // Get multiple .ico file image.
      byte[] srcBuf = null;
      using (MemoryStream stream = new MemoryStream())
      {
        icon.Save(stream);
        srcBuf = stream.ToArray();
      }

      List<Icon> splitIcons = new List<Icon>();
      {
        int count = BitConverter.ToInt16(srcBuf, 4); // ICONDIR.idCount

        for (int i = 0; i < count; i++)
        {
          using (MemoryStream destStream = new MemoryStream())
          using (BinaryWriter writer = new BinaryWriter(destStream))
          {
            // Copy ICONDIR and ICONDIRENTRY.
            writer.Write(srcBuf, 0, sICONDIR - 2);
            writer.Write((short)1);    // ICONDIR.idCount == 1;

            writer.Write(srcBuf, sICONDIR + sICONDIRENTRY * i, sICONDIRENTRY - 4);
            writer.Write(sICONDIR + sICONDIRENTRY);    // ICONDIRENTRY.dwImageOffset = sizeof(ICONDIR) + sizeof(ICONDIRENTRY)

            // Copy picture and mask data.
            int imgSize = BitConverter.ToInt32(srcBuf, sICONDIR + sICONDIRENTRY * i + 8);       // ICONDIRENTRY.dwBytesInRes
            int imgOffset = BitConverter.ToInt32(srcBuf, sICONDIR + sICONDIRENTRY * i + 12);    // ICONDIRENTRY.dwImageOffset
            writer.Write(srcBuf, imgOffset, imgSize);

            // Create new icon.
            destStream.Seek(0, SeekOrigin.Begin);
            splitIcons.Add(new Icon(destStream));
          }
        }
      }

      return splitIcons.ToArray();
    }

    #endregion  Public Class Methods

    #region  Private Class Methods

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool EnumResourceNames(
        IntPtr hModule, int lpszType, EnumResNameProc lpEnumFunc, IconResInfo lParam);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, int lpType);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    private static extern bool FreeLibrary(IntPtr hModule);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern int GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize);

    // sizeof(GRPICONDIRENTRY)
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, int dwFlags);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    private static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    private static extern IntPtr LockResource(IntPtr hResData);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    private static extern int SizeofResource(IntPtr hModule, IntPtr hResInfo);

    #endregion  Private Class Methods

    #region  Public Overridden Methods

    public override string ToString()
    {
      string text = String.Format("IconExtractor (Filename: '{0}', IconCount: {1})", this.Filename, this.IconCount);
      return text;
    }

    #endregion  Public Overridden Methods

    #region  Public Methods

    public void Dispose()
    {
      if (this._hModule != IntPtr.Zero)
      {
        try { FreeLibrary(this._hModule); }
        catch { }

        this._hModule = IntPtr.Zero;
      }

      if (this._iconCache != null)
      {
        foreach (Icon i in this._iconCache)
        {
          if (i != null)
          {
            try { i.Dispose(); }
            catch { }
          }
        }

        this._iconCache = null;
      }
    }

    /// <summary>
    /// Extract an icon from the loaded executable file or DLL. 
    /// </summary>
    /// <param name="iconIndex">The zero-based index of the icon to be extracted.</param>
    /// <returns>A System.Drawing.Icon object which may consists of multiple icons.</returns>
    /// <remarks>Always returns new copy of the Icon. It should be disposed by the user.</remarks>
    public Icon GetIcon(int iconIndex)
    {
      if (this._hModule == IntPtr.Zero)
      {
        throw new ObjectDisposedException("IconExtractor");
      }

      if (iconIndex < 0 || this.IconCount <= iconIndex)
      {
        throw new ArgumentException(
            "iconIndex is out of range. It should be between 0 and " + (this.IconCount - 1).ToString() + ".");
      }

      if (this._iconCache[iconIndex] == null)
      {
        this._iconCache[iconIndex] = CreateIcon(iconIndex);
      }

      return (Icon)this._iconCache[iconIndex].Clone();
    }

    #endregion  Public Methods

    #region  Public Properties

    // Full path 
    public string Filename
    {
      get { return this._filename; }
    }

    public int IconCount
    {
      get { return this._resInfo.IconNames.Count; }
    }

    #endregion  Public Properties

    #region  Private Methods

    private Icon CreateIcon(int iconIndex)
    {
      // Get group icon resource.
      byte[] srcBuf = GetResourceData(this._hModule, this._resInfo.IconNames[iconIndex], RT_GROUP_ICON);

      // Convert the resouce into an .ico file image.
      using (MemoryStream destStream = new MemoryStream())
      using (BinaryWriter writer = new BinaryWriter(destStream))
      {
        int count = BitConverter.ToUInt16(srcBuf, 4); // ICONDIR.idCount
        int imgOffset = sICONDIR + sICONDIRENTRY * count;

        // Copy ICONDIR.
        writer.Write(srcBuf, 0, sICONDIR);

        for (int i = 0; i < count; i++)
        {
          // Copy GRPICONDIRENTRY converting into ICONDIRENTRY.
          writer.BaseStream.Seek(sICONDIR + sICONDIRENTRY * i, SeekOrigin.Begin);
          writer.Write(srcBuf, sICONDIR + sGRPICONDIRENTRY * i, sICONDIRENTRY - 4);   // Common fields of structures
          writer.Write(imgOffset);                                                    // ICONDIRENTRY.dwImageOffset

          // Get picture and mask data, then copy them.
          IntPtr nID = (IntPtr)BitConverter.ToUInt16(srcBuf, sICONDIR + sGRPICONDIRENTRY * i + 12); // GRPICONDIRENTRY.nID
          byte[] imgBuf = GetResourceData(this._hModule, nID, RT_ICON);

          writer.BaseStream.Seek(imgOffset, SeekOrigin.Begin);
          writer.Write(imgBuf, 0, imgBuf.Length);

          imgOffset += imgBuf.Length;
        }

        destStream.Seek(0, SeekOrigin.Begin);
        return new Icon(destStream);
      }
    }

    private bool EnumResNameCallBack(IntPtr hModule, int lpszType, IntPtr lpszName, IconResInfo lParam)
    {
      // Callback function for EnumResourceNames().

      if (lpszType == RT_GROUP_ICON)
      {
        lParam.IconNames.Add(new ResourceName(lpszName));
      }

      return true;
    }

    private byte[] GetResourceData(IntPtr hModule, IntPtr lpName, int lpType)
    {
      // Get binary image of the specified resource.

      IntPtr hResInfo = FindResource(hModule, lpName, lpType);
      if (hResInfo == IntPtr.Zero)
      {
        throw new Win32Exception();
      }

      IntPtr hResData = LoadResource(hModule, hResInfo);
      if (hResData == IntPtr.Zero)
      {
        throw new Win32Exception();
      }

      IntPtr hGlobal = LockResource(hResData);
      if (hGlobal == IntPtr.Zero)
      {
        throw new Win32Exception();
      }

      int resSize = SizeofResource(hModule, hResInfo);
      if (resSize == 0)
      {
        throw new Win32Exception();
      }

      byte[] buf = new byte[resSize];
      Marshal.Copy(hGlobal, buf, 0, buf.Length);

      return buf;
    }

    private byte[] GetResourceData(IntPtr hModule, ResourceName name, int lpType)
    {
      try
      {
        IntPtr lpName = name.GetValue();
        return GetResourceData(hModule, lpName, lpType);
      }
      finally
      {
        name.Free();
      }
    }

    #endregion  Private Methods
  }
}

Donate

Donate