在 C# 中显示多个文件属性

本文关键字:文件属性 显示 | 更新日期: 2023-09-27 18:36:11

我使用了这里提到的方法来显示文件属性,就像在窗口中一样。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct SHELLEXECUTEINFO
{
        public int cbSize;
        public uint fMask;
        public IntPtr hwnd;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpVerb;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpFile;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpParameters;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpDirectory;
        public int nShow;
        public IntPtr hInstApp;
        public IntPtr lpIDList;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpClass;
        public IntPtr hkeyClass;
        public uint dwHotKey;
        public IntPtr hIcon;
        public IntPtr hProcess;
}
public static bool ShowFileProperties(string Filename)
{
       SHELLEXECUTEINFO info = new SHELLEXECUTEINFO();
       info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info);
       info.lpVerb = "properties";
       info.lpFile = Filename;
       info.nShow = SW_SHOW;
       info.fMask = SEE_MASK_INVOKEIDLIST;
       return ShellExecuteEx(ref info);
}

我想知道是否有办法在选择多个文件时显示属性。

显示"多个文件的属性",我的意思是当用户按住 ctrl 并选择多个文件时,右键单击>属性。链接中提到的代码适用于单个文件。但是我需要显示多个文件。知道如何做到这一点吗?

在 C# 中显示多个文件属性

我在MSDN上发现了一种类似于SHELLEXECUTEINFO的方法,我觉得很有趣。根据文章...

SHMulti文件属性函数

显示一组文件的合并属性表。显示所有文件共有的属性值,而不同的属性值显示字符串(多个值)。

https://msdn.microsoft.com/en-us/library/windows/desktop/bb762230(v=vs.85).aspx

我不确定如何将其转换为可用的 C# 代码,但当我这样做时,我会再次更新我的答案。

溶液

我找到了解决方案! :D

public class Properties
{
    #region Import Methods
    [DllImport("shell32.dll", SetLastError = true)]
    static extern int SHMultiFileProperties(IDataObject pdtobj, int flags);
    [DllImport("shell32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr ILCreateFromPath(string path);
    [DllImport("shell32.dll", CharSet = CharSet.None)]
    public static extern void ILFree(IntPtr pidl);
    [DllImport("shell32.dll", CharSet = CharSet.None)]
    public static extern int ILGetSize(IntPtr pidl);
    #endregion
    #region Static Methods
    #region Private
    private static MemoryStream CreateShellIDList(StringCollection filenames)
    {
        // first convert all files into pidls list
        int pos = 0;
        byte[][] pidls = new byte[filenames.Count][];
        foreach (var filename in filenames)
        {
            // Get pidl based on name
            IntPtr pidl = ILCreateFromPath(filename);
            int pidlSize = ILGetSize(pidl);
            // Copy over to our managed array
            pidls[pos] = new byte[pidlSize];
            Marshal.Copy(pidl, pidls[pos++], 0, pidlSize);
            ILFree(pidl);
        }
        // Determine where in CIDL we will start pumping PIDLs
        int pidlOffset = 4 * (filenames.Count + 2);
        // Start the CIDL stream
        var memStream = new MemoryStream();
        var sw = new BinaryWriter(memStream);
        // Initialize CIDL witha count of files
        sw.Write(filenames.Count);
        // Calcualte and write relative offsets of every pidl starting with root
        sw.Write(pidlOffset);
        pidlOffset += 4; // root is 4 bytes
        foreach (var pidl in pidls)
        {
            sw.Write(pidlOffset);
            pidlOffset += pidl.Length;
        }
        // Write the root pidl (0) followed by all pidls
        sw.Write(0);
        foreach (var pidl in pidls) sw.Write(pidl);
        // stream now contains the CIDL
        return memStream;
    }
    #endregion
    #region Public 
    public static int Show(IEnumerable<string> Filenames)
    {
        StringCollection Files = new StringCollection();
        foreach (string s in Filenames) Files.Add(s);
        var data = new DataObject();
        data.SetFileDropList(Files);
        data.SetData("Preferred DropEffect", new MemoryStream(new byte[] { 5, 0, 0, 0 }), true);
        data.SetData("Shell IDList Array", Properties.CreateShellIDList(Files), true);
        return SHMultiFileProperties(data, 0);
    }
    public static int Show(params string[] Filenames)
    {
        return Properties.Show(Filenames as IEnumerable<string>);
    }
    #endregion
    #endregion
}

这经过测试,适用于 Windows 10。我实际上是根据另外两篇 SO 文章想出来的,因为两者都不能独立工作。

来源:

P/Invoke for shell32.dll's SHMultiFileProperties

SHMultiFileProperties 在 XP 上不起作用