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

show multiple file properties in c#

我使用 here 中提到的方法来显示文件属性,如 windows。

[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);
}

我想知道是否有一种方法可以在选择多个文件时显示属性。

显示 "properties for multiple files",我的意思是当用户按住 ctrl 并选择多个文件时,右键单击 -> 属性。 link 中提到的代码适用于单个文件。但我需要显示多个文件。知道怎么做吗?

在MSDN上找到了类似SHELLEXECUTEINFO的方法,觉得很有意思。根据文章...

SHMultiFileProperties 函数

Displays a merged property sheet for a set of files. Property values common to all the files are shown while those that differ display the string (multiple values).

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 doens't work on XP