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

发布于 2024-07-25 22:22:49 字数 874 浏览 5 评论 0原文

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

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

  • Z:\Music\Thursday Blues\01。 我希望是 friday.mp3
  • Z:\Music\Counting Sheep\01。 Sheep #1.mp3
  • Z:\Music\Counting Sheep\02. Sheep #2.mp3

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

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


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

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.

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

  • 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

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

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.


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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

无言温柔 2024-08-01 22:22:49

在同事遇到问题后寻找答案时,我没有找到答案,所以我写了一个小课程来做到这一点。 代码位于 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;
            }
        }
    }
}

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 Gist and i will paste the curent version at the end of this post.

With your sample files, the syntax will be :

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"
    );

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

  • 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 :

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;
            }
        }
    }
}
上课铃就是安魂曲 2024-08-01 22:22:49

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

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

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

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

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\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")

(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

(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

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

//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);
第几種人 2024-08-01 22:22:49

尝试开始这个:

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

Try starting this:

explorer.exe /select,Z:\Music\Thursday Blues\01. I wish it was friday.mp3
我三岁 2024-08-01 22:22:49

总结:使用 Process.Start

From 是不可能的:
programatically-select-multiple-files-in-windows-explorer

< a href="https://stackoverflow.com/questions/9355/programatically-select-multiple-files-in-windows-explorer/3011284#3011284">flashk 的回答“这应该可以通过 shell函数 SHOpenFolderAndSelectItems”对我来说似乎是可能的,但我还没有厌倦它

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

To summarize: It is not possible using Process.Start

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

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

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.

夏天碎花小短裙 2024-08-01 22:22:49

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

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

聽兲甴掵 2024-08-01 22:22:49

这是一个 .NET Core 版本,它使用 CsWin32 nuget 进行互操作代码生成。
在 Shell 级别,它使用 IShellItemIParentAndItem 接口比 IShellFolder 更容易使用。

由于它使用的是 IShellItem 而不是物理文件,因此此代码

ShellUtilities.OpenFoldersAndSelectFiles(
[
    @"c:\",
    @"d:\",
]);

将在“This PC”shell 命名空间中选择 c: 和 d:。

C# .csproj 文件:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>
</Project>

NativeMethods.txt 文件,定义我们要导入的 Win32 接口和函数

IShellItem
IParentAndItem
SHOpenFolderAndSelectItems
SHCreateItemFromParsingName

示例 program.cs 文件:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Windows.Win32;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.Shell.Common;

[assembly: SupportedOSPlatform("windows6.0.6000")]

namespace ConsoleApp;

internal class Program
{
    static void Main()
    {
        ShellUtilities.OpenFoldersAndSelectFiles(
        [
          @"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"
        ]);

        // select c: and d: in "This PC"
        ShellUtilities.OpenFoldersAndSelectFiles(
        [
            @"c:\",
            @"d:\",
        ]);
    }
}

public static class ShellUtilities
{
    public static unsafe void OpenFoldersAndSelectFiles(IEnumerable<string> files)
    {
        ArgumentNullException.ThrowIfNull(files);

        // get all items & group by folder (path)
        var items = Item.FromPaths(files);

        foreach (var group in items.GroupBy(g => g.ToString()))
        {
            var childPidls = group.Select(g => (nint)g.ChildPidl).ToArray();
            var pidls = Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(childPidls));
            PInvoke.SHOpenFolderAndSelectItems(group.First().ParentPidl, (uint)group.Count(), (ITEMIDLIST**)pidls, 0);
        }
        items.ForEach(i => i.Dispose());
    }

    private unsafe sealed class Item : IDisposable
    {
        public char* ParentPath;
        public ITEMIDLIST* ParentPidl;
        public ITEMIDLIST* ChildPidl;
        public override string ToString() => new(ParentPath);

        public static List<Item> FromPaths(IEnumerable<string> files) // return list cause unsafe code cannot appear in iterators
        {
            var list = new List<Item>();
            foreach (var file in files)
            {
                // build IShellItem
                if (PInvoke.SHCreateItemFromParsingName(file, null, typeof(IShellItem).GUID, out var obj).Failed)
                    continue;

                var item = (IShellItem)obj;
                item.GetParent(out var parent);
                parent.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out var path);

                // get parent & item relative pidls
                ITEMIDLIST* childPidl; ITEMIDLIST* parentPidl;
                ((IParentAndItem)item).GetParentAndItem(&parentPidl, null, &childPidl);
                list.Add(new Item { ParentPath = path.Value, ParentPidl = parentPidl, ChildPidl = childPidl });
            }
            return list;
        }

        public void Dispose()
        {
            if (ParentPath != null) { Marshal.FreeCoTaskMem((nint)ParentPath); ParentPath = null; }
            if (ParentPidl != null) Marshal.FreeCoTaskMem((nint)ParentPidl); ParentPidl = null;
            if (ChildPidl != null) Marshal.FreeCoTaskMem((nint)ChildPidl); ChildPidl = null;
            GC.SuppressFinalize(this);
        }
    }
}

Here is a .NET Core version that uses CsWin32 nuget for interop code generation.
At Shell level it uses IShellItem and IParentAndItem interfaces that are much easier to work with than IShellFolder.

Since it's using IShellItem and not necessarily physical files, this code

ShellUtilities.OpenFoldersAndSelectFiles(
[
    @"c:\",
    @"d:\",
]);

will select c: and d: in "This PC" shell namespace.

C# .csproj file:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>
</Project>

NativeMethods.txt file that define what Win32 interfaces and functions we want to import

IShellItem
IParentAndItem
SHOpenFolderAndSelectItems
SHCreateItemFromParsingName

Sample program.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Windows.Win32;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.Shell.Common;

[assembly: SupportedOSPlatform("windows6.0.6000")]

namespace ConsoleApp;

internal class Program
{
    static void Main()
    {
        ShellUtilities.OpenFoldersAndSelectFiles(
        [
          @"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"
        ]);

        // select c: and d: in "This PC"
        ShellUtilities.OpenFoldersAndSelectFiles(
        [
            @"c:\",
            @"d:\",
        ]);
    }
}

public static class ShellUtilities
{
    public static unsafe void OpenFoldersAndSelectFiles(IEnumerable<string> files)
    {
        ArgumentNullException.ThrowIfNull(files);

        // get all items & group by folder (path)
        var items = Item.FromPaths(files);

        foreach (var group in items.GroupBy(g => g.ToString()))
        {
            var childPidls = group.Select(g => (nint)g.ChildPidl).ToArray();
            var pidls = Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(childPidls));
            PInvoke.SHOpenFolderAndSelectItems(group.First().ParentPidl, (uint)group.Count(), (ITEMIDLIST**)pidls, 0);
        }
        items.ForEach(i => i.Dispose());
    }

    private unsafe sealed class Item : IDisposable
    {
        public char* ParentPath;
        public ITEMIDLIST* ParentPidl;
        public ITEMIDLIST* ChildPidl;
        public override string ToString() => new(ParentPath);

        public static List<Item> FromPaths(IEnumerable<string> files) // return list cause unsafe code cannot appear in iterators
        {
            var list = new List<Item>();
            foreach (var file in files)
            {
                // build IShellItem
                if (PInvoke.SHCreateItemFromParsingName(file, null, typeof(IShellItem).GUID, out var obj).Failed)
                    continue;

                var item = (IShellItem)obj;
                item.GetParent(out var parent);
                parent.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out var path);

                // get parent & item relative pidls
                ITEMIDLIST* childPidl; ITEMIDLIST* parentPidl;
                ((IParentAndItem)item).GetParentAndItem(&parentPidl, null, &childPidl);
                list.Add(new Item { ParentPath = path.Value, ParentPidl = parentPidl, ChildPidl = childPidl });
            }
            return list;
        }

        public void Dispose()
        {
            if (ParentPath != null) { Marshal.FreeCoTaskMem((nint)ParentPath); ParentPath = null; }
            if (ParentPidl != null) Marshal.FreeCoTaskMem((nint)ParentPidl); ParentPidl = null;
            if (ChildPidl != null) Marshal.FreeCoTaskMem((nint)ChildPidl); ChildPidl = null;
            GC.SuppressFinalize(this);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文