如何以编程方式派生Windows下载文件夹"%USERPROFILE%/ Downloads"?

Mui*_*uis 23 .net registry environment-variables special-folders registrykey

在.Net中,我们可以检索"特殊文件夹"的路径,例如Documents/Desktop等.今天我试图找到一种方法来获取"下载"文件夹的路径,但它看起来并不特别.

我知道我可以做'C:\ Users\Username\Downloads',但这似乎是一个丑陋的解决方案.那么如何使用.Net来修复路径呢?

Han*_*ant 23

是的,它很特别,发现这个文件夹的名称直到Vista才成为可能..NET仍然需要支持以前的操作系统.你可以调用SHGetKnownFolderPath()来绕过这个限制,如下所示:

using System.Runtime.InteropServices;
...

public static string GetDownloadsPath() {
    if (Environment.OSVersion.Version.Major < 6) throw new NotSupportedException();
    IntPtr pathPtr = IntPtr.Zero;
    try {
        SHGetKnownFolderPath(ref FolderDownloads, 0, IntPtr.Zero, out pathPtr);
        return Marshal.PtrToStringUni(pathPtr);
    }
    finally {
        Marshal.FreeCoTaskMem(pathPtr);
    }
}

private static Guid FolderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int SHGetKnownFolderPath(ref Guid id, int flags, IntPtr token, out IntPtr path);
Run Code Online (Sandbox Code Playgroud)

  • @Kiquenet:“Environment.SpecialFolder”不涵盖_所有_已知文件夹(请参阅https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder?view=netframework-4.8),并且_Downloads_ 文件夹是一个值得注意的遗漏。 (4认同)

Jen*_*eaf 4

您的第一个答案的问题是,如果默认下载目录已更改为 [Download1],它会给您错误的结果!涵盖所有可能性的正确方法是

using System;
using System.Runtime.InteropServices;

static class cGetEnvVars_WinExp    {
    [DllImport("Shell32.dll")] private static extern int SHGetKnownFolderPath(
        [MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags, IntPtr hToken,
        out IntPtr ppszPath);

    [Flags] public enum KnownFolderFlags : uint { SimpleIDList = 0x00000100
        , NotParentRelative = 0x00000200, DefaultPath = 0x00000400, Init = 0x00000800
        , NoAlias = 0x00001000, DontUnexpand = 0x00002000, DontVerify = 0x00004000
        , Create = 0x00008000,NoAppcontainerRedirection = 0x00010000, AliasOnly = 0x80000000
    }
    public static string GetPath(string RegStrName, KnownFolderFlags flags, bool defaultUser) {
        IntPtr outPath;
        int result = 
            SHGetKnownFolderPath (
                new Guid(RegStrName), (uint)flags, new IntPtr(defaultUser ? -1 : 0), out outPath
            );
        if (result >= 0)            {
            return Marshal.PtrToStringUni(outPath);
        } else {
            throw new ExternalException("Unable to retrieve the known folder path. It may not "
                + "be available on this system.", result);
        }
    }

}   
Run Code Online (Sandbox Code Playgroud)

要测试它,如果您特别需要个人下载目录,请将默认值标记为 false -->

using System.IO;

class Program    {
    [STAThread]
    static void Main(string[] args)        {
        string path2Downloads = string.Empty;
        path2Downloads = 
            cGetEnvVars_WinExp.GetPath("{374DE290-123F-4565-9164-39C4925E467B}", cGetEnvVars_WinExp.KnownFolderFlags.DontVerify, false);
        string[] files = { "" };
        if (Directory.Exists(path2Downloads)) {
            files = Directory.GetFiles(path2Downloads);
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 您的第一个使用“SHGetKnownFolderPath”的示例将泄漏内存。“SHGetKnownFolderPath”的文档表示调用者必须使用“CoTaskMemFree”释放“ppszPath”值。`,而 `Marshal.PtrToStringUni` 的文档表示它不会释放传递给它的字符串。 (3认同)