【问题标题】:C#: How to open Windows Explorer windows with a number of files selectedC#:如何打开选择了多个文件的 Windows 资源管理器窗口
【发布时间】:2010-11-07 14:01:48
【问题描述】:

在 Windows Media Player 的库中,您可以选择一个或多个音乐文件。然后您可以右键单击并在其上下文菜单中选择打开文件位置。这将为文件所在的每个目录打开一个 Windows 资源管理器窗口,并为您选择文件。

假设我们的库中有一堆 mp3 文件,其中三个是:

  • Z:\Music\Thursday Blues\01。我希望是friday.mp3
  • Z:\音乐\数羊\01。绵羊#1.mp3
  • Z:\音乐\数羊\02。绵羊#2.mp3

如果我们选择这三个(在所有这些都可见的视图中)并执行打开文件位置,则会弹出两个资源管理器窗口。一个是 Z:\Music\Thursday Blues 文件夹,01。我希望它是 friday.mp3 被选中,而另一个将是 *Z:\Music\Counting Sheep** 文件夹,01.绵羊#1.mp302。 Sheep #2.mp3 已选中。

我自己如何在 C# 中做到这一点?我们有一个应用程序要将数据导出为各种格式,例如 CSV 和 Excel,我想打开资源管理器窗口,并在创建这些文件并准备好查看时选择这些文件。目前我只做Process.Start(path),这是可行的,但我也希望能够突出显示这些特定文件。会使刚刚创建的文件更加明显。


Windows Media Player 做得很好...我也想这样做 =/ 这里有微软员工可以弄清楚如何做到这一点吗? (一)

【问题讨论】:

    标签: c# file windows-explorer directory


    【解决方案1】:

    在同事遇到问题后寻找答案,但我没有找到,所以我写了一个小班来做这件事。代码is on Gist,我将在本文末尾粘贴当前版本。

    使用您的示例文件,语法将是:

    ShowSelectedInExplorer.FilesOrFolders(
        @"Z:\Music\Thursday Blues\01. I wish it was friday.mp3",
        @"Z:\Music\Counting Sheep\01. Sheep #1.mp3",
        @"Z:\Music\Counting Sheep\02. Sheep #2.mp3"
        );
    

    与低级API相比,我的代码有一些限制,主要是:

    • 未实现在桌面上选择
    • 父目录必须是目录或驱动器,因此不能在我的电脑文件夹中选择多个驱动器。

    无论如何,这里是 ShowSelectedInExplorer 类的源代码:

    namespace SHOpenFolderAndSelectItems
    {
        using System;
        using System.Collections.Generic;
        using System.IO;
        using System.Linq;
        using System.Runtime.CompilerServices;
        using System.Runtime.InteropServices;
        using System.Runtime.InteropServices.ComTypes;
    
        static class ShowSelectedInExplorer
        {
            [Flags]
            enum SHCONT : ushort
            {
                SHCONTF_CHECKING_FOR_CHILDREN = 0x0010,
                SHCONTF_FOLDERS = 0x0020,
                SHCONTF_NONFOLDERS = 0x0040,
                SHCONTF_INCLUDEHIDDEN = 0x0080,
                SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
                SHCONTF_NETPRINTERSRCH = 0x0200,
                SHCONTF_SHAREABLE = 0x0400,
                SHCONTF_STORAGE = 0x0800,
                SHCONTF_NAVIGATION_ENUM = 0x1000,
                SHCONTF_FASTITEMS = 0x2000,
                SHCONTF_FLATLIST = 0x4000,
                SHCONTF_ENABLE_ASYNC = 0x8000
            }
    
            [ComImport,
            Guid("000214E6-0000-0000-C000-000000000046"),
            InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
            ComConversionLoss]
            interface IShellFolder
            {
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void ParseDisplayName(IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, [Out] out uint pchEaten, [Out] out IntPtr ppidl, [In, Out] ref uint pdwAttributes);
                [PreserveSig]
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                int EnumObjects([In] IntPtr hwnd, [In] SHCONT grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenumIDList);
    
                [PreserveSig]
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                int BindToObject([In] IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IShellFolder ppv);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void BindToStorage([In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, out IntPtr ppv);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void CompareIDs([In] IntPtr lParam, [In] ref IntPtr pidl1, [In] ref IntPtr pidl2);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void GetAttributesOf([In] uint cidl, [In] IntPtr apidl, [In, Out] ref uint rgfInOut);
    
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void GetUIObjectOf([In] IntPtr hwndOwner, [In] uint cidl, [In] IntPtr apidl, [In] ref Guid riid, [In, Out] ref uint rgfReserved, out IntPtr ppv);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void GetDisplayNameOf([In] ref IntPtr pidl, [In] uint uFlags, out IntPtr pName);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                void SetNameOf([In] IntPtr hwnd, [In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, [In] uint uFlags, [Out] IntPtr ppidlOut);
            }
    
            [ComImport,
            Guid("000214F2-0000-0000-C000-000000000046"),
            InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            interface IEnumIDList
            {
                [PreserveSig]
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                int Next(uint celt, IntPtr rgelt, out uint pceltFetched);
    
                [PreserveSig]
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                int Skip([In] uint celt);
    
                [PreserveSig]
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                int Reset();
    
                [PreserveSig]
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                int Clone([MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum);
            }
    
            static class NativeMethods
            {
                [DllImport("shell32.dll", EntryPoint = "SHGetDesktopFolder", CharSet = CharSet.Unicode,
                    SetLastError = true)]
                static extern int SHGetDesktopFolder_([MarshalAs(UnmanagedType.Interface)] out IShellFolder ppshf);
    
                public static IShellFolder SHGetDesktopFolder()
                {
                    IShellFolder result;
                    Marshal.ThrowExceptionForHR(SHGetDesktopFolder_(out result));
                    return result;
                }
    
                [DllImport("shell32.dll", EntryPoint = "SHOpenFolderAndSelectItems")]
                static extern int SHOpenFolderAndSelectItems_(
                    [In] IntPtr pidlFolder, uint cidl, [In, Optional, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
                    int dwFlags);
    
                public static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, int dwFlags)
                {
                    var cidl = (apidl != null) ? (uint)apidl.Length : 0U;
                    var result = SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags);
                    Marshal.ThrowExceptionForHR(result);
                }
    
                [DllImport("shell32.dll")]
                public static extern void ILFree([In] IntPtr pidl);
            }
    
            static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, string displayName)
            {
                uint pchEaten;
                uint pdwAttributes = 0;
                IntPtr ppidl;
                parentFolder.ParseDisplayName(IntPtr.Zero, null, displayName, out pchEaten, out ppidl, ref pdwAttributes);
    
                return ppidl;
            }
    
            static IntPtr PathToAbsolutePIDL(string path)
            {
                var desktopFolder = NativeMethods.SHGetDesktopFolder();
                return GetShellFolderChildrenRelativePIDL(desktopFolder, path);
            }
    
            static Guid IID_IShellFolder = typeof(IShellFolder).GUID;
    
            static IShellFolder PIDLToShellFolder(IShellFolder parent, IntPtr pidl)
            {
                IShellFolder folder;
                var result = parent.BindToObject(pidl, null, ref IID_IShellFolder, out folder);
                Marshal.ThrowExceptionForHR((int)result);
                return folder;
            }
    
            static IShellFolder PIDLToShellFolder(IntPtr pidl)
            {
                return PIDLToShellFolder(NativeMethods.SHGetDesktopFolder(), pidl);
            }
    
            static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, bool edit)
            {
                NativeMethods.SHOpenFolderAndSelectItems(pidlFolder, apidl, edit ? 1 : 0);
            }
    
            public static void FileOrFolder(string path, bool edit = false)
            {
                if (path == null) throw new ArgumentNullException("path");
    
                var pidl = PathToAbsolutePIDL(path);
                try
                {
                    SHOpenFolderAndSelectItems(pidl, null, edit);
                }
                finally
                {
                    NativeMethods.ILFree(pidl);
                }
            }
    
            static IEnumerable<FileSystemInfo> PathToFileSystemInfo(IEnumerable<string> paths)
            {
                foreach (var path in paths)
                {
                    var fixedPath = path;
                    if (fixedPath.EndsWith(Path.DirectorySeparatorChar.ToString())
                        || fixedPath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
                    {
                        fixedPath = fixedPath.Remove(fixedPath.Length - 1);
                    }
    
                    if (Directory.Exists(fixedPath))
                    {
                        yield return new DirectoryInfo(fixedPath);
                    }
                    else if (File.Exists(fixedPath))
                    {
                        yield return new FileInfo(fixedPath);
                    }
                    else
                    {
                        throw new FileNotFoundException
                            (string.Format("The specified file or folder doesn't exists : {0}", fixedPath),
                            fixedPath);
                    }
                }
            }
    
            public static void FilesOrFolders(string parentDirectory, ICollection<string> filenames)
            {
                if (filenames == null) throw new ArgumentNullException("filenames");
                if (filenames.Count == 0) return;
    
                var parentPidl = PathToAbsolutePIDL(parentDirectory);
                try
                {
                    var parent = PIDLToShellFolder(parentPidl);
                    var filesPidl = filenames
                        .Select(filename => GetShellFolderChildrenRelativePIDL(parent, filename))
                        .ToArray();
    
                    try
                    {
                        SHOpenFolderAndSelectItems(parentPidl, filesPidl, false);
                    }
                    finally
                    {
                        foreach (var pidl in filesPidl)
                        {
                            NativeMethods.ILFree(pidl);
                        }
                    }
                }
                finally
                {
                    NativeMethods.ILFree(parentPidl);
                }
            }
    
            public static void FilesOrFolders(params string[] paths)
            {
                FilesOrFolders((IEnumerable<string>)paths);
            }
    
            public static void FilesOrFolders(IEnumerable<string> paths)
            {
                if (paths == null) throw new ArgumentNullException("paths");
    
                FilesOrFolders(PathToFileSystemInfo(paths));
            }
    
            public static void FilesOrFolders(IEnumerable<FileSystemInfo> paths)
            {
                if (paths == null) throw new ArgumentNullException("paths");
                var pathsArray = paths.ToArray();
                if (pathsArray.Count() == 0) return;
    
                var explorerWindows = pathsArray.GroupBy(p => Path.GetDirectoryName(p.FullName));
    
                foreach (var explorerWindowPaths in explorerWindows)
                {
                    var parentDirectory = Path.GetDirectoryName(explorerWindowPaths.First().FullName);
                    FilesOrFolders(parentDirectory, explorerWindowPaths.Select(fsi => fsi.Name).ToList());
                }
            }
        }
    
        class Program
        {
            static void Main()
            {
    
                var test = 3;
                switch (test)
                {
                    case 0:
                        var mydocs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                        ShowSelectedInExplorer.FileOrFolder(Path.Combine(mydocs, "Visual Studio 2010"), edit: true);
    
                        break;
    
                    case 1:
                        ShowSelectedInExplorer.FileOrFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
                        break;
    
                    case 2:
                        ShowSelectedInExplorer.FilesOrFolders(@"C:\Windows\", new[] { "Microsoft.NET", "System32", "Setup" });
                        break;
    
                    case 3:
                        ShowSelectedInExplorer.FilesOrFolders(@"C:\Windows\Microsoft.NET\", @"C:\Windows\System32", @"C:\Windows\Setup", @"C:\Program Files");
                        break;
                }
            }
        }
    }
    

    【讨论】:

    • 这是否适用于分布在多个文件夹中的更多文件?
    • 我修复了添加此功能的代码,它现在在这种情况下会打开多个资源管理器窗口。
    • @m0s:公共域或 BSD 2 子句,我并不真正关心 API 包装器。
    【解决方案2】:

    免责声明:我认为VirtualBlackFox's answer 比我的要好,尽管目前它的票数较少,所以请向下滚动并先阅读:)

    简单的方法(可能不适用于所有平台):

    Process.Start(String, String)
    

    第一个参数是应用程序,第二个参数是应用程序的命令行参数..

    例如:

    Process.Start("explorer.exe",
    "/select,Z:\Music\Thursday Blues\01. I wish it was friday.mp3")
    
    Process.Start("explorer.exe",
    "/select,Z:\Music\Counting Sheep\01. Sheep #1.mp3 /select,Z:\Music\Counting Sheep\02. Sheep #2.mp3")
    

    (如果文件路径有空格,我认为您可能需要在文件路径周围使用转义引号)。

    更多信息:http://msdn.microsoft.com/en-us/library/h6ak8zt5.aspx

    (根据this question的几个答案编译)


    更难的方法,但更有可能奏效,取自this answer to another question

    使用shell函数SHOpenFolderAndSelectItems

    以下是一些示例代码,展示了如何在 C/C++ 中使用该函数,无需进行错误检查:

    //Directory to open
    ITEMIDLIST *dir = ILCreateFromPath(_T("C:\\"));
    
    //Items in directory to select
    ITEMIDLIST *item1 = ILCreateFromPath(_T("C:\\Program Files\\"));
    ITEMIDLIST *item2 = ILCreateFromPath(_T("C:\\Windows\\"));
    const ITEMIDLIST* selection[] = {item1,item2};
    UINT count = sizeof(selection) / sizeof(ITEMIDLIST);
    
    //Perform selection
    SHOpenFolderAndSelectItems(dir, count, selection, 0);
    
    //Free resources
    ILFree(dir);
    ILFree(item1);
    ILFree(item2);
    

    【讨论】:

    • 最后一个不起作用,因为没有 Process.Start(string, string, string) 这样的东西。这些参数是否应该以某种方式在同一个字符串中?
    • 是的,你是对的。我回答后意识到并更新了答案;现在可以用了吗?
    • 嗯。它会运行,但只会打开一个资源管理器窗口并选择第一个文件。
    • 在这种情况下,可能无法通过此方法完成多个文件。不知道从那里去哪里,除非你想通过这个解决方法:stackoverflow.com/questions/9355/…
    【解决方案3】:

    尝试开始这个:

    explorer.exe /select,Z:\Music\Thursday Blues\01. I wish it was friday.mp3
    

    【讨论】:

    • 适用于一个文件,但如何处理多个文件?
    【解决方案4】:

    总结:无法使用 Process.Start

    来自: programatically-select-multiple-files-in-windows-explorer

    flashk's answer of "This should be possible with the shell function SHOpenFolderAndSelectItems" 对我来说似乎可行,但我没有厌倦它

    这是一个老问题,但出现了 第一次当我在谷歌搜索类似的时候,所以 我试图得出结论 更容易找到。

    【讨论】:

      【解决方案5】:

      也许您可以使用 ProcessExplorer 找出从 Media Player 启动 explorer.exe 时使用了哪些参数?

      【讨论】:

      • 首先设置资源管理器,以便资源管理器的每个实例都在新进程中启动。然后从媒体播放器中打开文件。在 ProcessExplorer 中,您应该看到媒体播放器的子进程。双击它,完整的命令行应该会显示在属性的某处。
      • 这就是我尝试过的......但没有弹出资源管理器的新实例:S Windows 7 是否忽略该设置或其他什么?
      • 抱歉,我还没有在 Windows 7 上尝试过。如果你手动启动一个新的资源管理器,你会得到一个新的进程吗?
      • 我相信该选项会在同一进程中打开所有文件夹,但与任务栏分开。 (我说的是“在单独的进程中启动文件夹窗口”的选项。如果有一个选项可以单独打开每个窗口,请随时启发我!)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-24
      • 1970-01-01
      相关资源
      最近更新 更多