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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1073353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 07:35:28  来源:igfitidea点击:

C#: How to open Windows Explorer windows with a number of files selected

c#filewindows-explorerdirectory

提问by Svish

In the Library of Windows Media Player you can select one or more music files. You can then right-click and in their context menu choose Open File Location. This will open up one windows explorer window for each directory that the files are in, and the files will be selected for you.

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

So let's say we have a bunch of mp3 files in our library where three of them are these:

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

  • 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
  • Z:\音乐\星期四蓝调\01。我希望是星期五.mp3
  • Z:\音乐\数羊\01. 羊#1.mp3
  • Z:\音乐\数羊\02. 羊#2.mp3

If we select those three (in a view where all of them are visible) and do Open File Locationthen two explorer windows will pop up. One will be the Z:\Music\Thursday Bluesfolder with 01. I wish it was friday.mp3selected, and the other one will be the *Z:\Music\Counting Sheep** folder with both 01. Sheep #1.mp3and 02. Sheep #2.mp3selected.

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

How can I do this myself in C#? We have an application which is going to export data to various formats, for example CSV and Excel, and I would like to open up explorer windows with these files selected when they are created and ready to be viewed. Currently I just do Process.Start(path), and this works but I would love to be able to highlight those particular files as well. Would make the files that were just created much more obvious.

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



Windows Media Player does it so well... I want to do it too =/ Are there any Microsoft employees here that could figure out how it can be done? (A)

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

采纳答案by Julien Roncaglia

Searching for an answer after a coworker had the issue i found none so i wrote a small class to do this. The code is on Gistand i will paste the curent version at the end of this post.

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

With your sample files, the syntax will be :

对于您的示例文件,语法将是:

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

There are some limitations to my code compared to the low level API, mainly :

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

  • Selecting on the desktop is not implemented
  • The parent directory must be a directory or a drive, so you can't select multiple drives in the My Computer folder for example.
  • 没有实现在桌面上选择
  • 父目录必须是目录或驱动器,因此您不能在例如“我的电脑”文件夹中选择多个驱动器。

Anyway, here is the ShowSelectedInExplorer class source code :

无论如何,这是 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;
            }
        }
    }
}

回答by Blindy

Try starting this:

尝试开始:

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

回答by Colin Pickard

Disclaimer: I think VirtualBlackFox's answeris better than mine although it has less votes at present, so scroll down and read that one first :)

免责声明:我认为VirtualBlackFox 的答案比我的好,尽管目前它的票数较少,因此请向下滚动并先阅读该答案:)

Easy method (might not work on all platforms):

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

Process.Start(String, String)

First argument is the application, second argument is the command line parameters of the application..

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

So for example:

例如:

Process.Start("explorer.exe",
"/select,Z:\Music\Thursday Blues. I wish it was friday.mp3")

Process.Start("explorer.exe",
"/select,Z:\Music\Counting Sheep. Sheep #1.mp3 /select,Z:\Music\Counting Sheep. Sheep #2.mp3")

(I think you might need escaped quotes around the file paths if they have spaces).

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

more info: http://msdn.microsoft.com/en-us/library/h6ak8zt5.aspx

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

(compiled from several answers to this question)

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



Harder method, but more likely to work, taken from this answer to another question:

更难的方法,但更可能奏效,取自另一个问题的答案

Use the shell function SHOpenFolderAndSelectItems

使用shell函数 SHOpenFolderAndSelectItems

Here is some sample code showing how to use the function in C/C++, without error checking:

下面是一些示例代码,展示了如何在 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);

回答by Sebastiaan M

Maybe you can use ProcessExplorer to find out which arguments are used when explorer.exe is launched from Media Player?

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

回答by Thymine

To summarize: It is not possible using Process.Start

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

From: programatically-select-multiple-files-in-windows-explorer

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

flashk's answerof "This should be possible with the shell function SHOpenFolderAndSelectItems" seems possible to me, but I have not tired it

flashk的回答“这应该可以用shell函数实现SHOpenFolderAndSelectItems”在我看来是可能的,但我并没有厌倦它

This is an old question, but came up first when I was googling similar, so I'm trying to make the conclusion easier to find.

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