The task was harder than expected :-)
First of all, you need to use P / Invoke, there is no built-in .NET path. For example, you can use the SHGetKnownFolderPath
function with a suitable KNOWNFOLDERID
. It connects like this .
You will need 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); } } }
The KnownFolder
class KnownFolder
see here , the part you are interested in is:
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 you can override SHGetKnownFolderPath
so that you do not 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 am not 100% sure that interop is always full of surprises.