воскресенье, 29 марта 2009 г.

Почему InterlockedIncrement/Decrement возвращали только знак результата?

Это перевод Why did InterlockedIncrement/Decrement only return the sign of the result? Автор: Реймонд Чен.

Если вы прочтёте старую документацию на функции InterlockedIncrement и InterlockedDecrement, то вы увидите, что на Windows NT 3.51 и младше, а также на Windows 95, возвращаемое значение соответствует только знаку результата увеличения или уменьшения. Почему так?

Отправка широковещательных сообщений, определяемых пользователем

Это перевод Broadcasting user-defined messages. Автор: Реймонд Чен.

Когда вы отправляете широковещательное сообщение (с помощью HWND_BROADCAST), не забывайте, что ваше сообщение должно иметь глобальный смысл.

Ранее я уже обсуждал, что означают различные диапазоны кодов сообщений. Заметьте, что только системный диапазон (0..WM_USER-1) и диапазон зарегистрированных сообщений (MAXINTATOM .. MAXWORD) имеют глобальный смысл. Остальные два диапазон имеют смысл в рамках класса или приложения.

Другими словами, вы не можете отправить широковещательное приложение в диапазоне кодов WM_USER, потому что это сообщение имеет различное значение для каждого оконного класса. Аналогично, сообщение в диапазоне WM_APP имеет различное значение для каждого приложения.

Мы обнаружили эту проблему в Windows 95. У нас были программы, которые отправляли широковещательные сообщения вроде WM_USER + $0100, подразумевая, что их надо доставить другим запущенным копиям этой же программы. Конечно же, когда эти сообщения приходили каким-то другим окнам - эти окна интерпретировали WM_USER + $0100 как какое-то другое внутреннее сообщение и либо начинали странно себя вести, либо вовсе вылетали.

С другой стороны, программы на самом деле хотели доставить это сообщение только копиям себя, так что мы не могли просто взять и заблокировать отправку этих широковещательных сообщений - иначе эти программы перестали бы работать. Программы ожидали от системы, что она не будет останавливать их от попыток подвесить чужие программы!

Решение: как-то разделять эти программы. Если вы отправляете небезопасное широковещательное сообщение, то Windows 95 отправит его только старым программам. Новые программы (помеченные в PE заголовке версией 4.0 или выше) не получат этих сообщений.

Таким образом, старые программы продолжат "портить друг другу жизнь", как они всегда это делали, а новые программы будут играть по новым правилам.

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

пятница, 27 марта 2009 г.

Чище, элегантнее и неверно

Это перевод Cleaner, more elegant, and wrong. Автор: Реймонд Чен.

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

Почему система не может отправить в гибернацию только один процесс?

Это перевод Why can't the system hibernate just one process? Автор: Реймонд Чен.

Windows позволяет вам отправить в гибернацию (hibernate) машину целиком, но почему нельзя сделать это только для одного процесса? Сохранить состояние процесса и возобновить его позднее.

Почему сообщение WM_KILLFOCUS не подходит для проверки правильности ввода

Это перевод WM_KILLFOCUS is the wrong time to do field validation. Автор: Реймонд Чен.

"Я буду делать проверку ввода, когда мне придёт сообщение WM_KILLFOCUS".

Это плохо по многим причинам.

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

Рассмотрим диалоговое окно с edit-контролом и кнопкой ОК. Edit-контрол проверяет своё содержимое при получении сообщения WM_KILLFOCUS. Предположим, пользователь ввёл некоторые неверные данные.

При благоприятных обстоятельствах, пользователь нажимает кнопку ОК. Нажатие на кнопку ОК приводит к тому, что фокус уходит с edit-контрола, поэтому получает управление код edit-контрола для WM_KILLFOCUS, и edit-контрол получает шанс сообщить пользователю, что введённые данные не годятся. Поскольку щелчок на кнопку не срабатывает, пока кнопку мыши не отпустят, всплывающее окно с сообщением о недействительных данных крадёт фокус, и теперь отпускание кнопки мыши не перейдёт к кнопке ОК. Результат: появляется сообщение об ошибке и действие IDOK не выполняется.

Теперь рассмотрим менее благоприятные условия. Вместо нажатия на кнопку ОК, пользователь просто нажимает Enter или набирает быструю комбинацию клавиш для любой кнопки, которая закрывает диалог. Нажатия этих кнопок приводят к появлению WM_COMMAND, но фокус при этом не меняется.

Теперь обработчик IDOK (или любой другой) запускается и вызывает EndDialog или выполняет любые другие действия, для которых предназначена кнопка. Если диалоговое окно закрывается, тогда фокус уходит с edit-контрола как часть уничтожения диалогового окна, и только в этот момент произойдёт проверка ввода, но теперь уже слишком поздно. Диалог уже закрывается.

Или же, если реакция на кнопку предусматривает не закрытие диалога, а скорее запуск какой-либо процедуры, то тогда работа будет происходить с непроверенными данными в диалоговом окне - скорее всего, это не то, чего вы хотите. Только тогда, когда эта процедура переместит фокус (например, для показа диалога хода операции), edit-контрол получит WM_KILLFOCUS, но в это время уже слишком поздно что-либо проверять. Процедура (с использованием непроверенных данных) уже запущена.

Существует также проблема юзабилити при проверке данных при смене фокуса. Предположим, пользователь начинает вводить данные в edit-контрол, а затем он отвлекается. Может быть, он хочет прочитать фрагмент электронной почты, где находится нужная ему информация. Возможно, он получил телефонный звонок, и ему нужно посмотреть что-то в своей базе данных контактов. Может быть, он пошёл в ванную и поэтому запустился хранитель экрана. Пользователь не хочет видеть в эти моменты диалог с ошибкой "Извините, но вот эта частично введённая вами информация недопустима", потому что он еще не закончил ввод данных.

Я сейчас говорил вам о тех местах, где вам не нужно делать проверки, но ничего не сказал о том, где вам следует их делать.

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

(Предупреждения, которые не изменяют фокус - разрешены. Например, всплывающий балун с подсказкой, что вы включили Caps Lock при вводе пароля).

Проецирование всех этих "странных" цифр в "0"-"9"

Это перевод Mapping all those "strange" digits to "0" through "9". Автор: Реймонд Чен.

В предыдущей статье, я обсудил вопрос о том, что метод Char.IsDigit и его Win32-коллега GetStringTypeEx сообщают, что некие вещи, отличные от "0"-"9", также являются цифрами.

Если вас действительно волнуют только "0"-"9", то вы можете проверять их явно. Например, используйте [0-9] вместо \d в регулярных выражениях. Кроме того, для регулярных выражений, вы можете включить режим ECMA через RegexOptions.ECMAScript. Заметим, что этот режим контролирует больше, чем просто интерпретация класса символа \d, поэтому не забудьте внимательно прочитать, что вы действительно хотите получить всё ECMA поведение.

Мне также указали, что есть способ превратить все эти "странные" цифры в обычный диапазон "0"-"9", а именно: вызвав функцию FoldString с флагом MAP_FOLDDIGITS (я ставлю слово "странный" в кавычки, потому что, конечно же, они нисколько не странные. А просто другие).

Этот способ переводит цифры, но не помогает с десятичными точками, так что вам еще придется иметь дело с правильной интерпретацией "1,500" либо как "одной тысячи пятисот" (как было бы в Соединенных Штатах), либо как "один с половиной" (как это будет в большинстве стран Европы). Для этого вам нужно вызвать GetLocaleInfo, чтобы получить строки LOCAL_SDECIMAL и LOCAL_STHOUSAND.

Не у всех коротких имён файлов есть тильда

Это перевод Not all short filenames contain a tilde. Автор: Реймонд Чен.

Я уверен, что все видели автоматически сгенерированные короткие имена для длинных имен файлов. Для длинного имени "Long name for file.txt", вы можете получить "LONGNA~1.txt", или, возможно, "LO18C9~1.txt", если в каталоге много коллизий.

Но вы можете не знать, что иногда там вообще нет тильды!

Каждая файловая система сама решает, как она хочет составлять короткие имена файлов. Windows 95 использует только метод "~N". Windows NT добавляет технику переполнения шестнадцатиричного хэша (hexadecimal hash overflow technique). Но некоторые файловые системы (например, Novell) просто обрезают имя. "Long name for file.txt" на сервере Novell будет просто "LONGNAME.TXT".

Так что не думайте, что все короткие имена содержат тильды. Они этого не делают. Это означает, что вам не следует пропускать вызов GetLongFileName, если вы не видите тильды в имени файла, поскольку такая "оптимизация" будет недействительна в сетях Novell.

История о USB-флоппиках

Это перевод A story about USB floppy drives. Автор: Реймонд Чен.

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

Одна из ранних демонстраций была компанией, которая делала USB флоппи диски. Представитель компании рассказал о том, как хорошо они делают дисководы, и упомянул о том, что они делают два варианта: один для ПК и другой для Mac.

"Это странно" - подумали про себя члены комитета, - "зачем нужны эти раздельные PC и Mac версии? Спецификация сделана очень аккуратно, чтобы быть уверенными в том, что один и тот же дисковод будет работает на обеих системах. Вам не нужно делать два варианта".

Откуда панель задач берёт название заголовка для кнопки сгруппированных окон?

Это перевод Where does the taskbar get grouped button titles from? и Where does the taskbar get grouped button icons from? Автор: Реймонд Чен.

Если установлен флажок "Группировать сходные кнопки панели задач"/"Group similar taskbar buttons" (по-умолчанию так и есть), а на панели задач начинает заканчиваться место - то тогда панель задач будет группировать кнопки окон от одной программы вместе и даст им общее название. Откуда панель задач берёт это общее название?

Имя для сгруппированных кнопок на панели задач происходит из версионного ресурса (version resource) этой программы. Вы можете сами просмотреть это значение, открыв свойства исполняемого файла и взглянув на вкладку "Версия".

Чтобы установить это свойство в своих программах, добавьте к своим программам версионный ресурс и установите имя, которое вы хотите увидеть, в свойство FileDescription.

Предупреждая следующий вопрос: иконка для сгруппированной кнопки берётся из иконки ассоциированного EXE-файла - это та самая иконка, которая появляется у EXE-файла, когда вы открываете папку в Проводнике и перемещаетесь к EXE-файлу.

Например, если у вас открыто несколько окон Проводника (Explorer) и кнопки начинают группироваться, то иконка группы будет являться иконкой Проводника. Система не пытается слить вместе все иконки окон - одна из которых может быть иконкой жёсткого диска, вторая - Панели Управления, третья - папкой и т.п.

Почему очень большой словарь является не очень хорошей идеей

Это перевод Why a really large dictionary is not a good thing. Автор: Реймонд Чен. Входит в книгу The Old New Thing.

Иногда вы можете увидеть, как кто-то хвастается тем, как много слов в их словаре проверки орфографии. На самом деле, слишком много слов в словаре - это ещё хуже, чем когда их слишком мало.

Изображение для входа "Боевые искусства"

Это перевод The martial arts logon picture. Автор: Реймонд Чен. Входит в книгу The Old New Thing.

По аналогии с "Windows проверяет каждого тестом Роршаха", вот пример как кто-то приписывает вредоносное поведение простой случайности.

четверг, 26 марта 2009 г.

Тема Luna

Это перевод The look of Luna. Автор: Реймонд Чен.

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

Почему не следует использовать клавиатурный модификатор Ctrl+Alt

Это перевод Why Ctrl+Alt shouldn't be used as a shortcut modifier. Автор: Реймонд Чен.

Вы могли заметить, что Windows нигде не использует комбинацию Ctrl+Alt как клавиатурный модификатор (shortcut modifier) для сокращённой клавиатурной команды (или, по крайней мере, не должна использовать). Если нужен похожий модификатор, то обычно используется Ctrl+Shift.

Что люди любят делать не так в IUnknown.QueryInterface

Это перевод The ways people mess up IUnknown::QueryInterface. Автор: Реймон Чен.

Когда вы имеете дело с вопросами совместимости приложений, каких только вещей, работающих только благодаря случайности, вы ни обнаруживаете! Сегодня я поговорю о некоторых "творческих" способах напутать с методом IUnknown.QueryInterface.

Сейчас вы должно быть подумали: "Этот интерфейс так важен для всего COM, как же можно сделать с ним что-то не так?". Ну-ну.

Некоторые файлы как-то странно показываются в Блокноте

Это перевод Some files come up strange in Notepad. Автор: Реймонд Чен.

Дэвид Кампс обнаружил, что некоторые текстовые файлы в Блокноте выглядят странно.

пятница, 20 марта 2009 г.

Создание приложений для Windows Vista в Delphi - часть 2

Это перевод Creating Windows Vista Ready Applications with Delphi. Update - January 2007. Автор: Nathanial Woolls.

Я был, по меньшей мере, поражён реакцией на мою первую статью по созданию приложений для Windows Vista в Delphi. Я был очень польщён, что меня включили в Delphi Hour (повтор доступен здесь).

Эта статья имеет целью представить обновленную и дополнительную информацию о создании готовых к Vista приложений Delphi. С кодом, представленым в оригинале статьи, есть небольшие проблемы, которые мы изучим и исправим. Также мы посмотрим на новый код для работы со шрифтами и воспользуемся преимуществами нового TreeView в стиле Vista, а также многое другое.

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

четверг, 19 марта 2009 г.

Создание приложений для Windows Vista в Delphi - часть 1

Это перевод Creating Windows Vista Ready Applications with Delphi. Автор: Nathanial Woolls.

Прим. пер.: речь идёт в основном о Delphi до 2007.

Итак, ваши приложения "работают"

К настоящему времени, надеюсь, Вы, как ответственный разработчик приложений, загрузили несколько из публичных бета-версий Microsoft Windows Vista, и убедились, что ваши приложения (и среда!) работают в новой ОС.

Хотя 99% всех хорошо написанных Delphi приложений будет работать под Vista без проблем (проблемы типа требования админских прав, элевации и UAC находятся за пределами этой статьи), они не имеют никаких бонусов с новых возможностей Windows Vista. Фактически, чем больше вы будете смотреть на новые возможности пользовательского интерфейса в Vista, тем больше ваши приложения будут смотреться как древние динозавры.

Но не беспокойтесь! Вполне возможно (и достаточно просто) преодолеть эти расхождения, и сделать ваши приложения выглядящими и "чувствующими" себя как дома с новым пользовательским интерфейсом Windows Vista. Давайте посмотрим на типичные проблемы приложений Delphi, и что мы можем сделать, чтобы улучшить наши программы.

вторник, 17 марта 2009 г.

Установка Delphi 7/2006 на Windows Vista

Это перевод Delphi on Windows Vista. Автор: Dr.Bob.

Прим. пер.: я выделил описание установки Delphi 7 на Windows 7 в отдельную статью.

Дополнение к статье: как писать приложения для Windows Vista.

Подписчики MSDN уже могут скачать и установить Windows Vista (я установил Vista Business на свой ноутбук, на котором теперь стоят аж четыре операционки: Windows 2000, Windows XP, Windows 2003 Server, а теперь и Windows Vista "Business").

В отличие от Windows XP и Windows 2003, которые визуально отличаются от Windows 2000 в основном службой Themes (которая отключена по умолчанию в Windows 2003), в Windows Vista внешний вид пользовательского интерфейса значительно изменился. Я пишу внешний вид, потому что содержимое осталось практически тем же самым. Нельзя сказать, что это совершенно новый мир: мне не составило труда найти все нужные и знакомые места (хотя деталей и возможностей было изменено достаточно).

Одной из важных новых возможностей Windows Vista является так-называемый User Account Control (UAC), который представляет из себя добавку к безопасности, которая следит за тем, что конкретно разрешено выполнять каждому приложению на вашей машине. Приложениям следует работать по принципу минимально возможных прав и привилегий (и очень редко - с правами администратора), чтобы избежать потенциального ущерба. С UAC все пользователи становятся обычными пользователями (без администраторских прав), с возможностью добавить (временно) приложениям больше привилегий, когда они необходимы.

UAC усиливает защиту против вирусов и spyware, но иногда надоедает, когда дело касается приложений, которым можно доверять. Например, запись в папку Program Files по-умолчанию запрещена - мы увидим это, когда будем запускать Delphi на Vista.

Поскольку я в основном использую Delphi 7 (для Win32) и Delphi 2006 (для Win32 и .NET), я начал процесс установки этих версий Delphi на релизную версию Windows Vista для проверки совместимости как Delphi, так и приложений Delphi Win32 (и .NET) под Windows Vista.

вторник, 10 марта 2009 г.

Использование @ в HTTP URL никогда и не было законным

Это перевод @-notation was never legal in HTTP URLs anyway. Автор: Реймонд Чен.

Некоторые люди находят возмутительным, что IE перестал поддерживать символы @ в HTTP URL. Но при этом они как-то упускают из вида, что @ никогда и не был законен в HTTP URL.

Если вы посмотрите в RFC 1738, раздел 3.3 (HTTP), то там явно сказано:
HTTP URL имеет форму:

http://<сервер>:<порт>/<путь>?<параметры>
где <сервер> и <порт> описаны в разделе 3.1. Если :<порт> опускается, то подразумевается порт по-умолчанию 80. В URL запрещены имена пользователей или пароли.
(Выделение моё)

Поэтому получаем три мнения по этому вопросу:
  • "Я хочу, чтобы Internet Explorer был обратно-совместим с моими плохими URL" (эти люди хотят сохранить старый синтаксис с @).
  • "Я хочу, чтобы Internet Explorer был более безопасным" (эти люди за удаление @-синтаксиса).
  • "Я хочу, чтобы Internet Explorer больше соответствовал стандартам" (эти люди за удаление @-синтаксиса).
Лично я считаю, что удаление поддержки @-нотации было правильной вещью.

Почему компилятор ресурсов жалуется на строки длиннее 255 символов?

Это перевод Why does the Resource Compiler complain about strings longer than 255 characters? Автор: Реймонд Чен.

Как мы узнали в прошлый раз, строковые ресурсы группируются в кучки по 16, перед каждой Unicode-строкой записывается её длина 16-ти битным числом. Так почему же Resource Compiler жалуется нас строки, если её длина превышает 255 символов?
Это ещё один рудимент из времён 16-ти битных Windows.

Во времена Win16 строковые ресурсы также группировались в блоки по 16, но строки хранились как ANSI, не Unicode, и префикс длины был только 8-ми битным.

А 255 - это максимальная длина, которую вы можете указать в 8-ми битном поле.

Если ваша 32-х битная DLL содержит строки длиннее 255 символов, то 16-ти битные программы не смогут их использовать.

Сегодня это обычно не имеет значения, но это предупреждение оставалось в Resource Compiler довольно долго.
Похоже, сейчас его уже убрали. Ну и слава богу.

пятница, 6 марта 2009 г.

Почему терминатором строки является CR+LF?

Это перевод Why is the line terminator CR+LF? Автор: Реймонд Чен.

Этот протокол восходит к временам телетайпов.

CR - это аббревиатура для "carriage return" (возврат каретки) - управляющий символ CR возвращал печатающую головку ("carriage") к нулевой колонке без движения бумаги. LF - это аббревиатура для "linefeed" (подача бумаги) - управляющий символ LF сдвигал бумагу на одну строчку без движения каретки. Поэтому, если вы хотели вернуть головку к нулевой колонке (чтобы быть готовым печатать на новой строчке) и сдвинуть бумагу (чтобы печатать на чистом месте), то вам нужны были и CR и LF.
Если вы посмотрите на большинство интернет протоколов, таких как RFC 0821 (SMTP), RFC 1939 (POP), RFC 2060 (IMAP) или RFC 2616 (HTTP), то вы увидите, что все они указывают пару CR+LF как последовательность, терминирующую строки. Поэтому на самом деле вопрос звучит не как "Почему CP/M, MS-DOS и Win32 используют CR+LF как разделитель строк?", а скорее как "Почему другие люди решили взять другой разделитель, отличный от этих стандартов?".

Unix принял в качестве разделителя строк простой LF. Если вы посмотрите на опции stty, то увидите, что опция onlcr указывает, следует ли менять LF на CR+LF. Если вы установите эту опцию неверно, то вероятнее всего получите текст "лесенкой", где
каждая
строка
начинается
там, где закончилась предыдущая. Так что даже Unix может требовать CR+LF для разделения строк. Неявный CR перед LF - это изобретение Unix, вероятно с целью экономии одного байта на строчку.

Unix является "папой" языка C, поэтому стандарт языка C унаследовал это соглашение: разделителем строк в языке является один символ "\n" (что есть LF). Это загружает runtime библиотеки дополнительной работой по преобразованию одиночных символов в разделители строк.

Также язык C предложил термин "newline" для выражения концепции "общего разделителя строк". Я слышал, что комитет ASCII изменил название символа $0A (LF) на "newline" примерно в 1996, так что уровень запутанности возрос ещё выше.

На сервере подкачка = смерти

Это перевод On a server, paging = death. Автор: Реймонд Чен.

Последний пост Chris Brumme содержал предложение: "на сервере не должно быть подкачки". Это потому что на сервере подкачка (Paging) эквивалентна смерти.

Я как-то встретил человека из другого отдела, который рассказал мне эту маленькую историю: у них был сервер, который умирал каждые 10 часов - точно, как по часам. Для продолжения работы его надо было перезагрузить. Чтобы скрыть эту проблему, сервер был переделан в кластер. Поэтому получалось, что когда отдельная машина в кластере повисала, её перезагружали, а сам кластер продолжал работать, и клиенты ничего не замечали. Но администратры серверов раздражались очень сильно ("Эй Кленси, похоже №2 надо перезагрузить. Она опять висит").

В чём была причина этих зависаний на серверах? В подкачке.

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

После более подробного исследования проблемы, эту утечку нашли и исправили. Теперь сервера в кластере работают гладко и без заминки.

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

Почему текстовые файлы оканчиваются символом Ctrl+Z?

Это перевод Why do text files end in Ctrl+Z? Автор: Реймонд Чен.

Вообще-то, текстовые файлы не обязаны оканчиваться на Ctrl+Z, но это соглашение сохраняется в определённых кругах (хотя, к счастью, сегодня эти круги являются небольшими).

четверг, 5 марта 2009 г.

Чему равен дескриптор безопасности по-умолчанию?

Это перевод What is the default security descriptor? Автор: Реймонд Чен.

Большинство функций ядра имеют параметр, в который вы должны передать указатель на TSecurityAttributes, и в который все всегда передают nil. Документация говорит, что в этом случае объект получает дескриптор безопасности по-умолчанию. Но что такое дескриптор безопасности по-умолчанию?

Мы начнём искать, конечно же, с MSDN - в разделе, озаглавленном Security Descriptors for New Objects.

Там сказано, что DACL по-умолчанию формируется из наследованных ACE (если объект принадлежит какой-либо иерархии, типа файловой системы или реестра) или же из первичного (primary) или имперсонированного (impersonation) токена создателя.

Но что такое первичный токен по-умолчанию?

А, чёрт, я тоже этого не знаю. Так что давайте напишем программку, чтобы узнать это.
uses
JwaWindows;

procedure TForm1.FormCreate(Sender: TObject);
var
Token: THandle;
RequiredSize: DWord;
DefaultDacl: PTokenDefaultDacl;
SD: TSecurityDescriptor;
StringSD: PChar;
begin
if OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token) then
try
RequiredSize := 0;
GetTokenInformation(Token, TokenDefaultDacl, nil, 0, RequiredSize);

GetMem(DefaultDacl, RequiredSize);
try
if GetTokenInformation(Token, TokenDefaultDacl, DefaultDacl, RequiredSize, RequiredSize) and
InitializeSecurityDescriptor(@SD, SECURITY_DESCRIPTOR_REVISION) and
SetSecurityDescriptorDacl(@SD, True, DefaultDacl.DefaultDacl, False) and
ConvertSecurityDescriptorToStringSecurityDescriptor(@SD, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, StringSD, nil) then
try
MessageBox(Handle, StringSD, 'Result', MB_OK);
finally
LocalFree(Cardinal(StringSD));
end;
finally
FreeMem(DefaultDacl);
end;
finally
CloseHandle(Token);
end;
end;
Ладно, я признаю это: единственное назначение всего этого кода только в том, чтобы я вызывал функцию ConvertSecurityDescriptorToStringSecurityDescriptor - наверное, это самое длинное имя функции в Win32 API. А чтобы было ещё веселее, я использовал стиль именования переменных NT вместо венгерской нотации.

Если вы запустите эту программу, то увидите сообщение типа:
D:(A;;GA;;;S-1-5-21-1935655697-839522115-854245398-1003)(A;;GA;;;SY)
Для расшифровки этой строки мы достаём наш полезнейший справочник по формату строкового представления дескриптора безопасности - Security Descriptor String Format:
  • "D:" - указывает, что это DACL.
  • "(A;;GA;;;S-...)" - Разрешить ("Allow") полный доступ ("Generic All") для "S-..." - что, кажется, является моим SID. Т.е. каждый пользователь по-умолчанию имеет полные права для своих процессов.
  • "(A;;GA;;;SY)" - Разрешить ("Allow") полный доступ ("Generic All") для "Local System".

среда, 4 марта 2009 г.

Почему диалоговые окна создаются невидимыми?

Это перевод Why are dialog boxes initially created hidden? Автор: Реймонд Чен.

Если только вы не приглядывались действительно внимательно, вы могли бы и не заметить, что диалоговые окна на самом деле изначально создаются невидимыми, даже если в шаблоне (*) вы указали WS_VISIBLE. И причина опять кроется в истории.

Перемотайте время назад, в старые дни (мы говорим о временах Windows 1.0) видео-карты были медленными, процессоры были медленными и память была медленная. Вы могли выбрать пункт меню, запускающий диалог, и ждать секунду или две, пока диалог не загрузится с дискеты (жёсткие диски были только для богатеньких). А потом вам ещё нужно было дождаться окончания прорисовки.

Чтобы сэкономить ценные секунды, диалоговые окна создавались скрытыми, а весь начальный ввод (т.е. то, что вы понажимали, пока диалог грузился) обрабатывался до показа окна. Диалоговое окно отображалось на экране только когда заканчивалась обработка начального ввода. И если вы печатали быстро, то вы могли успеть вбить все команды и нажать Enter до того как диалог показался. В этом случае диалог не показывался вовсе! Вот это эффективность.

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

Вообще-то даже сегодня это поведение бывает полезным: если бы диалоговые окна показывались изначально видимыми, то пользователь видел бы, как создаются все элементы управления, как обрабатывается WM_INITDIALOG (обработчик которого обычно изменяет значения по-умолчанию на реальные, скрывает и показывает контролы и т.п.). Это было бы и некрасиво и сбивало бы с толку ("как это все флажки показываются установленными, а потом неожиданно меняются, причём до того, как я по ним успеваю щёлкнуть").

Примечание переводчика:
(*) Речь идёт о системных диалогах, формируемых шаблоном, а вовсе не о диалогах в Delphi (где это обычные окна). Впрочем, в какой-то мере сказанное справедливо и в этом случае тоже.

Почему операции с Byte дают в результате Integer?

Это перевод Why do operations on "byte" result in "int"? Автор: Реймонд Чен.

Люди жалуются, что следующий код выдаёт ошибку:
const
  B = Byte(1);
  C: Byte = not B; // Constant expression violates subrange bounds (*)
Они говорят: "Результат операции с 'Byte' должен быть ещё одним 'Byte', а не 'Integer'".

Будьте осторожны в своих желаниях. Они могут вам не понравиться.

воскресенье, 1 марта 2009 г.

Под Char.IsDigit() подходит больше символов, чем только "0".."9"

Это перевод Char.IsDigit() matches more than just "0" through "9". Автор: Реймонд Чен.

Внимание: впереди тема .NET!
Вчера, Брэд Абрамс заметил, что метод Char.IsLetter() фильтрует больший диапазон символов, чем просто от "A" до "Z".
Но что люди действительно могут не осознавать, так это то, что Char.IsDigit() соответствует не только символам от "0" до "9".
Допустимые цифры являются членами следующей категории в UnicodeCategory: DecimalDigitNumber.
Но что конкретно принадлежит DecimalDigitNumber?
DecimalDigitNumber
Указывает, что символ является десятичной цифрой; т.е. находится в диапазоне от 0 до 9. Обозначается Unicode названием "Nd" (номер, десятичная цифра). Имеет код 8.
К этому моменту вам нужно зайти на сайт Unicode Standard Committee, чтобы посмотреть, что же в точности принимается за "Nd", и тогда вы затеряетесь в запутанном лабиринте различных спецификаций и документов.

Давайте проведём эксперимент.
class Program {
public static void Main(string[] args) {
System.Console.WriteLine(
System.Text.RegularExpressions.Regex.Match(
"\x0661\x0662\x0663", // "١٢٣"
"^\\d+$").Success);
System.Console.WriteLine(
System.Char.IsDigit('\x0661'));
}
}
Символы в строке являются арабскими цифрами - но они всё же цифры, что и подтверждается следующим выводом программы:
True
True
Ой. А нет ли у вас бага при проверке параметров? Если вы использовали шаблон типа @"^\d$" для проверки того, что вы получили только цифры, а потом позже использовали System.Int32.Parse() для парсинга этой строки, тогда я могу скормить вам несколько арабских цифр, откинуться на спинку кресла и наслаждаться получившимся фейерверком. Арабские цифры пройдут ваши проверки, но как только вы попытаетесь использовать - бум! - вы возбуждаете System.FormatException и умираете.

Читать далее.

Надувательство процесса WHQL-сертификации драйверов

Это перевод Defrauding the WHQL driver certification process. Автор: Реймонд Чен.

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

Если вы не измените интерфейс - вашу работу никто не заметит

Это перевод If You Don't Change the UI, Nobody Notices. Автор: Джефф Этвуд.

Несколько дней назад я увидел скриншот, из-за которого я решил, что Windows 7 Beta стоит того, чтобы на неё взглянуть.


Да, точно - Microsoft наконец-то улучшила калькулятор! Мы годами жаловались на то, что Microsoft выпускает новые версии операционных систем со всё теми-же старыми приложениями, что и у предыдущей версии. И из-за этого вся новая система выглядит не лучшим образом:
Я знаю, что это прозвучит ужасно тривиальным. Но не является ли уместность и завершённость небольших программ типа этих: Блокнот, Калькулятор, Таблица Символов, Paint, Очистка Диска, Сжатие папок и дюжины других - показателем усилий и заботы, вложенных во всю операционную систему? Если Microsoft не хочет даже добавить, скажем, тулбар в Блокнот (такую простую вещь!), то что же тогда творится с остальной операционной системой?
Если вы визуально сравните калькулятор и блокнот в Windows XP из эры 2001 с их аналогами в Windows Vista 2007-й эры, то вы можете решить, что они идентичны. Но, как говорит Реймонд Чен, это не так:
Когда люди жалуются, что программы Calc (калькулятор) и Notepad (блокнот) не меняются, я нахожу это забавным. Потому что, все эти программы менялись (у блокнота появились новые пункты в меню и настройки строки статуса. Калькулятор вообще был переписан с нуля).

Я не удивлюсь, если это окажутся те же самые люди, которые жалуются: "Почему Microsoft тратит все свои силы на то, чтобы Windows 'выглядела круто'? Им следовало бы направить эти усилия на технические улучшения и перестать играться с визуальным оформлением".

Но именно это и произошло с калькулятором: значительные технические изменения. Но визуальный интерфейс не трогали. И никто ничего не заметил. Фактически, жалобы просто продолжились: "ну посмотрите на этот калькулятор - как был, так и остался".

Внутренности калькулятора - арифметический движок - были выброшены на свалку и переписаны с нуля. Стандартная библиотека чисел с плавающей запятой IEEE была заменена на библиотеку, поддерживающую числа с произвольной точностью. Это было сделано из-за того, что люди продолжали писать ха-ха истории в стиле, как калькулятор не умеет считать: например, вычисляя 10.21 - 10.2 и получая 0.0100000000000016.

Сегодня, все внутренние вычисления в калькуляторе выполняются с бесконечной точностью для основных операций (сложение, вычитание, умножение и деление) и с точностью до 32 цифр для расширенных операций (квадратный корень и трансцендентные операции).
Это, вероятно, идеальный пост Реймонда Чена - технически точный, он одновременно доказывает, что быть технически точным совершенно неактуально. В этом и есть Раймонд Чен: он загадка, завернутая в тайну внутри загадки, покрытая сверху вкусным соусом секрета.

Вот почему, этот скриншот калькулятора в Windows 7, хотя и является таким простым, так взволновал меня. Это указание на то, что Microsoft в этот раз собирается уделить больше внимания видимым частям операционной системы. Я большой поклонник Vista (прим.пер.: и я тоже! XD ), несмотря на бушующие вокруг неё споры, но я первый готов признать, что Vista наводит блеск на тупом булыжнике (Vista had all the polish of a particularly dull rock). Скажем так, что общий опыт общения пользователя с ОС был... не воодушевляющим. Это заставило многих людей плюнуть, вздохнуть: "ну и зачем суетиться?", и остаться на старушке XP.

Да, очень жаль. Потому что если вы копнёте поглубже, то найдёте в Vista огромные технические преимущества над, теперь уже древней, Windows XP. Но многие из этих улучшений были сделаны "под капотом" и поэтому невидимы для обычного пользователя.


Запомните: если пользователь не может найти вашу функцию - то её здесь нет. Не начинайте улучшать свой продукт, если только вы не предусмотрели изменения, видимые пользователю (и которые, надеюсь, придутся ему по вкусу).

Примечание переводчика:
Посмотрите сколько положительных отзывов получает Windows 7. И даже от тех людей, который плевались на Vista (хотя 7-ка - это просто приглаженная Vista). Так что если в следующий раз кто-то будет говорить "не надо нам рюшечек - давайте функциональность" - плюньте ему в лицо :))

Когда вы меняете что-то внутри - то этого никто не замечает

Это перевод When you change the insides, nobody notices. Автор: Реймонд Чен.

Когда люди жалуются, что программы Calc (калькулятор) и Notepad (блокнот) не меняются, я нахожу это забавным. Потому что, все эти программы менялись.