WinAPI方法SHGetKnownFolderPath是检索特殊文件夹(包括个人文件夹和下载文件夹)路径的唯一正确方法。
还有其他方法可以获得相似的结果,这些结果看起来很有希望,但最终只能在特定系统上出现完全错误的路径(例如,对路径的一部分进行合并或硬编码或滥用旧的注册表项)。其背后的原因在我的CodeProject文章中进行了说明,该文章还列出了完整的解决方案。它提供了一个包装类,以支持检索所有已知的94个特殊文件夹以及其他一些好东西。
作为此处的一个简单示例,我只是粘贴了该解决方案的简化版本,使其只能检索个人专用文件夹,例如下载:
using System;using System.Runtime.InteropServices;/// <summary>/// Class containing methods to retrieve specific file system paths./// </summary>public static class KnownFolders{ private static string[] _knownFolderGuids = new string[] { "{56784854-C6CB-462B-8169-88E350ACB882}", // Contacts "{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}", // Desktop "{FDD39AD0-238F-46AF-ADB4-6C85480369C7}", // documents "{374DE290-123F-4565-9164-39C4925E467B}", // Downloads "{1777F761-68AD-4D8A-87BD-30B759FA33DD}", // Favorites "{BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968}", // links "{4BD8D571-6D19-48D3-BE97-422220080E43}", // Music "{33E28130-4E1E-4676-835A-98395C3BC3BB}", // Pictures "{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}", // SavedGames "{7D1D3A04-DEBB-4115-95CF-2F29DA2920DA}", // SavedSearches "{18989B1D-99B5-455B-841C-AB7C74E4DDFC}", // Videos }; /// <summary> /// Gets the current path to the specified known folder as currently configured. This does /// not require the folder to be existent. /// </summary> /// <param name="knownFolder">The known folder which current path will be returned.</param> /// <returns>The default path of the known folder.</returns> /// <exception cref="System.Runtime.InteropServices.ExternalException">Thrown if the path /// could not be retrieved.</exception> public static string GetPath(KnownFolder knownFolder) { return GetPath(knownFolder, false); } /// <summary> /// Gets the current path to the specified known folder as currently configured. This does /// not require the folder to be existent. /// </summary> /// <param name="knownFolder">The known folder which current path will be returned.</param> /// <param name="defaultUser">Specifies if the paths of the default user (user profile /// template) will be used. This requires administrative rights.</param> /// <returns>The default path of the known folder.</returns> /// <exception cref="System.Runtime.InteropServices.ExternalException">Thrown if the path /// could not be retrieved.</exception> public static string GetPath(KnownFolder knownFolder, bool defaultUser) { return GetPath(knownFolder, KnownFolderFlags.DontVerify, defaultUser); } private static string GetPath(KnownFolder knownFolder, KnownFolderFlags flags, bool defaultUser) { int result = SHGetKnownFolderPath(new Guid(_knownFolderGuids[(int)knownFolder]), (uint)flags, new IntPtr(defaultUser ? -1 : 0), out IntPtr outPath); if (result >= 0) { string path = Marshal.PtrToStringUni(outPath); Marshal.FreeCoTaskMem(outPath); return path; } else { throw new ExternalException("Unable to retrieve the known folder path. It may not " + "be available on this system.", result); } } [Dllimport("Shell32.dll")] private static extern int SHGetKnownFolderPath( [MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath); [Flags] private enum KnownFolderFlags : uint { SimpleIDList = 0x00000100, NotParentRelative = 0x00000200, DefaultPath = 0x00000400, Init= 0x00000800, NoAlias = 0x00001000, DontUnexpand = 0x00002000, DontVerify = 0x00004000, Create = 0x00008000, NoAppcontainerRedirection = 0x00010000, Aliasonly = 0x80000000 }}/// <summary>/// Standard folders registered with the system. These folders are installed with Windows Vista/// and later operating systems, and a computer will have only folders appropriate to it/// installed./// </summary>public enum KnownFolder{ Contacts, Desktop, documents, Downloads, Favorites, links, Music, Pictures, SavedGames, SavedSearches, Videos}(在上面链接的CodeProject文章中找到了完整注释的版本。)
尽管这只是一堆令人讨厌的代码,但您必须处理的表面非常简单。这是一个控制台程序示例,它输出Downloads文件夹的路径。
private static void Main(){ string downloadsPath = KnownFolders.GetPath(KnownFolder.Downloads); Console.WriteLine("Downloads folder path: " + downloadsPath); Console.ReadLine();}例如,只需KnownFolders.GetPath()使用KnownFolder文件夹的枚举值调用要查询的路径即可。
NuGet软件包
如果您不想经历所有麻烦,只需安装我最近创建的NuGet软件包。这是项目站点,这是图库链接(请注意用法不同且经过修饰,请查阅项目站点上的“用法”部分以获取更多信息)。
PM> Install-Package Syroot.Windows.IO.KnownFolders
用法:
using System;using Syroot.Windows.IO;class Program{ static void Main(string[] args) { string downloadsPath = new KnownFolder(KnownFolderType.Downloads).Path; Console.WriteLine("Downloads folder path: " + downloadsPath); Console.ReadLine(); }}


