0

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?

Basic
  • 26,321
  • 24
  • 115
  • 201
  • One edge case is domains. GPOs can remap the `Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)` folder on a per user basis so all of the users may not reside in the same folder (think multiple NAS storages). – Scott Chamberlain May 27 '14 at 20:38
  • 1
    Out of curiosity, how will your program use the "previously-installed dependency"? – Conrad Frix May 27 '14 at 20:48
  • @ConradFrix If an external elasticsearch (Java) service is not available, I launch once locally. The service itself is bundled with my app so the dependency is java (I search if the `JAVA_HOME` variable is not set and offer a list to the user). I've found a number of machines with a JRE installed but no environment variable. – Basic May 27 '14 at 21:37
  • Ah. Well you might want to take a look at [How to determine Windows Java installation location](http://stackoverflow.com/q/3038140) – Conrad Frix May 27 '14 at 21:46
  • @ConradFrix Thanks for the tip, I'll factor that info in to take an intelligent guess/default. Depressingly, when I scanned my dev machine, I've got 10 different java installations (JDK/JRE 6/7, a number of other apps seem to install their own). – Basic May 27 '14 at 21:56

1 Answers1

3

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
         );
}
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431