понедельник, 1 декабря 2008 г.

Длинная и печальная история ключа Shell Folders

Это перевод The long and sad story of the Shell Folders key. Автор: Реймонд Чен.

Когда вы создаёте архитектуру операционной системы, обратная совместимость - это одна из тех вещей, которые вам при этом нужно просто принять. Но когда новые программы начинают зависеть от хаков, созданных для старых программ, вам захочется рвать на себе волосы.

Давным-давно, в какой-то, кажется, далёкой-предалёкой галактике (это я про Windows 95 бета-релиз под названием "M3"), мы документировали ключ реестра с именем "Shell Folders", который мог использоваться программами для получения специальных папок, типа папки "Шрифты" или "Мои документы".

Разработчики, получившие Windows 95 M3 Beta, следовали документации и использовали этот ключ.

Потом, при дальнейшей работе над Windows 95, мы собразили, что ключ реестра - неподходящее место для этой информации. В частности, потому что множество вещей (к примеру - Панель Управления) не являются реальными папками на диске, поэтому путь к ним нельзя записать в реестр. И ещё потому что мы забыли принять во внимание одну фишку Windows NT, называемую перемещаемые профили пользователя (roaming user profiles) - это когда профиль пользователя может перемещаться с места на место, поэтому жёстко зашитый в реестре путь тут совершенно не подойдёт.

Поэтому мы создали функцию SHGetSpecialFolderLocation, и обновили документацию, чтобы указать разработчикам на использование новой функции для получения специальных папок. Документация по старому ключу "Shell Folders" была полностью удалена.

Но чтобы упростить переход от M3 к RTM, мы оставили в реестре старый ключ "Shell Folders", но он больше не был хранилищем реальных данных. Это была просто копия настоящих данных, хранимых в совершенно другом месте.

Мы выпустили Windows 95 RTM с этим "временным" ключом, потому что ещё осталось небольшое количество программ (скажем, четыре), которые не успели сконвертироваться для использования новой функции SHGetSpecialFolderLocation. Но функциональность этого ключа была серьёзно ограничена и его только-только хватало, чтобы работали эти четыре программы. В конце концов, это был всего лиш хак для обратной совместимости. Все новые программы должны были использовать SHGetSpecialFolderLocation.

Другими словами, ключ реестра "Shell Folders" существует только затем, чтобы на RTM версии Windows 95 могли работать четыре программы, написанные в 1994-м году.

Вы можете угадать, что случилось дальше.

Вышла Windows 95 и все кругом захотели писать под неё программы. Но чтение документации - это же куча работы. Поэтому, когда вы хотите узнать какую-то информацию и не хотите читать документацию, то что вы делаете? Точно, вы ищете её в реестре! (звучит знакомо? Люди продолжают делать это даже сегодня).

И теперь у нас есть сотни, тысячи программ, которые не используют SHGetSpecialFolderLocation; они просто читают информацию из "Shell Folders" напрямую. Но они не понимают, что эта поддержка ключа "Shell Folders" была разработана только для поддержания работы тех четырёх программ.

Например, знали ли вы, что если вы ни разу не открывали свою папку "Шрифты", и никакая программа ни разу не вызывала SHGetSpecialFolderLocation(CSIDL_FONTS), то никакой записи "Fonts" в ключе "Shell Folders" не будет? Это потому что записи создаются только когда их кто-нибудь просит. Если никому они не нужны, то они и не создаются. Нет смысла активизировать хак для приложения, пока он не понадобится.

Конечно же, когда вы проверяете свою программу, вы не форматируете свой диск и не делаете чистую установку Windows 95, а потом запускаете свою программу. Вы просто копируете свою программу на машину с Windows 95, которая работает уже несколько месяцев, и проверяете, что происходит с вашей программой. А происходит вот что: поскольку на машине, которая работает уже несколько месяцев, наверняка за это время кто-нибудь да открыл папку "Шрифты", то значение "Fonts" существует и все счастливы.

А в то же время, в наших лабораториях проверки программ на обратную совместимость, ваша программа получает метку "не прошла", потому что в наших лабораториях мы форматируем компьютер перед установкой каждой программы, чтобы быть уверенными, что ничто от предыдущих программ не повлияет на работу новой программы.

А потом вызывают команду разработчиков ядра, чтобы разобраться, почему это программа получает отметку "не прошла", и мы обнаруживаем, что, фактически, эта программа, будучи установленной на нулевую машину, никогда и не работала.

Философский вопрос: если программа изначально не работала, то является ли багом то, что она не работает и сегодня?

Теперь для тех из вас, кто сейчас облизывает губы и говорит: "вау, тут есть ключ 'User Shell Folders', который ещё круче, чем 'Shell Folders', ну-ка я его сейчас пощупаю". Я призываю вас проявить сдержанность и не полагаться на этот новый ключ. Просто используйте функцию SHGetFolderPath, которая возвращает путь к любой папке, какую вы только захотите. Пусть ключ "User Shell Folders" покоится в мире. Потому что в Longhorn (прим. пер.: кодовое имя Windows Vista) мы собираемся делать ещё больше всяких вещей с пользовательскими профилями, и я лично буду весьма расстроен, если нам придётся забросить ключ "User Shell Folders", как жертву обратной совместимости, и перейти к новому "Real User Shell Folders".

Я сильно подозреваю, что ни одна из тех четырёх программ, ради которых изначально создавался ключ "Shell Folders", сегодня больше не используется.

Читать далее: три примера плохих программ.

8 комментариев:

  1. Анонимный24 июня 2011 г., 21:50

    В Windows 7 в том ключе создали значение "!Do not use this registry key" с данными "Use the SHGetFolderPath or SHGetKnownFolderPath function instead".

    ОтветитьУдалить
  2. А как найти расположение %рабочего стола% в командном файле?

    ОтветитьУдалить
  3. Никак.

    Нужно дёргать вышеуказанные функции. Это можно делать, либо написав свою программу, либо используя скрипты (VBScript, PowerShell, WMI).

    ОтветитьУдалить
  4. >Поэтому мы создали функцию SHGetSpecialFolderLocation, и обновили документацию, чтобы указать разработчикам на использование новой функции для получения специальных папок. Документация по старому ключу "Shell Folders" была полностью удалена.
    В документации по SHGetSpecialFolderLocation написано, что эта функция устаревшая (чуть ли не Win2k only) и вместо неё рекомендуют использовать SHGetFolderLocation.
    Ну ладно, SHGetFolderLocation это конечно хорошо, но как быть если нужно узнать местоположение специальных папок на удалённом компьютере? Кроме как чтения через удалённый реестр несчастного ключа "Shell Folders" я ничего другого не нашёл. Может плохо искал?

    ОтветитьУдалить
  5. А зачем вам нужно знать расположение папок пользователя на удалённой машине?

    ОтветитьУдалить
  6. >А зачем вам нужно знать расположение папок пользователя на удалённой машине?
    Так как я занимаюсь поддержкой пользователей на удалённых рабочих местах (в локальной сети), то мне довольно часто нужно знать где находится "Рабочий стол", "Мои документы" и другие папки пользователя на удалённом компьютера, чтобы туда что-то скопировать, или наоборот забрать.
    Из последнего - так называемая "чистка кэша 1С82". Подробнее что это такое можно посмотреть например здесь: http://infostart.ru/public/287511/
    Вкратце - после обновлений 1С82 временами начинает работать нестабильно и показывать какие-то странные ошибки. Помогает только "очистка кэша 1С82", т.е удаление временных файлов которые 1С82 накопировала на локальный компьютер с сервера. Но чтобы удалить эти файлы нужно знать где они находятся, т.е. пути к папкам типа "Local Settings" и "Application Data".

    ОтветитьУдалить
  7. Чтение реестра может работать в частном случае, но не в общем:
    - Что если записи в Shell Folders не будет?
    - Что если папка перенаправлена групповой политикой?
    - Что если профиль пользователя на машине - не актуален (в случае перемещаемых профилей, aka roaming profiles)?

    Не уверен, но подозреваю, что официальная рекомендацией Microsoft будет: "вам нужно запустить ваш код/скрипт на удалённой машине под выбранным пользователем".

    В целом, для работы с удалёнными машинами из официальных API есть WMI.

    ОтветитьУдалить
  8. Позорище галимое!!! Дебилы!!! Не могут и не умеют обычную несчастную папку запрограммировать. Обратная совместимость, перемещаемый профиль (который работает очень медленно) и прочие наборы всевозможных костылей и убогостей. Всё это вместо простого и элегантного решения ;-(((( Лишь бы бабло на "очень нужное" программирование отпилить. Фу!

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.