2011-02-28 14 views
6

Piszę funkcję w języku C#, gdzie jestem wymagane, aby wyświetlić wszystkie pliki/nazwy folderów w danym katalogu. Funkcjonalność działa dobrze na systemie EN OS, ale kiedy uruchamiam aplikację w zlokalizowanym systemie operacyjnym (na przykład) po niemiecku, nadal otrzymuję angielskie nazwy folderów specjalnych (pliki programów zamiast programu, ulubione zamiast ulubionych). Nie sądzę, że Environment.GetFolderPath z Environment.SpecialFolder może być pomocne, ponieważ ma dokładnie odwrotną wartość, co chcę, tzn. Podaje pełną ścieżkę do folderu specjalnego, a ja chcę zlokalizowaną nazwę danego ścieżka. Próbowałem używać File, SHFileInfo, ale bezużyteczne. Jakikolwiek pomysł, jak mogę uzyskać nazwy folderów wyświetlane w systemie operacyjnym?Jak uzyskać rzeczywiste (zlokalizowane) nazwy folderów?

+0

myślę, że u trzeba ustawić swoje lokum w kodzie ... –

+0

powiedziałbym, że angielska nazwa jest rzeczywista nazwa (potrzebujesz jej aby uzyskać dostęp do pliku), a niemiecka nazwa to tylko wyświetlana nazwa. – CodesInChaos

Odpowiedz

10

można uzyskać zlokalizowaną nazwę wyświetlaną z 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

dokładnie tego, czego szukałem. Dzięki. Mam jednak jeszcze jeden problem (nie regresję tego kodu, ale wcześniej istniejący). Podczas wyświetlania plików, teraz otrzymuję dwa pliki programu w języku niemieckim. Jednym z nich jest Folder, a inny pokazuje się jako łącze, które faktycznie jest widoczne w systemie operacyjnym. Przed wprowadzeniem sugerowanej zmiany otrzymywałem nie zlokalizowaną nazwę tych folderów i zlokalizowaną nazwę skrótów. Nie chcę pokazywać skrótów, ponieważ powodują, że lista jest powtarzalna. – Scotti

+0

po prostu odfiltruj pliki .lnk. –

+0

Otrzymuję '敄 歳 潴 p 敄 歳 潴 p' dla' Environment.SpecialFolder.Desktop' z kulturą 'de-DE' (niem.). Czemu? –

2

zrobiłem dowiedzieć się, jak uzyskać to do pracy. Nie jestem pewien, co jest nie tak z powyższym kodem (mam również chińskie znaki Unicode), ale wydaje się, że działa niezawodnie. Wystarczy przejść się na ścieżce (na przykład poprzez wywołanie:

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

i zwraca wyświetlaną nazwę folderu (w tym przykładzie „My Documents” lub cokolwiek masz przemianowano go)

.
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

Działa to w porównaniu do innego rozwiązania, które daje niektóre znaki chińskie. – whywhywhy

0

Musisz upewnić się, że jest ustawiony do CharSet Unicode dla dllimport i StructLayout.

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