Это перевод Disabling the program crash dialog. Автор: Реймонд Чен.
Если вы не хотите, чтобы ваша программа в случае вылета показывала бы стандартный диалог о вылете, то вы можете отключить его установкой флага SEM_NOGPFAULTERRORBOX для режима ошибок процесса (process error mode).
...when altering one's mind becomes as easy as programming a computer, what does it mean to be human?..
суббота, 16 мая 2009 г.
Компьютер длиной 6 метров
Это перевод A twenty-foot-long computer. Автор: Реймонд Чен.
Когда-то во времена Windows 95, когда Plug and Play был в зачаточном состоянии, одной из вещей, которые нужно было сделать команде разработчиков Plug and Play - это выжать из спецификации PCI всё, что можно, вплоть до абсурдного предела.
Когда-то во времена Windows 95, когда Plug and Play был в зачаточном состоянии, одной из вещей, которые нужно было сделать команде разработчиков Plug and Play - это выжать из спецификации PCI всё, что можно, вплоть до абсурдного предела.
Почему некоторые убитые процессы продолжают показываться в Диспетчере Задач?
Это перевод Why do some process stay in Task Manager after they've been killed? Автор: Реймонд Чен.
Когда процесс завершается (либо по естественным причинам, либо из-за чего-то более грубого, типа TerminateProcess) - часть процесса, принадлежащая пользовательскому режиму, отбрасывается. Но часть процесса от режима ядра не может быть отброшена, пока все драйверы не закончат работу с потоком.
Например, если поток во время завершения производил операцию ввода-вывода (I/O operation), то ядро оповещает драйвер, выполняющего эту операцию, о том, что эту операцию надо бы отменить. Если драйвер - "хороший", то он отменяет недовыполненный запрос ввода-вывода и отпускает поток.
Если же драйвер не слишком хорошо написан (или же это выделывается железо, которым управляет драйвер), то отмена запроса может занять много времени, т.к. драйвер попросту будет ждать завершения операции. В это время драйвер держит в заложниках поток, сделавший запрос (а, следовательно, и процесс, которому принадлежит поток).
Ну, это вообще-то упрощённая картина того, что происходит на самом деле. Комментатор Commenter Skywing дал более точное объяснение для тех, кто любит более точные объяснения.
Если вы считаете, что у вас проблема из-за плохого драйвера, вы можете, используя отладчик режима ядра, найти застрявший процесс и взглянуть на его потоки, чтобы узнать, почему они не завершаются. Вы можете использовать команду отладчика !irp для просмотра всех активных IRP, чтобы увидеть, какое устройство ещё не ответило.
После того, как все драйверы признали смерть процесса, "мясо" процесса наконец-то уходит. Всё, что после него остаётся - "объект процесса", который живёт до тех пор, пока не закроются все описатели процесса и его потоков (вы ведь не забываете вызывать CloseHandle для закрытия дескрипторов в записи TProcessInformation, возвращаемой вам функцией CreateProcess, не так ли?).
Другими словами, если процесс всё ещё слоняется по округе после того, как вы его убили - то это значит, что он действительно мёртв, просто не все системные драйверы поставили на это событие своё "добро".
Когда процесс завершается (либо по естественным причинам, либо из-за чего-то более грубого, типа TerminateProcess) - часть процесса, принадлежащая пользовательскому режиму, отбрасывается. Но часть процесса от режима ядра не может быть отброшена, пока все драйверы не закончат работу с потоком.
Например, если поток во время завершения производил операцию ввода-вывода (I/O operation), то ядро оповещает драйвер, выполняющего эту операцию, о том, что эту операцию надо бы отменить. Если драйвер - "хороший", то он отменяет недовыполненный запрос ввода-вывода и отпускает поток.
Если же драйвер не слишком хорошо написан (или же это выделывается железо, которым управляет драйвер), то отмена запроса может занять много времени, т.к. драйвер попросту будет ждать завершения операции. В это время драйвер держит в заложниках поток, сделавший запрос (а, следовательно, и процесс, которому принадлежит поток).
Ну, это вообще-то упрощённая картина того, что происходит на самом деле. Комментатор Commenter Skywing дал более точное объяснение для тех, кто любит более точные объяснения.
Если вы считаете, что у вас проблема из-за плохого драйвера, вы можете, используя отладчик режима ядра, найти застрявший процесс и взглянуть на его потоки, чтобы узнать, почему они не завершаются. Вы можете использовать команду отладчика !irp для просмотра всех активных IRP, чтобы увидеть, какое устройство ещё не ответило.
После того, как все драйверы признали смерть процесса, "мясо" процесса наконец-то уходит. Всё, что после него остаётся - "объект процесса", который живёт до тех пор, пока не закроются все описатели процесса и его потоков (вы ведь не забываете вызывать CloseHandle для закрытия дескрипторов в записи TProcessInformation, возвращаемой вам функцией CreateProcess, не так ли?).
Другими словами, если процесс всё ещё слоняется по округе после того, как вы его убили - то это значит, что он действительно мёртв, просто не все системные драйверы поставили на это событие своё "добро".
Почему я не могу перехватить TerminateProcess?
Это перевод Why can't you trap TerminateProcess? Автор: Реймонд Чен.
Если пользовать запускает менеджер задач и щёлкает по кнопке "Снять Задачу", то Windows сначала попробует закрыть вас мягко: отправляя сообщения WM_CLOSE для GUI-программы или событие CTRL_CLOSE_EVENT для консольных программ. Но у вас нет аналогичного способа отреагировать на TerminateProcess. Почему нет?
Если пользовать запускает менеджер задач и щёлкает по кнопке "Снять Задачу", то Windows сначала попробует закрыть вас мягко: отправляя сообщения WM_CLOSE для GUI-программы или событие CTRL_CLOSE_EVENT для консольных программ. Но у вас нет аналогичного способа отреагировать на TerminateProcess. Почему нет?
воскресенье, 10 мая 2009 г.
Как определить включение "больших шрифтов"?
Это перевод How do you detect "Large Fonts"? Автор: Реймонд Чен.
Когда люди спрашивают "Как мне определить, что включены большие шрифты?", они на самом деле спрашивают не именно о больших шрифтах. Скорее, большие шрифты - это просто обобщение для "необычное DPI".
По-умолчанию Windows использует DPI равное 96 пикслей на дюйм (pixels per inch). Другими словами, если Windows хочет нарисовать линию длиной 1 дюйм, она рисует 96 пикселей. Конечно же, реальный физический размер этой линии зависит от вашего разрешения экрана и размера вашего монитора. Значение 96 - это просто формальность.
Вы можете изменить это значение DPI в настройках экрана в Панели управления, либо выбором опции Большие Шрифты, либо выбором пользовательского размера шрифта. Стандартный размер - это 96 dpi, Большой - это 120 dpi, пользовательский - это, ну, пользовательский.
DPI выше 96 будут становиться всё более частым выбором с улучшением технологии LCD. Программы могут запросить настройки DPI с помощью вызова GetDeviceCaps с LOGPIXELSX экранного DC.
В старые дни было много устройств с не-квадратными пикселями. Например, у видео-адаптера EGA были пиксели, высота которых в 1.33 раза больше их ширины.
Для устройств с не-квадратными пикселями, значения LOGPIXELSX и LOGPIXELSY будут различными. На EGA, если значение метрики LOGPIXELSX было 96, тогда метрика LOGPIXELSY было бы 72, т.к. в одном дюйме было бы 72 пикселей по вертикали. Аналогично, значения ASPECTX, ASPECTY и ASPECTXY для не-квадратных пикселей тоже выглядят достаточно интересно, как показано на этой диаграмме:
36
27
45
Значение ASPECTX равно 27, а ASPECTY - 36, показывая соотношение 4:3 вертикали к горизонтали, а ASPECTXY равно 45, представляя гипотенузу.
Когда люди спрашивают "Как мне определить, что включены большие шрифты?", они на самом деле спрашивают не именно о больших шрифтах. Скорее, большие шрифты - это просто обобщение для "необычное DPI".
По-умолчанию Windows использует DPI равное 96 пикслей на дюйм (pixels per inch). Другими словами, если Windows хочет нарисовать линию длиной 1 дюйм, она рисует 96 пикселей. Конечно же, реальный физический размер этой линии зависит от вашего разрешения экрана и размера вашего монитора. Значение 96 - это просто формальность.
Вы можете изменить это значение DPI в настройках экрана в Панели управления, либо выбором опции Большие Шрифты, либо выбором пользовательского размера шрифта. Стандартный размер - это 96 dpi, Большой - это 120 dpi, пользовательский - это, ну, пользовательский.
DPI выше 96 будут становиться всё более частым выбором с улучшением технологии LCD. Программы могут запросить настройки DPI с помощью вызова GetDeviceCaps с LOGPIXELSX экранного DC.
function GetScreenDPI: Integer;Код выше предполагает, что пиксели являются квадратными, что имеет место для большинства современных устройств (вы можете устанавливать необычные экранные разрешения, при которых пиксели не будут квадратными, но большинство людей избегают таких разрешений).
var
hdcScreen: HDC;
begin
hdcScreen := GetDC(0);
if hdcScreen = 0 then
RaiseLastOSError;
try
Result := GetDeviceCaps(hdcScreen, LOGPIXELSX);
finally
ReleaseDC(0, hdcScreen);
end;
end;
В старые дни было много устройств с не-квадратными пикселями. Например, у видео-адаптера EGA были пиксели, высота которых в 1.33 раза больше их ширины.
Для устройств с не-квадратными пикселями, значения LOGPIXELSX и LOGPIXELSY будут различными. На EGA, если значение метрики LOGPIXELSX было 96, тогда метрика LOGPIXELSY было бы 72, т.к. в одном дюйме было бы 72 пикселей по вертикали. Аналогично, значения ASPECTX, ASPECTY и ASPECTXY для не-квадратных пикселей тоже выглядят достаточно интересно, как показано на этой диаграмме:
36
27
45
Значение ASPECTX равно 27, а ASPECTY - 36, показывая соотношение 4:3 вертикали к горизонтали, а ASPECTXY равно 45, представляя гипотенузу.
Аккуратнее с этими URL для примеров
Это перевод Watch out for those sample URLs. Автор: Реймонд Чен. Входит в книгу The Old New Thing.
Когда мы пишем документацию, нам иногда нужно вставить URL-пример, чтобы продемонстрировать что-то. Когда вы это делаете, убедитесь, что URL для примера находится под вашим контролем.
Когда мы пишем документацию, нам иногда нужно вставить URL-пример, чтобы продемонстрировать что-то. Когда вы это делаете, убедитесь, что URL для примера находится под вашим контролем.
Позиционный и не-позиционный виды в ListView
Это перевод Positioned vs. non-positioned listview views. Автор: Реймонд Чен.
Иногда мне попадаются вопросы, возникающие из-за непонимания разницы между позиционными (positioned) и не-позиционными (non-positioned) видами ListView. Вопрос обычно содержит строки наподобие: "Я вставляю новый элемент с помощью LVM_INSERTITEM, но он появляется в конце списка, а не в той позиции, что я указал".
Иногда мне попадаются вопросы, возникающие из-за непонимания разницы между позиционными (positioned) и не-позиционными (non-positioned) видами ListView. Вопрос обычно содержит строки наподобие: "Я вставляю новый элемент с помощью LVM_INSERTITEM, но он появляется в конце списка, а не в той позиции, что я указал".
Как "Установка и удаление программ" получает размер программы и другую информацию?
Это перевод How does Add/Remove Programs get the size and other information? Автор: Реймонд Чен.
Если программа сама не предоставляет эту информацию, "Установка и удаление программ" вынуждена угадывать.
Если программа сама не предоставляет эту информацию, "Установка и удаление программ" вынуждена угадывать.
среда, 6 мая 2009 г.
В чём разница между SHGetMalloc, SHAlloc, CoGetMalloc и CoTaskMemAlloc?
Это перевод What's the difference between SHGetMalloc, SHAlloc, CoGetMalloc, and CoTaskMemAlloc? Автор: Реймонд Чен.
Ну, сегодня это уже одно и то же.
Ну, сегодня это уже одно и то же.
Не называйте вашу DLL именем "Security.dll"
Это перевод Don't name your DLL "Security.dll". Автор: Реймонд Чен.
Снова ныряем в водоворот истории...
Некоторые люди обнаружили, что если вы назовёте свою DLL "security.dll", то начнут происходить странные вещи.
Снова ныряем в водоворот истории...
Некоторые люди обнаружили, что если вы назовёте свою DLL "security.dll", то начнут происходить странные вещи.
Почему я не могу использовать один TTreeItem в нескольких местах?
Это перевод Why can't I use the same tree item multiple times? Автор: Реймонд Чен.
Это продолжение борьбы между гибкостью и простотой использования.
Вы не можете использовать один и тот же элемент дерева (tree item) в нескольких местах, потому что тогда многие свойства узла станут неоднозначными - например, свойства типа Parent или Expanded (если узел может быть в двух местах, то у него будет два родителя, один из которых может быть развёрнут, а второй - нет).
Конечно же, эта проблема может быть решена отделением содержания узла от его местоположения. Так, например, вместо просто дескриптора HTREEITEM, у нас могли бы быть, скажем, HTREENODE и HTREENODECONTENTS. Узел (node) мог бы представлять собой место в дереве, а элемент (item) мог представлять сами данные: имя, иконка и т.п.
Конечно, так можно было бы сделать, но не забывайте о балансе. Вы делаете общим случаем сложный вариант, только ради того, чтобы облегчить редкие сценарии. Теперь, всякий, кто стал бы работать с деревом, был бы вынужден иметь дело со всеми этими новыми сложностями (то, что раньше было одним элементом, теперь стало двумя). Обычно это не тот баланс, которого вы хотите достигнуть, когда проектируете интерфейс.
Когда вы проектируете интерфейс, вы должны хотеть упростить действия для типичных сценариев, а не для редких.
А программа, которая хочет иметь такое разделение, вполне может сделать его руками. Положите все данные в отдельную запись и пусть ваши узлы в дереве ссылаются на неё (через св-во Data). Да, теперь у программы будет больше работы, но только сейчас эта дополнительные расходы идут только для тех, кому нужна дополнительная функциональность.
Это продолжение борьбы между гибкостью и простотой использования.
Вы не можете использовать один и тот же элемент дерева (tree item) в нескольких местах, потому что тогда многие свойства узла станут неоднозначными - например, свойства типа Parent или Expanded (если узел может быть в двух местах, то у него будет два родителя, один из которых может быть развёрнут, а второй - нет).
Конечно же, эта проблема может быть решена отделением содержания узла от его местоположения. Так, например, вместо просто дескриптора HTREEITEM, у нас могли бы быть, скажем, HTREENODE и HTREENODECONTENTS. Узел (node) мог бы представлять собой место в дереве, а элемент (item) мог представлять сами данные: имя, иконка и т.п.
Конечно, так можно было бы сделать, но не забывайте о балансе. Вы делаете общим случаем сложный вариант, только ради того, чтобы облегчить редкие сценарии. Теперь, всякий, кто стал бы работать с деревом, был бы вынужден иметь дело со всеми этими новыми сложностями (то, что раньше было одним элементом, теперь стало двумя). Обычно это не тот баланс, которого вы хотите достигнуть, когда проектируете интерфейс.
Когда вы проектируете интерфейс, вы должны хотеть упростить действия для типичных сценариев, а не для редких.
А программа, которая хочет иметь такое разделение, вполне может сделать его руками. Положите все данные в отдельную запись и пусть ваши узлы в дереве ссылаются на неё (через св-во Data). Да, теперь у программы будет больше работы, но только сейчас эта дополнительные расходы идут только для тех, кому нужна дополнительная функциональность.
Подписаться на:
Сообщения (Atom)