C#:如何打开选择了多个文件的Windows资源管理器窗口

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

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

  • Z:\ Music \ Thursday Blues \ 01。 我希望它是星期五.mp3
  • Z:\ Music \ Counting Sheep \ 01。 绵羊#1.mp3
  • Z:\ Music \ Counting Sheep \ 02。 绵羊#2.mp3

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

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


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

在一位同事遇到问题后寻找答案我没有找到,所以我写了一个小class来做这件事。 代码在Gist上 ,我将在本文末尾粘贴curent版本。

使用示例文件,语法将为:

 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 PathToFileSystemInfo(IEnumerable 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 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)paths); } public static void FilesOrFolders(IEnumerable paths) { if (paths == null) throw new ArgumentNullException("paths"); FilesOrFolders(PathToFileSystemInfo(paths)); } public static void FilesOrFolders(IEnumerable 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; } } } } 

免责声明:我认为VirtualBlackFox的答案比我的好,虽然它目前的票数较少,所以向下滚动并先阅读那个:)

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

 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

(根据这个问题的几个答案编译)


更难的方法,但更有可能工作,从这个答案的另一个问题 :

使用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); 

尝试开始:

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

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

问候,

Sebastiaan

总结一下 :使用Process.Start是不可能的

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

flashk的答案 “这应该是可以使用shell函数SHOpenFolderAndSelectItems ”似乎对我来说可能,但我还没累呢

这是一个古老的问题,但是当我在谷歌上搜索相似时首先出现,所以我试图让结论更容易找到。