mackenir
mackenir

Reputation: 10959

How do I determine the Windows 'Download folder' path?

On my machine, it's here:

string downloadsPath = Path.Combine(
   Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
   "Downloads");

But on a colleagues machine, this folder doesnt exist, and his Downloads folder is in his 'My Documents' folder. We are both on Windows 7*.

*Edit: in fact, it turns out he was not running the app on his own machine but a Windows Server 2003 machine.

Upvotes: 28

Views: 44868

Answers (3)

Pavel Tsimokhautsau
Pavel Tsimokhautsau

Reputation: 141

You can use the Windows API Code Pack for Microsoft .NET Framework.

Reference: Microsoft.WindowsAPICodePack.Shell.dll

Need the following namespace:

using Microsoft.WindowsAPICodePack.Shell;

Simple usage:

string downloadsPath = KnownFolders.Downloads.Path;

Upvotes: 14

schlebe
schlebe

Reputation: 3716

The VB.Net function that I use is following

<DllImport("shell32.dll")>
Private Function SHGetKnownFolderPath _
    (<MarshalAs(UnmanagedType.LPStruct)> ByVal rfid As Guid _
    , ByVal dwFlags As UInt32 _
    , ByVal hToken As IntPtr _
    , ByRef pszPath As IntPtr
    ) As Int32
End Function

Public Function GetDownloadsFolder() As String

    Dim Result As String = ""
    Dim ppszPath As IntPtr
    Dim gGuid As Guid = New Guid("{374DE290-123F-4565-9164-39C4925E467B}")

    If SHGetKnownFolderPath(gGuid, 0, 0, ppszPath) = 0 Then
        Result = Marshal.PtrToStringUni(ppszPath)
        Marshal.FreeCoTaskMem(ppszPath)
    End If
    
   'as recommended by Ray (see comments below) 
    Marshal.FreeCoTaskMem(ppszPath)

    Return Result
End Function

In my program, I call it to move some CSV files in another folder.

    Dim sDownloadFolder = GetDownloadsFolder()
    Dim di = New DirectoryInfo(sDownloadFolder)

    'Move all CSV files that begin with BE in specific folder
    'that has been defined in a CONFIG file (variable: sExtractPath

    For Each fi As FileInfo In di.GetFiles("BE*.csv")
        Dim sFilename = sExtractPath & "\" & fi.Name
        File.Move(fi.FullName, sFilename)
    Next

Upvotes: 0

David Heffernan
David Heffernan

Reputation: 612814

Windows does not define a CSIDL for the Downloads folder and it is not available through the Environment.SpecialFolder enumeration.

However, the new Vista Known Folder API does define it with the ID of FOLDERID_Downloads. Probably the easiest way to obtain the actual value is to P/invoke SHGetKnownFolderPath.

public static class KnownFolder
{
    public static readonly Guid Downloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
}

[DllImport("shell32.dll", CharSet=CharSet.Unicode)]
static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out string pszPath);

static void Main(string[] args)
{
    string downloads;
    SHGetKnownFolderPath(KnownFolder.Downloads, 0, IntPtr.Zero, out downloads);
    Console.WriteLine(downloads);
}

Note that the P/invoke given on pinvoke.net is incorrect since it fails to use Unicode character set. Also I have taken advantage of the fact that this API returns memory allocated by the COM allocator. The default marshalling of the P/invoke above is to free the returned memory with CoTaskMemFree which is perfect for our needs.

Be careful that this is a Vista and up API and do not attempt to call it on XP/2003 or lower.

Upvotes: 30

Related Questions