[WPF] C# 指定したファイルのアイコンを表示する

2018-05-29 (火)

Windows API Code Packを使用してアイコンを取得して画面表示します。
ローカルファイルの場合は、System.Drawing.Icon.ExtractAssociatedIconで取得することもできますが、UNC(’\‘から始まるパス)は例外になります。

環境

  • Windows 10 Pro 64bit 1709
  • Visual Studio Community 2017 15.5.7
  • .NET Framework 4.6.1
  • C# 7.0
  • Windows API Code Pack - Core 1.1.2
  • Windows API Code Pack - Shell 1.1.1

https://github.com/aybe/Windows-API-Code-Pack-1.1

NuGetから取得します。

PM> Install-Package WindowsAPICodePack-Core
PM> Install-Package WindowsAPICodePack-Shell

結果

ファイルのアイコン取得

MainWindow.xaml

<Grid>
    <Image Name="IconImage" Stretch="None" />
</Grid>

MainWindow.xaml.cs

using Microsoft.WindowsAPICodePack.Shell;

public MainWindow()
{
    InitializeComponent();

    using (var file = ShellFile.FromFilePath(@"C:\Sample.lnk"))
    {
        file.Thumbnail.FormatOption = ShellThumbnailFormatOption.IconOnly;
        IconImage.Source = file.Thumbnail.BitmapSource; // 256x256

        // IconImage.Source = file.Thumbnail.SmallBitmapSource;      // 16x16
        // IconImage.Source = file.Thumbnail.MediumBitmapSource;     // 32x32
        // IconImage.Source = file.Thumbnail.LargeBitmapSource;      // 48x48
        // IconImage.Source = file.Thumbnail.ExtraLargeBitmapSource; // 256x256
    }
}

ショートカットのアイコン取得

ショートカットファイル(.lnk)のオーバーレイアイコンを付けて取得したい場合は、以下を使用します。

public MainWindow()
{
    InitializeComponent();

    IconImage.Source = AssociatedIcon.Create(@"C:\Sample.lnk");
}

実装

ショートカットのアイコン取得は、shell32.dllを使用します。

using System;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;

static class AssociatedIcon
{
    [DllImport("shell32.dll", EntryPoint = "ExtractAssociatedIcon")]
    private static extern IntPtr ExtractAssociatedIcon
    (
        IntPtr hInst,
        [MarshalAs(UnmanagedType.LPStr)] string lpIconPath,
        ref int lpiIcon
    );

    [DllImport("user32.dll")]
    private static extern long DestroyIcon(IntPtr hIcon);

    public BitmapSource Create(string path)
    {
        IntPtr hInst = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
        int lpiIcon = 0;

        IntPtr hIcon = ExtractAssociatedIcon(hInst, path, ref lpiIcon);

        try
        {
            var icon = Icon.FromHandle(hIcon);
            return Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
        finally
        {
            DestroyIcon(hIcon);
        }
    }
}

その他の方法

以下のような手軽な方法もあります。
ただし、UNC(\\から始まるパス)のファイルを指定すると例外になるため、使用用途に注意してください。

using System.Windows.Interop;
using System.Windows.Media.Imaging;

public MainWindow()
{
    InitializeComponent();

    // UNCのファイル(new Uri(path).IsUnc == true)の場合は例外になる
    var path = @"C:\Sample.exe";
    var icon = System.Drawing.Icon.ExtractAssociatedIcon(path);
    var source = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}

感謝

2018-05-29 (火)