Windows 10で拡張子の分類情報など(Perceived Type等)を取得するにはWin32APIのAssocGetPerceivedType
関数を使用します。以下はそのサンプルコードです。record
やnew (...)
を使用しているのでC# 9.0以降対応です。
using System; using System.Runtime.InteropServices; static class Program { private record PerceivedInfo( PERCEIVED Perceived, PERCEIVEDFLAG PerceivedFlag, string TypeString); static void Main() { var exePerceivedTypeInfo = GetPerceivedType(".exe"); // {PerceivedInfo { Perceived = PERCEIVED_TYPE_APPLICATION, PerceivedFlag = PERCEIVEDFLAG_HARDCODED, TypeString = application }} var bmpPerceivedTypeInfo = GetPerceivedType(".bmp"); // {PerceivedInfo { Perceived = PERCEIVED_TYPE_IMAGE, PerceivedFlag = PERCEIVEDFLAG_HARDCODED, PERCEIVEDFLAG_NATIVESUPPORT, PERCEIVEDFLAG_GDIPLUS, TypeString = image }} var txtPerceivedTypeInfo = GetPerceivedType(".txt"); // {PerceivedInfo { Perceived = PERCEIVED_TYPE_TEXT, PerceivedFlag = PERCEIVEDFLAG_SOFTCODED, PERCEIVEDFLAG_NATIVESUPPORT, TypeString = text }} } static PerceivedInfo GetPerceivedType(string extenionNameWithDot) { var str = NativeMethods.AssocGetPerceivedType( extenionNameWithDot, out var type, out var flag); return new (type, flag, str); } static class NativeMethods { // https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-assocgetperceivedtype [DllImport("shlwapi.dll", ExactSpelling = true, PreserveSig = false, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(CoTaskMemToStringUniMarshaler))] public static extern string AssocGetPerceivedType( [In] string pszExt, out PERCEIVED ptype, out PERCEIVEDFLAG pflag); } enum PERCEIVED : int { PERCEIVED_TYPE_FIRST = -3, PERCEIVED_TYPE_CUSTOM = -3, PERCEIVED_TYPE_UNSPECIFIED = -2, PERCEIVED_TYPE_FOLDER = -1, PERCEIVED_TYPE_UNKNOWN = 0, PERCEIVED_TYPE_TEXT = 1, PERCEIVED_TYPE_IMAGE = 2, PERCEIVED_TYPE_AUDIO = 3, PERCEIVED_TYPE_VIDEO = 4, PERCEIVED_TYPE_COMPRESSED = 5, PERCEIVED_TYPE_DOCUMENT = 6, PERCEIVED_TYPE_SYSTEM = 7, PERCEIVED_TYPE_APPLICATION = 8, PERCEIVED_TYPE_GAMEMEDIA = 9, PERCEIVED_TYPE_CONTACTS = 10, PERCEIVED_TYPE_LAST = 10, } [Flags] enum PERCEIVEDFLAG : ushort { PERCEIVEDFLAG_UNDEFINED = 0x0000, PERCEIVEDFLAG_SOFTCODED = 0x0001, PERCEIVEDFLAG_HARDCODED = 0x0002, PERCEIVEDFLAG_NATIVESUPPORT = 0x0004, PERCEIVEDFLAG_GDIPLUS = 0x0010, PERCEIVEDFLAG_WMSDK = 0x0020, PERCEIVEDFLAG_ZIPFOLDER = 0x0040, } } // https://potisan-programming-memo.hatenablog.jp/entry/2020/11/26/214836 internal sealed class CoTaskMemToStringUniMarshaler : ICustomMarshaler { private static CoTaskMemToStringUniMarshaler instance; internal static ICustomMarshaler GetInstance(string cookie) { return instance ??= new CoTaskMemToStringUniMarshaler(); } public void CleanUpManagedData(object ManagedObj) => throw new NotImplementedException(); public IntPtr MarshalManagedToNative(object ManagedObj) => throw new NotImplementedException(); public object MarshalNativeToManaged(IntPtr pNativeData) => Marshal.PtrToStringUni(pNativeData); public void CleanUpNativeData(IntPtr pNativeData) => Marshal.FreeCoTaskMem(pNativeData); public int GetNativeDataSize() => -1; // 値型ではない。 }
蛇足
AssocGetPerceivedType
関数は複数の出力引数を返すため、ラッパー関数でrecord
に変換しています。C# 8.0以前では他の複合型やタプル(Tuple
、ValueTuple
)で代替します。AssocGetPerceivedType
関数は戻り値HRESULT
型でサフィックス(A/W
)なくユニコード文字列を受け取る関数です。これらを示すためにDllImport
属性にExactSpelling = true
(文字列型を扱うがサフィックスは自動付加しない)、PreserveSig = false
(HRESULT
型戻り値を隠して失敗時は例外を発生させ、最後の引数を戻り値にする)、CharSet = CharSet.Unicode
(文字列はユニコード)を指定しています。record PerceivedInfo(...);
は...
で与えられた引数をフィールドに持ち、作成時にそれらを指定する必要のあるレコードの実装です。;
で終わらず{...}
を続けることで引数以外のメンバー変数や関数なども追加できます。