2009-07-02 6 views
19

Nella Libreria di Windows Media Player è possibile selezionare uno o più file musicali. È quindi possibile fare clic con il pulsante destro del mouse e nel loro menu di scelta rapida scegliere Apri posizione file. Questo aprirà una finestra di Windows Explorer per ogni directory in cui si trovano i file, e i file saranno selezionati per te.C#: Come aprire Windows Explorer con un numero di file selezionati

Quindi diciamo che abbiamo un sacco di file mp3 nella nostra biblioteca, dove tre di loro sono questi:

  • Z: \ Musica \ giovedì Blues \ 01. Vorrei che fosse venerdì.mp3 ​​
  • Z: \ Music \ Counting Sheep \ 01. Pecora # 1.mp3
  • Z: \ Music \ Counting Sheep \ 02. Sheep # 2.mp3

Se selezioniamo quei tre (in una visione in cui tutti sono visibili) e facciamo Apri percorso file poi due finestre Explorer pop-up. Uno sarà la cartella Z: \ Music \ Thursday Blues con 01. Vorrei che fosse venerdì.mp3 ​​ selezionata e l'altra sarà la cartella * Z: \ Music \ Counting Sheep ** con entrambi 01 . Pecore 1.mp3 e 02. Pecora # 2.mp3 selezionata.

Come posso fare da solo in C#? Abbiamo un'applicazione che sta per esportare i dati in vari formati, ad esempio CSV ed Excel, e vorrei aprire explorer windows con questi file selezionati quando sono creati e pronti per essere visualizzati. Attualmente faccio solo Process.Start(path), e questo funziona, ma mi piacerebbe poter mettere in evidenza anche quei file particolari. Renderebbe i file appena creati molto più ovvi.


Windows Media Player fa così bene ... voglio farlo troppo =/Ci sono dipendenti Microsoft qui che riusciva a capire come si può fare? (A)

risposta

36

Alla ricerca di una risposta dopo che un collega ha riscontrato il problema, non l'ho trovato, quindi ho scritto una piccola classe per farlo. Il codice is on Gist e incollerò la versione aggiornata alla fine di questo post.

Con i tuoi file di esempio, la sintassi sarà:

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

Ci sono alcune limitazioni per il mio codice rispetto alle API di basso livello, principalmente:

  • Selezione sul desktop non è implementata
  • La directory padre deve essere una directory o un'unità, pertanto non è possibile selezionare più unità nella cartella Risorse del computer, ad esempio.

Ad ogni modo, ecco il codice sorgente della classe 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

Funziona con più file distribuiti in più di una cartella? – Svish

+0

Ho riparato il codice per aggiungere questa funzionalità ora apre più finestre di explorer in questo caso. –

+0

Fantastico, grazie! –

1

provare ad avviare questo:

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

Opere per un file, ma come si fa a farlo per più di uno? – Svish

21

Disclaimer: io penso VirtualBlackFox's answer è migliore del mio, anche se ha meno voti attualmente, in modo da scorrere e letto che una prima :)

metodo Easy (potrebbe non funzionare su tutte le piattaforme):

Process.Start(String, String) 

primo argomento è l'applicazione, secondo argomento è esimo parametri della riga di comando e dell'applicazione ..

Così, per esempio:

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

(penso che si potrebbe aver bisogno sfuggito virgolette i percorsi dei file se hanno spazi).più

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

(compilato da più risposte a this question) Metodo


più difficile, ma più propensi a lavorare, tratto da this answer to another question:

Utilizzare la funzione di shell SHOpenFolderAndSelectItems

Ecco alcuni esempi di codice che mostrano come utilizzare la funzione in C/C++, senza controllo degli errori:

//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

Quest'ultimo non funziona, perché non esiste una cosa come Process.Start (stringa, stringa, stringa). Questi argomenti dovrebbero essere stati nella stessa stringa o qualcosa del genere? – Svish

+0

Sì, hai ragione. Mi sono reso conto dopo che ho risposto e ho aggiornato la risposta; funziona ora? –

+0

Hm. Funziona, ma apre solo una finestra di Explorer con il primo file selezionato. – Svish

0

forse è possibile utilizzare ProcessExplorer per scoprire quali argomenti vengono utilizzati quando explorer.exe viene lanciato da Media Player?

saluti,

Sebastiaan

+0

Hm, come lo farebbe? – Svish

+0

Prima imposta explorer in modo che ogni istanza di explorer venga avviata in un nuovo processo. Quindi aprire i file dall'interno del lettore multimediale. In ProcessExplorer dovresti vedere un processo figlio di media player. Fare doppio clic su di esso e la riga di comando completa dovrebbe essere visualizzata da qualche parte nelle proprietà. –

+0

Questo è quello che ho provato ... ma non c'è una nuova istanza di explorer che si apre: S Windows 7 ignora questa impostazione o qualcosa del genere? – Svish