ファイル名・ファイルパスから 特大アイコン (48x48 256x256 ピクセル) を取得する - C#

ファイル名・ファイルパスから 「特大アイコン」や「並べて表示」のアイコンを取得するコードを紹介します。
「特大アイコン」や「並べて表示」のアイコンはWindows Vistaから導入された新しいサイズのアイコンです。

アイコンのサイズ

アイコンのサイズは以下になります。
  • 「並べて表示」のアイコン : 48x48 ピクセル
  • 「特大アイコン」のアイコン : 256x256 ピクセル

概要

大きいサイズのアイコンを取得する場合は、システムイメージリストを取得する必要があります。
従来のシステムイメージリストは、SHGetFileInfo() APIで第4引数に"SHGFI_SYSICONINDEX"を与えて取得しますが、大きい画像を格納するシステムイメージリストはSHGetImageList() APIを利用してシステムイメージリストを取得します。
SHGetFileInfo()でファイルのアイコンインデックスを取得し、取得したイメージリストからアイコンを取り出すことで、大きなアイコンを取得できます。

UI

下図のUIを作成します。
TextBox, Button, Panelを1つづつ配置し、RadioButtonを2つ配置します。

コード

下記のコードを記述します。
FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GetBigShellIcon
{
  public partial class FormMain : Form
  {
    public FormMain()
    {
      InitializeComponent();
    }

    private void FormMain_Load(object sender, EventArgs e)
    {
    
    }

    private void button1_Click(object sender, EventArgs e)
    {
      WindowsShellAPI.SHFILEINFO shinfo = new WindowsShellAPI.SHFILEINFO();

      string filename =textBox1.Text;
      IntPtr hImg = WindowsShellAPI.SHGetFileInfo(filename, 0, out shinfo, (uint)Marshal.SizeOf(typeof(WindowsShellAPI.SHFILEINFO)), WindowsShellAPI.SHGFI.SHGFI_SYSICONINDEX);
      
      WindowsShellAPI.SHIL currentshil= WindowsShellAPI.SHIL.SHIL_EXTRALARGE;
      if (radioButton2.Checked == true) {
        currentshil = WindowsShellAPI.SHIL.SHIL_JUMBO;
      }

      
      WindowsShellAPI.IImageList imglist = null;
      //int rsult = WindowsShellAPI.SHGetImageList(WindowsShellAPI.SHIL.SHIL_EXTRALARGE, ref WindowsShellAPI.IID_IImageList, out imglist);
      //int rsult = WindowsShellAPI.SHGetImageList(WindowsShellAPI.SHIL.SHIL_JUMBO, ref WindowsShellAPI.IID_IImageList, out imglist);
      int rsult = WindowsShellAPI.SHGetImageList(currentshil, ref WindowsShellAPI.IID_IImageList, out imglist);

      IntPtr hicon = IntPtr.Zero;
      imglist.GetIcon(shinfo.iIcon, (int)WindowsShellAPI.ImageListDrawItemConstants.ILD_TRANSPARENT, ref hicon);

      Icon myIcon = Icon.FromHandle(hicon);
      Graphics g = Graphics.FromHwnd(panel1.Handle);
      g.DrawIcon(myIcon, 10, 10);
    }
  }
}
WindowsShellAPI.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace GetBigShellIcon
{
  public class WindowsShellAPI
  {
    [DllImport("shell32.dll")]
    public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttribs, out SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags);

    [DllImport("shell32.dll", EntryPoint = "#727")]
    public static extern int SHGetImageList(int iImageList, ref Guid riid, ref IImageList ppv);

    //[DllImport("shell32.dll", EntryPoint = "#727")]
    //public static extern int SHGetImageList(SHIL iImageList, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, ref IImageList ppv);

    [DllImport("shell32.dll", EntryPoint = "#727")]
    public static extern int SHGetImageList(SHIL iImageList, ref Guid riid, out IImageList ppv);

    //
    [DllImport("shell32.dll", EntryPoint = "#727")]
    public static extern int SHGetImageList(SHIL iImageList, ref Guid riid, out IntPtr ppv);

    [DllImport("comctl32.dll", SetLastError = true)]
    public static extern IntPtr ImageList_GetIcon(IntPtr himl, int i, int flags);

    //SHFILEINFO
    [Flags]
    public enum SHGFI
    {
      SHGFI_ICON = 0x000000100,
      SHGFI_DISPLAYNAME = 0x000000200,
      SHGFI_TYPENAME = 0x000000400,
      SHGFI_ATTRIBUTES = 0x000000800,
      SHGFI_ICONLOCATION = 0x000001000,
      SHGFI_EXETYPE = 0x000002000,
      SHGFI_SYSICONINDEX = 0x000004000,
      SHGFI_LINKOVERLAY = 0x000008000,
      SHGFI_SELECTED = 0x000010000,
      SHGFI_ATTR_SPECIFIED = 0x000020000,
      SHGFI_LARGEICON = 0x000000000,
      SHGFI_SMALLICON = 0x000000001,
      SHGFI_OPENICON = 0x000000002,
      SHGFI_SHELLICONSIZE = 0x000000004,
      SHGFI_PIDL = 0x000000008,
      SHGFI_USEFILEATTRIBUTES = 0x000000010,
      SHGFI_ADDOVERLAYS = 0x000000020,
      SHGFI_OVERLAYINDEX = 0x000000040
    }

    public struct SHFILEINFO
    {
      public IntPtr hIcon;
      public int iIcon;
      public uint dwAttributes;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
      public string szDisplayName;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
      public string szTypeName;
    }



    //IMAGE LIST
    public static Guid IID_IImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
    public static Guid IID_IImageList2 = new Guid("192B9D83-50FC-457B-90A0-2B82A8B5DAE1");
    //Private Const IID_IImageList    As String = "{46EB5926-582E-4017-9FDF-E8998DAA0950}"
    //Private Const IID_IImageList2   As String = "{192B9D83-50FC-457B-90A0-2B82A8B5DAE1}"


    [Flags]
    public enum SHIL
    {
      SHIL_JUMBO = 0x0004,
      SHIL_EXTRALARGE = 0x0002
    }

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

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
      public int left, top, right, bottom;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct IMAGEINFO
    {
      public IntPtr hbmImage;
      public IntPtr hbmMask;
      public int Unused1;
      public int Unused2;
      public RECT rcImage;
    }

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

    [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
    }


    // interface COM IImageList
    [ComImportAttribute()]
    [GuidAttribute("46EB5926-582E-4017-9FDF-E8998DAA0950")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public 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);
    };
  }
}

解説

下記コードにより、SHGetFileInfo() APIを呼び出し与えたファイルパスのアイコンインデックスを取得します。
  WindowsShellAPI.SHFILEINFO shinfo = new WindowsShellAPI.SHFILEINFO();
  string filename =textBox1.Text;
  IntPtr hImg = WindowsShellAPI.SHGetFileInfo(
    filename, 0, out shinfo, (uint)Marshal.SizeOf(typeof(WindowsShellAPI.SHFILEINFO)),
    WindowsShellAPI.SHGFI.SHGFI_SYSICONINDEX);

イメージリストを取得します。ラジオボタンのチェック状態によって、48x48サイズのイメージリストを取得するか、256x256サイズのイメージリストを取得するかを決定します。
  WindowsShellAPI.SHIL currentshil= WindowsShellAPI.SHIL.SHIL_EXTRALARGE;
  if (radioButton2.Checked == true) {
    currentshil = WindowsShellAPI.SHIL.SHIL_JUMBO;
  }
      
  WindowsShellAPI.IImageList imglist = null;
  //int rsult = WindowsShellAPI.SHGetImageList(WindowsShellAPI.SHIL.SHIL_EXTRALARGE, ref WindowsShellAPI.IID_IImageList, out imglist);
  //int rsult = WindowsShellAPI.SHGetImageList(WindowsShellAPI.SHIL.SHIL_JUMBO, ref WindowsShellAPI.IID_IImageList, out imglist);
  int rsult = WindowsShellAPI.SHGetImageList(currentshil, ref WindowsShellAPI.IID_IImageList, out imglist);

SHGetImageListの第一引数による違いは下記の通りです。
動作
SHIL_EXTRALARGE並べて表示サイズ (48x48 ピクセル)のシステムイメージリストを取得します。
SHIL_JUMBO特大サイズ (256x256 ピクセル)のシステムイメージリストを取得します。

イメージリストからアイコンを取得して画面に描画します。アイコンの取得はIImageListインターフェイスのGetIcon()メソッドを利用します。取得できたアイコンのハンドルをIconクラスのFromHandle()メソッドを利用してアイコン(Iconクラスオブジェクト)を取得します。
      IntPtr hicon = IntPtr.Zero;
      imglist.GetIcon(shinfo.iIcon, (int)WindowsShellAPI.ImageListDrawItemConstants.ILD_TRANSPARENT, ref hicon);

      Icon myIcon = Icon.FromHandle(hicon);
      Graphics g = Graphics.FromHwnd(panel1.Handle);
      g.DrawIcon(myIcon, 10, 10);

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


TextBoxに"c:\"を入力し[ExtraLarge]ラジオボタンをチェックします。[button1]をクリックするとドライブC:のアイコン(48x48)が表示されます。


ラジオボタンの[Jumbo]を選択し、[button1]をクリックします。256x256 ピクセルサイズのアイコン画像が表示されます。


テキストボックスの内容を変更します。フォルダを指定した場合です。


実行ファイル(Microsoft Office 2013)を指定した場合です。


コントロールパネルの実行ファイルを指定した場合です。

参考

IImageListのインターフェイスが利用できない、もしくは、利用しない場合は、IImageListのGetIconメソッドではなく、ImageList_GetIcon() APIを利用してアイコン画像を取得することもできます。
FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GetBigShellIcon
{
  public partial class FormMain : Form
  {
    public FormMain()
    {
      InitializeComponent();
    }

    private void FormMain_Load(object sender, EventArgs e)
    {
    
    }

    private void button1_Click(object sender, EventArgs e)
    {
      WindowsShellAPI.SHFILEINFO shinfo = new WindowsShellAPI.SHFILEINFO();

      string filename =textBox1.Text;
      IntPtr hImg = WindowsShellAPI.SHGetFileInfo(filename, 0, out shinfo, (uint)Marshal.SizeOf(typeof(WindowsShellAPI.SHFILEINFO)), WindowsShellAPI.SHGFI.SHGFI_SYSICONINDEX);
      
      WindowsShellAPI.SHIL currentshil= WindowsShellAPI.SHIL.SHIL_EXTRALARGE;
      if (radioButton2.Checked == true) {
        currentshil = WindowsShellAPI.SHIL.SHIL_JUMBO;
      }

      
      WindowsShellAPI.IImageList imglist = null;
      //int rsult = WindowsShellAPI.SHGetImageList(WindowsShellAPI.SHIL.SHIL_EXTRALARGE, ref WindowsShellAPI.IID_IImageList, out imglist);
      //int rsult = WindowsShellAPI.SHGetImageList(WindowsShellAPI.SHIL.SHIL_JUMBO, ref WindowsShellAPI.IID_IImageList, out imglist);
      int rsult = WindowsShellAPI.SHGetImageList(currentshil, ref WindowsShellAPI.IID_IImageList, out imglist);

      IntPtr pimgList;
      int rsult = WindowsShellAPI.SHGetImageList(currentshil, ref WindowsShellAPI.IID_IImageList, out pimgList);
      IntPtr hicon = WindowsShellAPI.ImageList_GetIcon(pimgList, shinfo.iIcon, 0);
      Icon myIcon = Icon.FromHandle(hicon);
      Graphics g = Graphics.FromHwnd(panel1.Handle);
      g.DrawIcon(myIcon, 10, 10);
    }
  }
}
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2015-06-02
iPentec all rights reserverd.