c# – How in feng shui to get the path to AppData for a user different from the current one?

Question:

There is a great method to get the path to the AppData folder of the current user:

string applicationDataPath = Environment.GetFolderPath(
    Environment.SpecialFolder.ApplicationData);

The good thing about the method is that it does not depend on the real location of the user's folder, OS version, and the like.

Actually, I would like to see a way to get the path to AppData not only for the current user, but for anyone, if I have a login string for this user.

Answer:

The task turned out to be more difficult than expected 🙂

First, you need to use P / Invoke, there is no way built into .NET. For example,you can use the SHGetKnownFolderPath function with an appropriate KNOWNFOLDERID . It connects like this .

You will need an AccessToken , which can be obtained using the LogonUser function as described in the example here :

public class FolderDemo
{
    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername,
        String lpszDomain, String lpszPassword,
        int dwLogonType, int dwLogonProvider, out IntPtr phToken);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

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

    // If you incorporate this code into a DLL, be sure to demand FullTrust.
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public static void Main(string[] args)
    {
        // Get the user token for the specified user, domain, and password
        // using the unmanaged LogonUser method. 
        // The local machine name can be used for the domain name to
        // impersonate a user on this machine.
        string domainName = ...;    
        string userName = ...;
        string userPassword = ...;

        const int LOGON32_PROVIDER_DEFAULT = 0;
        //This parameter causes LogonUser to create a primary token. 
        const int LOGON32_LOGON_INTERACTIVE = 2;

        IntPtr handle;

        // Call LogonUser to obtain a handle to an access token. 
        bool returnValue = LogonUser(userName, domainName, userPassword,
            LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
            out handle);

        if (!returnValue)
            return;

        try
        {
            // судя по всему, можно объявить SHGetKnownFolderPath
            // поинтеллектуальнее, чтобы не понадобилось маршалирование вручную
            IntPtr pPath;
            if (SHGetKnownFolderPath(KnownFolder.LocalAppData, 0, handle,
                                     out pPath) == 0)
            {
                string path = Marshal.PtrToStringUni(pPath);
                Marshal.FreeCoTaskMem(pPath);
                // тут строку можно использовать
            }
        }
        finally
        {
            // обязательно! а то останемся с правами другого юзера
            CloseHandle(handle);
        }
    }
}

See the KnownFolder class here , the part you're interested in is this:

public static class KnownFolder
{
    public static readonly Guid LocalAppData =
            new Guid("F1B32785-6FBA-4FCF-9D55-7B8E7F157091");
    public static readonly Guid LocalAppDataLow =
            new Guid("A520A1A4-1780-4FF6-BD18-167343C5AF16");
    public static readonly Guid RoamingAppData =
            new Guid("3EB685DB-65F9-4CF6-A03A-E3EF65729F3D");
    // ...
}

It seems it is possible to override SHGetKnownFolderPath so as not to manually call FreeCoTaskMem :

[DllImport("shell32.dll")]
public static extern int SHGetKnownFolderPath(
    [MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags,
    IntPtr hToken, out String path);

...

string path;
if (SHGetKnownFolderPath(KnownFolder.LocalAppData, 0, handle,
                                     out path) == 0)
{
    // тут строку можно использовать
}    

But I'm not 100% sure, interop is always full of surprises.

Scroll to Top