potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

C# 9 IShellItemインターフェイスをパスから作成する

IShellItemインターフェイスをパスから作成して表示名、親フォルダとその表示名を取得するサンプルコードです。

using System;
using System.Runtime.InteropServices;

var item = default(IShellItem);
try
{
    item = NativeMethods.SHCreateItemFromParsingName(
        Environment.GetFolderPath(Environment.SpecialFolder.Personal),
        IntPtr.Zero,
        typeof(IShellItem).GUID);
    using var displayNamePointer = item.GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY);
    var displayName = Marshal.PtrToStringUni(displayNamePointer.DangerousGetHandle());

    // TODO:ここで表示名を処理します。
    Console.WriteLine(displayName);

    var parent = default(IShellItem);
    try
    {
        parent = item.GetParent();
        using var parentDisplayNamePointer = parent.GetDisplayName(
            SIGDN.SIGDN_NORMALDISPLAY);
        var parentDisplayName = Marshal.PtrToStringUni(
            parentDisplayNamePointer.DangerousGetHandle());

        // TODO:ここで親フォルダの表示名を処理します。
        Console.WriteLine(parentDisplayName);
    }
    finally
    {
        if (parent != null)
            Marshal.FinalReleaseComObject(parent);
    }
}
finally
{
    if (item != null)
        Marshal.FinalReleaseComObject(item);
}

static class NativeMethods
{
    [DllImport("shell32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, PreserveSig = false)]
    public static extern IShellItem SHCreateItemFromParsingName(
        [In] string pszPath, IntPtr pbc, in Guid riid);
}

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
interface IShellItem
{
    [return: MarshalAs(UnmanagedType.IUnknown)]
    object BindToHandler(IntPtr pbc, in Guid bhid, in Guid riid);
    IShellItem GetParent();
    SafeCoTaskMemHandle GetDisplayName(SIGDN sigdnName);
    SFGAOF GetAttributes(SFGAOF sfgaoMask);
    int Compare(IShellItem psi, SICHINTF hint);
}

enum SIGDN : uint
{
    SIGDN_NORMALDISPLAY = 0x00000000,
    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 = 0x00000000,
    SICHINT_ALLFIELDS = 0x80000000,
    SICHINT_CANONICAL = 0x10000000,
    SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000,
}

[Flags]
enum SFGAOF : uint
{
    SFGAO_CANCOPY = 0x1,
    SFGAO_CANMOVE = 0x2,
    SFGAO_CANLINK = 0x4,
    SFGAO_STORAGE = 0x00000008,
    SFGAO_CANRENAME = 0x00000010,
    SFGAO_CANDELETE = 0x00000020,
    SFGAO_HASPROPSHEET = 0x00000040,
    SFGAO_DROPTARGET = 0x00000100,
    SFGAO_CAPABILITYMASK = 0x00000177,
    SFGAO_PLACEHOLDER = 0x00000800,
    SFGAO_SYSTEM = 0x00001000,
    SFGAO_ENCRYPTED = 0x00002000,
    SFGAO_ISSLOW = 0x00004000,
    SFGAO_GHOSTED = 0x00008000,
    SFGAO_LINK = 0x00010000,
    SFGAO_SHARE = 0x00020000,
    SFGAO_READONLY = 0x00040000,
    SFGAO_HIDDEN = 0x00080000,
    SFGAO_DISPLAYATTRMASK = 0x000FC000,
    SFGAO_FILESYSANCESTOR = 0x10000000,
    SFGAO_FOLDER = 0x20000000,
    SFGAO_FILESYSTEM = 0x40000000,
    SFGAO_HASSUBFOLDER = 0x80000000,
    SFGAO_CONTENTSMASK = 0x80000000,
    SFGAO_VALIDATE = 0x01000000,
    SFGAO_REMOVABLE = 0x02000000,
    SFGAO_COMPRESSED = 0x04000000,
    SFGAO_BROWSABLE = 0x08000000,
    SFGAO_NONENUMERATED = 0x00100000,
    SFGAO_NEWCONTENT = 0x00200000,
    SFGAO_CANMONIKER = 0x00400000,
    SFGAO_HASSTORAGE = 0x00400000,
    SFGAO_STREAM = 0x00400000,
    SFGAO_STORAGEANCESTOR = 0x00800000,
    SFGAO_STORAGECAPMASK = 0x70C50008,
    SFGAO_PKEYSFGAOMASK = 0x81044000,
}

sealed class SafeCoTaskMemHandle : SafeHandle
{
    public SafeCoTaskMemHandle()
        : base(default, true)
    {
    }

    public SafeCoTaskMemHandle(IntPtr handle, bool ownsHandle)
        : base(handle, ownsHandle)
    {
    }

    public override bool IsInvalid => handle == default;

    protected override bool ReleaseHandle()
    {
        Marshal.FreeCoTaskMem(handle);
        return true;
    }
}

2021/3/10:この記事は別のブログで投稿した記事を移動したものです。