如何检索所有文件类型的所有可用文件属性的列表

问题描述 投票:0回答:1

我希望检索所有可用文件属性的列表(即与在资源管理器中单击

More
时获得的列表相同)。

目前,我可以通过运行 Nirsoft 的 PropertySystemView 工具及其

/AllProperties
参数,然后解析其输出以包含具有非空白
Display Name
Viewable
值为
Yes
的属性来获得所需的结果。 .

但是,我希望消除 PropertySystemView.exe 的使用,并直接在我自己的 C# 代码中检索属性列表。我找到了许多用于检索单个文件的属性的代码示例,但我还没有找到任何显示如何检索所有属性的内容。因此,我的问题中没有可显示的代码。

这个问题不是这个问题的重复。正如您所看到的,我在评论中询问了 Simon Mourier 关于检索所有属性的问题,他说代码不会这样做,我应该问一个新问题。

c#
1个回答
0
投票

要获取所有属性,必须使用 PSEnumeratePropertyDescriptions 函数

这是一个 .NET Framework 版本,它重新定义了(部分)您需要的一些接口和类型:

internal class Program
{
    static void Main()
    {
        PSEnumeratePropertyDescriptions(PROPDESC_ENUMFILTER.PDEF_ALL, typeof(IPropertyDescriptionList).GUID, out var list);
        for (var i = 0; i < list.GetCount(); i++)
        {
            var pd = list.GetAt(i, typeof(IPropertyDescription).GUID);

            var pk = pd.GetPropertyKey();
            Console.WriteLine($"Property Key   : {pk.fmtid:B} {pk.pid}");

            pd.GetCanonicalName(out var name);
            Console.WriteLine($"Canonical Name : {Marshal.PtrToStringUni(name)}");
            Marshal.FreeCoTaskMem(name);

            pd.GetDisplayName(out name);
            if (name != IntPtr.Zero)
            {
                Console.WriteLine($"Display Name   : {Marshal.PtrToStringUni(name)}");
                Marshal.FreeCoTaskMem(name);
            }

            var viewable = pd.GetTypeFlags(PROPDESC_TYPE_FLAGS.PDTF_ISVIEWABLE) == PROPDESC_TYPE_FLAGS.PDTF_ISVIEWABLE;
            Console.WriteLine($"Viewable       : {viewable}");
            Console.WriteLine();
        }
    }

    public struct PROPERTYKEY
    {
        public Guid fmtid;
        public int pid;
    }

    public enum PROPDESC_ENUMFILTER
    {
        PDEF_ALL = 0,
        PDEF_SYSTEM = 1,
        PDEF_NONSYSTEM = 2,
        PDEF_VIEWABLE = 3,
        PDEF_QUERYABLE = 4,
        PDEF_INFULLTEXTQUERY = 5,
        PDEF_COLUMN = 6,
    }

    [Flags]
    public enum PROPDESC_TYPE_FLAGS
    {
        PDTF_DEFAULT = 0,
        PDTF_MULTIPLEVALUES = 0x1,
        PDTF_ISINNATE = 0x2,
        PDTF_ISGROUP = 0x4,
        PDTF_CANGROUPBY = 0x8,
        PDTF_CANSTACKBY = 0x10,
        PDTF_ISTREEPROPERTY = 0x20,
        PDTF_INCLUDEINFULLTEXTQUERY = 0x40,
        PDTF_ISVIEWABLE = 0x80,
        PDTF_ISQUERYABLE = 0x100,
        PDTF_CANBEPURGED = 0x200,
        PDTF_SEARCHRAWVALUE = 0x400,
        PDTF_DONTCOERCEEMPTYSTRINGS = 0x800,
        PDTF_ALWAYSINSUPPLEMENTALSTORE = 0x1000,
        PDTF_ISSYSTEMPROPERTY = unchecked((int)0x80000000),
        PDTF_MASK_ALL = unchecked((int)0x80001fff),
    }

    [DllImport("propsys")]
    public static extern int PSEnumeratePropertyDescriptions(PROPDESC_ENUMFILTER filterOn, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IPropertyDescriptionList ppv);

    [ComImport, Guid("1F9FC1D0-C39B-4B26-817F-011967D3440E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPropertyDescriptionList
    {
        int GetCount();
        [return: MarshalAs(UnmanagedType.Interface)]
        IPropertyDescription GetAt(int iElem, [MarshalAs(UnmanagedType.LPStruct)] Guid riid);
    }

    [ComImport, Guid("6F79D558-3E96-4549-A1D1-7D75D2288814"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPropertyDescription
    {
        PROPERTYKEY GetPropertyKey();
        [PreserveSig] int GetCanonicalName(out IntPtr name);
        int GetPropertyType();
        [PreserveSig] int GetDisplayName(out IntPtr name);
        [PreserveSig] int GetEditInvitation(out IntPtr name);
        PROPDESC_TYPE_FLAGS GetTypeFlags(PROPDESC_TYPE_FLAGS mask);
        // following methods are undefined in this code since we don't need it
    }
}

如果您使用 .NET Core 5+,您可以从 CsWin32 项目中受益,该项目将为您定义所有需要的互操作。请注意,使用此功能需要以某种方式声明您的代码不安全。

csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>

  <ItemGroup>
    <None Remove="NativeMethods.txt" />
  </ItemGroup>

  <ItemGroup>
    <AdditionalFiles Include="NativeMethods.txt" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

</Project>

NativeMethods.txt:

IPropertyDescription
IPropertyDescriptionList
PSEnumeratePropertyDescriptions

程序.cs

using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Windows.Win32;
using Windows.Win32.UI.Shell.PropertiesSystem;

[assembly: SupportedOSPlatform("windows6.0.6000")]

namespace DumpShellProps;

internal class Program
{
    static unsafe void Main()
    {
        PInvoke.PSEnumeratePropertyDescriptions(PROPDESC_ENUMFILTER.PDEF_ALL, typeof(IPropertyDescriptionList).GUID, out var ppv).ThrowOnFailure();
        var list = (IPropertyDescriptionList)Marshal.GetTypedObjectForIUnknown((nint)ppv, typeof(IPropertyDescriptionList));
        list.GetCount(out var count);
        for (uint i = 0; i < count; i++)
        {
            list.GetAt(i, typeof(IPropertyDescription).GUID, out var obj);
            var pd = (IPropertyDescription)obj;

            pd.GetPropertyKey(out var pk);
            Console.WriteLine($"Property Key   : {pk.fmtid:B} {pk.pid}");

            pd.GetCanonicalName(out var cname);
            Console.WriteLine($"Canonical Name : {cname}");
            Marshal.FreeCoTaskMem((nint)cname.Value);
            try
            {
                pd.GetDisplayName(out var dname);
                Console.WriteLine($"Display Name   : {dname}");
                Marshal.FreeCoTaskMem((nint)dname.Value);
            }
            catch { } // not all properties have a display name
            Console.WriteLine();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.