C #: Comment utiliser SHOpenFolderAndSelectItems

Quelqu’un pourrait-il donner un exemple d’utilisation de la fonction shell SHOpenFolderAndSelectItems à partir de C #? Je ne comprends pas trop comment utiliser ce genre de fonctions et je ne le trouve pas sur pinvoke.net … = /

Disons que j’ai trois fichiers appelés

  • X:\Pictures\a.jpg
  • X:\Pictures\s.jpg
  • X:\Pictures\d.jpg

Je veux ensuite ouvrir le dossier X:\Pictures avec a.jpg , s.jpg et d.jpg sélectionnés.

Comme vous semblez avoir posé deux fois la même question (l’autre étant C #: Comment ouvrir les fenêtres de l’explorateur Windows avec un certain nombre de fichiers sélectionnés sans réponse), j’envoie ma solution aux deux questions. Je ne sais pas si je devrais en créer une. un wiki de communauté.

À la recherche d’une réponse après qu’un collègue eut eu le problème, je n’en ai trouvé aucun, alors j’ai écrit une petite classe pour le faire. Le code est sur Gist et je vais coller la version actuelle à la fin de ce post.

Avec vos exemples de fichiers, la syntaxe sera la suivante:

  ShowSelectedInExplorer.FilesOrFolders( @"X:\Pictures\a.jpg", @"X:\Pictures\s.jpg", @"X:\Pictures\d.jpg" ); 

Mon code présente certaines limitations par rapport à l’API de bas niveau, notamment:

  • La sélection sur le bureau n’est pas implémentée
  • Le répertoire parent doit être un répertoire ou un lecteur. Par exemple, vous ne pouvez pas sélectionner plusieurs lecteurs dans le dossier Poste de travail.

Quoi qu’il en soit, voici le code source de la classe ShowSelectedInExplorer:

 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.ComstackrServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; static class ShowSelectedInExplorer { [Flags] internal 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] internal interface IShellFolder { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] void ParseDisplayName(IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In, MarshalAs(UnmanagedType.LPWStr)] ssortingng pszDisplayName, [Out] out uint pchEaten, [Out] out IntPtr ppidl, [In, Out] ref uint pdwAtsortingbutes); [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 GetAtsortingbutesOf([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)] ssortingng pszName, [In] uint uFlags, [Out] IntPtr ppidlOut); } [ComImport, Guid("000214F2-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal 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); } class NativeMethods { static readonly int pointerSize = Marshal.SizeOf(typeof(IntPtr)); [DllImport("ole32.dll", EntryPoint = "CreateBindCtx")] public static extern int CreateBindCtx_(int reserved, out IBindCtx ppbc); public static IBindCtx CreateBindCtx() { IBindCtx result; Marshal.ThrowExceptionForHR(CreateBindCtx_(0, out result)); return result; } [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 = NativeMethods.SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags); Marshal.ThrowExceptionForHR(result); } [DllImport("shell32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ILCreateFromPath([In, MarshalAs(UnmanagedType.LPWStr)] ssortingng pszPath); [DllImport("shell32.dll")] public static extern void ILFree([In] IntPtr pidl); } static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, ssortingng displayName) { var bindCtx = NativeMethods.CreateBindCtx(); uint pchEaten; uint pdwAtsortingbutes = 0; IntPtr ppidl; parentFolder.ParseDisplayName(IntPtr.Zero, null, displayName, out pchEaten, out ppidl, ref pdwAtsortingbutes); return ppidl; } static IntPtr PathToAbsolutePIDL(ssortingng path) { var desktopFolder = NativeMethods.SHGetDesktopFolder(); return GetShellFolderChildrenRelativePIDL(desktopFolder, path); } static Guid IID_IShellFolder = typeof(IShellFolder).GUID; static int pointerSize = Marshal.SizeOf(typeof(IntPtr)); 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(ssortingng 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) { ssortingng fixedPath = path; if (fixedPath.EndsWith(Path.DirectorySeparatorChar.ToSsortingng()) || fixedPath.EndsWith(Path.AltDirectorySeparatorChar.ToSsortingng())) { 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("The specified file or folder doesn't exists : " + fixedPath, fixedPath); } } } public static void FilesOrFolders(ssortingng parentDirectory, ICollection filenames) { if (filenames == null) throw new ArgumentNullException("filenames"); if (filenames.Count == 0) return; var parentPidl = PathToAbsolutePIDL(parentDirectory); try { var parent = PIDLToShellFolder(parentPidl); List filesPidl = new List(filenames.Count); foreach (var filename in filenames) { filesPidl.Add(GetShellFolderChildrenRelativePIDL(parent, filename)); } try { SHOpenFolderAndSelectItems(parentPidl, filesPidl.ToArray(), false); } finally { foreach (var pidl in filesPidl) { NativeMethods.ILFree(pidl); } } } finally { NativeMethods.ILFree(parentPidl); } } public static void FilesOrFolders(params ssortingng[] paths) { FilesOrFolders((IEnumerable)paths); } public static void FilesOrFolders(IEnumerable paths) { FilesOrFolders(PathToFileSystemInfo(paths)); } public static void FilesOrFolders(IEnumerable paths) { if (paths == null) throw new ArgumentNullException("paths"); if (paths.Count() == 0) return; var explorerWindows = paths.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()); } } } 

Pas une réponse à 100%, mais cet extrait montre comment sélectionner un seul élément dans l’explorateur à partir de C #.

  private void SelectInFileExplorer(ssortingng fullPath) { if (ssortingng.IsNullOrEmpty(fullPath)) throw new ArgumentNullException("fullPath"); fullPath = Path.GetFullPath(fullPath); IntPtr pidlList = NativeMethods.ILCreateFromPathW(fullPath); if (pidlList != IntPtr.Zero) try { // Open parent folder and select item Marshal.ThrowExceptionForHR(NativeMethods.SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0)); } finally { NativeMethods.ILFree(pidlList); } } static class NativeMethods { [DllImport("shell32.dll", ExactSpelling=true)] public static extern void ILFree(IntPtr pidlList); [DllImport("shell32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)] public static extern IntPtr ILCreateFromPathW(ssortingng pszPath); [DllImport("shell32.dll", ExactSpelling=true)] public static extern int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags); } 

Consultez http://www.cnblogs.com/qiuyi21/archive/2009/06/24/1510592.html . L’exemple utilise IShellLink pour obtenir les pidls du chemin avant de lancer SHOpenFolderAndSelectItems. J’utiliserais plutôt ILCreateFromPath.

La plupart des besoins de SHOpoenFolderSelectedItems seraient gérés par:

Pour la sélection de fichier en C #, vous utiliseriez normalement: System.Windows.Forms.OpenFileDialog .

Pour sélectionner un dossier en C #, vous utiliseriez normalement: System.Windows.Forms.FolderBrowserDialog .

Vous définissez un filtre approprié et vous pouvez définir un élément sélectionné initialement.

C’est peut-être assez proche de ce dont vous avez besoin?