2011-02-28 11 views
6

Estoy escribiendo una funcionalidad en C# donde estoy obligado a enumerar todos los nombres de archivos/carpetas en un directorio determinado. La funcionalidad funciona bien en EN OS, pero cuando ejecuto la aplicación en un sistema operativo localizado (por ejemplo) alemán, sigo recibiendo los nombres en inglés de las carpetas especiales (Archivos de programa en lugar de Program, Favorites en lugar de Favoriten, etc.). No creo que Environment.GetFolderPath con Environment.SpecialFolder puede ser de ninguna ayuda, ya que hace exactamente lo contrario de lo que quiero, es decir, da la ruta completa de la carpeta especial enumerada, mientras que, quiero el nombre localizado de la dada camino. He intentado usar File, SHFileInfo, pero no sirve de nada. Alguna idea, ¿cómo puedo obtener los nombres de las carpetas como se muestran en el sistema operativo?¿Cómo obtener los nombres de las carpetas reales (localizadas)?

+0

creo que u necesidad de establecer la configuración regional en el código ... –

+0

diría el nombre Inglés es el nombre real (lo necesitas) para acceder al archivo) y el nombre alemán es solo el nombre para mostrar. – CodesInChaos

Respuesta

10

Usted puede obtener el nombre de visualización localizada con la API SHGetFileInfo:

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

exactamente lo que estaba buscando. Gracias. Sin embargo, tengo un problema más (no una regresión de este código, sino preexistente). Mientras hago una lista de los archivos, ahora obtengo dos archivos para el programa en alemán. Una es una carpeta y otra muestra como un enlace que en realidad es visible en el sistema operativo. Antes de realizar el cambio sugerido, obtenía el nombre no localizado para estas carpetas y el nombre localizado para los accesos directos. No quiero mostrar los accesos directos ya que hacen que la lista sea repetitiva. – Scotti

+0

simplemente filtra los archivos .lnk –

+0

obtengo '敄 歳 敄 p 敄' p' para 'Environment.SpecialFolder.Desktop' con culture' de-DE' (alemania). ¿Por qué? –

2

lo hice encontrar la manera de conseguir que esto funcione. No estoy seguro de lo que está mal con el código anterior (también obtuve caracteres chinos Unicode), pero parece que funciona de manera confiable. Sólo tiene que pasar en el camino (por ejemplo, llamando a:

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

y devuelve el nombre de visualización de la carpeta (en este ejemplo, "Mis documentos" o lo que sea que haya cambiado el nombre 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

Esto funciona en comparación con la otra solución que ofrece algunos caracteres chinos. – whywhywhy

0

Usted tiene que asegurarse de que CharSet se establece en Unicode para el DllImport y la StructLayout.

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