Технологические ипохондрики

Это перевод Technology hypochondriacs. Автор: Реймонд Чен.

Я часто замечаю один феномен, который я буду называть «технологическая ипохондрия» — вера в то, что вы страдаете от проблемы (перевод поста), о которой только что прочитали (перевод поста). Для этого есть бородатый анекдот:

К доктору пришёл один мужчина: «Доктор», — сказал он. — «Я просто уверен, что у меня именно эта болезнь. Совпадают все симптомы: у меня усталость, раздражительность и потеря памяти.»

«Вы знаете», — ответил доктор. — «Я же, напротив, просто уверен, что вы не страдаете от менопаузы.»


Один из моих знакомых, врач в обычной больнице, сказал мне, что, исходя из его наблюдений, вам никогда не следует верить диагнозу студентов: «Мы приводим их сюда, показываем пациента и спрашиваем, чем, по их мнению, он болеет. И знаешь что? Они всегда называют то, про что им читали на последней неделе на лекциях».

Если я пишу про то, как программа может зависнуть, это совсем не означает, что именно в этом кроется причина зависания вашей программы. Программа может зависнуть из-за миллиона причин, большинство из которых имеют один и тот же симптом: «Когда я щёлкаю по программе, ничего не происходит». Этого не достаточно, чтобы сделать диагноз. А чтобы сделать диагноз, вам нужно взять отладочный инструмент, подключить его к программе и проанализировать, почему поток, ответственный за UI (как правило — главный), не обрабатывает сообщения (вот, к примеру, как это сделал Марк Руссинович при диагностике задержек запуска процесса; этот случай даже я вижу в первый раз). Прим.пер.: а вот как это делали мы.

Если вы задаёте в комментариях к моим постам вопрос: «Это поэтому моя программа тоже так делает?», то не ждите от меня ответа. Это всё равно что писать письмо в газету для колонки «Здоровье»: «У меня усталость и потеря аппетита. У меня СПИД?».

Читать на сайте автора.

Что это за странные переменные окружения с =C:?

Это перевод What are these strange =C: environment variables? Автор: Реймонд Чен.

Вы не увидите их при выполнении команды SET, но вы увидите их, если получите список переменных окружения сами, программным путём. К примеру, если вы напишете программу, которая получает список всех переменных окружения и выводит их на консоль, и запустите её из командной строки, то увидите странные переменные с именами вроде =C: и значениями, соответствующими каталогам на этих дисках. Что это такое?

Эти переменные являются частью командного интерпретатора cmd.exe. Вот почему я добавил «и запустите её из командной строки» выше — потому что если запустить программу из Проводника или диалога «Выполнить», то вы не увидите эти переменные. Если cmd.exe не будет среди тех, кто изменял ваш блок переменных окружения, то вы не увидите переменные от cmd.exe.

Окей, командный процессор устанавливает эти переменные. Но зачем? Это остатки от попыток командного процессора имитировать старый способ, которым MS-DOS работала с дисками и каталогами. В Win32 существует только один текущий каталог, но в MS-DOS у каждого диска был свой текущий каталог. Посмотрите на такую последовательность команд:

A> CD SUBDIR
// текущим каталогом для диска A: является A:SUBDIR
A> B:
B> CD TWO
// текущим каталогом для диска B: является B:TWO
B> A:
A> DIR
// показывает содержимое каталога A:SUBDIR

В этой последовательности команд мы начинаем с A: (текущего диска) и устанавливаем его текущий каталог в A:SUBDIR. Далее, мы меняем текущий диск на B: и ставим B:TWO его текущим каталогом. Наконец, мы возвращаемся на диск A: и когда мы просим показать текущий каталог, нам выводят содержимое A:SUBDIR — потому что именно этот каталог является текущим на текущем диске.

В Win32 нет концепции отдельного текущего каталога для каждого диска, но командному процессору нужно сохранять старое поведение MS-DOS, потому что к нему все привыкли (и для этого поведения написаны базилионы командных файлов). Решение заключается в том, чтобы хранить «текущий каталог для диска» в переменных окружения, используя несколько странное имя переменной, чтобы избежать конфликта имён с другими переменными окружения.

Если вы повторите последовательность команд выше на современном cmd.exe, то результат будет одинаков, но достигаться он будет весьма иначе.

A> CD SUBDIR
// Переменная окружения с именем =A: устанавливается равной A:SUBDIR
// Текущий каталог Win32 устанавливается в A:SUBDIR
A> B:
B> CD TWO
// Переменная окружения с именем =B: устанавливается равной B:TWO
// Текущий каталог Win32 устанавливается в B:TWO
B> A:
// Текущий каталог Win32 устанавливается в A:SUBDIR
A> DIR
// Показывает содержимое A:SUBDIR

Когда мы переключаемся обратно на диск A:, командный процессор спрашивает: «Эй, каким был текущий каталог на диске A:, когда я последний раз был на нём?». Для этого он пытается прочитать переменную окружения с именем =A:, которая говорит ему: «Ах, да, это был A:SUBDIR«. И именно этот каталог он устанавливает в качестве текущего.

Но почему эти внутренние переменные выносятся в переменные окружения? Разве нельзя их сделать обычными переменными внутри процесса cmd.exe?

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

C:SUBDIR> D:
D:> emacs
M-x shell
D:> C:
C:SUBDIR>
// "Текущий каталог на диске C" был сохранён - как и ожидает пользователь

Что вам тогда нужно делать с этими переменными окружения?

Ничего. Просто оставьте их в покое и дайте им делать свою работу. Я так подробно описал эти переменные, только чтобы вы не пугались их.

Читать на сайте автора.

Что на самом деле делает флаг SEE_MASK_UNICODE в ShellExecuteEx?

Это перевод What does the SEE_MASK_UNICODE flag in ShellExecuteEx actually do? Автор: Реймонд Чен.

Кое-кто с невежливым ником хотел узнать, что делает флаг SEE_MASK_UNICODE.

А ничего он не делает.

Этот флаг был добавлен во время переноса Оболочки Windows 95 в Windows NT. Это случилось раньше, чем у меня есть доступ к базе данных исходников, но я могу предположить, как он был добавлен.

Одной из вещей, которые было необходимо сделать во время переноса, было создание Unicode-вариантов всех ANSI-функций, добавленных в Windows 95. Это можно было делать несколькими способами. Иногда создавали два варианта одной функции: с A и W суффиксами. Иногда это достигалось A и W вариантами одного интерфейса. Иногда это достигалось добавлением в запись флага, говорящего нужно ли использовать/трактовать данные как ANSI или как Unicode.

Я подозреваю, что изначально для Shell­Execute­Ex планировалось использовать третью модель (с флагом). Вероятно, потом разработчики изменили решение и вместо этого сделали A и W варианты самой записи SHELL­EXECUTE­INFO (SHELL­EXECUTE­INFOA и SHELL­EXECUTE­INFOW) и функции Shell­Execute­Ex (Shell­Execute­ExA и Shell­Execute­ExW). Но когда они переключились к другой модели, они оставили флаг нетронутым — вероятно, с целью убрать его позднее, когда будет исправлен весь код, который уже передаёт этот флаг. Однако эта задача так и не была выполнена.

Итак, сегодня этот флаг всё ещё находится в заголовочных файлах Windows, хотя на него никто не обращает внимания.

Читать на сайте автора.

Что за дела с сообщением EM_SETHILITE?

Это перевод What’s the deal with the EM_SETHILITE message? Автор: Реймонд Чен.

Если вы посмотрите на документацию по сообщениям EM_SETHILITE и EM_GETHILITE, то увидите просто «not implemented» («не реализовано»). Что тут происходит?

Сообщения EM_SETHILITE и EM_GETHILITE были добавлены в 2002 году для элемента управления «breadcrumb bar» (панель типа «хлебные крошки» aka «навигационная цепочка»). В те времена этот элемент управления был не таким, каким вы можете видеть его сегодня в Windows Vista (набор кнопок со стрелочками, каждая из которых представляет уровень иерархии). В 2002 году breadcrumb bar был просто несколько иначе выглядевшей строкой адреса (т.е. элементом управления edit). Вместо кнопки для каждого уровня в иерархии breadcrumb bar подсвечивал часть пути, когда вы наводили на неё мышью (или использовали клавиатуру для выделения). Вместо стрелочек с выпадающими меню breadcrumb bar ждал, пока вы наведёте на часть пути мышь, и автоматически показывал меню с дочерними элементами.

Потом дизайн breadcrumb bar изменился, а вариант с «просто немного иначе выглядящая строка адреса» был заброшен. Функциональность сообщений EM_SETHILITE и EM_GETHILITE была удалена, но номера сообщений остались зарезервированными — чтобы не сломать код, который уже начал отправлять эти сообщения (прим.пер.: речь идёт о коде Оболочке, внутреннем коде Microsoft). Конечно же, сообщения уже ничего не делают, но, по крайней мере, старый код компилируется и не отправляет случайно какое-то другое сообщение. Те, кто до сих пор продолжают использовать эти сообщения в своём коде, могут удалить их по собственному желанию.

Такова реальность разработки одновременно и библиотеки и клиентского приложения к ней. Если вы ответственны за библиотеку и хотите сделать в ней ключевое изменение (breaking change), то вам нужно делать его по частям, чтобы все клиентские приложения могли плавно совершить переход. Вы не можете просто пройтись по коду всех клиентов и исправить его — это не ваш код, у вас нет к нему доступа. Клиенты принадлежат другим командам разработчиков, а иногда — и другим компаниям. Вам нужно скоординироваться с этими разработчиками, сообщить им ваш план перехода, чтобы они могли продолжить использовать существующий код и выделить время на ваш план перехода.

Сообщения EM_SETHILITE и EM_GETHILITE — это просто остатки, которые так и не были вычищены. То, что сейчас находится в заголовочных файлах — это предпоследний шаг плана по переходу. Последним шагом этого плана было бы полное удаление этих сообщений из файлов заголовочников, но, к сожалению, конечный срок «больше не допускается изменение публичных заголовочных файлов» наступил раньше, чем успели сделать этот последний шаг — поэтому теперь эти сообщения продолжают находится в (публичном) заголовочном файле, и им придётся оставаться там вечно. Даже хотя они ничего не делают.

Читать на сайте автора.

Возможность-изгой: пристыковка папки к краю экрана

Это перевод Rogue feature: Docking a folder at the edge of the screen. Автор: Реймонд Чен.

Начиная с Windows 2000 и вплоть до Windows Vista вы могли перетащить папку из Проводника и бросить её на край экрана — как только вы отпускали папку, она пристыковывалась (dock) к краю экрана по аналогии с панелью (toolbar). Один клиент заметил, что это поведение больше не работает в Windows 7, и спросил: «Была ли эта возможность полностью удалена из Windows 7 или есть способ её включить обратно?»

Да, эта функциональность была удалена из Windows 7. Не существует способа её включить, поскольку код, который её реализует, был полностью удалён из продукта. Ну, хорошо, вы можете «включить» её с помощью вашего представителя поддержки, который отправит Design Change Request (запрос на изменение дизайна) с просьбой восстановить этот код в команду Windows Sustained Engineering. Но, я думаю что они будут злодейски смеяться, нажимая ОТКАЗАТЬ. Может быть, для пущего эффекта они даже добавят звуковой эффект.

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

Во-первых, очень мало людей вообще использовали эту возможность. И среди тех, кто хотя бы раз использовал её, большинство делало это по ошибке и не знало, как вернуть всё обратно (звучит знакомо?). Так что эта возможность приносила больше проблем, чем пользы — и только из-за этого была хорошим кандидатом на удаление из продукта. Кроме того, команда дизайна была заинтересована в новом способе использования краёв экрана. Никто не знает, как эта функциональность была добавлена на самом деле. Мы сильно подозреваем, что она является ещё одной забытой нестандартной возможностью, добавленной разработчиком, который имел плохую привычку добавлять такие «фишки» в продукт.

Читать на сайте автора.

Атака забытой функциональности: о, нет, куда пропали надписи в Проводнике?

Это перевод Attack of the rogue feature: Oh no, where did my Explorer icon labels go? Автор: Реймонд Чен.

Один клиент сообщил о проблеме на Windows Vista: если вы зажмёте клавишу Shift и будете многократно щёлкать по кнопке Вид в панели команд окна Проводника, то в итоге вы войдёте в состояние, в котором все подписи под значками исчезнут! «Куда они пропали, и как мне их вернуть?»

Поздравляю, вы попали в сети забытой возможности Windows.

Один из разработчиков Windows XP решил добавить милую возможность: удерживание кнопки Shift во время переключение в режим эскизов (thumbnail mode) скроет все подписи. По крайней мере, такова была его исходная цель, но на деле эта возможность получила побочный эффект: удерживание Shift также работало и для некоторых других операций, поскольку проверка на нажатие Shift была реализована в разделяемой вспомогательной функции.

Отлично, подписи пропали, как их вернуть? В Windows XP это было просто: нужно зажать Shift и переключиться в режим эскизов. Подождите-ка, но в Windows Vista нет никакого режима эскизов? Поскольку удерживание Shift для скрытия подписей было забытой возможностью, никто не знал, что переключение в режим эскизов было для этой возможности способом её отмены!

Ок, вот как вы можете вернуть всё на свои места: щёлкните правой кнопкой по фону папки и выберите «Настроить папку…». В диалоге персонализации переключите шаблон в «Изображения и видео», нажмите OК. Теперь вернитесь в папку и щёлкните правой по фону папки снова, но теперь выберите меню Вид (или нажмите Alt+V). В этом меню теперь будет новый пункт: «Скрывать имена файлов» — сбросьте с него галочку (а если галочки нет, то сначала поставьте её, а потом сбросьте). Готово. Если хотите, то можете вернуть шаблон папки на «Общие элементы».

Ребята из команды поддержки продукта, вероятно, были счастливы узнать, что эта функциональность была полностью убрана в Windows 7.

Читать на сайте автора.

Drag&drop — это модель переноса данных общего назначения, не привязанная к каталогам Проводника

Это перевод Drag and drop is a general purpose transfer model, not exclusive to Explorer directories. Автор: Реймонд Чен.

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

piers хочет определить назначение операции перетаскивания. Однако из постановки вопроса становится ясно, что piers, на самом деле, заинтересован в пути назначения. Но кто сказал, что назначением будет каталог? Пользователь может перетащить объект в сообщение e-mail, бросить на FTP-сайт, на Web-сайт (через Web-папки), или даже в каталог операционной системы внутри виртуальной машины!

Следующее уточнение ещё больше запутывает. Если пользователь перетащит файл на FTP или другую виртуальную папку, то как ваша программа может перезапустить закачку? Вы же не знаете пароля для FTP. Вы не знаете как перезапустить виртуальную машину и войти в неё тем же пользователем. А даже если вы сможете это сделать, то вы понятия не имеете, как писать в папку внутри виртуальной машины — только менеджер виртуальной машины знает, как это сделать. В мире сегодня существует бесчисленное множество вариантов виртуальных папок. Я крайне сомневаюсь, что вы знаете как запихать свои данные в каждый вариант виртуальной папки.

Как только пользователь перетащит объект, сам процесс переноса — это личное дело только источника (source) и назначения (target). И вы, как источник, не можете просто взять и сказать: «теперь командую я», потому что даже если бы назначение согласилось, то вы всё ещё остаётесь с проблемой, а как же это осуществить.

Какова моя рекомендация?†

Объект перетаскивания (data object) в цикле drag/drop должен следовать стандартному протоколу Оболочки, так что пользователь сможет перетащить объект в e-mail, FTP и т.д.‡

Для дополнительного шика, я бы создал ловушку drag/drop (drag/drop hook). Пользователь сможет перетащить объект, используя правую кнопку мыши°. Когда пользователь отпустит кнопку мыши, появится контекстное drop-меню — вместе с вашей ловушкой. Ловушка может создать пункт вроде «Скопировать с КрутойПрограммой» (конечно же, пункт создаётся ловушкой только в случае, если объект данных идентифицировал себя как созданный в КрутойПрограмме). Если пользователь выбирает «Скопировать с КрутойПрограммой», то вы можете выполнить своё копирование с дополнительными возможностями.

Уголок зануды

† Заметьте, что я не утверждаю, что все продукты Microsoft следуют моим рекомендациям. Также заметьте, что это мои личные рекомендации, не являющиеся официальной позицией Корпорации Microsoft.

‡ И, прежде чем реализовывать не стандартный протокол передачи объекта, вам нужно понимать стандартный протокол.

° Точнее: вторичную кнопку мыши, поскольку вы могли поменять кнопки мыши местами.

Читать на сайте автора.

Списывание остатков

Это перевод Scrapping the Scraps. Автор: Реймонд Чен.

Хотя это случается не часто, но иногда всё же из Windows удаляется какая-то старая функциональность (что, конечно же, празднуется всей командой).

К примеру, в Windows XP был удалён интерфейс по установке фонового узора рабочего стола. Сама функциональность сохранена, и вы можете написать программу, которая вызывает SystemParametersInfo(SPI_SETDESKPATTERN) — просто теперь нет интерфейса пользователя для этой функциональности. Почему интерфейс для установки узоров был удалён из апплета Экран Панели управления?

Наши исследования показали, что практически никто не использует сегодня узоры. Они были очень популярны в старые времена, когда памяти было мало, она была дорогой, и пользователи не хотели тратить четверть своей памяти на мегабайтный растровый рисунок обоев. Крохотный монохромный рисунок 8х8, повторённый по всему экрану, предоставлял возможности по персонализации экрана 640х480 за гораздо меньшую «цену».

Однако время делало узоры всё менее привлекательными. Во-первых, конечно же, сегодня компьютеры имеют намного больше памяти, чем в 1983 году. Во-вторых (также конечно же), сегодня мониторы имеют гораздо большее разрешение экрана. Симпатичный для экрана 640х480 узор 8х8 будет выглядеть серым пятном на мониторе 1900х1080.

Это не единственная возможность, которую мы отправили в мусорную корзину за эти годы. Фрагменты (scraps, .shs-файлы) — вот ещё один пример удалённой функциональности. Впервые представленные в Windows 95, фрагменты являются частями документа, сохранёнными в файл. Файл в действительности является OLE-объектом. Идея была в том, что вы могли, к примеру, выделить текст в редакторе и перетащить его на рабочий стол, где создавался файл фрагмента. Потом вы могли взять этот фрагмент и перетащить его обратно в редактор или любую другую программу, и сохранённый в фрагменте текст вставился бы в новый документ. Это что-то вроде копирования/вставки, только вместо временного хранения в буфере обмена, данные сохранялись в постоянный файл.

Итак, когда вы создали файл фрагмента, то единственное, что вы можете с ним сделать, так это «перетащить» его на другой документ — аналогично тому, что единственное, что можно сделать с содержанием буфера обмена, это вставить его куда-то. Позже кто-то добавил новую возможность: вы могли дважды-щёлкнуть по файлу фрагмента, и он открывался в программе, которая его создала (поскольку внутри фрагмента могло быть что угодно, то для его отображения мы могли только попросить сделать это программу, его создавшую).

Я не знаю, была ли эта возможность добавлена как отладочный инструмент или как реальная возможность для пользователей посмотреть содержимое фрагмента без создания пустого документа и перетаскивания в него фрагмента. В любом случае, эту возможность сразу полюбили писатели вирусов, потому что она позволяла им создавать фрагменты с данными вида «приложение, которое создало этот фрагмент — это cmd.exe, а сам фрагмент документа — вот этот .bat-файл». И когда пользователь дважды-щёлкал по такому файлу фрагмента, просмотрщик фрагментов передавал .bat-файл из фрагмента командному интерпретатору: «Пожалуйста, открой вот это и покажи его пользователю».

Учитывая историю просмотра фрагментов, команде Оболочки (Shell) было поручено удалить эту функциональность из Windows Vista. Чтобы выполнить назначенную задачу, команда провела исследование: насколько популярной была эта функциональность в реальном мире. Для этого команда Оболочки попросила команду поддержки продукта поднять свои записи и сказать им, сколько людей позвонило с вопросами по фрагментам. Идея состояла в том, что по популярной функциональности будет много вопросов, а по не популярной — не будет (поскольку её никто и не использует). В частности, фрагменты не совсем относятся к категории «абсолютно очевидно», поэтому малое число вопросов нельзя будет объяснить «ну, это же так просто, поэтому нам никто и не звонит!»

Команда поддержки продуктов подготовила ответ. За прошедший год она получила целых четыре вопроса по фрагментам. Все они были заданы в форме «Я как-то создал вот такой странный файл. Что это такое и как мне его удалить?»

Читать на сайте автора.