Версия для печати
Книга "О чём не пишут в книгах по Delphi"
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=1326Антон Григорьев
дата публикации 11-09-2007 08:14Книга "О чём не пишут в книгах по Delphi" В конце января в издательстве BHV-Петербург выходит книга "О чём не пишут в книгах по Delphi". Это первая и, надеюсь, далеко не последняя книга, выпущенная под эмблемой Королевства. Автор книги — ваш покорный слуга. Книга основана на статьях, опубликованных мною в разное время в Королевстве.
Обложка книгиПо этой ссылке можно найти официальную информацию о книге от издательства. Здесь же будет приведено более полное содержание, а также выдержки из книги — введение и приложение 1. Кроме того, будет описание того, что добавлено в книгу по сравнению со статьями. В конце статьи приведены все обнаруженные в книге ошибки и опечатки, эта информация регулярно обновляется.
Введение
Благодарности:
Елене Филипповой, создательнице и бессменному
главному администратору сайта "Королевство
Delphi".Алексею Ковязину (российское отделение
CodeGear) за помощь в выпуске этой книги.Юрию Зотову, натолкнувшему меня на идею
четвертой главы и некоторых разделов первой и
третьей глав.Многочисленным посетителям сайта
"Королевство Delphi", при общении с которыми
выяснялись интересные факты и рождались
идеи, нашедшие себе место в этой книге.Среда программирования Delphi заслуженно приобрела свою популярность. Этот удобный и красивый инструмент, основанный на не менее красивом языке Паскаль, первым избавил программиста от рутинных операций, сохранив при этом гибкость, присущую универсальным языкам программирования. Не удивительно, что об этой среде написано много книг, а в Интернете можно найти множество различных сайтов, посвященных Delphi.
Автор данной книги с 1999 года является постоянным посетителем (а с 2004 года — еще и модератором) сайта "Королевство Delphi" (www.delphikingdom.ru; подробнее этот сайт описан в Приложении 1), одного из самых известных русскоязычных ресурсов по Delphi. За это время изучено, какие вопросы интересуют посетителей сайта и какие ответы они хотели бы получить. Наблюдения показывают, что существует целый ряд тем, традиционно вызывающих большой интерес, но информацию по которым найти сложно. Авторы книг по Delphi стараются как можно быстрее перейти к описанию возможностей различных библиотек, оставляя в стороне другие важные вопросы.
"За бортом" остается множество тем, касающихся более низкоуровневых средств, которые в большинстве своем неплохо документированы и описаны в книгах, проиллюстрированы готовыми примерами, которые, правда, обычно даются на C++. Конечно, немного опыта — и код переведен с C++ на Delphi. Только обидно программировать в Delphi, никак не задействуя ее высокоуровневые библиотеки — хочется как-то "сшить" гибкость низкоуровневых вещей и удобство библиотек, использовав библиотеки везде, где это возможно, а низкоуровневый код — только там, где без него никак не обойтись. И вот как раз по этим вопросам и наблюдается острая нехватка информации.
Природа не терпит пустоты, поэтому в Интернете время от времени появляются рекомендации по поводу того, как же все-таки "впрячь в одну упряжку" библиотеки и низкоуровневый код. Но эти советы, за редким исключением, страдают тем, что дают готовое решение с минимальными объяснениями, почему надо делать это именно так (иногда авторы этих рекомендаций при всем желании не смогли бы дать такое объяснение, т. к. сами дошли до этого "методом тыка"). Так что такие советы могут оказаться очень полезными в конкретной ситуации, но не дают общего понимания проблемы.
Эта книга призвана заполнить информационный вакуум по некоторым из таких вопросов. Но самое главное — это то, что мы здесь принципиально будем избегать изложения в стиле "делай так, и будет тебе счастье", т. е. уклон будет не в сторону готовых рецептов, а в сторону объяснения, как это все устроено, чтобы читатель потом сам был в состоянии искать решения для своих проблем. Для этого мы будем разбирать стандартные средства Delphi с позиции "а как оно все работает".
Первая глава книги посвящена интеграции библиотеки VCL и Windows API, прежде всего той части Windows API, которая управляет окнами на экране. Не секрет, что в VCL отсутствуют многие возможности по управлению окнами, которые предоставляет операционная система Windows, но их можно задействовать и в VCL-приложении, если знать, как и куда можно вставить код, использующий API, так, чтобы это не нарушило работу VCL. В первой главе даются базовые сведения о Windows API и о том, как VCL использует API. Здесь приведен ряд примеров программ различной степени сложности, которые демонстрируют методы применения Windows API совместно с VCL в различных ситуациях. Особое внимание уделяется тому, как использовать Windows API, не нарушая работу VCL.
Вторая глава посвящена применению сокетов в Delphi. Сокеты — это самые низкоуровневые сетевые средства Windows, своего рода ассемблер сетевого программирования. Они хорошо документированы, но из-за обилия возможностей эта документация оказывается практически "неподъемной" для человека, который только-только начал знакомится с сокетами и которому не нужны все эти возможности, а требуется просто научиться передавать данные с помощью TCP/IP. Книг по сокетам очень мало, а по использованию сокетов в Delphi — вообще ни одной. Между тем сокеты в Delphi имеют свою специфику из-за отличий языка C, на который ориентирована библиотека сокетов, и Delphi: макросы заменены функциями, изменены параметры некоторых функций, определения типов приспособлены к возможностям Delphi. Кроме того, стандартный модуль Delphi для импорта функций из библиотеки сокетов импортирует библиотеку не полностью и содержит некоторые неточности. Все это делает освоение сокетов "с нуля" очень сложным делом. Вторая глава книги ориентирована на человека, который не имеет опыта сетевого программирования и не знаком с терминологией. Даются все необходимые определения и пояснения, чтобы можно было полностью понять, как работают примеры, но при этом читатель не перегружается избыточной на данном этапе информацией. Попутно излагаются особенности работы с сокетами, присущие именно Delphi. После прочтения данной главы читатель получает достаточно полное представление о протоколах стека TCP/IP и об основных режимах работы сокетов, и после этого способен дальше читать документацию самостоятельно.
Третья глава посвящена ситуациям, в которых стандартные средства ведут себя не так, как этого ожидает программист. Иногда это объясняется ошибками в реализации этих средств, но чаще тем, что программист просто не знает некоторых особенностей данной реализации. Конечно, детально изучив документацию, можно не только дать объяснение ошибкам, но и научиться предсказывать, где они могут возникнуть, но такой метод имеет очевидные сложности. В третьей главе выбран другой подход — "от ошибки". Мы сначала будем рассматривать ситуацию, в которой возникает ошибка, а потом объяснять, какие особенности реализации приводят к этому. Такой порядок изложения позволяет одновременно и рассказать о том, как соответствующие средства реализованы, и предостеречь от неверного их использования.
Четвертая глава целиком посвящена одному очень популярному в форумах вопросу: как вычислить арифметическое выражение, которое становится известным только во время выполнения программы (т. е., например, у нас есть арифметическое выражение в строковой переменной, а требуется вычислить его значение). С одной стороны, в Интернете можно найти немало самодельных библиотек, решающих эту задачу. Но не все из них работаю достаточно корректно, потому что их авторы зачастую реализуют доморощенные методы анализа выражений, дающие в некоторых случаях сбои. С другой стороны, существует литература, в которой довольно полно изложена формальная теория создания трансляторов. Но эта теория выходит далеко за рамки простого вычисления арифметических выражений и требует соответствующих усилий для ее освоения. Мы же, с одной стороны, ограничимся только той частью теоретических сведений, которая необходима для построения вычислителя, но с другой, — будем этой теории строго следовать, создавая действительно работоспособное решение. И хотя на выходе мы получим несколько вполне работоспособных примеров, не они будут нашей главной целью. Мы будем стремиться к тому, чтобы читатель понял сам принцип построения таких анализаторов и при необходимости смог вносить в них изменения. В дальнейшем это поможет при изучении теории синтаксического анализа по специализированным книгам.
Книга ориентирована на Delphi для Win32. О Delphi для .NET мы здесь говорить не будем. При написании книги были исследованы особенности всех версий Delphi от 3-й до 2007-й, за исключением BDS 2005, и если какая-то особенность или ошибка, описанная в данной книге, присутствует только в некоторых из этих версий, то это обстоятельство обязательно отмечается. Но из-за того, что с BDS 2005 автор книги не имел возможности ознакомиться, фраза "до Delphi 7 включительно" может означать "до BDS 2005" включительно, а фраза "начиная с BDS 2006" — "начиная с BDS 2005".
Автор надеется, что книга действительно окажется полезной читателю. Актуальность изложенных в ней тем подтверждается многочисленными вопросами в форумах, а полезность сведений — многочисленными ответами.
Содержание
- Глава 1. Windows API и Delphi
Глава посвящена разбору основ Windows API и специфике их использования в Delphi
- 1.1 Основы работы с Windows API в VCL-приложениях
Основы Windows API, внутреннее устройство классов VCL, способы сопряжения кода, использующего Windows API и VCL. К разделу прилагается восемь примеров.
- 1.1.1 Что такое Windows API
Что такое функции WinAPI, методы их импорта в приложение
- 1.1.2 Как получить справку по функциям Windows API
Описание справки по API-функциям, поставляемой с Delphi. Что такое MSDN. Как правильно переводить описания типов и функции из справочной системы с C/C++ на Delphi.
- 1.1.3 Дескрипторы вместо классов
Правила идентификации объектов в Windows. Дескрипторы и доступ к объектам через них.
- 1.1.4 Формы VCL и окна Windows
Сопоставление понятия формы в VCL и окна в API. Оконные и неоконные визуальные компоненты. Оконные классы: предопределённые классы и регистрация новых классов. Родительские окна, свойство TControl.Parent. Разница между владельцем и родителем оконного компонента. Стили окна, их переопределение при создании формы в Delphi через метод CreateParams.
- 1.1.5 Функции обратного вызова
Определение функций обратного вызова, примеры их использования в Windows API.
- 1.1.6 Сообщения Windows
Определение понятия сообщения, способы их отправки. Обработка сообщений получателем: оконная процедура, петля сообщений, диспетчеризация сообщений. Почему приложение, занятое длительным процессом, перестаёт реагировать на действия пользователя, способы борьбы с этим. Локальная петля сообщений. Диалоговые окна. Создание подкласса.
- 1.1.7 Создание окон средствами VCL
Свойства и методы VCL, отвечающие за создание окна. Момент создания окна. Параметры окна, их изменение с помощью метода CreateParams. Механизм подмены оконной процедуры, создание уникальной оконной процедуры для экземпляра.
- 1.1.8 Обработка сообщений с помощью VCL
Организация приёма и обработки сообщений в VCL. Главная форма и невидимое окно, создаваемое объектом Application. Реализация петли сообщений в TApplication. Предварительная обработка сообщения перед диспетчеризацией. Что делает Application в фоновом режиме, когда нет сообщений. Синхронизация с главной нитью. Показ окна с помощью ShowModal, отличия этого режима от обычных диалоговых окон. Реализация оконной процедуры в классе TWinControl. Этапы обработки сообщения компонентом: методы WndProc, Dispatch, DefaultHandler, обработчики сообщений. Тип TMessage и его производные. Метод Perform, имитация оконной процедуры в неоконных визуальных компонентах. Трансляция сообщений в VCL, сообщение WM_COMMAND. Способы внедрения своего кода в процесс обработки сообщений.
- 1.1.9 Сообщения, определяемые пользователем
Сообщения, определяемые пользователем, и их диапазоны: диапазон уровня оконного класса, уровня приложения, уровня системы. Константы WM_USER и WM_APP. Регистрация сообщений с помощью RegisterWindowMessage. Написание обработчиков определённых пользователем сообщений в VCL-приложениях.
- 1.1.10 Особые сообщения
Особенности отправки и обработки сообщений WM_COPYDATA, WM_PAINT, WM_TIMER.
- 1.1.11 Графика в Windows API
Графические средства GDI, контекст устройства. Класс TCanvas и GDI. Как использовать Canvas и GDI одновременно. Возможности GDI, не поддерживаемые классом TCanvas. Способы задания цвета в GDI и VCL, преобразования между этими представлениями. Форматы представления растров: DDB, DIB, DIB-секция. Класс TBitmap и используемые им форматы. Особенности использования свойства TBitmap.ScanLine при работе с форматом DDB.
- 1.1.12 ANSI и Unicode
Одно- и двухбайтные кодировки. Поддержка кодировок различными версиями Windows. Два варианта функций и типов API для поддержки разных кодировок. Импорт функций API для поддержки различных кодировок.
- 1.1.13 Строки в Windows API
Способы представления строк в API, нуль-терминированные строки. Частичная совместимость типа string и строк API. Методы передачи строк функциям API только для чтения и для чтения и записи.
- 1.2. Примеры использования Windows API
Относительно простые примеры к первой части статьи. Каждый иллюстрирует один-два аспекта использования API в VCL-приложениях.
- 1.2.1. Пример EnumWnd
Написание функции обратного вызова для EnumWnd и EnumChildWnd. Три варианта получения строк от функций Windows API.
- 1.2.2. Пример Line
Невизуальный компонент, перехватывающий сообщения владельца. Проблемы удаления компонента, перехватившего сообщения владельца.
- 1.2.3. Пример CoordLabel
Визуальный компонент, перехватывающий сообщения родителя. Реакция на смену родителя.
- 1.2.4. Пример PanelMsg
Перехват формой оконных сообщений дочернего компонента. Обработка перехваченного WM_PAINT с правильной отрисовкой неоконных компонентов. Фиктивный наследник для вызова защищённых методов.
- 1.2.5. Пример NumBroadcast
Регистрация пользовательского сообщения для широковещательной рассылки. Функция BroadcasrSystemMessage, её отличия от PostMessage с адресатом HWND_BROADCAST.
- 1.2.6. Пример ButtonDel
Невозможность непосредственного удаления кнопки из обработчика. Обход ограничения через посылку сообщений. Проблемы взаимного удаления компонентов при наличии локальной петли сообщений.
- 1.2.7. Пример GDIDraw
Пример использования графических возможностей системы, не поддерживающихся классом TCanvas. Регионы, тракетории, обрезание рисунка по границам букв. Правила заливки сложных фигур. Режимы заливки. Рисование и заливка многоконтурных фигур с помощью функции PolyPolygon. Инвертирование цветов в заданной области. "Полупрозрачная" надпись. Вывод текста под углом с учётом особенностей новых версий Delphi.
- 1.2.8. Пример BitmapSpeed
Сравнение скорости различных операций для рисунков в форматах DIB и DDB. Использование высокопроизводительных счётчиков для измерения времени. Обсуждение результатов.
- 1.3. Обобщающие примеры
- 1.3.1. Обобщающий пример 1 — Информация о процессах
Пример приложения, которое выводит список всех выполняемых процессов, а для выбранного процесса - список его модулей и окон.
- 1.3.1.1. Получение списка процессов
Знакомство с функциями ToolHelp32 API.
- 1.3.1.2. Получение списка и свойств окон
Функции для перечисления окон и получения информации по конкретным окнам. Разница между получением заголовка окна с помощью GetWindowText и WM_GETTEXT. Класс окна, базовый класс.
- 1.3.2. Обобщающий пример 2 — Ассоциированные файлы и предотвращение запуска второй копии приложения
Пример программы (DKSView), которая умеет ассоциировать файлы с расширением dks с собой, а также проверять, не были ли они ассоциированы с другим приложением. DKSView является MDI-приложением, т.е. может открывать одновременно несколько файлов. Если приложение уже запущено, а пользователь пытается открыть ещё один dks-файл, желательно, чтобы он открывался не в новом экземпляре DKSView, а появлялось новое окно в уже имеющемся. Поэтому наш пример будет также уметь обнаруживать уже запущенный экземпляр программы и переадресовывать открытие файла ему.
- 1.3.2.1. Ассоциирование расширения с приложением
Записи в реестре. Регистрация собственного расширения и связь команд с ним.
- 1.3.2.2. Командная строка
Командная строка и передача параметров через неё. Разделители параметров. Что делать, если параметр содержит пробелы. Функции Delphi для работы с командной строкой.
- 1.3.2.3. Поиск уже запущенной копии приложения
Использование объектов синхронизации для обнаружения запущенной копии приложения и недостатки этого метода. Использование почтовых ящиков (mailslots) для обнаружения запущенной копии и для передачи ей данных.
- 1.3.2.4. Перевод приложения на передний план
Проблемы, возникающие при попытке второй копии приложения вывести первую на передний план. Способы преодоления проблемы с учётом структуры VCL-приложения.
- 1.3.3. Обобщающий пример 3 — "Дырявое" окно
Пример создания окна с прямоугольным отверстием посередине. Отверстие имеет рамку, за которую пользователь может изменять его размеры.
- 1.3.3.1. Сообщение WM_NCHCHITTEST
Клиентская и неклиентская области окна. Определение границ неклиентской области. Составляющие неклиентской области. Определение принадлежности пикселя той или иной области с помощью события WM_NCHITTEST.
- 1.3.3.2. Регионы
Регионы, изменение формы окна с помощью SetWindowRgn.
- 1.3.3.3. Сообщения WM_SIZE и WM_SIZING
Сообщения WM_SIZE и WM_SIZING: когда они посылаются и их параметры.
- 1.3.3.4. А теперь — все вместе
Использование механизмов из предыдущих разделов для создания "дырявого" окна.
- 1.3.4. Обобщающий пример 4 — Линии нестандартного стиля
Два примера рисования прямых и кривых линий нестандартными стилями.
- 1.3.4.1. Получение координат точек прямой
Функция LineDDA и её использование. Рисование линии произвольного стиля с помощью LineDDA.
- 1.3.4.2. "Резиновая" линия и растровые операции
Создание линии, которая "тянется" за мышью. Задача восстановления фона. Двойное инверсирование фона. Растровые операции в GDI.
- 1.3.4.3. Кривые Безье
Математические основы кривых Безье. Поддержка кривых Безье в GDI.
- 1.3.4.4. Траектории
Понятие траектории. Поддержка траекторий в различных версиях Windows. Внутреннее представление траекторий, преобразование траекторий. Преобразование кривых Безье в ломаную с помощью траекторий. Использование LineDDA для рисования ломаной, полученной из кривой Безье.
- 1.3.4.5. Интерактивная кривая
Создание "резиновой" кривой Безье. Сохранение фона в растре.
- Глава 2. Использование сокетов Delphi
Глава посвящена общим сведениям о сетевых протоколах, протоколам TCP и UDP, использованию сокетов для работы с этими протоколами и особенности использования WinSock API в Delphi.
- 2.1. Стандартные сокеты
Сокеты Беркли: идеология и реализация в Windows.
- 2.1.1. Соглашения об именах
Соглашения о наименовании типов, функций и параметров функций, принятые в стандартной библиотеке сокетов. Невозможность точного следования этим правилам в Delphi. Соглашения о наименованиях, принятые при переносе заголовочных файлов WinSock API в Delphi.
- 2.1.2. Общие сведения о сокетах
Понятие сокета. Связь сокета с протоколом и адресом. Входящий и исходящий буферы сокета. Сетевой порядок хранения байт в целых числах. Функции для изменения порядка байт.
- 2.1.3. Сетевые протоколы. Семиуровневая модель OSI
Понятие сетевого протокола. Вопросы, требующие согласования при передаче данных по сети. Семиуровневая модель OSI и задачи, решаемые каждым из уровней.
- 2.1.4. Стек TCP/IP
Особенности работы сети Ethernet: возможность возникновения коллизий, методы разрешения коллизий. Роутеры и их задачи. Необходимость учёта существования роутеров в протоколе сетевого уровня. Протокол IP, понятие MAC- и IP-адресов. Протоколы ARP, ICMP, IGMP. Понятие надёжного и ненадёжного протокола. Общие сведения о протоколах TCP, UDP, HTTP, FTP, SMTP.
- 2.1.5. Протокол UDP
Свойства протокола UPD. Понятие дейтаграммы, максимальный размер дейтаграммы. Возможность пропадания дейтаграмм и изменения порядка их следования. Порт как часть адреса сокета. Понятие широковещательных сообщений.
- 2.1.6. Протокол TCP
Свойства протокола TCP. Понятие соединения, диагностика потери соединения. Понятие сервера и клиента. Действия сервера и клиента при установлении соединения. Понятие потокового протокола, возможность склейки и разбивки отправленных данных. Надёжность протокола TCP.
- 2.1.7. Сетевые экраны
Понятие сетевого экрана. Базовые принципы работы сетевых экранов. Возможные проблемы с выполнением примеров из книги из-за настройки сетевых экранов.
- 2.1.8. Создание сокета
Инициализация библиотеки сокетов: функции WSAStartup и WSACleanup. Создание сокета и привязка к адресу: функции socket и bind. Типы sockaddr и sockaddr_in для хранения адресов в стандартной библиотеке. Типы TSockAddr и TSockAddrIn в Delphi, их неполное соответствие типам sockaddr и sockaddr_in. Функция inet_addr. Закрытие сокета, функции shutdown и closesocket. Особенности закрытия сокета в протоколах TCP и UDP.
- 2.1.9. Передача данных при использовании UDP
Функции для передачи и получения данных при использовании UDP: sendto и recvfrom. Имитация соединения с помощью функций connect, send и recv.
- 2.1.10. Пример программы: простейший чат на UDP
Описание программы UDPChat, находящейся на диске. Невозможность использования одного сокета и для отправки, и для приёма сообщений в рамках описанных на данный момент технологий. Вынесение приёма сообщений в отдельную нить. Неудобство реализации чата: сообщения приходят с одного порта, а отправлять их надо на другой.
- 2.1.11. Передача данных при использовании TCP
Установка соединения при использовании TCP. Функции стороны сервера: listen, accept. Очередь соединений. Способы борьбы со склейкой и разбиением сообщений в тех случаях, когда это мешает работе.
- 2.1.12. Примеры передачи данных с помощью TCP
Описание протокола уровня представлений, используемого примерами на диске. Создание простейшего однонитевого консольного TCP-сервера, который способен обслуживать только одного клиента в каждый момент времени. Создание клиента для этого сервера. Распараллеливание работы сервера для того, чтобы он мог работать одновременно с несколькими клиентами. Уязвимость такого сервера к DoS-атакам.
- 2.1.13. Определение готовности сокета
Блокирование функциями WinSock вызывающей нити из-за невозможности немедленного выполнения операции. Функция select для определения того, какая из операций может быть выполнена немедленно. Тип TFDSet и функции для работы с ним. Отличия TFDSet от стандартного FDSET. Пример использования select.
- 2.1.14. Примеры использования функции select
UPD-чат, использующий один сокет как для отправки, так и для получения сообщений. Использование таймера для определения готовности сокета и чтения входящих сообщений. Методы уменьшения нежелательных последствий от действий злоумышленника, парализующего работу чата. Консольный TCP-сервер с использованием функции select. Более высокая устойчивость такого сервера к DoS-атакам по сравнению с многонитевым сервером. Отсутствие устойчивости к нарушению клиентом протокола из-за возможной блокировки.
- 2.1.15. Неблокирующий режим
Понятие неблокирующего режима, включение неблокирующего режима. Ситуации, когда возможно блокирование. Контроль выполнения операции в неблокирующем режиме с помощью ошибки WSAEWOULDBLOCK.
- 2.1.16. Сервер на неблокирующих сокетах
TCP-сервер с пользовательским интерфейсом, использующий неблокирующие сокеты и проверяющий их по таймеру. Чтение сообщений по частям как способ полностью избежать проблем с блокировками. Повышение устойчивости сервера по отношению к возможному нарушению протокола обмена клиентом.
- 2.1.17. Параметры сокета
Параметры сокета уровня сокета и уровня протокола. Функции getsockopt и setsockopt для чтения и установки параметров. Размеры входного и выходного буфера: параметры SO_RCVBUF и SO_SNDBUF. Правила работы с входным и выходным буферами. Управление широковещательной рассылкой и способом закрытия сокета.
- 2.1.18. Итоги первого раздела
Краткие итоги раздела. Задания для самостоятельного изучения.
- 2.2. Сокеты Windows
Дополнительные функции WinSock API, ориентированные на работу в приложении, управляемом сообщениями.
- 2.2.1. Версии Windows Sockets
Существующие версии WinSock, особенности работы и реализации. Поддержка различных версий WinSock в Delphi.
- 2.2.2. Устаревшие функции WinSock 1
Функции для борьбы с блокированием в условиях корпоративной многозадачности. Особенности реализации этих функций в современных версиях ОС с вытесняющей многозадачностью.
- 2.2.3. Информация о протоколе
Получение информации о протоколе обмена. Тип WSAPROTYOCOL_INFO и функция WSA_EnumProtocols.
- 2.2.4. Новые функции
Функции WSASocket, WSAConnect, WSAAccept и особенности их работы по сравнению с socket, connect и accept. Возможность отклонения запроса на подключение, защита от DoS-атак. Функции WSAStringToAddress и WSAAddressToString. Новые функции перестановки байт. Функция WSADuplicateSocket.
- 2.2.5. Асинхронный режим, основанный на сообщениях
Понятие асинхронного режима с уведомлением через оконные сообщения. Функция WSAAsyncSelect. Условия возникновения различных событий, с которыми связываются сообщения.
- 2.2.6. Пример сервера, основанного на сообщениях
Пример создания TCP-сервера, основанного на сообщениях. Чтение по частям. Устойчивость сервера к DoS-атакам и нарушению протокола клиентом.
- 2.2.7. Асинхронный режим, основанный на событиях
Понятие асинхронного режима с уведомлением через события. Отсутствие в Delphi готовых модулей для импорта соответствующих функций и их самостоятельный импорт. Функции WSACreateEvent, WSASetEvent, WSAResetEvent, WSACloseEvent и WSAWaitForMultipleEvents для работы с событиями. Привязка событий к происходящему в сокете, функция WSAEventSelect. Функция WSAEnumNetworkEvents.
- 2.2.8. Пример использования сокетов с событиями
Пример создания TCP-сервера, основанного на событиях. Использование событий для управления нитями, работающими с клиентами. Таймаут взаимодействия с клиентом.
- 2.2.9. Перекрытый ввод-вывод
Выполнение блокирующих операций в фоновом режиме; перекрытый ввод-вывод. Создание сокета для перекрытого ввода-вывода, флаг WSA_FLAG_OVERLAPPED. Функции WSASend и WSARecv. Контроль выполнения перекрытых операций, функция WSAGetOverlappedResult.
- 2.2.10. Сервер, использующий перекрытый ввод-вывод
Создание TCP-сервера с использованием перекрытого ввода-вывода на основе процедур завершения. Деление обмена данными на этапы с использованием своей процедуры завершения для каждого из них.
- 2.2.11. Многоадресная рассылка
Поддержка многоадресной рассылки с помощью протокола IGMP. Понятие группового адреса. Добавление сокета в группу, функция WSAJoinLeaf.
- 2.2.12. Дополнительные функции
Функции WSARecvEx, частичное получение дейтаграмм. Функция AcceptEx для подключения клиента с одновременным получением от него данных. Передача файла по сети, функция TransmitFile.
- 2.3. Итоги главы
Краткие итоги главы. Стандартные компоненты для работы с сокетами. Установка компонентов TClientSocket и TServerSocket в Delphi 7 и выше.
- Глава 3. "Подводные камни"
Эта глава посвящена "подводным камням" — ситуациям, в которых код по разным причинам даёт неожиданные результаты.
- 3.1. Неочевидные особенности целых чисел
Раздел посвящён неожиданным ситуациям, возникающим при использовании целочисленных операций.
- 3.1.1. Аппаратное представление целых чисел
Двоичное представление знаковых и беззнаковых чисел. Реализация процессором операций сложения и вычитания. Переполнения при сложении и вычитании.
- 3.1.2. Выход за пределы диапазона при присваивании
Присваивание переменной значения, не укладывающегося в диапазон её типа - примеры искажения значения.
- 3.1.3. Переполнение при арифметических операциях
Контроль компилятором выхода результата арифметических операций за рамки разрешённого диапазона.
- 3.1.4. Сравнение знакового и беззнакового числа
Проблемы, возникающие при сравнении знакового числа с беззнаковым. Использование компилятором более "широкого" типа, включающего оба диапазона.
- 3.1.5. Неявное преобразование в цикле for
Нежелательные последствия использования беззнакового числа в цикле for для перечисления элементов массивов и списков. Ошибка, возникающая при нулевом размере массива или списка.
- 3.2. Неочевидные особенности вещественных чисел
Раздел посвящён тому, как устроены вещественные числа и почему при их использовании результат часто не совпадает с ожидаемым.
- 3.2.1. Двоичные дроби
Представление числа в виде двоичной дроби с плавающей точкой.
- 3.2.2. Вещественные типы Delphi
Вещественные типы данных в Delphi: внутреннее представление, размерности мантиссы и экспоненты, история появления. Поддержка FPU.
- 3.2.3. Внутренний формат вещественных чисел
Интерпретация содержимого вещественных переменных. Нормализованная и денормализованная запись. Сочетания INF и NAN.
- 3.2.4. "Неполноценный" Extended
Управляющее слово FPU. Ограничение точности вычислений FPU с помощью управляющего слова. Средства, предоставляемые Delphi, для работы с управляющим словом FPU.
- 3.2.5. Бесконечные дроби
Невозможность представления любого числа в виде конечной десятичной дроби. Периодические и непериодические бесконечные дроби. Невозможность представления в виде конечной двоичной дроби некоторых чисел, представляемых в виде конечной десятичной дроби.
- 3.2.6. "Неправильное" значение
Пример занесения в вещественную переменную числа, не совпадающего с заданной в программе константой.
- 3.2.7. Cравнение
Присваивание переменной константы и последующее сравнение с той же константой — пример неожиданного поведения операции "равно".
- 3.2.8. Сравнение разных типов
Сравнение переменных разных вещественных типов, которым были присвоены одинаковые значения — ещё один пример неожиданного поведения операции "равно".
- 3.2.9. Вычитание в цикле
Накопление ошибки при многократном вычитании вещественного числа.
- 3.2.10. Неожиданная потеря точности
Неожиданное уменьшение точности вещественных операций на некоторых компьютерах. Причины и способы борьбы.
- 3.2.11. Борьба с потерей точности в VCL
Средства борьбы с потерей точности, реализованные в стандартных модулях Delphi.
- 3.2.12. Машинное эпсилон
Определение понятия машинного эпсилон. Теоретические оценки значения, программа для вычисления. Независимость машинного эпсилон от используемого типа данных.
- 3.2.13. Методы решения проблем
Некоторые способы решения проблем, возникающих при использовании вещественной арифметики.
- 3.3. Тонкости работы со строками
В данном разделе описываются ситуации неожиданного поведения программы при выполнении операций со строками.
- 3.3.1. Виды строк в Delphi
Строки типа AnsiString, ShortString и PChar. История появления, особенности реализации. Ответственность за выделение и освобождение памяти для строк разных типов.
- 3.3.2. Хранение строковых литералов
Где хранятся строковые литералы, заданные в тексте программы. В каких случаях одинаковые литералы дублируются, а в каких - нет. Различие поведения глобальных и локальных переменных при присваивании им литералов.
- 3.3.3. Приведение литералов к типу PChar
Автоматическое неявное приведение строковых литералов к типу PChar, отсутствие необходимости делать это явно. Ошибка Access violation, возникающая при попытке привести к PChar литерал, состоящий из одного символа.
- 3.3.4. Сравнение строк
Способы сравнения строк различных типов. Сравнения по значению и по указателю. Ошибки, возникающие при сравнении строк различных типов.
- 3.3.5. Побочное изменение
Ситуации, в которых манипуляции с одной строкой меняю значение другой строки.
- 3.3.6. Нулевой символ в середине строки
Возможность использования символа #0 в строках типа AnsiString и невозможность в строках типа PChar. Потеря "хвоста" строки, содержащей нулевой символ, при конвертировании из AnsiString в PChar и обратно. Некорректная работа некоторых стандартных функций со строками, содержащими #0.
- 3.3.7. Функция, возвращающая AnsiString
Особенности инициализации переменной Result в функциях, возвращающих AnsiString. Зависимость результата от способа вызова функции при отсутствии явной инициализации Result.
- 3.3.8. Строки в записях
Проблемы, возникающие при сохранении в поток записей, содержащих строки. Различные варианты решения проблем. Сокрытие ошибки при копировании записей со строками в пределах процесса. Правильное выделение и освобождение динамической памяти для записей со строками.
- 3.3.9. Использование ShareMem
Проблемы, возникающие при выделении памяти одним менеджером и освобождении другим. Разные менеджеры памяти в основной программе и DLL. Невозможность передачи параметров типа string при использовании разных менеджеров памяти. Библиотека borlandmm.dll и модуль ShareMem. SimpleShareMem — альтернатива ShareMem, появившаяся в новых версиях Delphi. Способы передачи строк без использования ShareMem и SimpleShareMem.
- 3.4. Прочие "подводные камни"
Разрозненные "подводные камни" — ситуации, когда поведение кода отличается от ожидаемого. Методы решения проблем.
- 3.4.1. Порядок вычисления операндов
Неопределённость порядка вычисления операндов в бинарных операциях. Неправильный результат выражения с функциями с побочными эффектами.
- 3.4.2. Зацикливание обработчика TUpDown.OnClick при открытии диалогового окна в обработчике OnMouseDown
Захват мыши в компоненте TUpDown и вызываемые им проблемы при открытии диалогового окна в обработчике OnMouseDown. Решение проблемы методом исключения стиля csCpatureMouse.
- 3.4.3. Access violation при закрытии формы с перекрытым методом WndProc
Некорректная реализация метода TCustomForm.Release и обработчика CM_RELEASE и связанные с этим проблемы. Решение проблем самостоятельной обработкой CM_RELEASE в Application.OnMessage.
- 3.4.4. Подмена имени оконного класса, возвращаемого функцией GetClassInfo
Возврат функцией GetClassInfo указателя на память, которая может быть освобождена раньше, чем этот указатель выйдет из области видимости.
- 3.4.5. Ошибка EReadError при использовании вещественных свойств
Ошибка в IDE и в программе при использовании вещественных свойств видимости published при присваивании им значений из определённого диапазона (проблема проявляется только в Delphi 5 и 6).
- 3.4.6. Ошибка List index out of bounds при корректном значении индекса
Ошибка, возникающая при занесении в свойство Objects[I] классов TComboBox и TListBox значения -1, причины возникновения ошибки. Использование CB_GETITEMDATA и LB_GETITEMDATA для решения проблемы. Решение проблемы в BDS 2006 и выше.
- 3.4.7. Неправильное поведение свойства Anchors
Некорректное поведение свойства Anchors в тех случаях, когда начальный размер окна во время исполнения отличается от установленного в дизайнере. Два примера проявления проблемы: окна с WindowStyle = wsMaximized и дочерние MDI-окна. Способы борьбы с проблемой. Частичное исправление ситуации в BDS 2006 и выше.
- 3.4.8. Ошибка при сравнении указателей на метод
Внутренняя структура указателей на методы. Критерий равенства таких указателей. Несоответствие реализации операции сравнения указателей этому критерию. Правильный способ сравнения указателей.
- 3.4.9. Возможность получения адреса свойства
Некорректность понятия "адрес свойства". Ошибка компилятора — возможность применения оператора "@" к свойствам объекта, при объявлении которых в разделе read используется переменная. Нарушение принципа инкапсуляции и возможные ошибки, связанные с этим.
- 3.4.10. Невозможность использования некоторых свойств оконного компонента в деструкторе
Свойства, нуждающиеся в наличии окна. Момент уничтожения окна при уничтожении оконного компонента. Попытка повторного создания окна и ошибки, связанные с этим.
- Глава 4. Разбор и вычисление выражений
Основы теории синтаксического анализа и её применение на практике для вычисления арифметических выражений.
- 4.1. Синтаксис и семантика
Определение понятий языка, грамматики, синтаксиса и семантики.
- 4.2. Формальное описание синтаксиса
Способы формального описания синтаксиса. Простая и расширенная форма Бэкуса-Наура. Рельсовые диаграммы.
- 4.3. Синтаксис вещественного числа
Описание синтаксиса вещественного числа методом БНФ. Функция, использующая это описание для проверки правильности записи вещественного числа.
- 4.4. Простой калькулятор
Синтаксис простого арифметического выражения с поддержкой числовых констант и четырёх действий арифметики без учёта приоритета операций. Пример реализации калькулятора для такого синтаксиса.
- 4.5. Учет приоритета операторов
Модификация синтаксиса для учёта приоритета операций. Калькулятор, реализующий такой синтаксис.
- 4.6. Выражения со скобками
Модификация синтаксиса для изменения приоритета операций с помощью скобок. Введение унарного оператора. Рекурсивный синтаксис и его реализация в калькуляторе.
- 4.7. Полноценный калькулятор
Поддержка в синтаксисе функций, переменных и возведения в степень. Реализация калькулятора.
- 4.8. Калькулятор с лексическим анализатором
Выделение лексического анализатора в отдельную задачу. Реализация двухпроходного калькулятора с лексическим и синтаксическим анализатором.
- 4.9. Однопроходный калькулятор и функции с несколькими переменными
Пример однопроходного калькулятора с лексическим анализатором. Функции с несколькими аргументами. Способ создания анализатора, не использующего исключения.
- 4.10. Еще немного теории
Краткое описание альтернативных методов анализа и вычисления выражений. Понятие контекстно-зависимой, контекстно-свободной и регулярной грамматик. Конечные автоматы и автоматы с магазинной памятью. Польская запись и польская инверсная запись.
- Приложение 1. Сайт "Королевство Delphi"
История сайта. Разделы сайта. Правила, сложившиеся в Королевстве. Конкурсы. (Содержимое данного приложения см. ниже.)
Приложение 2. Содержимое компакт-диска Краткое описание содержимого приложенного компакт-диска.
Приложение 1. Сайт "Королевство Delphi"
Эта книга появилась на свет благодаря сайту "Королевство Delphi" (http://www.delphikingdom.com), поэтому будет справедливо, если мы уделим ему здесь немного внимания. Тем более что этот сайт сам по себе интересен для программиста, использующего Delphi.
История сайта "Королевство Delphi" началась 20 ноября 1998 года (об истории создания см. страницу http://www.delphikingdom.com/team/about.asp). Он задумывался как виртуальный клуб программистов для взаимопомощи независимо от географии и расстояний (для тех, кто в Интернете недавно, заметим, что в 1998 году тематических форумов практически не было, и до такой идеи еще надо было додуматься). На данный момент "Королевство Delphi" является одним из самых популярных сайтов, посвященных Delphi. В Королевстве имеется форум (который называется "Круглый стол"), где можно задавать вопросы и ряд разделов для публикации различных материалов от небольших советов до серьезных циклов статей. Королевство принципиально не копирует чужие статьи и публикует только оригинальные материалы, написанные специально для сайта и присланные лично авторами. Некоторые количественные характеристики сайта (по состоянию на 7 сентября 2007 года) приведены в табл. П1.1 (информация взята со страницы http://www.delphikingdom.com/asp/tth.asp).
Таблица П1.1. Характеристики сайта "Королевство Delphi"
Наименование показателя Значение Зарегистрировано жителей 15351 Опубликовано материалов 905 Задано вопросов 48348 Из них с ответами 47335 Всего дано ответов 179704 В среднем в день задается вопросов 26 В среднем в день дается ответов 115 Сайт "Королевство Delphi" был создан Еленой Филипповой и некоторое время она работала в одиночку. Сейчас сайт поддерживается командой из шести человек во главе с Еленой (свои впечатления о ведении этого проекта Елена с недавних пор начала описывать в блоге, который находится по адресу http://delphikingdom.blogspot.com). Команда Королевства поддерживает контакты с российским отделением CodeGear, благодаря чему в новостной ленте появляется информация о проводимых этой компанией мероприятиях и об интересных новостях, связанной с ней. Кроме того, на встречу с генеральным директором CodeGear Джимом Дугласом, посетившим Россию в июне 2007 года, были приглашены два представителя Королевства (с отчетом об этой встрече можно познакомиться по адресу http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1320).
На сайте "Королевство Delphi" присутствует легкий антураж настоящего средневекового королевства, из-за чего разделы имеют непривычные названия. Чтобы разобраться во всех этих непонятных ссылках, требуются определенные усилия, которые, впрочем, вознаграждаются. Для тех, кто заинтересовался сайтом, приведем описание его основных разделов.
Круглый стол. Так в Королевстве называется форум, где каждый может задать вопрос. Вопросы сначала просматривает модератор и только потом они появляются (или не появляются) на Круглом столе. Если модератор принял решение отклонить вопрос, автору вопроса по почте отправляется уведомление с описанием причин, по которым вопрос отклонен. Наиболее частая причина отклонения — такой вопрос уже задавался ранее (и, может быть, много раз), ответы на него уже даны. В этом случае письмо будет содержать ссылки на ответы или рекомендации, как эти ответы быстро найти. Тем не менее, не стоит злоупотреблять этой особенностью сайта и сразу задавать вопрос, надеясь, что ответ будет получен если не на форуме, то через модератора. Королевство имеет целый ряд сервисов для самостоятельного поиска ответа, и такой поиск в итоге дает больше знаний, чем готовый ответ. Задать вопрос и написать ответ можно без предварительной регистрации.
Для удобства навигации вопросы на Круглом столе можно сортировать по дате поступления или по дате последнего ответа. Можно также получить список вопросов, заданных за определенный период и вопросов, на которые даны ответы за определенный период. Для зарегистрированных пользователей доступна также выборка всех своих вопросов, всех вопросов, на которые пользователь давал ответы, и сервис "Избранные вопросы", с помощью которого пользователь может отметить заинтересовавшие его вопросы и отслеживать появление ответов на них. Уведомления о новых вопросах и ответах при желании можно получать с помощью RSS.
Вопросы на Круглом столе остаются навсегда, они не отправляются в архив, и ссылки на них остаются действительными. Обсуждение вопроса не закрывается (за исключением случаев, когда модератор закрывает обсуждение из-за нарушения автором правил), поэтому все, даже самые "старые" вопросы можно не только прочитать, но и что-то ответить или попросить уточнить, если это потребуется.
Существует список offtopic-вопросов. Туда попадают проблемы, которые обсуждаются часто, и их решения уже есть на Круглом столе. Каждый, кто спрашивает о чем-то, согласно правилам Королевства сначала должен ознакомиться с этим списком, чтобы не задать такой вопрос, который там уже есть.
Круглый стол посвящен только решению конкретных технологических проблем. Вопросы, связанные, например, с обсуждением стоимости работы, прочитанных книг, новостей программирования и т. п. сюда не попадают. Для них есть отдельные форумы.
Базарная площадь. В этом разделе можно обсуждать "неформатные" для Круглого стола темы. Но они все же должны иметь какое-то отношение к компьютерным наукам. Темы ориентированы на длительные обсуждения, есть такие, в которых обсуждение ведется в течение многих лет, то затухая, то вновь возобновляясь. В подобной ситуации неизбежны постоянные лирические отступления от темы ветки слегка в сторону, но модераторы к этому не придираются, если это не заходит совсем уж далеко. Это создает на Базарной площади атмосферу неформального общения на интересные темы.
Городская площадь. Этот раздел предназначен для поиска и предложений работы и сотрудничества. Любой работодатель может разместить здесь объявление о вакансии программиста, а программист — о поиске работы. Также допускаются сообщения о поиске и предложении разовой работы. Отдельный раздел на Городской площади посвящен поиску подельника для совместной работы "за так" над каким-нибудь интересным проектом.
Также на Городской площади можно размещать объявления о поиске готовых компонентов. Их нужно задавать именно здесь, на Круглом столе они не приветствуются, потому что основная цель Круглого стола — помочь человеку с чем-то разобраться, что-то понять, а не дать ссылку на готовое решение проблемы.
Помимо форумов, в Королевстве также публикуются статьи. Для них отведено несколько разных разделов, чтобы можно было не мешать в одну кучу статьи, разные по стилистике, глубине охвата темы, требованиям к уровню читающего.
Сокровищница. Сюда попадают небольшие статьи, посвященные частным задачам. Здесь можно найти интересное решение какой-то проблемы или поделиться своей находкой.
Подземелье магов. Этот раздел предназначен для статей, посвященных технологиям, которые считаются уделом "крутых спецов". В основном, материалы ориентированы на изложение основ соответствующих технологий для тех, кто с ними не знаком. Отметим, что именно здесь опубликованы статьи Михаила Краснова, посвященные использованию OpenGL в Delphi, которые затем легли в основу его книги "OpenGL в проектах Delphi".
Свитки. Этот раздел посвящен обзорным статьям, описывающим какие-то общие проблемы. Обзоры могут быть как технического характера, так и общефилософского. Хотя многое из того, что там написано, можно с успехом применять на практике.
Hello, World! Назначение этого раздела понятно из его названия. Сюда помещаются статьи для начинающих. Вопросы могут быть достаточно сложными (поэтому многие статьи из Hello, World! могли бы быть отнесены и к Подземелью магов), но основное требование раздела — подробное объяснение, рассчитанное на начинающего. На того, кто может не знать не только данную тему, но и многие другие вещи, так что небольшие экскурсы в сторону в этих статьях вполне допустимы.
Лицей. По своей целевой аудитории этот раздел очень близок к Hello, World!, но отличается от него по характеру изложения. Здесь публикуются не отдельные статьи, а циклы связанных уроков, посвященные какой-то обширной теме или общим вопросам Delphi. Среди авторов Лицея такие известные в сообществе Delphi люди как Юрий Зотов и Анатолий Подгорецкий.
Подводные камни. В этом разделе (его ведет Александр Малыгин) собирается информация о ситуациях, когда что-то работает не так, как ожидалось. Это может происходить по самым разным причинам: из-за аппаратной ошибки, ошибок компилятора, библиотек и самого программиста. Главный критерий — чтобы ошибка оказалась там, где ее не ждут. Основные требования к статьям раздела: это должно быть четкое описание ошибки (по возможности с примером), должны быть описаны условия ее возникновения (версия Delphi, операционной системы и т. п.) и пути решения. Раздел уже превратился в достаточно большую коллекцию подводных камней, подстерегающих программиста.
Полигон. Здесь публикуются законченные решения достаточно объемных вопросов. Обязательное условие публикации — наличие готового модуля или библиотеки, которые можно скачать и использовать. При этом Королевство Delphi не является хранилищем компонентов и не конкурирует с такими сайтами, как, например, http://www.torry.net. Публикация компонента в разделе Полигон — это приглашение к участию в совместном тестировании и оценке получившегося кода. В результате автор получает подсказки, что можно и нужно исправить, как еще можно расширить компонент, а остальные посетители сайта — код, который можно применить в своих программах.
Королевские Хроники. В этом разделе собираются статьи, посвященные событиям, происходящим вокруг Delphi, и интересным людям, которые имеют какое-то отношение к Delphi. В этот раздел попал, например, уже упоминавшийся отчет о встрече представителей российского сообщества Delphi с генеральным директором CodeGear Джимом Дугласом, а также впечатления от лекции Никлауса Вирта в Политехническом музее в Москве. Здесь же опубликованы интервью, которые специально для Королевства Delphi давали интересные для сообщества Delphi люди, в частности, такие известные авторы книг по Delphi, как Валерий Фаронов, Анатолий Тенцер и Валентин Озеров.
Все статьи во всех разделах доступны для оценки и обсуждения. Каждый посетитель сайта может оценить стиль изложения и актуальность сведений, приведенных в статье, добавить свой комментарий или задать вопрос автору. Посетители сайта имеют возможность подписаться на получение по RSS уведомлений о новых комментариях к заинтересовавшей их статье.
Одна из самых острых проблем для всех форумов, посвященных программированию — это то, что информация быстро обновляется, и полезные сведения быстро "тонут" под все новыми и новыми слоями других ответов (может быть, не менее полезных). И поэтому вопросы, на которые уже были даны исчерпывающие ответы, задаются снова и снова. Опубликованные статьи постепенно тоже опускаются вниз, прячась под новыми статьями. В Королевстве Delphi предусмотрены специальные средства для поиска ответов на свой вопрос среди уже накопленных материалов. Помимо уже упоминавшегося списка offtopic-вопросов и обычного поиска по Круглому столу и по статьям, существуют еще четыре раздела, назначение которых также заключается в том, чтобы помочь найти имеющуюся на сайте информацию.
Тематический каталог. В Королевстве создан каталог тем (общим числом более шестисот), относящихся к Delphi. Каждый вопрос на Круглом столе и каждая статья из любого раздела может быть связана с одной или несколькими темами. Тематический каталог позволяет выбрать тему и посмотреть все вопросы и все статьи, связанные с ней. Для удобства поиска темы в каталоге упорядочены в иерархическую структуру.
Карта VCL. Помимо тем, каждый вопрос и статья могут быть связаны с одним или несколькими классами из стандартной библиотеки VCL. С помощью раздела Карта VCL можно получить список всех вопросов и статей, связанных с нужным классом.
ОШИБКИ. В этом разделе собрана информация о различных ошибках, которые могут возникнуть при компиляции и выполнении программы, при взаимодействии с конкретным пакетом и т. п. Общее число сообщений об ошибке в списке Королевства — около восьмисот. Вопросы и статьи могут привязываться к ним, а в разделе ОШИБКИ, соответственно, можно получить список вопросов и статей, связанных с требуемой ошибкой. Для удобства нахождения нужной ошибки в списке предусмотрен поиск по ключевому слову в сообщениях об ошибке.
Системные сообщения. Еще один список, к элементам которого могут привязываться вопросы и статьи, — это оконные сообщения Windows. В этом разделе можно получить список вопросов и статей, в которых идет речь о заданном оконном сообщении.
Королевство содержит также еще ряд разделов, которые трудно отнести к какой-либо группе.
Фолианты. В этом разделе публикуется информация о книгах, относящихся к программированию: краткая аннотация, изображение обложки и ссылки на эту книгу в различных интернет-магазинах. По каждой книге посетитель Королевства может оставить свой отзыв и прочитать отзывы других посетителей. Здесь же помещаются рецензии на книги.
Арсенальная башня. Здесь публикуется справочная информация о различных сторонних утилитах и библиотеках, которые могут быть полезны при разработке программ на Delphi. По каждой утилите даются краткие сведения о ее предназначении и ссылка на сайт данной утилиты. Для удобства поиска утилиты разбиты по категориям.
Рыцарский зал. Здесь перечислены все зарегистрировавшиеся в Королевстве люди. Отдельно отмечены люди, имеющие какие-то особые заслуги перед Королевством, например, опубликовавшие статью или написавшие какой-нибудь сценарий для сайта. Регистрация не является обязательной, но некоторые неосновные сервисы незарегистрированным пользователям недоступны по техническим причинам. При регистрации указание адреса электронной почты обязательно, но сам адрес не публикуется. Со страницы посетителя в Рыцарском зале ему можно отправить сообщение по почте.
Служба личных сообщений (СЛС). С помощью этого сервиса зарегистрированные пользователи могут отправлять друг другу сообщения, которые можно прочитать на сайте Королевства.
Глас народа! В этом разделе проводятся опросы по разным актуальным для программистов темам.
Книга Песка. Здесь собираются ссылки на сайты по Delphi и интернет-ресурсы смежной тематики. Ссылки упорядочены по темам, благодаря чему легко получить список сайтов нужной тематики.
Дальние земли. Здесь представлены ссылки на сайты, с которыми у Королевства установились особо дружественные отношения вплоть до проведения совместных проектов. Когда Королевство только-только появилось, существовало очень много сайтов, посвященных Delphi (буквально каждый второй программист считал необходимым создать свой сайт), и казалось, что в этом множестве сайтов действительно следует выделять особо близкие. Но в дальнейшем количество сайтов резко уменьшилось (далеко не у всех хватило сил наполнять сайт оригинальным содержанием), и смысл в особом выделении кого-то пропал. Поэтому раздел практически пустой.
Школа ОБЕРОНА. Этот раздел посвящен языку Оберон и его потомкам. Оберон — на данный момент последний из разработанных Никлаусом Виртом языков, в котором заложен ряд интересных решений. В разделе Школа ОБЕРОНА собраны ссылки на ресурсы, посвященные этому языку, а также ссылки на несколько обсуждений на Базарной площади, которые имеют к нему отношение.
В Королевстве регулярно проводятся конкурсы, позволяющие выявить тех, кто лучше других отвечает на вопросы, появляющиеся на Круглом столе. В период проведения конкурса каждый зарегистрированный посетитель Королевства может проголосовать за понравившийся ему ответ, указав, на какую из возможных номинаций он его выдвигает. Голоса проверяются жюри (состоящем из членов команды Королевства) на соответствие требованиям номинации, несоответствующие отбраковываются, и составляется рейтинг отвечающих. По рейтингу определяется победитель в каждой из номинаций. Победители получают значок щита к своему нику и венок в личную страницу в Рыцарском зале. Обычно в конкурсе три номинации: "Самый фундаментальный ответ", "Самый терпеливый рыцарь" и "Хороший совет". Первая подразумевает ответы, которые не только устраняют проблему, но и детально объясняют, почему она возникает и почему решать ее следует именно так. Вторая номинация предназначена для людей, которые терпеливо объясняют что-либо, раз за разом возвращаясь к одному и тому же вопросу и дают дополнительные пояснения до тех пор, пока автор вопроса не поймет все. Под третью номинацию попадают ответы, в которых автору вопроса действительно дан полезный совет, но с обязательной оговоркой, что вопрос не должен быть слишком простым, а ответ на него — тривиальным.
Королевство Delphi — принципиально некоммерческий проект, на котором отсутствует реклама. Поддержка и развитие сайта осуществляется исключительно за счет энтузиазма команды Королевства и его жителей, которые время от времени помогают улучшать сайт. В настоящее время сайт настолько разросся, что найти для него бесплатный хостинг стало невозможно, поэтому для оплаты хостинга собираются добровольные пожертвования. В соответствии с принципиальной позицией команды Королевства все эти пожертвования анонимны, и пожертвовавший не получает никаких преимуществ по сравнению с теми, кто не заплатил.
Автор данной книги является постоянным посетителем Королевства Delphi. В эту книгу вошел ряд статей, опубликованных автором на страницах Королевства и переработанных с учетом замечаний и пожеланий, высказанных посетителями сайта. Связаться с автором можно через его личную страницу в Рыцарском зале.
Дополнения по отношению к статьям
Прежде всего, в статьях, опубликованных на сайте, рассматриваются особенности Delphi до 7-ой версии включительно, в то время как в книге — до 2007-ой (без сервиспака, т.к. на момент написания книги его ещё не было). В некоторых случаях изменения в более поздних версиях Delphi значительны, что и отмечено в книге. Появился ряд рисунков, которые в статьях на сайте практически отсутствуют. Теперь — более детально.
Раздел 1.1 сделан на основе статьи "Основы работы с WinAPI в VCL-приложениях". Из существенно нового — раздел 1.1.7, посвящённый тому, как и в какой момент VCL создаёт окна для своих оконных компонентов и как можно вмешаться в этот процесс. Много мелких замечаний, касающихся новшеств, появившихся в BDS 2006.
Раздел 1.2 — описание примеров к той же статье. На сайте сами примеры есть, но отдельного подробного описания нет.
Разделы 1.3.1, 1.3.2 и 1.3.3 — написаны на основе статей "Обобщающие примеры работы с WinAPI. Пример №5 — работа с процессами системы", "Обобщающий пример работы с WinAPI №3 — Ассоциированные файлы и предотвращение запуска второй копии приложения" и "Обобщающие примеры работы с WinAPI. Пример №4 — "дырявое окно"" соответственно. Изменения минимальны.
Раздел 1.3.4 — компиляция статей "Канва и нестандартные приемы рисования" и "Использование кривых Безье". Немного переработаны примеры, существенно увеличена теоретическая часть.
Глава 2 написана на основе статей "Использование сокетов в Delphi. Часть первая: стандартные сокеты" и "Использование сокетов в Delphi. Часть вторая: сокеты Windows". Теоретическая часть почти без изменений — добавлен небольшой обзор того, что такое сетевые экраны и отмечено, какие ошибки в файле WinSock.pas в новых версиях Delphi исправлены. Но добавились полностью функциональные примеры — то, чего в статьях на сайте вообще нет. Всего 11 примеров: 7 TCP-серверов, 2 TCP-клиента и 2 UDP-чата. Отсутствие примеров было самым слабым местом этих статей, и в книге это исправлено.
Раздел 3.1 на сайте аналогов не имеет.
Раздел 3.2 — это доработанная статья "Неочевидные особенности вещественных чисел". Сделаны стилистические изменения, добавлен раздел 3.2.11, посвящённый тому, как разработчики стандартных модулей Delphi борются с неконтролируемым изменением управляющего слова FPU.
Раздел 3.3 вырос из статьи "Тонкости работы со строками". Добавлена информация о хранении строковых литералов, о правильном выделении и освобождении памяти для записей, содержащих строки, о работе нового менеджера памяти, который появился в BDS 2006 и о его влиянии на некоторые тонкие места работы со строками, о модуле SimpleShareMem, который можно использовать вместо ShareMem и не таскать со своей программой borlndmm.dll. Добавлен пример того, как правильно передавать строки из DLL и как оптимизировать этот процесс.
Раздел 3.4.1 идейно связан со статьёй "ПРОГРАММИСТ.Побочные эффекты при вычислении выражений с функциями". Описывается тот же эффект, но пример сделан более наглядным и исследован более детально.
Разделы 3.4.2 и 3.4.3 написаны на основе статей "VCL.Зацикливание TUpDown.OnChanging при открытии модального окна в обработчике" и "VCL.AV при закрытии формы с перекрытым методом WndProc", изменений практически нет.
Раздел 3.4.4 — это доработанная статья "WIN32.Перетирание имени оконного класса, возвращаемого GetClassInfo". Добавлено исследование того, как на описываемый эффект влияет новый менеджер памяти из BDS 2006.
Раздел 3.4.5 — это статья "VCL.Ошибка EReadError при использовании вещественных свойств" практически без изменений.
Раздел 3.4.6 — статья "VCL.List index out of bounds при корректном значении индекса", дополненная информацией о том, как в BDS 2006 решена данная проблема.
Разделы 3.4.7-3.4.10 аналогов на сайте не имеют.
Глава 4 — это доработанная статья "Введение в теорию синтаксического анализа". Более полно разобран код примеров, добавлен пример однопроходного калькулятора с лексическим анализатором, пример вычисления функции с несколькими аргументами (что у многих почему-то вызывало проблемы), появился небольшой экскурс в сторону других средств распознавания выражений.
Обнаруженные ошибки и опечатки
- с. 17, 6-ая строка снизу, вместо "или MSND" должно быть "или MSDN"
- c. 19, первая строка таблицы 1.1, в правой колонке вместо INT должно быть Integer
- c. 31, вторая строка листинга 1.2, вместо "BS_PUSBUTTON" должно быть "BS_PUSHBUTTON"
- c. 79, 2-е преложение 4-го абзаца, вместо "DDB - это Device Dependent Format" должно быть "DDB - это Device Dependent Bitmap"
- c. 105, листинг 1.27, во второй строке должно быть Form1, а не Form2
- c. 139, в предпоследней сторке примечания вместо "Поучить дескриптор объекта" должно быть "Получить дескриптор объекта".
- c. 175, последнее предложение второго снизу абзаца, вместо "начальная линии, замыкающая точка отрезка" следует читать "начальная точка отрезка, замыкающая точка отрезка".
- с. 219, рис. 2.1. В условном клиенте в ветке после "connect" в квадратах должно быть "send" и "recv", а не "socket".
- с. 282, в первом абзаце раздела 2.1.17 фразу "Существуют параметры уровня сокета, которые относятся к сокету как к объекту безотносительно используемого протокола и его уровня" следует читать "Существуют параметры уровня сокета, которые относятся к сокету как к объекту безотносительно используемого протокола, и параметры уровня протокола"
- c. 408, в первом абзаце две формулы разложения чисел по степеням двойки и десятки содержат удвоенный плюс, хотя должен быть одинарный.
- c. 412, 3-ий снизу абзац, вместо "в типах Single и Float" должно быть "в типах Single и Double".
- c. 415, 5-ая снизу строка, вместо "в виде m/2n" должно быть "в виде m/2n".
- с. 456 Листинг 3.43 должен называться не "Базовый", а "Стандартная заготовка для DLL"
- с. 499 На рисунке 499 все три петли, возвращающие в символ "Цифра", не должны иметь собственного символа "Цифра", а то получается, что допускаются последовательнсти только из нечётного числа цифр
- с. 506, 3-я снизу строка, вместо "чтобы аргументом операций сложения и умножения могли служить" следует читать "чтобы аргументами операций умножения и деления могли служить".
- с. 536, 12-ая снизу строка, вместо "Контекстно-свободные автоматы не пригодны" должно быть "Конечные автоматы не пригодны"