Search code examples
.netuser-profilespecial-folders

Locate the Users' path


I've got a program which looks for a previously-installed dependency. Unfortunately, it can be installed almost anywhere (including Program files or nested 6-7 levels deep in an arbitrary folder on C:/) with a couple of exceptions...

It should never be in the Windows or Users directories. Since these are usually quite large (and I've got no need to crawl user paths), I'd like to exclude them from the scan.

I know I can use Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) to get the path to the current user profile but is there a generic way to get the root users folder (C:\Users on my machine)?

My working plan is to get the current user profile's parent folder but I'm unsure if there will be edge cases where this won't always give the correct result?


Solution

  • There is nothing in .NET that can do it (to my knowledge). However if you are targeting Vista or newer you can do it through a P/Invoke to SHGetKnownFolderPath

    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.WriteLine(GetFolderOfUsers());
            Console.ReadLine();
        }
    
        private static string GetFolderOfUsers()
        {
            if (Environment.OSVersion.Version.Major >= 6)
            {
                IntPtr pPath;
                var code = SHGetKnownFolderPath(new Guid("0762D272-C50A-4BB0-A382-697DCD729B80"), //Guid of FOLDERID_UserProfiles, defaults to %SystemDrive%\Users
                                                0, IntPtr.Zero, out pPath);
                string s = System.Runtime.InteropServices.Marshal.PtrToStringUni(pPath);
                System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath);
                return s;
            }
            else
            {
                throw new NotSupportedException("You must be using Vista or newer");
            }
        }
    
        [DllImport("shell32.dll")]
        static extern int SHGetKnownFolderPath(
             [MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
             uint dwFlags,
             IntPtr hToken,
             out IntPtr pszPath  // API uses CoTaskMemAlloc
             );
    }