カタバミさんのプログラミングノート

日曜プログラマーがプログラミング関係のメモを記録するブログです。

C#用IShellFolderのファイル名(表示名)変更に必要な関数のラッパーを提供するクラスと拡張メソッドファイル

概要とコード

動作確認環境:Windows 10 64ビット、Microsoft Visual Studio 2019、C# 7.3

Win32 API IShellFolderインターフェイスのファイル名(表示名)変更に必要な関数のラッパーを提供するクラスと拡張メソッドファイルの組み合わせです。サイズよりも独立性を優先しており、拡張メソッドはそれぞれ別ファイルに定義して、各ファイルにIShellFolderインターフェイスを最小限定義しています。

IShellFolderインターフェイスのラッパークラス。このクラスはCOMオブジェクトラッパー以外の機能を持たず、別のファイルで拡張メソッドを定義します。

ShellFolderWrapper.cs - GitHub

上記ラッパークラスの拡張メソッド定義ファイル。それぞれのファイルが拡張メソッドとそれに必要なIShellFolderインターフェイスの定義、列挙型などを持ちます。

ShellFolderSetNameOfExtensions.cs - GitHub

ShellFolderGetDisplayNameOfExtensions.cs - GitHub

ShellFolderBindToObjectAsIShellFolderExtensions.cs - GitHub

サンプルコード

C#の標準機能(Data.GetData(DataFormats.FileDrop))では取得できないコントロールパネル項目の名前なども取得できます。なお、このサンプルでは以前に公開したSTRRETとCIDAのラッパーを使用しています。

  1. Windows フォーム アプリケーション (.NET Framework) [C# Windows デスクトップ]を作成する。
  2. Form1.csのコードを以下の通り書き換える。名前空間WindowsFormsApp1は必要に応じて変更する。
  3. プロジェクトを実行して適当なファイルやコントロールパネルの項目をドラッグする。
  4. IDEの出力ウィンドウを確認する。
using System;
using System.IO;
using System.Windows.Forms;
using Oxalis.Windows.Shell;
using Oxalis.Windows.Shell.ShellFolder;

namespace WindowsFormsApp1
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            this.AllowDrop = true;
            this.DragDrop += new System.Windows.Forms.DragEventHandler(this.MainForm_DragDrop);
            this.DragOver += new System.Windows.Forms.DragEventHandler(this.MainForm_DragOver);
        }

        private void MainForm_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = e.AllowedEffect;
        }

        private void MainForm_DragDrop(object sender, DragEventArgs e)
        {
            var desktop = default(ShellFolderWrapper);
            var folder = default(ShellFolderWrapper);
            try
            {
                desktop = ShellFolderWrapper.GetDesktopFolder();
                using (var stream = (MemoryStream)e.Data.GetData("Shell IDList Array"))
                {
                    using (var shellItemIDList = new ShellIDListArray(stream))
                    {
                        if (!shellItemIDList.IsFolderDesktop)
                        {
                            folder = desktop.BindToShellFolder(
                                shellItemIDList.FolderItemIDListAddress);
                        }
                        else
                        {
                            // デスクトップからデスクトップを取得しようとするエラーを防ぐ。
                            folder = desktop;
                        }
                        foreach (var pidl in shellItemIDList.FileItemIDListAddresses)
                        {
                            var oldName = folder.GetDisplayNameOf(
                                pidl, ShellFolderGetDisplayNameOfExtensions.SHGDN.SHGDN_NORMAL);
                            Console.WriteLine(oldName);

                            //TODO:名前を変更する場合は以下をコメントアウトします。
                            //   ここでは前後の空白と途中の改行(CR、LF)を削除します。
                            var newName = oldName.Trim()
                                .Replace('\r', ' ')
                                .Replace('\n', ' ');
                            if (oldName != newName)
                            {
                                folder.SetNameOf(
                                    pidl,
                                    newName,
                                    ShellFolderSetNameOfExtensions.SHCONTF.SHCONTF_FOLDERS,
                                    Handle);
                            }
                        }
                    }
                }
            }
            finally
            {
                desktop?.Dispose();
                folder?.Dispose();
            }
        }
    }
}

memos-by-oxalis.hatenablog.com memos-by-oxalis.hatenablog.com