potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C# 4.5,9 FOLDERIDからフォルダのパスを取得する

C# 9.0

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;

var FOLDERID_DocumentsLibrary = new Guid("{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}");

Console.WriteLine(SHGetKnownFolderPath(FOLDERID_DocumentsLibrary, 0));

[return: MaybeNull]
static string SHGetKnownFolderPath(
    in Guid knownFolderID,
    uint flags = 0,
    IntPtr tokenHandle = default)
{
    SafeCoTaskMemHandle handle = default;
    NativeMethods.SHGetKnownFolderPath(knownFolderID, flags, tokenHandle, out handle);
    using (handle)
    {
        return Marshal.PtrToStringUni(handle.DangerousGetHandle());
    }
}

static class NativeMethods
{
    [DllImport("shell32.dll")]
    public static extern int SHGetKnownFolderPath(
        in Guid rfid,
        uint dwFlags,
        IntPtr hToken,
        out SafeCoTaskMemHandle ppszPath);
}

sealed class SafeCoTaskMemHandle : SafeHandle
{
    private SafeCoTaskMemHandle()
        : base(IntPtr.Zero, true)
    {
    }

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

    public override bool IsInvalid => handle == IntPtr.Zero;

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

C# 4.5

失敗時は例外が発生することに注意してください。

using System;
using System.Runtime.InteropServices;
using System.Security;

namespace ConsoleApplication1
{
    [SecurityCritical]
    class Program
    {
        [SuppressUnmanagedCodeSecurity]
        private static class NativeMethods
        {
            [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
            public static extern SafeCoTaskMemHandle SHGetKnownFolderPath(
                ref Guid rfid,
                uint dwFlags,
                IntPtr hToken);
        }

        static void Main()
        {
            Guid FOLDERID_DocumentsLibrary = new Guid(
                "{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}");

            Console.WriteLine(SHGetKnownFolderPath(
                FOLDERID_DocumentsLibrary, 0, IntPtr.Zero));

            Console.WriteLine("PRESS ANY KEY.");
            Console.ReadKey();
        }

        public static string SHGetKnownFolderPath(
            Guid knownFolderID,
            uint flags,
            IntPtr tokenHandle)
        {
            using (var handle = NativeMethods.SHGetKnownFolderPath(
                ref knownFolderID, flags, tokenHandle))
            {
                return Marshal.PtrToStringUni(
                    handle.DangerousGetHandle());
            }
        }
    }

    public sealed class SafeCoTaskMemHandle : SafeHandle
    {
        private SafeCoTaskMemHandle()
            : base(IntPtr.Zero, true)
        {
            // 戻り値としての作成に対応します。
        }

        public SafeCoTaskMemHandle(IntPtr handle, bool ownsHandle)
            : base(IntPtr.Zero, ownsHandle)
        {
            SetHandle(handle);
        }

        public override bool IsInvalid
        {
            get
            {
                return handle == IntPtr.Zero;
            }
        }

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

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