Aprende a obtener correctamente la ruta del directorio de descargas con C# en WinForms.

Para obtener la ruta del directorio de descargas en C# correctamente, algunos desarrolladores podrían usar una ruta fija en una cadena de texto, "C:\Users\username\Downloads" especialmente cuando la aplicación es privada. Sin embargo, si planeas lanzar tu aplicación públicamente, es muy probable que algunos usuarios usen un directorio diferente para la ruta de Descargas.

Sorprendentemente, la ruta del directorio de descargas no se puede obtener mediante el método EnvironmentFolders.GetPath y la enumeración de Environment.SpecialFolders. ¿Entonces que debemos hacer ahora? Usaremos la función  SHGetKnownFolderPath disponible en las características del entorno de Windows Legacy (encabezado shlobj_core.h). Este método te permite recuperar la ruta completa de una carpeta conocida identificada por el KNOWNFOLDERID de la carpeta. La constante KNOWNFOLDERID representa un GUID que identifica una carpeta estándar registrada en el sistema como Carpetas conocidas. Estas carpetas se instalan con Windows Vista y sistemas operativos posteriores, y una computadora solo tendrá instaladas las carpetas correspondientes.

En nuestro caso, la ruta de la carpeta de Descargas es la que estamos intentando obtener y el KNOWNFOLDERID de la carpeta de Descargas es 374DE290-123F-4565-9164-39C4925E467B. Teniendo eso, podemos proceder con la implementación para obtener la ruta de Descargas.

El siguiente fragmento de código debería funcionar bastante bien para lo que necesitas:

// 1. Importar InteropServices
using System.Runtime.InteropServices;

/// 2. Declarar DownloadsFolder KNOWNFOLDERID
private static Guid FolderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");

/// 3. Importar método SHGetKnownFolderPath
/// <summary>
/// Recupera la ruta completa de una carpeta conocida identificada por el KnownFolderID de la carpeta.
/// </summary>
/// <param name="id">Un KnownFolderID que identifica la carpeta.</param>
/// <param name="flags">Banderas que especifican opciones especiales de recuperación. Este valor puede ser
///     0; de lo contrario, uno o más valores de KnownFolderFlag.</param>
/// <param name="token">Un token de acceso que representa a un usuario en particular. Si esto
///     parámetro es NULL, que es el uso más común, la función solicita la carpeta conocida
///     para el usuario actual. Asignar un valor de -1 indica el usuario predeterminado.
///     El perfil de usuario predeterminado se duplica cuando se crea una nueva cuenta de usuario.
///     Ten en cuenta que el acceso a las carpetas de Usuario predeterminado requiere privilegios de administrador.
///     </param>
/// <param name="path">Cuando este método regresa, contiene la dirección de una cadena que
/// especifica la ruta de la carpeta conocida. La ruta devuelta no incluye un
/// barra invertida al final.</param>
/// <returns>Returns S_OK if successful, or an error value otherwise.</returns>
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int SHGetKnownFolderPath(ref Guid id, int flags, IntPtr token, out IntPtr path);

/// 4. Método de declaración que devuelve la ruta de descargas como cadena
/// <summary>
/// Devuelve el directorio de descargas absoluto especificado en el sistema.
/// </summary>
/// <returns></returns>
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);
    }
}


/// 5. Mostrar el directorio de descargas en la consola
// imprime algo como: C:\Users\username\Downloads
Console.WriteLine(GetDownloadsPath());

Ejemplo en formulario

El siguiente ejemplo completo debería ayudarte a comprender el contexto de dónde debes posicionar cada línea de código en tu propio proyecto:

using System;
using System.Windows.Forms;

// 1. Importar InteropServices
using System.Runtime.InteropServices;

namespace Sandbox
{
    public partial class Form1 : Form
    {

        /// 2. Declara la GUI de DownloadsFolder e importe el método SHGetKnownFolderPath
        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);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 3. Cuando se cargue el formulario, muestre el directorio de Descargas a través de un cuadro de mensaje
            // imprime algo como: C:\Users\username\Downloads
            MessageBox.Show(GetDownloadsPath());
        }

        /// <summary>
        /// Devuelve el directorio de descargas absoluto especificado en el sistema.
        /// </summary>
        /// <returns></returns>
        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);
            }
        }
    }
}

Que te diviertas ❤️!


Ingeniero de Software Senior en EPAM Anywhere. Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores