2011-02-28 9 views
6

Sto scrivendo una funzionalità in C# in cui sono richiesto di elencare tutti i nomi di file/cartelle in una determinata directory. La funzionalità funziona bene su EN OS, ma quando eseguo l'applicazione su OS localizzato (ad esempio tedesco), sto ancora ricevendo i nomi inglesi delle cartelle speciali (Programmi invece di Programmi, Preferiti invece di Favoriten ecc.). Non penso che Environment.GetFolderPath con Environment.SpecialFolder possa essere di alcun aiuto in quanto fa esattamente l'opposto di quello che voglio, vale a dire che enumera il percorso completo della cartella speciale, mentre, voglio il nome localizzato del dato sentiero. Ho provato a utilizzare File, SHFileInfo, ma non serve a niente. Qualche idea, come posso ottenere i nomi delle cartelle come visualizzati nel sistema operativo?Come ottenere i nomi delle cartelle (localizzati) attuali?

+0

penso che u bisogno di impostare il locale nel codice ... –

+0

direi il nome inglese è il nome attuale (ne hai bisogno per accedere al file) e il nome tedesco è solo il nome visualizzato. – CodesInChaos

risposta

10

è possibile ottenere il nome visualizzato localizzato con il SHGetFileInfo API:

public static string GetDisplayName(Environment.SpecialFolder specialFolder) 
    { 
     IntPtr pidl = IntPtr.Zero; 
     try 
     { 
      HResult hr = SHGetFolderLocation(IntPtr.Zero, (int) specialFolder, IntPtr.Zero, 0, out pidl); 
      if (hr.IsFailure) 
       return null; 

      SHFILEINFO shfi; 
      if (0 != SHGetFileInfo(
         pidl, 
         FILE_ATTRIBUTE_NORMAL, 
         out shfi, 
         (uint)Marshal.SizeOf(typeof(SHFILEINFO)), 
         SHGFI_PIDL | SHGFI_DISPLAYNAME)) 
      { 
       return shfi.szDisplayName; 
      } 
      return null; 
     } 
     finally 
     { 
      if (pidl != IntPtr.Zero) 
       ILFree(pidl); 
     } 
    } 

    public static string GetDisplayName(string path) 
    { 
     SHFILEINFO shfi; 
     if (0 != SHGetFileInfo(
        path, 
        FILE_ATTRIBUTE_NORMAL, 
        out shfi, 
        (uint)Marshal.SizeOf(typeof(SHFILEINFO)), 
        SHGFI_DISPLAYNAME)) 
     { 
      return shfi.szDisplayName; 
     } 
     return null; 
    } 

    private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; 
    private const uint SHGFI_DISPLAYNAME = 0x000000200;  // get display name 
    private const uint SHGFI_PIDL = 0x000000008;  // pszPath is a pidl 

    [DllImport("shell32")] 
    private static extern int SHGetFileInfo(IntPtr pidl, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint flags); 
    [DllImport("shell32")] 
    private static extern HResult SHGetFolderLocation(IntPtr hwnd, int nFolder, IntPtr token, int dwReserved, out IntPtr pidl); 
    [DllImport("shell32")] 
    private static extern void ILFree(IntPtr pidl); 

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] 
    private struct SHFILEINFO 
    { 
     public IntPtr hIcon; 
     public int iIcon; 
     public uint dwAttributes; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
     public string szDisplayName; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] 
     public string szTypeName; 
    } 

[StructLayout(LayoutKind.Sequential)] 
public struct HResult 
{ 
    private int _value; 

    public int Value 
    { 
     get { return _value; } 
    } 

    public Exception Exception 
    { 
     get { return Marshal.GetExceptionForHR(_value); } 
    } 

    public bool IsSuccess 
    { 
     get { return _value >= 0; } 
    } 

    public bool IsFailure 
    { 
     get { return _value < 0; } 
    } 
} 
+0

esattamente quello che stavo cercando. Grazie. Ho comunque un altro problema (non una regressione di questo codice, ma preesistente). Mentre elenco i file, ora sto ottenendo due file per programma in tedesco. Uno è una cartella e un altro mostra come un collegamento che è effettivamente visibile nel sistema operativo. Prima di apportare la modifica suggerita, stavo ottenendo il nome non localizzato per queste cartelle e il nome localizzato per le scorciatoie. Non voglio mostrare le scorciatoie perché rendono ripetitiva la lista. – Scotti

+0

filtra solo i file .lnk –

+0

Ottengo '敄 歳 潴 p 敄 歳 潴 p' per' Ambiente.SpecialFolder.Desktop' con cultura 'de-DE' (germania). Perché? –

2

ho fatto capire come farlo funzionare. Non sono sicuro di cosa non vada nel codice sopra (ho anche ottenuto caratteri Unicode cinesi), ma questo sembra funzionare in modo affidabile. Basta passare nel percorso (ad esempio, chiamando:

GetDisplayName(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); 

e restituisce il nome di visualizzazione della cartella (in questo esempio, "Documenti" o qualsiasi altra cosa che hai rinominato a)

.
using System.Runtime.InteropServices; 
... 
public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; 
public const uint SHGFI_DISPLAYNAME = 0x000000200;  // get display name 

[DllImport("shell32")] 
public static extern int SHGetFileInfo(string pszPath, uint dwFileAttributes, 
    out SHFILEINFO psfi, uint cbFileInfo, uint flags); 

[StructLayout(LayoutKind.Sequential)] 
public struct SHFILEINFO 
{ 
    public IntPtr hIcon; 
    public IntPtr iIcon; 
    public uint dwAttributes; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
    public string szDisplayName; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] 
    public string szTypeName; 
}; 


public static string GetDisplayName(string path) 
{ 
    SHFILEINFO shfi = new SHFILEINFO(); 
    if (0 != SHGetFileInfo(path,FILE_ATTRIBUTE_NORMAL,out shfi, 
     (uint)Marshal.SizeOf(typeof(SHFILEINFO)),SHGFI_DISPLAYNAME)) 
    { 
     return shfi.szDisplayName; 
    } 
    return null; 
} 
+0

Questo funziona rispetto all'altra soluzione che fornisce alcuni caratteri cinesi. – whywhywhy

0

si deve fare in modo che CharSet è impostata su Unicode per la DllImport e StructLayout.

[DllImport("shell32", CharSet = CharSet.Unicode)] 
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]