システムイメージリストの作成と利用 - C#

エクスプローラのアイコンを管理している、システムイメージリストを作成し、アイコンを参照して利用するコードを紹介します。

概要

SHGetFileInfo() APIで第4引数に"SHGFI_SYSICONINDEX"を与えて呼び出すと、システムイメージリストのハンドルを取得できます。合わせて"SHGFI_LARGEICON"を指定すると大きいアイコンを取得できます。

プログラム

UI

下図のUIを作成します。

コード

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

namespace ShellObjects
{
  public class SystemImageList
  {
    public enum SystemIconSize {Small, Large};

    // Used to store the handle of the system image list.
    private static IntPtr m_pImgHandle = IntPtr.Zero;

    // Flags whether we've already retrieved the image list handle or not.
    private static Boolean m_bImgInit = false;

    // TreeView message constants.
    private const UInt32 TVSIL_NORMAL = 0x0000;
    private const UInt32 TVSIL_STATE  = 0x0002;
    private const UInt32 TVM_SETIMAGELIST = 0x1109; //4361;

    // ListView message constants.
    private const UInt32 LVSIL_NORMAL = 0x0000;
    private const UInt32 LVSIL_SMALL  = 0x0001;
    private const UInt32 LVSIL_STATE  = 0x0002;
    private const UInt32 LVSIL_GROUPHEADER  = 0x0003;
    private const UInt32 LVM_SETIMAGELIST = 0x1003;


    public SystemImageList(bool SelectedImage, SystemIconSize iconSize)
    {
      InitImageList(SelectedImage, iconSize);
    }

    private void InitImageList(bool selected, SystemIconSize iconSize)
    {
      IntPtr ppidl = IntPtr.Zero;
      ShellWindowsAPI.SHGetSpecialFolderLocation(IntPtr.Zero, ShellWindowsAPI.CSIDL.CSIDL_DESKTOP, ref ppidl);

      ShellWindowsAPI.SHFILEINFO shInfo = new ShellWindowsAPI.SHFILEINFO();
      ShellWindowsAPI.SHGFI dwAttribs;
      
      
      dwAttribs = ShellWindowsAPI.SHGFI.SHGFI_USEFILEATTRIBUTES | ShellWindowsAPI.SHGFI.SHGFI_SYSICONINDEX;

      switch (iconSize) {
        case SystemIconSize.Small:
          dwAttribs = dwAttribs | ShellWindowsAPI.SHGFI.SHGFI_SMALLICON;
          break;
        case SystemIconSize.Large:
          dwAttribs = dwAttribs | ShellWindowsAPI.SHGFI.SHGFI_LARGEICON;
          break;
      }

      if (selected == true) {
        dwAttribs = dwAttribs | ShellWindowsAPI.SHGFI.SHGFI_SELECTED;
      }

      m_pImgHandle = ShellWindowsAPI.SHGetFileInfo(ppidl, ShellWindowsAPI.FILE_ATTRIBUTE_NORMAL, out shInfo, (uint)Marshal.SizeOf(shInfo), dwAttribs);
    }

    /// <summary>
    /// Sets the image list for the TreeView to the system image list.
    /// </summary>
    /// <param name="tvwHandle">The window handle of the TreeView control</param>
    public void TreeViewSetImageList(TreeView targetTreeView)
    {
      //InitImageList();
      Int32 hRes = ShellWindowsAPI.SendMessage(targetTreeView.Handle, TVM_SETIMAGELIST, TVSIL_NORMAL, m_pImgHandle);
      if (hRes != 0)
        Marshal.ThrowExceptionForHR(hRes);
    }

    /// <summary>
    /// Sets the image list for the ListView to the system image list.
    /// </summary>
    /// <param name="tvwHandle">The window handle of the TreeView control</param>
    public void ListViewSetImageList(ListView targetListView)
    {
      //InitImageList();
      Int32 hRes = ShellWindowsAPI.SendMessage(targetListView.Handle, LVM_SETIMAGELIST, LVSIL_NORMAL, m_pImgHandle);
      if (hRes != 0)
        Marshal.ThrowExceptionForHR(hRes);
    }
  }
}
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 ShellObjects;

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

    private void Form1_Load(object sender, EventArgs e)
    {
      SystemImageList sil1 = new SystemImageList(false, SystemImageList.SystemIconSize.Small);
      sil1.TreeViewSetImageList(treeView1);

      SystemImageList sil2 = new SystemImageList(false, SystemImageList.SystemIconSize.Large);
      sil2.ListViewSetImageList(listView1);
    }

    private void button1_Click(object sender, EventArgs e)
    {
      for (int i=0; i < 100; i++) {
        TreeNode tn = new TreeNode("test-"+i.ToString(), i, i);
        treeView1.Nodes.Add(tn);
      }

      for (int i=0; i < 100; i++) {
        ListViewItem lv = new ListViewItem("test-" + i.ToString());
        lv.ImageIndex = i;
        
        listView1.Items.Add(lv);
      }   
    }
  }
}

解説

プロジェクト配置

SystemImageList.csは別のクラスライブラリプロジェクト"ShellObjects"に配置しています。Windowsフォームアプリ側で参照設定にShellObjectsプロジェクトを追加して、uses ShellObjects を記述します。

システムイメージリスト

SHGetFileInfo() APIで第4引数に"SHGFI_SYSICONINDEX"を与えて呼び出すと、システムイメージリストのハンドルを取得できます。
リストビューでは大きい画像のシステムイメージリストを取得するため、第4引数に"SHGFI_LARGEICON"を加えて指定します。ツリービューでは、小さいアイコンを指定するため、第4引数に"SHGFI_SMALLICON"を加えて指定します。

コントロールへの設定

コントロールへの設定はWindowsメッセージの送信で設定します。ツリービューへイメージリストを設定する場合は、TVM_SETIMAGELISTメッセージをコントロールに送信します。リストビューの場合は、LVM_SETIMAGELISTメッセージを送信します。メッセージのwparamに設定したいイメージリストのハンドルを与えます。

実行結果

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


[button1]をクリックします。TreeViewとListViewに項目が追加され、システムイメージリストのアイコンが表示されます。エクスプローラのフォルダやディスクドライブ、ネットワークのアイコンが表示されることが確認できます。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2020-03-21
作成日: 2015-05-27
iPentec all rights reserverd.