前回に引き続き、Windows Forms で、エクスプローラーのような表示をするために、
今回はファイル・フォルダの横にアイコンを表示してみます。
プログラムは前回のものを流用します。
https://www.doraxdora.com/blog/2018/01/30/post-3801/
システムイメージを利用するには「Shll32.dll」、「user32.dll」の関数を呼び出す必要があるため、関数呼び出しの宣言を追加します。
// DllImportに必要
using System.Runtime.InteropServices;
/// <summary>
/// ファイル情報を取得
/// </summary>
/// <param name="pszPath"></param>
/// <param name="dwFileAttributes"></param>
/// <param name="psfi"></param>
/// <param name="cbFileInfo"></param>
/// <param name="uFlags"></param>
/// <returns></returns>
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
/// <summary>
/// イメージリストを登録
/// </summary>
/// <param name="hWnd"></param>
/// <param name="Msg"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
DLL関数で利用する構造体や定数の定義を追加します。
/// <summary>
/// SHGetFileInfo関数で使用する構造体
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private 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;
};
// ファイル情報用
private const int SHGFI_LARGEICON = 0x00000000;
private const int SHGFI_SMALLICON = 0x00000001;
private const int SHGFI_USEFILEATTRIBUTES = 0x00000010;
private const int SHGFI_OVERLAYINDEX = 0x00000040;
private const int SHGFI_ICON = 0x00000100;
private const int SHGFI_SYSICONINDEX = 0x00004000;
private const int SHGFI_TYPENAME = 0x000000400;
// TreeView用
private const int TVSIL_NORMAL = 0x0000;
private const int TVSIL_STATE = 0x0002;
private const int TVM_SETIMAGELIST = 0x1109;
// ListView用
private const int LVSIL_NORMAL = 0;
private const int LVSIL_SMALL = 1;
private const int LVM_SETIMAGELIST = 0x1003;
// 選択された項目を保持
private String selectedItem = "";
起動時の処理で、TreeView、ListViewにイメージのリストを登録します。
/// <summary>
/// 起動時の処理
/// </summary>
public Form1()
{
InitializeComponent();
// イメージリストの設定
SHFILEINFO shFileInfo = new SHFILEINFO();
IntPtr imageListHandle = SHGetFileInfo(String.Empty, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
// TreeView
SendMessage(treeView1.Handle, TVM_SETIMAGELIST, new IntPtr(TVSIL_NORMAL), imageListHandle);
// ListView
SendMessage(listView1.Handle, LVM_SETIMAGELIST, new IntPtr(LVSIL_SMALL), imageListHandle);
// ドライブ一覧を走査してツリーに追加
foreach (String drive in Environment.GetLogicalDrives())
{
// アイコンの取得
int iconIndex = 0;
IntPtr hSuccess = SHGetFileInfo(drive, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_SYSICONINDEX );
if (hSuccess != IntPtr.Zero)
{
iconIndex = shFileInfo.iIcon;
}
// 新規ノード作成
// プラスボタンを表示するため空のノードを追加しておく
TreeNode node = new TreeNode(drive, iconIndex, iconIndex);
node.Nodes.Add(new TreeNode());
treeView1.Nodes.Add(node);
}
// 初期選択ドライブの内容を表示
setListItem(Environment.GetLogicalDrives().First());
}
TreeViewが選択された際にListViewの内容を更新する処理で、
表示するファイル、フォルダ―のイメージを取得して設定します。
/// <summary>
/// リストビューの項目を設定します.
/// </summary>
private void setListItem(String filePath)
{
// リストビューのヘッダーを設定
listView1.View = View.Details;
listView1.Clear();
listView1.Columns.Add("名前");
listView1.Columns.Add("種類");
listView1.Columns.Add("更新日時");
listView1.Columns.Add("サイズ");
try
{
// フォルダ一覧
DirectoryInfo dirList = new DirectoryInfo(filePath);
foreach (DirectoryInfo di in dirList.GetDirectories())
{
ListViewItem item = new ListViewItem(di.Name);
// フォルダ種類、アイコンの取得
String type = "";
int iconIndex = 0;
SHFILEINFO shFileInfo = new SHFILEINFO();
IntPtr hSuccess = SHGetFileInfo(di.FullName, 0, out shFileInfo, (uint)Marshal.SizeOf(shFileInfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (hSuccess != IntPtr.Zero)
{
type = shFileInfo.szTypeName;
iconIndex = shFileInfo.iIcon;
}
// 各列の内容を設定
item.ImageIndex = iconIndex;
item.SubItems.Add(type);
item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", di.LastAccessTime));
item.SubItems.Add("");
// リストに追加
listView1.Items.Add(item);
}
// ファイル一覧
List<String> files = Directory.GetFiles(filePath).ToList<String>();
foreach (String file in files)
{
FileInfo info = new FileInfo(file);
ListViewItem item = new ListViewItem(info.Name);
// ファイル種類、アイコンの取得
String type = "";
int iconIndex = 0;
SHFILEINFO shinfo = new SHFILEINFO();
IntPtr hSuccess = SHGetFileInfo(info.FullName, 0, out shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (hSuccess != IntPtr.Zero)
{
type = shinfo.szTypeName;
iconIndex = shinfo.iIcon;
}
// 各列の内容を設定
item.ImageIndex = iconIndex;
item.SubItems.Add(type);
item.SubItems.Add(String.Format("{0:yyyy/MM/dd HH:mm:ss}", info.LastAccessTime));
item.SubItems.Add(getFileSize(info.Length));
listView1.Items.Add(item);
}
}
catch (IOException ie)
{
MessageBox.Show(ie.Message, "選択エラー");
}
// 列幅を自動調整
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
同様に TreeView を展開する際の処理で、
フォルダ―のアイコンを取得して設定するように修正します。
/// <summary>
/// ツリービュー項目展開時(前)のイベントハンドラ.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
TreeNode node = e.Node;
node.Nodes.Clear();
try
{
DirectoryInfo dirList = new DirectoryInfo(node.FullPath);
foreach (DirectoryInfo di in dirList.GetDirectories())
{
// フォルダのアイコンを取得
SHFILEINFO shinfo = new SHFILEINFO();
int iconIndex = 0;
IntPtr hSuccess = SHGetFileInfo(di.FullName, 0, out shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
if (hSuccess != IntPtr.Zero)
{
iconIndex = shinfo.iIcon;
}
// 子を追加してノードを展開
TreeNode child = new TreeNode(di.Name, shinfo.iIcon, shinfo.iIcon);
child.ImageIndex = iconIndex;
child.Nodes.Add(new TreeNode());
node.Nodes.Add(child);
}
}
catch (IOException ie)
{
MessageBox.Show(ie.Message, "選択エラー");
}
}
無事に TreeView、ListViewにアイコンを表示することができ、
更にエクスプローラーのようなUIになりました。
プログラムについては共通化したり、別クラスに処理をまとめたりできるので整理が必要ですが、
ひとまずアイコンを表示する方法を試してみました。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント