Страницы

Поиск по вопросам

пятница, 29 ноября 2019 г.

Как по фэн-шую получить путь к AppData для пользователя отличного от текущего?

#c_sharp #windows #.net


Существует замечательный метод достать путь к папке AppData текущего пользователя:
string applicationDataPath = Environment.GetFolderPath(
    Environment.SpecialFolder.ApplicationData);

Метод хорош тем, что не зависит от реального расположения папки пользователя, версии
ОС и тому подобного.
Собственно, хотелось бы увидеть способ достать путь к AppData не только для текущего
пользователя, но для любого, если у меня есть строка логина этого пользователя.    


Ответы

Ответ 1



Задача оказалась сложнее, чем предполагалось :-) Для начала, вам нужно воспользоваться P/Invoke, встроенного в .NET пути нет. Например, вы можете воспользоваться функцией SHGetKnownFolderPath с подходящим KNOWNFOLDERID. Подключается она вот так. Вам понадобится AccessToken, который можно получить при помощи функции LogonUser как описано в примере тут: 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); } } } Класс KnownFolder смотрите тут, интересующая вас часть такая: 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"); // ... } Кажется, можно переопределить SHGetKnownFolderPath так, чтобы не вызывать вручную 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) { // тут строку можно использовать } Но я не уверен на 100%, interop всегда полон неожиданностей.

Комментариев нет:

Отправить комментарий