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?
Odpowiedz
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; }
}
}
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
po prostu odfiltruj pliki .lnk. –
Otrzymuję '敄 歳 潴 p 敄 歳 潴 p' dla' Environment.SpecialFolder.Desktop' z kulturą 'de-DE' (niem.). Czemu? –
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;
}
Działa to w porównaniu do innego rozwiązania, które daje niektóre znaki chińskie. – whywhywhy
Musisz upewnić się, że jest ustawiony do CharSet Unicode dla dllimport i StructLayout.
[DllImport("shell32", CharSet = CharSet.Unicode)]
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
myślę, że u trzeba ustawić swoje lokum w kodzie ... –
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