четверг, 8 апреля 2010 г.

Когда программы предполагают, что система никогда не изменится, эпизод 3

Это перевод When programs assume that the system will never change, episode 3. Автор: Реймонд Чен.

Мой коллега решил одну из самых странных загадок обратной совместимости, когда пытался понять, почему одна конкретная программа не могла открыть папку "Принтеры" в Панели управления.

Причина стала ясна при более внимательном рассмотрении. Программа открывала Панель управления, использовала FindWindow для нахождения окна, а затем искала меню "Файл" и перечисляла его элементы, выискивая пункт со словом "Принтер". Затем она отправляла сообщение WM_COMMAND Панели управления, эмулируя щелчок пользователя на этом пункте меню.

Очевидно, что с введением новой панели управления в Windows 95, этот метод больше не мог работать. В меню Панели управления теперь нет никакого меню "Принтеры". Авторы программы не осознавали, что это может быть возможным (заметьте, что это было возможно даже в Windows 3.1: если вы работали в системе с другим языком, то локализованное название пункта вполне могло быть вроде "Printers", "Skrivare" или "Drucker". Но это не имело значения, потому что само меню "Файл" называлось "File", "Arkiv" или "Datei"! Иными словами, разработчики программы думали, что все в мире говорят на одном языке).

Код, к тому же, не делал проверки на ошибки; он просто шёл дальше, предполагая, что всё идёт согласно плану. Когда код завершал работу, он отправлял Панели управления сообщение WM_COMMAND с мусором, которое, конечно же, игнорировалось, поскольку не подходило ни одной допустимой команды для меню.

Особо забавно (или нет?), что способ открытия папки принтеров был ясно документирован на самой первой странице Windows 3.1 SDK в разделе "Панель управления":
Следующий пример показывает, как приложение может открыть Панель управления с запущенным приложением Принтеры с помощью функции WinExec:

WinExec("control.exe printers", SW_SHOWNORMAL);
Другими словами, авторы программы вообще не читали документацию.

Решение: создать Панель управления-приманку - окно того же класса, что и в Windows 3.1, так чтобы эта программа могла его найти. Целью этой подсадной утки является отвлечение внимания от настоящей Панели управления, так что плохие программы могут счастливо использовать её как и раньше. В нашем случае, окно-приманка тихо ждало этого мусорного сообщения WM_COMMAND, после чего запускало Панель управления.

Сегодня, проблема такого рода, вероятно, решалась бы использованием регулировочной прокладкой (shim). Но во времена Windows 95 технологии совместимости приложений были относительно молоды. Всё, что вам было доступно в то время, - это флаги совместимости приложений и патчинг исполняемых файлов в памяти (hot-patching). Последнее было зарезервировано только для самых тяжёлых случаев, потому что требовалось получить разрешение от производителя на выполнение такой операции, что часто является очень длительным процессом. Патчинг рассматривался последним средством не только из-за проблем лицензирования, но и потому, что вы решали только проблему одной версии программы (одного двоичного модуля). Если производитель выпустил десять версий программы - вам нужно было разработать десять патчей. А если разработчик выпустил бы ещё одну версию, когда Windows 95 ехала в магазины, то эта версия не работала бы на Windows 95.

Очень важно понимать, в чём разница между документированной возможностью с гарантией поддержки в будущих версиях и деталью реализации. Документированная и поддерживаемая возможность является контрактом (соглашением) между Windows и вашей программой. Windows будет соблюдать свою сторону, пока эта возможность будет существовать. Детали реализации, с другой стороны, нестабильны; они меняются со временем, будь это следующая версия системы, новый сервис пак или даже очередное исправление. Если ваша программа зависит от деталей реализации, вы просто добавляете хлама, который Windows вынуждена будет таскать из версии в версию вечно.

В течение нескольких следующих дней я поговорю о других приманках, которые используются в Windows.

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

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

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

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

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

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

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

Примечание. Отправлять комментарии могут только участники этого блога.