Windows APIを使用してごみ箱やPCのような特殊オブジェクトの表示名を取得するコードです。SHCreateShellItemArrayFromDataObject
関数を使用しています。
#nullable enable using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows.Forms; using ComTypes = System.Runtime.InteropServices.ComTypes; namespace WinFormsApp1; static class Program { [STAThread] static void Main() { Application.Run(new Form1()); } } sealed class Form1 : Form { private readonly TextBox textBox1; public Form1() { AllowDrop = true; DragEnter += Form1_DragEnter; DragDrop += Form1_DragDrop; textBox1 = new() { Dock = DockStyle.Fill, Multiline = true, ReadOnly = true, WordWrap = false, ScrollBars = ScrollBars.Both }; Controls.AddRange(new[] { textBox1 }); } private const string CFSTR_SHELLIDLIST = "Shell IDList Array"; private void Form1_DragEnter(object? sender, DragEventArgs e) { if (e.Data is null || !e.Data.GetDataPresent(CFSTR_SHELLIDLIST)) return; e.Effect = DragDropEffects.Move; } private void Form1_DragDrop(object? sender, DragEventArgs e) { if (e.Data is null || !e.Data.GetDataPresent(CFSTR_SHELLIDLIST)) return; var items = ShellItemUtility.CreateShellItemArrayForDataObject(e.Data); textBox1.Text = string.Join<string>( Environment.NewLine, items.Select(item => item.GetDisplayName())); Marshal.FinalReleaseComObject(items); } } /// <summary> /// IShellItem関係のユーティリティ /// </summary> static class ShellItemUtility { /// <summary> /// DataObjectからIShellItemArrayを作成します。 /// </summary> public static IShellItemArray CreateShellItemArrayForDataObject(IDataObject dataObj) { var hr = NativeMethods.SHCreateShellItemArrayFromDataObject( (ComTypes.IDataObject)dataObj, typeof(IShellItemArray).GUID, out var unkItems); if (hr != 0 || unkItems as IShellItemArray is not { } items) throw Marshal.GetExceptionForHR(hr)!; return items; } /// <summary> /// IShellItemArrayの各IShellItemに処理を適用します。 /// </summary> public static void ForEach(this IShellItemArray items, Action<IShellItem> action) { var hr = items.GetCount(out var itemCount); if (hr != 0) Marshal.ThrowExceptionForHR(hr); for (uint i = 0; i < itemCount; i++) { hr = items.GetItemAt(i, out var item); try { if (hr != 0) Marshal.ThrowExceptionForHR(hr); action(item); } finally { Marshal.FinalReleaseComObject(item); } } } /// <summary> /// IShellItemArrayの各IShellItemに処理を適用した結果を返します。 /// </summary> public static IEnumerable<T> Select<T>(this IShellItemArray items, Converter<IShellItem, T> converter) { var hr = items.GetCount(out var itemCount); if (hr != 0) Marshal.ThrowExceptionForHR(hr); for (uint i = 0; i < itemCount; i++) { hr = items.GetItemAt(i, out var item); try { if (hr != 0) Marshal.ThrowExceptionForHR(hr); yield return converter(item); } finally { Marshal.FinalReleaseComObject(item); } } } /// <summary> /// IShellItemの表示名を取得します。 /// </summary> public static string GetDisplayName(this IShellItem item) { var hr = item.GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out var pname); if (hr != 0) throw Marshal.GetExceptionForHR(hr)!; return pname!; } private static class NativeMethods { [DllImport("shell32.dll")] public static extern int SHCreateShellItemArrayFromDataObject( ComTypes.IDataObject pdo, in Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); } } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("b63ea76d-1f85-456f-a19c-48159efa858b")] interface IShellItemArray { [PreserveSig] int BindToHandler( [MarshalAs(UnmanagedType.IUnknown)] object pbc, // IBindCtx in Guid bhid, in Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppvOut); [PreserveSig] int GetPropertyStore( uint flags, // GETPROPERTYSTOREFLAGS in Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); [PreserveSig] int GetPropertyDescriptionList( in Guid keyType, // REFPROPERTYKEY in Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); [PreserveSig] int GetAttributes( uint AttribFlags, // SIATTRIBFLAGS uint sfgaoMask, // SFGAOF out uint psfgaoAttribs); // SFGAOF [PreserveSig] int GetCount( out uint pdwNumItems); [PreserveSig] int GetItemAt( uint dwIndex, out IShellItem ppsi); [PreserveSig] int EnumItems( [MarshalAs(UnmanagedType.IUnknown)] out object ppenumShellItems); // IEnumShellItems } enum SIGDN : uint { SIGDN_NORMALDISPLAY = 0, SIGDN_PARENTRELATIVEPARSING = 0x80018001, SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, SIGDN_PARENTRELATIVEEDITING = 0x80031001, SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, SIGDN_FILESYSPATH = 0x80058000, SIGDN_URL = 0x80068000, SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, SIGDN_PARENTRELATIVE = 0x80080001, SIGDN_PARENTRELATIVEFORUI = 0x80094001 } enum SICHINTF : uint { SICHINT_DISPLAY = 0, SICHINT_ALLFIELDS = 0x80000000, SICHINT_CANONICAL = 0x10000000, SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000 } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] interface IShellItem { [PreserveSig] int BindToHandler( [MarshalAs(UnmanagedType.IUnknown)] object pbc, // IBindCtx in Guid bhid, in Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); [PreserveSig] int GetParent( out IShellItem ppsi); [PreserveSig] int GetDisplayName( SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string? ppszName); [PreserveSig] int GetAttributes( uint sfgaoMask, // SFGAOF out uint psfgaoAttribs); // SFGAOF [PreserveSig] int Compare( [In] IShellItem psi, SICHINTF hint, out int piOrder); }