0

When hardcoding a filepath, how do I account for different user profiles? For example, below I am using Directory.CreateDirectory to create a series of folders/sub-folders the user will proceed to move files to:

    Private Sub btnCreateFolders_Click(sender As Object, e As EventArgs) Handles btnCreateFolders.Click
        Directory.CreateDirectory("C:\Users\USERNAME\Downloads\\TEST\\SUB TEST")
    End Sub

However, "USERNAME" will be a variable according to the user utilizing the tool.

RockiesSkier
  • 105
  • 1
  • 8
  • See the [Environment.SpecialFolder](https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder) enumerator. The `Downloads` *special* folder is not among these, though. If you need specifically that Directory path, you *could* read the path provided by `Environment.SpecialFolder.UserProfile` and go from there, but you probably need [something like this](https://stackoverflow.com/a/21953690/7444103). Or read it from the Registry (see other answers there). – Jimi Feb 04 '20 at 22:12
  • 1
    I'm guessing he wants a new folder in `Environment.SpecialFolder.MyDocuments`; `Downloads` is a pretty peculiar place to put folders “the user will proceed to move files to”. – Dour High Arch Feb 04 '20 at 22:15

3 Answers3

2

One important thing to understand is users can and do redirect their downloads folder to weird locations. It's not a good idea at all to assume C:\Users\USERNAME\Downloads is correct. On my own system, for instance, I have a smallish SSD and a much larger traditional HDD. I prefer my downloads to end up on the HDD, well away from the rest of my profile.

Most of these folders can be had easily using Environment.GetFolderPath() method. For example, the documents folder is here:

Dim documents As String = Environment.GetFolderPath(SpecialFolder.MyDocuments)

Unfortunately, there's no SpecialFolder enum value for the Downloads folder. We have to work a little harder. I prefer this code-project solution:

<DllImport("shell32.dll")>
Private Shared 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 sResult 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
        sResult = Marshal.PtrToStringUni(ppszPath)
        Marshal.FreeCoTaskMem(ppszPath)
    End If
    Return sResult
End Function

It's really not that much code, and it does things the right way.

Paste the above as new methods in your existing class, add an Imports System.Runtime.InteropServices to the top of the file, and you can update the code in the question like this:

Private Sub btnCreateFolders_Click(sender As Object, e As EventArgs) Handles btnCreateFolders.Click
    Dim SubTest As String = Path.Combine(GetDownloadsFolder(), "TEST\SUB TEST")
    Directory.CreateDirectory(SubTest)
End Sub

That said, I also agree with the comment saying Downloads is an unusual place for this. The documents path used above is much more common.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
0

Instead of hard-coding it, you can build it dynamically with GetEnvironmentVariable(). You should concatenate the HOMEDRIVE value and the HOMEPATH, and then add subfolders after that.

Environment.GetEnvironmentVariable("HOMEDRIVE") + Environment.GetEnvironmentVariable("HOMEPATH")

https://learn.microsoft.com/en-us/dotnet/api/system.environment.getenvironmentvariable?view=netframework-4.8

digital.aaron
  • 5,435
  • 2
  • 24
  • 43
0

Thanks all that answered and commented - I quickly abandoned the idea of using the Downloads folder underestimating the increased difficulty around it. For now I am just identifying the user's desktop, but between everything shared I arrived at (Folders 1, etc just as temp placeholders for now):

        Dim dir As String
        dir = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
        dir = Path.Combine(dir, "Folder 1\\Folder 2\\Folder 3\\Folder 4")
        If Not Directory.Exists(dir) Then
            Directory.CreateDirectory(dir)
        End If

https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder?view=netframework-4.8

https://learn.microsoft.com/en-us/dotnet/api/system.io.path.combine?view=netframework-4.8

RockiesSkier
  • 105
  • 1
  • 8
  • You don't need to escape the backslashes - that's a C# thing. That is, use \, not \\. – Andrew Morton Feb 05 '20 at 09:22
  • Use `Path.Combine(dir, "Folder 1", "Folder 2", "Folder 3", "Folder 4")`. The entire purpose of `Path.Combine` is to remove escaping or dependencies on path separators. – Dour High Arch Feb 05 '20 at 17:01