Patrick Skelton Ответов: 2

Почему environment.specialfolder.mydocuments возвращает неверное значение?


У меня есть приложение WPF/.NET4.5.2, разработанное на компьютере с Windows 10, но развернутое на компьютере с Windows 7.

На моей машине разработки...

Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments )

...правильно возвращает "C:/Users/<имя пользователя>/документы".

Когда я запускаю этот же код на целевой машине Windows 7, я получаю ту же самую папку, но на машине Windows 7 эта папка называется "C:/Users/<имя пользователя>/Мои Документы", так что мой код не может найти папку.

Что я уже пробовал:

Я нашел несколько статей об этом в сети. Во многих статьях автор объясняет, почему это неправильный способ сделать это (например, очевидно, что доступ к реестру не всегда будет работать по причинам, которые я мог бы понять, если бы у меня было еще меньше волос).

Единственная статья, которую я нашел, которая, кажется, имеет убедительный способ сделать это, это Получение всех "специальных папок" в .NET[^] , но это кажется очень сложным для такого общего требования.

Я не могу избавиться от ощущения, что здесь мне не хватает какого-то простого знания. Кто-нибудь знает, что здесь может быть не так?

Richard MacCutchan

Вы хотите сказать, что в Windows 7 Вы получаете строку "C:/Users/<username>/Documents", который не является фактическим именем?

Patrick Skelton

Это верно, да. Фактическая папка-это "Мои документы", тогда как в моем коде я получаю обратно только "документы". Как ни странно, если я запрошу каталог профиля пользователя, а затем вручную добавлю "\Documents "в свой код, я все равно не смогу получить доступ ни к чему в "C:\Users\<имя пользователя>\Documents'. Однако мне нужно провести больше тестов вокруг этого. Это был последний результат, который я получил вчера вечером, прежде чем мне пришлось быстро выйти из целевой машины.

Richard MacCutchan

Я использовал этот механизм и не имел с ним проблем. К сожалению, у меня больше нет системы Win 7, поэтому я не могу повторно протестировать ее.

Richard MacCutchan

На самом деле, теперь, когда я думаю об этом, у меня есть чувство, что это правильно. Фактическая папка-это "документы", а "Мои Документы" - это ссылка.

CHill60

Это и мое воспоминание тоже

Patrick Skelton

Спасибо за ответ, Ричард.

Если 'C:\Users\<имя пользователя> в\Мои Документы' представляет собой ссылку на существующий физический каталог C:\Users\<имя пользователя&ГТ;\документы-тогда не мой код сможет использовать реальный физический путь (т. е. 'C:\Users\<имя пользователя&ГТ;\документы') получить доступ к этой папке? Другими словами, Почему мой код вообще не работает?

Richard MacCutchan

Не видя вашего кода, я понятия не имею.

Patrick Skelton

Справедливое замечание. Я не могу попасть в целевую систему прямо сейчас. В следующий раз я постараюсь написать небольшой фрагмент кода, чтобы проиллюстрировать неудачу. Я добавлю его к своему вопросу в разделе "Что я пробовал".

2 Ответов

Рейтинг:
2

Graeme_Grant

В дополнение к сообщению Maciej Los, путь к документу не только варьируется в разных операционных системах Windows, если пользователь использует виртуальную машину (VM) на внешней ОС, путь к папке документов может быть базовым путем ОС, а не путем к папке документов ОС Windows. Если вы попытаетесь получить доступ к пути вне виртуальной машины, то возникнет исключение.

Ниже приведено решение, которое устранит эту проблему.

Детали машины посу -:

public class VirtualMachineDetails
{
    public string Manufacturer { get; set; }
    public string Model { get; set; }
    public bool IsVirtual
    {
        get
        {
            return IsParallels || IsVirtualBox || IsVmWare || IsVirtualPc;
        }
    }
    public bool IsParallels { get; internal set; }
    public bool IsVmWare { get; set; }
    public bool IsVirtualBox { get; set; }
    public bool IsVirtualPc { get; set; }
    public string DocumentsPath { get; set; }
}

Методы расширения для заполнения информации:
using System;
using System.IO;
using System.Management;

public static class VirtualMachineDetailsExtensions
{
    public static void Init(this VirtualMachineDetails host)
    {
        using (var searcher =
            new ManagementObjectSearcher("Select * from Win32_ComputerSystem"))
        {
            using (var items = searcher.Get())
            {
                foreach (var item in items)
                {
                    host.Manufacturer = item["Manufacturer"].ToString();
                    host.Model = item["Model"].ToString();

                    string manufacturer = host.Manufacturer.ToLower();
                    string model = host.Model.ToLower();

                    host.IsVirtualPc = 
                        manufacturer == "microsoft corporation" &&
                                        model.Contains("virtual");
                    host.IsParallels = manufacturer.Contains("parallels");
                    host.IsVmWare = manufacturer.Contains("vmware");
                    host.IsVirtualBox = model == "virtualbox";
                }
            }
        }
        host.DocumentsPath = host.FixDocPath();
    }

    private static string FixDocPath(this VirtualMachineDetails host)
    {
        string pathSeperator = @"\";

        string path = Environment.GetFolderPath(
                       Environment.SpecialFolder.MyDocuments);

        string userPath = Environment.GetFolderPath(
                           Environment.SpecialFolder.UserProfile);

        var fixPath = new Func<string, string, string>((p, u) => (p.Contains(u)) ? 
                p : 
                Path.Combine(u, p.Substring(p.LastIndexOf(pathSeperator))));

        if (host.IsVirtual)
        {
            string parallelsPath = @"\\Mac\Home";
            string vmWarePath = @"\\vmware-host\Shared Folders";

            if (host.IsParallels)
            {
                if (path.Contains(parallelsPath))
                    path = path.Replace(parallelsPath, userPath);
                else
                    fixPath(path, userPath);
            }

            else if (host.IsVmWare)
            {
                if (path.Contains(vmWarePath))
                    path = path.Replace(vmWarePath, userPath);
                else
                    fixPath(path, userPath);
            }

            else
                fixPath(path, userPath);
        }

        return path;
    }
}

Использовать:
var vm = new VirtualMachineDetails();

vm.Init();

var documentsPath = vm.DocumentsPath;


Maciej Los

5ed!

Graeme_Grant

Спасибо... У меня есть довольно много пользователей Mac с виртуальными машинами... В то время это была забавная задача для решения... Xamarin значительно уменьшил эту проблему с помощью native app dev, однако я все еще вижу пользователей с виртуальными машинами...

Рейтинг:
12

Maciej Los

Пожалуйста, обратитесь к этому: Папку "Документы" Мои Документы против [^Там вы найдете краткое объяснение различий между ними. documents и my documents папки.

Как говорится в документации MSDN:

Цитата:
То GetFolderPath метод возвращает местоположения, связанные с этим перечислением. Расположение объектов эти папки могут иметь разные значения в разных операционных системах, пользователь может изменить некоторые из местоположений, и эти местоположения будут локализованы.

Дополнительные сведения о специальных папках см. В разделе KNOWNFOLDERID константы в документации Windows.


Вывод: чтобы получить правильную папку (documents вместо my documents) вы должны использовать SHGetKnownFolderPath функция API. Реализацию вы найдете здесь: VBnet� Ресурсный Центр Разработчиков Visual Basic[^]

Наконец я бы настоятельно рекомендовал прочитать этот совет: Где я должен хранить свои данные?[^]


Graeme_Grant

5 б... Кроме того, кое-что нужно знать... Если ваше приложение работает в Windows, но на виртуальной машине на MacOS или Linux, то папка, возвращаемая Environment.GetFolderPath может быть недействительным.

Maciej Los

Спасибо, Грэм.