2009-07-02 36 views
19

En la Biblioteca de Windows Media Player puede seleccionar uno o más archivos de música. A continuación, puede hacer clic con el botón derecho y, en el menú contextual, seleccionar Abrir ubicación de archivo. Esto abrirá una ventana de explorador de Windows para cada directorio en el que estén los archivos, y los archivos serán seleccionados por usted.C#: Cómo abrir ventanas de Windows Explorer con una cantidad de archivos seleccionados

Así que vamos a decir que tenemos un montón de archivos mp3 en nuestra biblioteca en la que tres de ellos son los siguientes:

  • Z: \ Música \ jueves azules \ 01. Desearía que fuera viernes.mp3
  • Z: \ Music \ Counting Sheep \ 01. Oveja # 1.mp3
  • Z: \ Music \ Counting Sheep \ 02. Ovejas 2.mp3

Si seleccionamos los tres (en una vista en la que todos ellos son visibles) y hacemos Abrir ubicación de archivo luego dos ventanas del explorador se abrirá #. Una será la carpeta Z: \ Music \ Thursday Blues con 01. Desearía que fuera friday.mp3 seleccionada, y la otra será la carpeta * Z: \ Music \ Counting Sheep ** con ambas 01 .Ovejas # 1.mp3 y 02. Ovejas # 2.mp3 seleccionadas.

¿Cómo puedo hacer esto yo mismo en C#? Tenemos una aplicación que va a exportar datos a varios formatos, por ejemplo, CSV y Excel, y me gustaría abrir las ventanas del explorador con estos archivos seleccionados cuando se crean y están listos para ser vistos. Actualmente solo hago Process.Start(path), y esto funciona, pero me gustaría poder resaltar esos archivos en particular también. Haría que los archivos que se acababan de crear fueran mucho más obvios.


Windows Media Player lo hace tan bien ... quiero hacerlo también =/¿Hay empleados de Microsoft aquí que pude averiguar cómo se puede hacer? (A)

Respuesta

36

Buscando una respuesta después de que un compañero de trabajo tuvo el problema, no encontré ninguno, así que escribí una clase pequeña para hacer esto. El código is on Gist y pegaré la versión actual al final de esta publicación.

Con sus archivos de ejemplo, la sintaxis será:

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

Hay algunas limitaciones a mi código en comparación con la API de bajo nivel, principalmente:

  • Selección en el escritorio no se ha implementado
  • El directorio principal debe ser un directorio o una unidad, por lo que no puede seleccionar varias unidades en la carpeta Mi PC, por ejemplo.

De todos modos, aquí está el código fuente de la clase 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; 
      } 
     } 
    } 
} 
+0

Funciona con más archivos repartidos en más de un ¿carpeta? – Svish

+0

He reparado el código para agregar esta funcionalidad, ahora abre varias ventanas del explorador en este caso. –

+0

Genial, gracias! –

1

intentar el inicio de esto:

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

que funciona para un archivo, pero ¿cómo lo haga por más de uno? – Svish

21

responsabilidad: Creo VirtualBlackFox's answer es mejor que la mía, aunque tiene menos votos en la actualidad, por lo que desplazarse hacia abajo y leído primero que uno :)

método fácil (podría no funcionar en todas las plataformas):

Process.Start(String, String) 

primer argumento es la aplicación, segundo argumento es º e parámetros de línea de comandos de la aplicación ..

Así, por ejemplo:

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 piensa que podría necesitar comillas alrededor de las rutas de archivos escapado si tienen espacios).

más información: http://msdn.microsoft.com/en-us/library/h6ak8zt5.aspx

(compilada a partir de varias respuestas a this question) Método


más difícil, pero más propensos a trabajar, tomada de this answer to another question:

Uso de la función de shell SHOpenFolderAndSelectItems

Aquí hay algunos ejemplos de código que muestran cómo usar la función en C/C++, sin comprobación de errores:

//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); 
+0

Ese último no funciona, porque no existe tal cosa como Process.Start (string, string, string). ¿Deberían esos argumentos estar de alguna manera en la misma cadena o algo así? – Svish

+0

Sí, tienes razón. Me di cuenta después de responder y actualicé la respuesta; funciona ahora? –

+0

Hm. Se ejecuta, pero solo abre una ventana del explorador con el primer archivo seleccionado. – Svish

0

Tal vez pueda utilizar ProcessExplorer para averiguar qué argumentos se utilizan cuando se inicia explorer.exe desde Media Player?

Regards,

Sebastiaan

+0

Hm, how uno haría eso? – Svish

+0

Primero configure el explorador para que cada instancia de explorador se inicie en un nuevo proceso. A continuación, abra los archivos desde el reproductor multimedia. En ProcessExplorer debería ver un proceso secundario de reproductor multimedia. Haga doble clic en él y la línea de comando completa se debe mostrar en algún lugar de las propiedades. –

+0

Eso es lo que probé ... pero no aparece una nueva instancia del explorador: S ¿Windows 7 ignora esa configuración o algo así? – Svish

Cuestiones relacionadas