среда, 31 августа 2011 г.

Как экспортируются DLL функции в 32-битных Windows?

Это перевод How are DLL functions exported in 32-bit Windows? Автор: Реймонд Чен.

Дизайнерам 32-битных Windows не нужно было беспокоиться о втискивании в 256 Кб памяти. Поскольку модули в Win32 построены на загрузке по запросу, то всё, что вам нужно сделать - спроецировать весь образ в память, а затем коснуться тех частей, которые вам нужны. Поэтому нет никакого различия между резидентной и не резидентной таблицами, так что имена экспортируемых функций просто записываются в исполняемый образ вместе с указателем (вернее относительным виртуальным адресом) на имя, хранимое в таблице экспорта.

вторник, 30 августа 2011 г.

Как импортировались DLL функции в 16-битных Windows?

Это перевод How were DLL functions imported in 16-bit Windows? Автор: Реймонд Чен.

В прошлый раз я рассказал о том, как экспортировались функции в 16-битных Windows. Сегодня мы посмотрим на их импорт.

понедельник, 29 августа 2011 г.

Как экспортировались DLL функции в 16-битных Windows?

Это перевод How were DLL functions exported in 16-bit Windows? Автор: Реймонд Чен.

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

В любом случае, давайте начнём с того, как 16-битные Windows управляли импортом и экспортом. После этого мы посмотрим что было изменено при миграции на 32-битные Windows, а затем мы посмотрим на импорт с точки зрения компилятора.

воскресенье, 28 августа 2011 г.

Pidl и моникеры делают примерно одно и то же, только по-разному

Это перевод Pidls and monikers do roughly the same thing, just backwards. Автор: Реймонд Чен.

Работая с Оболочкой (Shell) Windows, вам наверняка в какой-то момент пришлось работать с указателем на список ID элементов (pointer to item ID list), известным как "pidl" (рифмуется с "middle"). С другой стороны, работая с OLE, вы могли работать с моникерами (moniker). В каком-то смысле они делают одно и то же. Они позволяют вам ссылаться на какой-то объект внутри пространства имён (с которым вы как-то работаете), они имеют иерархическую структуру, вы можете их сериализовать и т.п.

Но почему тогда команда Оболочки Windows изобрела pidl-ы, если моникеры делали ровно это же?

суббота, 27 августа 2011 г.

Не всякий человек с не-Windows разделом является гиком

Это перевод Not everybody with a non-Windows partition type is a geek. Автор: Реймонд Чен.

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

пятница, 26 августа 2011 г.

Прежде чем учиться опознавать неправильное, вам нужно узнать, что есть правильное

Это перевод Before you can learn to recognize what's wrong, you must learn to recognize what's right. Автор: Реймонд Чен.

Иногда, когда я отлаживаю проблему, я могу проигнорировать какой-то поток, а кто-то спросит: "а что делает этот поток? Почему ты его игнорируешь?"

Мой ответ: "Я понятия не имею, что он делает, но что бы он ни делал, это - нормально".

четверг, 25 августа 2011 г.

Нет, а почему именно 160x31?

Это перевод No, really, why is it 160x31? Автор: Реймонд Чен.

Когда я ранее пояснял, почему свёрнутые (минимизированные) окна имеют размер 160x31, я не пояснил, почему размером выбрано именно ровно 160 и 31.

среда, 24 августа 2011 г.

Максимальный размер переменных окружения - это 32 или 64 Кб?

Это перевод Is the maximum size of the environment 32K or 64K? Автор: Реймонд Чен.

Кажется, есть некоторая путаница в максимальном размере переменных окружения: 32 Кб или 64 Кб. Какое значение правильное?

вторник, 23 августа 2011 г.

Безопасность: не забывайте обнулять вещи, на которые вам наплевать

Это перевод Security: Don't forget to initialize the stuff you don't care about. Автор: Реймонд Чен.

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

понедельник, 22 августа 2011 г.

Событие с авто-сбросом - это просто глупый семафор

Это перевод An auto-reset event is just a stupid semaphore. Автор: Реймонд Чен.

Когда вы создаёте событие с помощью функции CreateEvent, вы указываете, хотите ли вы создать событие с авто-сбросом (auto-reset event) или с ручным сбросом (manual-reset event).

Событие с ручным сбросом прозрачно для понимания: если событие сброшено, то вы ждёте сигнального состояния; если событие установлено (в сигнальном состоянии), то ожидания не происходит (ожидание удовлетворяется сразу). Не играет значения, сколько человек ждут события; они все обрабатываются одинаково, а состояние события не зависит от числа его ожидающих.

Событие с авто-сбросом - более запутывающая штука.

воскресенье, 21 августа 2011 г.

Одноэкземплярная программа является своим собственным отказом в обслуживании

Это перевод A single-instance program is its own denial of service. Автор: Реймонд Чен.

Есть много способов, которыми программа может достичь поведения запуска в едином экземпляре; я не буду разбирать их. Но как только люди встают на путь программы с одним запущенным экземпляром, они тут же спотыкаются о другую проблему при анализе безопасности: отказ в обслуживании (denial of service attack).
Мы используем мьютекс с фиксированным именем, чтобы определить, не запущена ли уже копия программы. Но это также означает, что злоумышленник может создать мьютекс с таким именем до запуска программы, блокируя, таким образом, запуск нашей программы! Как я могу предотвратить этот тип отказа в обслуживании?

суббота, 20 августа 2011 г.

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

Это перевод Why can't you programmatically reorder the items on the Start menu? Автор: Реймонд Чен.

Классическое меню Пуск и часть "Все программы" меню Пуск в стиле Windows XP позволяют вам изменить порядок ярлыков, показываемых в них. Вы можете использовать перетаскивание для его упорядочивания, либо же просто использовать сортировку по имени. Но почему нет никакого программного интерфейса для выполнения этих операций?

пятница, 19 августа 2011 г.

Разбираемся, что на самом деле значит "значимые цифры"

Это перевод Understanding what significant digits really mean. Автор: Реймонд Чен.

Числа с плавающей запятой двойной точности (double-precision floating point number) содержат 15 значащих цифр. Что это значит на самом деле?
Я умножил 0,619207 на 10'000'000 и получил 6'192'069,999999991 вместо 6'192'070. Это же только шесть цифр; где мои обещанные пятнадцать?

четверг, 18 августа 2011 г.

Свойства оконных классов применяются ко всем окнам этого класса

Это перевод Window class properties apply to all windows that belong to the class. Автор: Реймонд Чен.

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

среда, 17 августа 2011 г.

Подводные камни вывода сглаженного текста с прозрачным фоном

Это перевод Pitfalls of transparent rendering of anti-aliased fonts. Автор: Реймонд Чен.

Windows предоставляет несколько технологий рендеринга монохромного текста на цветных экранах, пользуясь преимуществами характеристик экрана для предоставления гладкого результата. Эти техники включают в себя сглаживание (grayscale anti-aliasing), а также и более продвинутую технику - ClearType. Обе техники читают фоновые пиксели, чтобы определить, что рисовать. Это означает, что рендеринг текста требует дополнительного внимания.

вторник, 16 августа 2011 г.

Блуждая в темноте и спотыкаясь о неверное решение

Это перевод Fumbling around in the dark and stumbling across the wrong solution. Автор: Реймонд Чен.

Я не хотел придираться к этой серии записей, но она иллюстрирует интересный шаблон спотыкания на неверном "решении".

Эта серия пытается запустить системный триггер неактивности монитора отправкой сообщения окну рабочего стола (desktop window).

понедельник, 15 августа 2011 г.

Помните, что происходит, когда вы делаете широковещательную рассылку

Это перевод Remember what happens when you broadcast a message. Автор: Реймонд Чен.

Иногда я вижу, как люди делают вещи вроде широковещательной рассылки (broadcasting) сообщения WM_COMMAND всем окнам верхнего уровня (top-level windows). Это одна из вещей, которые настолько очевидно неправильные, что я не понимаю, как кому-то вообще может приходить в голову идея, что это будет работать.

воскресенье, 14 августа 2011 г.

Забытые элементы управления: функция MenuHelp

Это перевод The forgotten common controls: The MenuHelp function. Автор: Реймонд Чен.

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

суббота, 13 августа 2011 г.

Что делает стиль оконного класса CS_CLASSDC?

Это перевод What does the CS_CLASSDC class style do? Автор: Реймонд Чен.

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

Стиль CS_CLASSDC - это то же самое, только хуже. Потому что он берёт все проблемы CS_OWNDC и умножает их.

пятница, 12 августа 2011 г.

Что делает стиль оконного класса CS_OWNDC?

Это перевод What does the CS_OWNDC class style do? Автор: Реймонд Чен.

Вспомните, что оконные DC (device context - контексты устройств) обычно используются только временно. Если вам нужно нарисовать что-то на окне, то вы вызываете BeginPaint или, если рисование происходит вне цикла рисования, GetDC (хотя вам следует избегать прорисовки вне цикла рисования). Оконный менеджер создаёт для окна DC и возвращает его. Вы используете полученный DC для рисования, а затем восстанавливаете состояние окна, возвращая DC оконному менеджеру вызовом EndPaint (или ReleaseDC). Внутренне, оконный менеджер хранит небольшой кэш DC, который он использует, когда его просят дать DC для окна, и когда DC возвращается - он помещается обратно в кэш (прим.пер.: отдельный кэш каждому потоку, кэш - per-thread). Поскольку оконные DC используются только временно, то число кэшированных DC обычно не сильно велико, так что небольшой кэш достаточен, чтобы удовлетворять запросы на DC в типичной работающей системе.

Если вы регистрируете оконный класс с флагом CS_OWNDC в классовых стилях, то оконный менеджер создаст DC для окна и поместит его в кэш, пометив специальным флагом "Не удалять этот DC из кэша, потому что он принадлежит окну с CS_OWNDC". Если вы вызовите BeginPaint или GetDC для получения DC окна со стилем CS_OWNDC, то этот DC всегда будет найден в кэше и всегда будет помещаться обратно в него (потому что он был помечен "никогда не удалять"). Из этого есть следствия: хорошие, плохие и ещё хуже.

среда, 10 августа 2011 г.

Если вы собираетесь эмулировать действия пользователя, убедитесь, что пользователь вообще смог бы их сделать

Это перевод If you're going to try to simulate user actions, make sure the user can do them. Автор: Реймонд Чен.

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

вторник, 9 августа 2011 г.

Забытые элементы управления: прокрутка страниц

Это перевод The forgotten common controls: The page scroller. Автор: Реймонд Чен.

Элемент управления "pager" был впервые представлен в библиотеке общих элементов управления (common controls library), которая поставлялась с Internet Explorer 4.0. Он был предназначен для реализации прокручивающихся меню в меню Пуск и меню Избранное (меню Пуск и Избранное не являются меню в смысле Win32 API. Они представляют собой пользовательские элементы управления, которые ведут себя аналогично классическим меню; пример fakemenu показывает эту основную идею). Меню было завёрнуто в элемент pager, и он предоставляет меню поведение прокрутки.

понедельник, 8 августа 2011 г.

Хак №15: замещение динамических и message-методов в run-time

Это перевод Hack#15: Overriding message and dynamic methods at run-time. Автор: Hallvard Vassbotn.

В прошлый раз мы посмотрели на способ полной замены класса. Как мы говорили, у этой техники есть несколько проблем. Но есть много способов снять шкуру с кошки (извините, любители кошек!), и в нашем случае (исправление мерцания TProgressBar без изменения интерфейса этого класса) есть как минимум три других решения.

воскресенье, 7 августа 2011 г.

Хак №14: изменение класса объекта в run-time

Это перевод Hack#14: Changing the class of an object at run-time. Автор: Hallvard Vassbotn.

Иногда (вроде, когда вам по той или иной причине нужно сохранить обратную совместимость с бинарным dcu) вам может быть необходимым использовать хак или два. Один такой хак заключается в изменении класса объекта в run-time. К примеру, это может понадобится для изменения виртуального, динамического или message-метода.

суббота, 6 августа 2011 г.

Анализ хака добавления "published" свойства без изменения класса

Это перевод Review: Delphi 2007 for Win32 (Beta) - part three. Автор: Hallvard Vassbotn.

Прим.пер.: в оригинале это была серия из трёх статей по обзору нововведений в Delphi 2007. Я оставил лишь одну часть, которая говорит не столько про нововведения, сколько про хаки - как часть серии "Хак №X".

В VCL (а равно и в RTL) появилось несколько исправлений багов, но мы не будем их рассматривать. Хотя Delphi 2007 остаётся совместимой с бинарными .dcu файлами предыдущей версии Delphi, CodeGear, тем не менее, удалось добавить новую функциональность и даже новые свойства в существующий класс TCustomForm. Как они это сделали?

пятница, 5 августа 2011 г.

Как добавить published свойство без нарушения совместимости DCU

Это перевод How to add a "published" property without breaking DCU compatibility. Автор: Allen Bauer.

Во-первых, если вы пурист ООП или фреймворков и имеете слабый желудок - лучше закройте эту страницу прямо сейчас.

В ожидаемом релизе Delphi 2007 for Win32 мы взяли беспрецедентный подход к расширению функциональности VCL. Если вы использовали Delphi более нескольких её версий, то вы очень хорошо знаете, что такое смена версии - это необходимость получить новые версии всех компонентов. Я не буду сейчас обсуждать причины этого, поскольку я уже неоднократно покрыл это в деталях за всё это время. В основном это сводится к тому, что нам нужна гибкость для внесения изменений в существующие классы и сам компилятор по своему усмотрению, чтобы обеспечить лучшее общее впечатление, какое только мы можем. Таким образом, для всех вас, кто собирается делать возмущённые комментарии по поводу "почему бы вам не делать это в каждом выпуске!?" - если бы мы делали это, то вы бы никогда не имели новых возможностей компилятора - пакетов, интерфейсов, классовых переменных, встроенных (inline) функций, а также генериков (пост-Delphi 2007). Просто просмотрите некоторые из моих прошлых постов для более подробной информации.

И несмотря на всё вышесказанное, мы решили следовать иному подходу при выпуске Delphi 2007. D2007 предназначено быть "non-breaking" выпуском. Что в точности это означает? В корне это означает, что вы можете просто взять большинство своих компонентов и модулей, собранных в BDS2006, и установить их в D2007. Я говорю "большинство" потому что, конечно же, будут какие-то краевые случаи, когда это не будет возможным. К примеру, если компонент работает с какими-то внутренними вещами в обход общедоступного/документированного интерфейса, а эти "вещи за сценой" изменены - такое поведение не является целью для "non-breaking" изменений. До тех пор, пока ваш (или сторонний) код придерживается общепринятого контракта - он будет работать без перекомпиляции.

Эмм... а что-ж тогда нового?? Это правда, что мы изменили много кода, и эти изменения были сделаны только в секции implementation - так что мы не меняли интерфейс и не нарушили совместимость двоичных DCU. Но в новостях объявлено о некоторых изменениях, которые проявляются либо в новых компонентах, либо в новых published свойствах! Правила по совместимости типов компилятора Delphi обманчиво просты. В принципе, для любого структурированного типа (класса, записи, объекта и т.п.) "версия" этого типа или символа выводится от всех входящих в его определение типов и символов. Так что вы не можете модифицировать существующий тип класса или объявление метода без смены "версии". Это приведёт к появлению сообщения об ошибке "xxx was compiled with a different version of yyy”.

Так как же мы сделали это?

четверг, 4 августа 2011 г.

Недокументированный CreateProcess

Это перевод Undocumented CreateProcess. Автор: James Brown.

Прим.пер.: эта статья была написана относительно давно. Некоторые возможности, упомянутые в ней, с тех пор стали документированы. В этом случае я заменил придуманные автором имена на те, которые сейчас используются в документации MSDN. И в любом случае, стандартное предупреждение - использовать хаки только как последнее средство.

Этот мануал является частью новой серии, которая будет сосредоточена на некоторых не-GUI вопросах, связанных с программированием в Windows. Предметом этого мануала будет Win32 API функция CreateProcess. Эта статья разделена на несколько секций, каждая из которых описывает приятный факт о CreateProcess, который можно использовать в своих интересах. То, что я буду описывать, нельзя найти в документации Microsoft, но эти вещи были обнаружены многими людьми на протяжении многих лет путём множества экспериментов. Вся информация, собранная здесь, была найдена в различных источниках - особенно в старых публикациях таких изданий, как "Windows Developer Journal", начиная с середины 90-х годов, а также старых сообщениях USENET.

среда, 3 августа 2011 г.

Хак №13: более быстрый доступ к глобальным данным ($ImportedData)

Это перевод Hack#13: Access globals faster ($ImportedData). Автор: Hallvard Vassbotn.

Вокруг пакетов времени выполнения Delphi (run-time packages) всегда была волшебная аура. Пакеты позволяют вам разделять Delphi код на более высоком уровне, чем это доступно с простыми DLL. Написание API библиотеки DLL включает в себя создание кучи плоских глобальных функций (анти-ООП) и избегание любых типов данных, хоть отдалённо сложнее Integer, Double, статических массивов, PChar и записей. Вы не можете обмениваться классами, объектами, глобальными переменными, не говоря уже про простые строки (если только и клиент и сервер не собраны в одной и той же версии Delphi и оба используют общий менеджер памяти).

вторник, 2 августа 2011 г.

Хак №12: создаём меньшие .exe файлы ($SetPEFlags)

Это перевод Hack#12: Create smaller .EXE files ($SetPEFlags). Автор: Hallvard Vassbotn.

Нет, этот пост - не про так называемые EXE-компрессоры: я не верю в их пользу. И это не чистый хак - мы не нарушаем никаких правил, это просто документирование слабо известной возможности Delphi 2006 (она не реализована в D7, и я ничего не знаю насчёт Delphi 2005, поскольку она давно у меня не стоит).

понедельник, 1 августа 2011 г.

Хак №11: получение GUID интерфейса по интерфейсной ссылке

Это перевод Hack#11: Get the GUID of an interface reference. Автор: Hallvard Vassbotn.

Недавно Randy Magruder обратился ко мне с одним своим очень интересным проектом, над которым он работает:
Что я пытаюсь сделать: добавлять и удалять поддерживаемые интерфейсы в класс в run-time и вызывать их. Я уже сделал достаточно, чтобы я мог использовать модель OTAServices model из Delphi для передачи дополнительных интерфейсов, добавления их во внутренний список, и заместил поведение QueryInterface, чтобы вызов возвращал интерфейс из списка, вместо стандартной таблицы объекта.
Это звучит как клёвый (и сложный) проект! Он продолжает:
Но если вызывающий объекта знает только GUID интерфейса, который ему нужен, и хочет получить подходящий интерфейс и вызвать метод в нём по имени, то что я могу с этим сделать? Мне использовать расширенный RTTI с IInvoker?
Ну, я не уверен, как это можно решить. AFAIK, не существует простого проецирования от объекта, реализующего интерфейс, к информации типа этого интерфейса. Одно из решений может заключаться в реализации проецирования GUID интерфейсов на информацию типа.
И ещё: ты случайно не знаешь способ извлечения GUID интерфейса в run-time, ...
Это должно быть возможным, хотя и немного сложновато.