开发者

How to get the actual (localized) folder names? [duplicate]

开发者 https://www.devze.com 2023-02-14 10:34 出处:网络
This question already has answers here: Function for getting localized path? (2 answers) Closed 5 years ago.
This question already has answers here: Function for getting localized path? (2 answers) Closed 5 years ago.

I am writing a functionality in c# where I am required to list all the files/folder names in a given directory. The functionality runs fine on EN OS, but when I run the application on localized OS (for e.g.) German, I am still getting the English names of the Special Folders(Program Files instead of Programme, Favourites instead of Favorit开发者_运维知识库en etc.). I don't think that Environment.GetFolderPath with Environment.SpecialFolder can be of any help as it does the exactly opposite of what I want i.e it gives the Full Path of the Special Folder enumerated, whereas, I want the localized name of the given path. I have tried using File, SHFileInfo, but of no use. Any idea, how can i get the folder names as displayed in the OS?


You can get the localized display name with the 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; }
    }
}


I did figure out how to get this to work. Not sure what's wrong with the above code (I also got Chinese Unicode characters), but this seems to work reliably. Just pass in the path (for example, by calling:

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

and it returns the display name of the folder (in this example, "My Documents" or whatever you've renamed it to).

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;
}


You have to make sure that CharSet is set to UniCode for the DllImport and the StructLayout.

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

精彩评论

暂无评论...
验证码 换一张
取 消